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' 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/README.md b/README.md index 41e5a094..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) | @@ -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). @@ -40,7 +44,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/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/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/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 0fdccce3..7321c2cc 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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/premake5.lua b/premake5.lua index b5b885b3..85f4d082 100644 --- a/premake5.lua +++ b/premake5.lua @@ -92,7 +92,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 { "system:macosx" } @@ -122,9 +125,11 @@ workspace "re3" filter { "platforms:*x86*" } architecture "x86" + floatingpoint "Fast" filter { "platforms:*amd64*" } architecture "amd64" + floatingpoint "Fast" filter { "platforms:*arm*" } architecture "ARM" @@ -184,6 +189,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 +211,9 @@ project "librw" includedirs {"/usr/local/include" } libdirs { "/opt/local/lib" } libdirs { "/usr/local/lib" } + + filter "platforms:*gl3_glfw*" + staticruntime "off" filter "platforms:*RW33*" flags { "ExcludeFromBuild" } @@ -214,6 +234,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") } @@ -236,6 +257,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" } @@ -284,9 +306,17 @@ project "re3" filter "platforms:win*" files { addSrcFiles("src/skel/win") } includedirs { "src/skel/win" } + buildoptions { "/Zc:sizedDealloc-" } linkoptions "/SAFESEH:NO" characterset ("MBCS") targetextension ".exe" + if(_OPTIONS["with-librw"]) then + -- external librw is dynamic + staticruntime "on" + end + + filter "platforms:win*glfw*" + staticruntime "off" filter "platforms:win*oal" includedirs { "vendor/openal-soft/include" } @@ -322,7 +352,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" } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..ef322a9a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,113 @@ +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" + "collision" + "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() diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp index 8c99b694..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 "RwHelper.h" +#include "MemoryMgr.h" CAnimBlendAssociation::CAnimBlendAssociation(void) { 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/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp index d40e8357..92515427 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 "MemoryMgr.h" CAnimBlendClumpData::CAnimBlendClumpData(void) diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp index feeaca3d..c7800de5 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,22 @@ 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; } + +#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 4578ec50..c958b71a 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) { @@ -15,6 +16,7 @@ CAnimBlendSequence::CAnimBlendSequence(void) CAnimBlendSequence::~CAnimBlendSequence(void) { + assert(keyFramesCompressed == nil); if(keyFrames) RwFree(keyFrames); } @@ -60,3 +62,138 @@ CAnimBlendSequence::RemoveQuaternionFlips(void) last = frame->rotation; } } + +void +CAnimBlendSequence::Uncompress(void) +{ + int i; + + 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; + 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; + } + REGISTER_MEMPTR(&keyFrames); + + RwFree(keyFramesCompressed); + keyFramesCompressed = nil; + + POP_MEMID(); +} + +void +CAnimBlendSequence::CompressKeyframes(void) +{ + int i; + + if(numFrames == 0) + return; + + PUSH_MEMID(MEMID_ANIMATION); + + 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; + } + REGISTER_MEMPTR(&keyFramesCompressed); + + POP_MEMID(); +} + +void +CAnimBlendSequence::RemoveUncompressedData(void) +{ + if(numFrames == 0) + return; + CompressKeyframes(); + RwFree(keyFrames); + 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 44ac8886..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; @@ -12,6 +16,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 +54,10 @@ 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); + bool MoveMemory(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/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 3fc9334f..7340e73e 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,12 +1925,11 @@ 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; case NEW_DOOR: - default: m_sQueueSample.m_nSampleIndex = SFX_NEW_CAR_DOOR_CLOSE; break; case TRUCK_DOOR: @@ -1939,9 +1938,16 @@ 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; +#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; @@ -1959,7 +1965,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; @@ -1975,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; @@ -2007,7 +2017,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; } @@ -2236,17 +2246,17 @@ 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; - SetupPedComments(&pedParams, SOUND_PED_HELI_PLAYER_FOUND); + 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; - SetupPedComments(&pedParams, SOUND_PED_BODYCAST_HIT); + pedParams.m_bDistanceCalculated = params.m_bDistanceCalculated; + pedParams.m_fDistance = params.m_fDistance; + SetupPedComments(pedParams, SOUND_PED_BODYCAST_HIT); continue; case SOUND_WATER_FALL: { const float SOUND_INTENSITY = 40.0f; @@ -2298,8 +2308,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) { @@ -2321,7 +2331,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) } bool -cAudioManager::ProcessTrainNoise(cVehicleParams *params) +cAudioManager::ProcessTrainNoise(cVehicleParams& params) { const float SOUND_INTENSITY = 300.0f; @@ -2329,12 +2339,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) { @@ -2360,7 +2370,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; @@ -2387,7 +2397,7 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params) } bool -cAudioManager::ProcessBoatEngine(cVehicleParams *params) +cAudioManager::ProcessBoatEngine(cVehicleParams& params) { CBoat *boat; float padRelativeAccerate; @@ -2401,10 +2411,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; @@ -2426,7 +2436,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; @@ -2465,7 +2475,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; @@ -2502,7 +2512,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; @@ -2528,22 +2538,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) { @@ -2576,7 +2586,7 @@ struct tHelicopterSampleData { }; bool -cAudioManager::ProcessHelicopter(cVehicleParams *params) +cAudioManager::ProcessHelicopter(cVehicleParams& params) { CHeli *heli; float MaxDist; @@ -2585,11 +2595,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; @@ -2626,9 +2636,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; @@ -2636,7 +2646,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; } } @@ -2652,14 +2662,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) { @@ -2955,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; @@ -3011,36 +3021,36 @@ 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; + bool narrowSoundRange; int16 sound; - bool noReflection; + bool stereo; CWeapon *weapon; float maxDist = 0.f; // uninitialized variable 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; + narrowSoundRange = false; m_sQueueSample.m_bRequireReflection = false; sound = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i]; 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; @@ -3084,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; @@ -3142,229 +3152,54 @@ 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; + narrowSoundRange = true; ++iSound; m_sQueueSample.m_nReleasingVolumeModificator = 3; m_sQueueSample.m_fSpeedMultiplier = 0.0f; @@ -3383,7 +3218,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3399,7 +3234,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case SOUND_WEAPON_SHOT_FIRED: weapon = ped->GetWeapon(); @@ -3408,7 +3243,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3425,13 +3260,13 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3450,7 +3285,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3467,13 +3302,13 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3492,7 +3327,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3511,7 +3346,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3528,13 +3363,13 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3551,7 +3386,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case WEAPONTYPE_FLAMETHROWER: m_sQueueSample.m_nSampleIndex = SFX_FLAMETHROWER_LEFT; @@ -3573,7 +3408,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; default: continue; @@ -3616,7 +3451,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) } 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; @@ -3637,7 +3472,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3654,7 +3489,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3678,7 +3513,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3697,7 +3532,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) 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; @@ -3717,23 +3552,23 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) continue; } - if (stereo && iSound > 60) + if (narrowSoundRange && 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) { + 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 || @@ -3752,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; @@ -3805,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: @@ -3992,15 +3827,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 +3848,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 +3872,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 +3896,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 +3920,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 +3946,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 +3962,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 +3996,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 +4033,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 +4053,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 +4087,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 +4121,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 +4158,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 +4199,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 +4233,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 +4267,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 +4301,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 +4340,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 +4372,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 +4404,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 +4437,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 +4460,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 +4479,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 +4510,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 +4547,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 +4584,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 +4621,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 +4655,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 +4689,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 +4723,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 +4754,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 +4788,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 +4822,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 +4856,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 +4890,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 +4921,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 +4952,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 +4986,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 +5017,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 +5048,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 +5079,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 +5110,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 +5147,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 +5178,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 +5209,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 +5240,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 +5280,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 +5317,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 +5357,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 +5394,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 +5428,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 +5459,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 +5487,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 +5512,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 +5546,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 +5571,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 +5599,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 +5621,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 +5655,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 +5689,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 +5726,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 +5760,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 +5837,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 +5862,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 +5887,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 +5929,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 +5945,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 +5981,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 +5998,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 +6024,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; @@ -6539,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: @@ -7924,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 40a2d056..d781ad71 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, @@ -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; @@ -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 ProcessPedHeadphones(cPedParams ¶ms); + void ProcessPedOneShots(cPedParams ¶ms); 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; @@ -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(); diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 0663bbd9..2514d963 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)); #ifdef FIX_BUGS 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/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 { 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/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..fb90e7dd --- /dev/null +++ b/src/collision/ColModel.cpp @@ -0,0 +1,190 @@ +#include "common.h" +#include "ColModel.h" +#include "Game.h" +#include "MemoryHeap.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) +{ + 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 +CColModel::RemoveTrianglePlanes(void) +{ + RwFree(trianglePlanes); + trianglePlanes = nil; +} + +void +CColModel::SetLinkPtr(CLink *lptr) +{ + assert(trianglePlanes); + *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; +} + +CLink* +CColModel::GetLinkPtr(void) +{ + assert(trianglePlanes); + return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); +} + +void +CColModel::GetTrianglePoint(CVector &v, int i) const +{ + v = vertices[i].Get(); +} + +CColModel& +CColModel::operator=(const CColModel &other) +{ + int i; + int numVerts; + + boundingSphere = other.boundingSphere; + boundingBox = other.boundingBox; + + // copy spheres + if(other.numSpheres){ + if(numSpheres != other.numSpheres){ + numSpheres = other.numSpheres; + if(spheres) + RwFree(spheres); + spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); + } + for(i = 0; i < numSpheres; i++) + spheres[i] = other.spheres[i]; + }else{ + numSpheres = 0; + if(spheres) + RwFree(spheres); + spheres = nil; + } + + // copy lines + if(other.numLines){ + if(numLines != other.numLines){ + numLines = other.numLines; + if(lines) + RwFree(lines); + lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); + } + for(i = 0; i < numLines; i++) + lines[i] = other.lines[i]; + }else{ + numLines = 0; + if(lines) + RwFree(lines); + lines = nil; + } + + // copy boxes + if(other.numBoxes){ + if(numBoxes != other.numBoxes){ + numBoxes = other.numBoxes; + if(boxes) + RwFree(boxes); + boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); + } + for(i = 0; i < numBoxes; i++) + boxes[i] = other.boxes[i]; + }else{ + numBoxes = 0; + if(boxes) + RwFree(boxes); + boxes = nil; + } + + // copy mesh + if(other.numTriangles){ + // copy vertices + numVerts = 0; + for(i = 0; i < other.numTriangles; i++){ + if(other.triangles[i].a > numVerts) + numVerts = other.triangles[i].a; + if(other.triangles[i].b > numVerts) + numVerts = other.triangles[i].b; + if(other.triangles[i].c > numVerts) + numVerts = other.triangles[i].c; + } + numVerts++; + if(vertices) + RwFree(vertices); + if(numVerts){ + vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); + for(i = 0; i < numVerts; i++) + vertices[i] = other.vertices[i]; + } + + // copy triangles + if(numTriangles != other.numTriangles){ + numTriangles = other.numTriangles; + if(triangles) + RwFree(triangles); + triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); + } + for(i = 0; i < numTriangles; i++) + triangles[i] = other.triangles[i]; + }else{ + numTriangles = 0; + if(triangles) + RwFree(triangles); + triangles = nil; + if(vertices) + RwFree(vertices); + vertices = nil; + } + return *this; +} diff --git a/src/collision/ColModel.h b/src/collision/ColModel.h new file mode 100644 index 00000000..7dcdfa4d --- /dev/null +++ b/src/collision/ColModel.h @@ -0,0 +1,37 @@ +#pragma once + +#include "templates.h" +#include "ColBox.h" +#include "ColSphere.h" +#include "ColLine.h" +#include "ColPoint.h" +#include "ColTriangle.h" + +struct CColModel +{ + CColSphere boundingSphere; + CColBox boundingBox; + int16 numSpheres; + int16 numLines; + int16 numBoxes; + int16 numTriangles; + int32 level; + bool ownsCollisionVolumes; // missing on PS2 + CColSphere *spheres; + CColLine *lines; + CColBox *boxes; + CompressedVector *vertices; + CColTriangle *triangles; + CColTrianglePlane *trianglePlanes; + + CColModel(void); + ~CColModel(void); + void RemoveCollisionVolumes(void); + void CalculateTrianglePlanes(void); + void RemoveTrianglePlanes(void); + CLink *GetLinkPtr(void); + void SetLinkPtr(CLink*); + void GetTrianglePoint(CVector &v, int i) const; + + CColModel& operator=(const CColModel& other); +}; \ No newline at end of file diff --git a/src/collision/ColPoint.cpp b/src/collision/ColPoint.cpp new file mode 100644 index 00000000..fbf9e8c3 --- /dev/null +++ b/src/collision/ColPoint.cpp @@ -0,0 +1,16 @@ +#include "common.h" +#include "ColPoint.h" + +CColPoint& +CColPoint::operator=(const CColPoint &other) +{ + point = other.point; + normal = other.normal; + surfaceA = other.surfaceA; + pieceA = other.pieceA; + surfaceB = other.surfaceB; + pieceB = other.pieceB; + + // no depth? + return *this; +} diff --git a/src/collision/ColPoint.h b/src/collision/ColPoint.h new file mode 100644 index 00000000..a15b2345 --- /dev/null +++ b/src/collision/ColPoint.h @@ -0,0 +1,34 @@ +#pragma once + +struct CColPoint +{ + CVector point; + int pad1; + // the surface normal on the surface of point + CVector normal; + int pad2; + uint8 surfaceA; + uint8 pieceA; + uint8 surfaceB; + uint8 pieceB; + float depth; + + const CVector &GetNormal() { return normal; } + float GetDepth() { return depth; } + void Set(float depth, uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->depth = depth; + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + void Set(uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + + CColPoint &operator=(const CColPoint &other); +}; + diff --git a/src/collision/ColSphere.cpp b/src/collision/ColSphere.cpp new file mode 100644 index 00000000..9aac01e0 --- /dev/null +++ b/src/collision/ColSphere.cpp @@ -0,0 +1,11 @@ +#include "common.h" +#include "ColSphere.h" + +void +CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) +{ + this->radius = radius; + this->center = center; + this->surface = surf; + this->piece = piece; +} \ No newline at end of file diff --git a/src/collision/ColSphere.h b/src/collision/ColSphere.h new file mode 100644 index 00000000..70e29763 --- /dev/null +++ b/src/collision/ColSphere.h @@ -0,0 +1,13 @@ +#pragma once + +#include "SurfaceTable.h" + +struct CColSphere +{ + // NB: this has to be compatible with a CVuVector + CVector center; + float radius; + uint8 surface; + uint8 piece; + void Set(float radius, const CVector ¢er, uint8 surf = SURFACE_DEFAULT, uint8 piece = 0); +}; \ No newline at end of file diff --git a/src/collision/ColTriangle.cpp b/src/collision/ColTriangle.cpp new file mode 100644 index 00000000..9120fcff --- /dev/null +++ b/src/collision/ColTriangle.cpp @@ -0,0 +1,41 @@ +#include "common.h" +#include "ColTriangle.h" + +void +CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) +{ + this->a = a; + this->b = b; + this->c = c; + this->surface = surf; +} + +#ifdef VU_COLLISION +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + CVector norm = CrossProduct(vc-va, vb-va); + norm.Normalise(); + float d = DotProduct(norm, va); + normal.x = norm.x*4096.0f; + normal.y = norm.y*4096.0f; + normal.z = norm.z*4096.0f; + dist = d*128.0f; +} +#else +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + normal = CrossProduct(vc-va, vb-va); + normal.Normalise(); + dist = DotProduct(normal, va); + CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); + // find out largest component and its direction + if(an.x > an.y && an.x > an.z) + dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; + else if(an.y > an.z) + dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; + else + dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; +} +#endif \ No newline at end of file diff --git a/src/collision/ColTriangle.h b/src/collision/ColTriangle.h new file mode 100644 index 00000000..9e918e38 --- /dev/null +++ b/src/collision/ColTriangle.h @@ -0,0 +1,68 @@ +#pragma once + +#include "CompressedVector.h" + +enum Direction { + DIR_X_POS, + DIR_X_NEG, + DIR_Y_POS, + DIR_Y_NEG, + DIR_Z_POS, + DIR_Z_NEG, +}; + +struct CColTriangle +{ + uint16 a; + uint16 b; + uint16 c; + uint8 surface; + + void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece); +}; + +struct CColTrianglePlane +{ +#ifdef VU_COLLISION + CompressedVector normal; + int16 dist; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n.x = normal.x/4096.0f; n.y = normal.y/4096.0f; n.z = normal.z/4096.0f; } + float CalcPoint(const CVector &v) const { CVector n; GetNormal(n); return DotProduct(n, v) - dist/128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "lh $11, 6(%1)\n" + "pextlw $10, $8\n" + "pextlw $11, $9\n" + "pextlw $2, $11, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$11", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = normal.x; + qword[1] = normal.y; + qword[2] = normal.z; + qword[3] = dist; + } +#endif +#else + CVector normal; + float dist; + uint8 dir; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n = normal; } + float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; +#endif +}; \ No newline at end of file diff --git a/src/core/Collision.cpp b/src/collision/Collision.cpp similarity index 86% rename from src/core/Collision.cpp rename to src/collision/Collision.cpp index d8603cd8..41997e32 100644 --- a/src/core/Collision.cpp +++ b/src/collision/Collision.cpp @@ -23,303 +23,8 @@ #include "Collision.h" #include "Frontend.h" - -// TODO: where do these go? - #ifdef VU_COLLISION - -struct VuTriangle -{ - // Compressed int16 but unpacked -#ifdef GTA_PS2 - uint128 v0; - uint128 v1; - uint128 v2; - uint128 plane; -#else - int32 v0[4]; - int32 v1[4]; - int32 v2[4]; - int32 plane[4]; -#endif -}; - -#ifndef GTA_PS2 -static int16 vi01; -static CVuVector vf01; -static CVuVector vf02; -static CVuVector vf03; - -CVuVector -DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) -{ - // center VF12 - // p0 VF14 - // line VF15 - CVuVector ret; // VF16 - CVuVector p1 = p0+line; - CVuVector dist0 = center - p0; // VF20 - CVuVector dist1 = center - p1; // VF25 - float lenSq = line.MagnitudeSqr(); // VF21 - float distSq0 = dist0.MagnitudeSqr(); // VF22 - float distSq1 = dist1.MagnitudeSqr(); - float dot = DotProduct(dist0, line); // VF23 - if(dot < 0.0f){ - // not above line, closest to p0 - ret = p0; - ret.w = distSq0; - return ret; - } - float t = dot/lenSq; // param of nearest point on infinite line - if(t > 1.0f){ - // not above line, closest to p1 - ret = p1; - ret.w = distSq1; - return ret; - } - // closest to line - ret = p0 + line*t; - ret.w = (ret - center).MagnitudeSqr(); - return ret; -} -inline int SignFlags(const CVector &v) -{ - int f = 0; - if(v.x < 0.0f) f |= 1; - if(v.y < 0.0f) f |= 2; - if(v.z < 0.0f) f |= 4; - return f; -} -#endif - -extern "C" void -LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x0(%3)\n" - "lqc2 vf16, 0x0(%4)\n" - "lqc2 vf17, 0x0(%5)\n" - "vcallms Vu0LineToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float dot0 = DotProduct(plane, p0); - float dot1 = DotProduct(plane, p1); - float dist0 = plane.w - dot0; - float dist1 = plane.w - dot1; - - // if points are on the same side, no collision - if(dist0 * dist1 > 0.0f){ - vi01 = 0; - return; - } - - CVuVector diff = p1 - p0; - float t = dist0/(dot1 - dot0); - CVuVector p = p0 + diff*t; - p.w = 0.0f; - vf01 = p; - vf03.x = t; - - // Check if point is inside - CVector cross1 = CrossProduct(p-v0, v1-v0); - CVector cross2 = CrossProduct(p-v1, v2-v1); - CVector cross3 = CrossProduct(p-v2, v0-v2); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.5f) flagmask |= 1; - if(Abs(plane.y) > 0.5f) flagmask |= 2; - if(Abs(plane.z) > 0.5f) flagmask |= 4; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - // inside if on the same side of all edges - if(flags1 != flags2 || flags1 != flags3){ - vi01 = 0; - return; - } - vi01 = 1; - vf02 = plane; - return; -#endif -} - -extern "C" void -LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x10(%2)\n" - "lqc2 vf16, 0x20(%2)\n" - "lqc2 vf17, 0x30(%2)\n" - "vcallms Vu0LineToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - LineToTriangleCollision(p0, p1, v0, v1, v2, plane); -#endif -} - -extern "C" void -SphereToTriangleCollision(const CVuVector &sph, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x0(%2)\n" - "lqc2 vf16, 0x0(%3)\n" - "lqc2 vf17, 0x0(%4)\n" - "vcallms Vu0SphereToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float planedist = DotProduct(plane, sph) - plane.w; // VF02 - if(Abs(planedist) > sph.w){ - vi01 = 0; - return; - } - // point on plane - CVuVector p = sph - planedist*plane; - p.w = 0.0f; - vf01 = p; - planedist = Abs(planedist); - // edges - CVuVector v01 = v1 - v0; - CVuVector v12 = v2 - v1; - CVuVector v20 = v0 - v2; - // VU code calculates normal again for some weird reason... - // Check sides of point - CVector cross1 = CrossProduct(p-v0, v01); - CVector cross2 = CrossProduct(p-v1, v12); - CVector cross3 = CrossProduct(p-v2, v20); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.1f) flagmask |= 1; - if(Abs(plane.y) > 0.1f) flagmask |= 2; - if(Abs(plane.z) > 0.1f) flagmask |= 4; - int nflags = SignFlags(plane) & flagmask; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - int testcase = 0; - CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 - if(flags1 == nflags){ - closest += v2; - testcase++; - } - if(flags2 == nflags){ - closest += v0; - testcase++; - } - if(flags3 == nflags){ - closest += v1; - testcase++; - } - if(testcase == 3){ - // inside triangle - dist to plane already checked - vf02 = plane; - vf02.w = vf03.x = planedist; - vi01 = 1; - }else if(testcase == 1){ - // outside two sides - closest to point opposide inside edge - vf01 = closest; - vf02 = sph - closest; - float distSq = vf02.MagnitudeSqr(); - vi01 = sph.w*sph.w > distSq; - vf03.x = Sqrt(distSq); - vf02 *= 1.0f/vf03.x; - }else{ - // inside two sides - closest to third edge - if(flags1 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v0, v01); - else if(flags2 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v1, v12); - else - closest = DistanceBetweenSphereAndLine(sph, v2, v20); - vi01 = sph.w*sph.w > closest.w; - vf01 = closest; - vf02 = sph - closest; - vf03.x = Sqrt(closest.w); - vf02 *= 1.0f/vf03.x; - } -#endif -} - -extern "C" void -SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x10(%1)\n" - "lqc2 vf16, 0x20(%1)\n" - "lqc2 vf17, 0x30(%1)\n" - "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - SphereToTriangleCollision(sph, v0, v1, v2, plane); -#endif -} +#include "VuCollision.h" inline int GetVUresult(void) @@ -362,17 +67,6 @@ GetVUresult(CVuVector &point, CVuVector &normal, float &dist) #endif - -enum Direction -{ - DIR_X_POS, - DIR_X_NEG, - DIR_Y_POS, - DIR_Y_NEG, - DIR_Z_POS, - DIR_Z_NEG, -}; - eLevelName CCollision::ms_collisionInMemory; CLinkList CCollision::ms_colModelCache; @@ -2412,11 +2106,12 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, assert(modelA.numLines <= MAXNUMLINES); // From model A space to model B space - Invert(matrixB, matAB); + matAB = Invert(matrixB, matAB); matAB *= matrixA; CColSphere bsphereAB; // bounding sphere of A in B space - bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); + bsphereAB.radius = modelA.boundingSphere.radius; + bsphereAB.center = matAB * modelA.boundingSphere.center; if(!TestSphereBox(bsphereAB, modelB.boundingBox)) return 0; // B to A space @@ -2449,7 +2144,8 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, int numBoxesB = 0; int numTrianglesB = 0; for(i = 0; i < modelB.numSpheres; i++){ - s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); + s.radius = modelB.spheres[i].radius; + s.center = matBA * modelB.spheres[i].center; if(TestSphereBox(s, modelA.boundingBox)) aSphereIndicesB[numSpheresB++] = i; } @@ -3037,254 +2733,4 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - - -/* - * ColModel code - */ - -void -CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) -{ - this->radius = radius; - this->center = center; - this->surface = surf; - this->piece = piece; -} - -void -CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) -{ - this->min = min; - this->max = max; - this->surface = surf; - this->piece = piece; -} - -void -CColLine::Set(const CVector &p0, const CVector &p1) -{ - this->p0 = p0; - this->p1 = p1; -} - -void -CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) -{ - this->a = a; - this->b = b; - this->c = c; - this->surface = surf; -} - -#ifdef VU_COLLISION -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - CVector norm = CrossProduct(vc-va, vb-va); - norm.Normalise(); - float d = DotProduct(norm, va); - normal.x = norm.x*4096.0f; - normal.y = norm.y*4096.0f; - normal.z = norm.z*4096.0f; - dist = d*128.0f; -} -#else -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - normal = CrossProduct(vc-va, vb-va); - normal.Normalise(); - dist = DotProduct(normal, va); - CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); - // find out largest component and its direction - if(an.x > an.y && an.x > an.z) - dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; - else if(an.y > an.z) - dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; - else - dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; -} -#endif - -CColModel::CColModel(void) -{ - numSpheres = 0; - spheres = nil; - numLines = 0; - lines = nil; - numBoxes = 0; - boxes = nil; - numTriangles = 0; - vertices = nil; - triangles = nil; - trianglePlanes = nil; - level = CGame::currLevel; - ownsCollisionVolumes = true; -} - -CColModel::~CColModel(void) -{ - RemoveCollisionVolumes(); - RemoveTrianglePlanes(); -} - -void -CColModel::RemoveCollisionVolumes(void) -{ - if(ownsCollisionVolumes){ - RwFree(spheres); - RwFree(lines); - RwFree(boxes); - RwFree(vertices); - RwFree(triangles); - } - numSpheres = 0; - numLines = 0; - numBoxes = 0; - numTriangles = 0; - spheres = nil; - lines = nil; - boxes = nil; - vertices = nil; - triangles = nil; -} - -void -CColModel::CalculateTrianglePlanes(void) -{ - // HACK: allocate space for one more element to stuff the link pointer into - trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); - for(int i = 0; i < numTriangles; i++) - trianglePlanes[i].Set(vertices, triangles[i]); -} - -void -CColModel::RemoveTrianglePlanes(void) -{ - RwFree(trianglePlanes); - trianglePlanes = nil; -} - -void -CColModel::SetLinkPtr(CLink *lptr) -{ - assert(trianglePlanes); - *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; -} - -CLink* -CColModel::GetLinkPtr(void) -{ - assert(trianglePlanes); - return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); -} - -void -CColModel::GetTrianglePoint(CVector &v, int i) const -{ - v = vertices[i].Get(); -} - -CColModel& -CColModel::operator=(const CColModel &other) -{ - int i; - int numVerts; - - boundingSphere = other.boundingSphere; - boundingBox = other.boundingBox; - - // copy spheres - if(other.numSpheres){ - if(numSpheres != other.numSpheres){ - numSpheres = other.numSpheres; - if(spheres) - RwFree(spheres); - spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); - } - for(i = 0; i < numSpheres; i++) - spheres[i] = other.spheres[i]; - }else{ - numSpheres = 0; - if(spheres) - RwFree(spheres); - spheres = nil; - } - - // copy lines - if(other.numLines){ - if(numLines != other.numLines){ - numLines = other.numLines; - if(lines) - RwFree(lines); - lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); - } - for(i = 0; i < numLines; i++) - lines[i] = other.lines[i]; - }else{ - numLines = 0; - if(lines) - RwFree(lines); - lines = nil; - } - - // copy boxes - if(other.numBoxes){ - if(numBoxes != other.numBoxes){ - numBoxes = other.numBoxes; - if(boxes) - RwFree(boxes); - boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); - } - for(i = 0; i < numBoxes; i++) - boxes[i] = other.boxes[i]; - }else{ - numBoxes = 0; - if(boxes) - RwFree(boxes); - boxes = nil; - } - - // copy mesh - if(other.numTriangles){ - // copy vertices - numVerts = 0; - for(i = 0; i < other.numTriangles; i++){ - if(other.triangles[i].a > numVerts) - numVerts = other.triangles[i].a; - if(other.triangles[i].b > numVerts) - numVerts = other.triangles[i].b; - if(other.triangles[i].c > numVerts) - numVerts = other.triangles[i].c; - } - numVerts++; - if(vertices) - RwFree(vertices); - if(numVerts){ - vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); - for(i = 0; i < numVerts; i++) - vertices[i] = other.vertices[i]; - } - - // copy triangles - if(numTriangles != other.numTriangles){ - numTriangles = other.numTriangles; - if(triangles) - RwFree(triangles); - triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); - } - for(i = 0; i < numTriangles; i++) - triangles[i] = other.triangles[i]; - }else{ - numTriangles = 0; - if(triangles) - RwFree(triangles); - triangles = nil; - if(vertices) - RwFree(vertices); - vertices = nil; - } - return *this; -} +} \ No newline at end of file diff --git a/src/collision/Collision.h b/src/collision/Collision.h new file mode 100644 index 00000000..f4270bc5 --- /dev/null +++ b/src/collision/Collision.h @@ -0,0 +1,70 @@ +#pragma once + +#include "ColModel.h" +#include "Game.h" // for eLevelName +#ifdef VU_COLLISION +#include "VuVector.h" +#endif + +struct CStoredCollPoly +{ +#ifdef VU_COLLISION + CVuVector verts[3]; +#else + CVector verts[3]; +#endif + bool valid; +}; + +// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32. +#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE) +#define MAX_COLLISION_POINTS 64 +#else +#define MAX_COLLISION_POINTS 32 +#endif + +class CCollision +{ +public: + static eLevelName ms_collisionInMemory; + static CLinkList ms_colModelCache; +#ifdef NO_ISLAND_LOADING + static bool bAlreadyLoaded; +#endif + + static void Init(void); + static void Shutdown(void); + static void Update(void); + static void LoadCollisionWhenINeedIt(bool changeLevel); + static void SortOutCollisionAfterLoad(void); + static void LoadCollisionScreen(eLevelName level); + static void DrawColModel(const CMatrix &mat, const CColModel &colModel); + static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); + + static void CalculateTrianglePlanes(CColModel *model); + + // all these return true if there's a collision + static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); + static bool TestSphereBox(const CColSphere &sph, const CColBox &box); + static bool TestLineBox(const CColLine &line, const CColBox &box); + static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); + static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineSphere(const CColLine &line, const CColSphere &sph); + static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); + + static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); + static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); + static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); + static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); + static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); + static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); + static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); + static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); + static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); + static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); + static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly); + + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); +}; diff --git a/src/collision/CompressedVector.h b/src/collision/CompressedVector.h new file mode 100644 index 00000000..d54e49b1 --- /dev/null +++ b/src/collision/CompressedVector.h @@ -0,0 +1,36 @@ +#pragma once + +struct CompressedVector +{ +#ifdef COMPRESSED_COL_VECTORS + int16 x, y, z; + CVector Get(void) const { return CVector(x, y, z)/128.0f; }; + void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "pextlw $10, $8\n" + "pextlw $2, $9, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = x; + qword[1] = y; + qword[2] = z; + qword[3] = 0; // junk + } +#endif +#else + float x, y, z; + CVector Get(void) const { return CVector(x, y, z); }; + void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; }; +#endif +}; \ No newline at end of file diff --git a/src/core/TempColModels.cpp b/src/collision/TempColModels.cpp similarity index 89% rename from src/core/TempColModels.cpp rename to src/collision/TempColModels.cpp index f6796909..dabb6ebb 100644 --- a/src/core/TempColModels.cpp +++ b/src/collision/TempColModels.cpp @@ -1,7 +1,6 @@ #include "common.h" #include "TempColModels.h" -#include "SurfaceTable.h" CColModel CTempColModels::ms_colModelPed1; CColModel CTempColModels::ms_colModelPed2; @@ -41,17 +40,17 @@ CTempColModels::Initialise(void) colmodel.numSpheres = ARRAY_SIZE(sphrs);\ colmodel.spheres = sphrs;\ colmodel.level = LEVEL_GENERIC;\ - colmodel.ownsCollisionVolumes = false;\ + 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.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); ms_colModelBBox.level = LEVEL_GENERIC; for (i = 0; i < ARRAY_SIZE(ms_colModelCutObj); i++) { - ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); + ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); ms_colModelCutObj[i].level = LEVEL_GENERIC; } @@ -73,8 +72,8 @@ CTempColModels::Initialise(void) s_aPedSpheres[i].piece = 0; } - ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f), SURFACE_DEFAULT, 0); + ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f)); SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); // Ped 2 Spheres @@ -92,8 +91,8 @@ CTempColModels::Initialise(void) s_aPed2Spheres[i].piece = 0; } - ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f)); SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); @@ -118,8 +117,8 @@ CTempColModels::Initialise(void) s_aPedGSpheres[2].piece = 0; s_aPedGSpheres[3].piece = 6; - ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f), SURFACE_DEFAULT, 0); + ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f)); SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); @@ -142,8 +141,8 @@ CTempColModels::Initialise(void) s_aDoorSpheres[i].piece = 0; } - ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f), SURFACE_DEFAULT, 0); + ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f)); SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); @@ -162,8 +161,8 @@ CTempColModels::Initialise(void) s_aBumperSpheres[i].piece = 0; } - ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f), SURFACE_DEFAULT, 0); + ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f)); SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); @@ -182,8 +181,8 @@ CTempColModels::Initialise(void) s_aPanelSpheres[i].piece = 0; } - ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f), SURFACE_DEFAULT, 0); + ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f)); SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); @@ -202,8 +201,8 @@ CTempColModels::Initialise(void) s_aBonnetSpheres[i].piece = 0; } - ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f)); + ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); @@ -222,8 +221,8 @@ CTempColModels::Initialise(void) s_aBootSpheres[i].piece = 0; } - ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f)); + ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); @@ -244,8 +243,8 @@ CTempColModels::Initialise(void) s_aWheelSpheres[i].piece = 0; } - ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f), SURFACE_DEFAULT, 0); + ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f)); SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); @@ -266,8 +265,8 @@ CTempColModels::Initialise(void) s_aBodyPartSpheres1[i].piece = 0; } - ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f)); + ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); @@ -288,8 +287,8 @@ CTempColModels::Initialise(void) s_aBodyPartSpheres2[i].piece = 0; } - ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f)); + ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f)); SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); diff --git a/src/core/TempColModels.h b/src/collision/TempColModels.h similarity index 100% rename from src/core/TempColModels.h rename to src/collision/TempColModels.h diff --git a/src/collision/VuCollision.cpp b/src/collision/VuCollision.cpp new file mode 100644 index 00000000..8828d2e1 --- /dev/null +++ b/src/collision/VuCollision.cpp @@ -0,0 +1,282 @@ +#include "common.h" +#ifdef VU_COLLISION +#include "VuVector.h" +#include "VuCollision.h" + +#ifndef GTA_PS2 +int16 vi01; +CVuVector vf01; +CVuVector vf02; +CVuVector vf03; + +CVuVector +DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) +{ + // center VF12 + // p0 VF14 + // line VF15 + CVuVector ret; // VF16 + CVuVector p1 = p0+line; + CVuVector dist0 = center - p0; // VF20 + CVuVector dist1 = center - p1; // VF25 + float lenSq = line.MagnitudeSqr(); // VF21 + float distSq0 = dist0.MagnitudeSqr(); // VF22 + float distSq1 = dist1.MagnitudeSqr(); + float dot = DotProduct(dist0, line); // VF23 + if(dot < 0.0f){ + // not above line, closest to p0 + ret = p0; + ret.w = distSq0; + return ret; + } + float t = dot/lenSq; // param of nearest point on infinite line + if(t > 1.0f){ + // not above line, closest to p1 + ret = p1; + ret.w = distSq1; + return ret; + } + // closest to line + ret = p0 + line*t; + ret.w = (ret - center).MagnitudeSqr(); + return ret; +} +inline int SignFlags(const CVector &v) +{ + int f = 0; + if(v.x < 0.0f) f |= 1; + if(v.y < 0.0f) f |= 2; + if(v.z < 0.0f) f |= 4; + return f; +} +#endif + +extern "C" void +LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x0(%3)\n" + "lqc2 vf16, 0x0(%4)\n" + "lqc2 vf17, 0x0(%5)\n" + "vcallms Vu0LineToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float dot0 = DotProduct(plane, p0); + float dot1 = DotProduct(plane, p1); + float dist0 = plane.w - dot0; + float dist1 = plane.w - dot1; + + // if points are on the same side, no collision + if(dist0 * dist1 > 0.0f){ + vi01 = 0; + return; + } + + CVuVector diff = p1 - p0; + float t = dist0/(dot1 - dot0); + CVuVector p = p0 + diff*t; + p.w = 0.0f; + vf01 = p; + vf03.x = t; + + // Check if point is inside + CVector cross1 = CrossProduct(p-v0, v1-v0); + CVector cross2 = CrossProduct(p-v1, v2-v1); + CVector cross3 = CrossProduct(p-v2, v0-v2); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.5f) flagmask |= 1; + if(Abs(plane.y) > 0.5f) flagmask |= 2; + if(Abs(plane.z) > 0.5f) flagmask |= 4; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + // inside if on the same side of all edges + if(flags1 != flags2 || flags1 != flags3){ + vi01 = 0; + return; + } + vi01 = 1; + vf02 = plane; + return; +#endif +} + +extern "C" void +LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x10(%2)\n" + "lqc2 vf16, 0x20(%2)\n" + "lqc2 vf17, 0x30(%2)\n" + "vcallms Vu0LineToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + LineToTriangleCollision(p0, p1, v0, v1, v2, plane); +#endif +} + +extern "C" void +SphereToTriangleCollision(const CVuVector &sph, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x0(%2)\n" + "lqc2 vf16, 0x0(%3)\n" + "lqc2 vf17, 0x0(%4)\n" + "vcallms Vu0SphereToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float planedist = DotProduct(plane, sph) - plane.w; // VF02 + if(Abs(planedist) > sph.w){ + vi01 = 0; + return; + } + // point on plane + CVuVector p = sph - planedist*plane; + p.w = 0.0f; + vf01 = p; + planedist = Abs(planedist); + // edges + CVuVector v01 = v1 - v0; + CVuVector v12 = v2 - v1; + CVuVector v20 = v0 - v2; + // VU code calculates normal again for some weird reason... + // Check sides of point + CVector cross1 = CrossProduct(p-v0, v01); + CVector cross2 = CrossProduct(p-v1, v12); + CVector cross3 = CrossProduct(p-v2, v20); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.1f) flagmask |= 1; + if(Abs(plane.y) > 0.1f) flagmask |= 2; + if(Abs(plane.z) > 0.1f) flagmask |= 4; + int nflags = SignFlags(plane) & flagmask; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + int testcase = 0; + CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 + if(flags1 == nflags){ + closest += v2; + testcase++; + } + if(flags2 == nflags){ + closest += v0; + testcase++; + } + if(flags3 == nflags){ + closest += v1; + testcase++; + } + if(testcase == 3){ + // inside triangle - dist to plane already checked + vf02 = plane; + vf02.w = vf03.x = planedist; + vi01 = 1; + }else if(testcase == 1){ + // outside two sides - closest to point opposide inside edge + vf01 = closest; + vf02 = sph - closest; + float distSq = vf02.MagnitudeSqr(); + vi01 = sph.w*sph.w > distSq; + vf03.x = Sqrt(distSq); + vf02 *= 1.0f/vf03.x; + }else{ + // inside two sides - closest to third edge + if(flags1 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v0, v01); + else if(flags2 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v1, v12); + else + closest = DistanceBetweenSphereAndLine(sph, v2, v20); + vi01 = sph.w*sph.w > closest.w; + vf01 = closest; + vf02 = sph - closest; + vf03.x = Sqrt(closest.w); + vf02 *= 1.0f/vf03.x; + } +#endif +} + +extern "C" void +SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x10(%1)\n" + "lqc2 vf16, 0x20(%1)\n" + "lqc2 vf17, 0x30(%1)\n" + "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + SphereToTriangleCollision(sph, v0, v1, v2, plane); +#endif +} +#endif \ No newline at end of file diff --git a/src/collision/VuCollision.h b/src/collision/VuCollision.h new file mode 100644 index 00000000..29ca4cbf --- /dev/null +++ b/src/collision/VuCollision.h @@ -0,0 +1,32 @@ +#pragma once + + +struct VuTriangle +{ + // Compressed int16 but unpacked +#ifdef GTA_PS2 + uint128 v0; + uint128 v1; + uint128 v2; + uint128 plane; +#else + int32 v0[4]; + int32 v1[4]; + int32 v2[4]; + int32 plane[4]; +#endif +}; + +#ifndef GTA_PS2 +extern int16 vi01; +extern CVuVector vf01; +extern CVuVector vf02; +extern CVuVector vf03; +#endif + +extern "C" { +void LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri); +void SphereToTriangleCollision(const CVuVector &sph, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri); +} diff --git a/src/core/vu0Collision.dsm b/src/collision/vu0Collision.dsm similarity index 100% rename from src/core/vu0Collision.dsm rename to src/collision/vu0Collision.dsm diff --git a/src/core/vu0Collision_1.s b/src/collision/vu0Collision_1.s similarity index 100% rename from src/core/vu0Collision_1.s rename to src/collision/vu0Collision_1.s diff --git a/src/core/vu0Collision_2.s b/src/collision/vu0Collision_2.s similarity index 100% rename from src/core/vu0Collision_2.s rename to src/collision/vu0Collision_2.s diff --git a/src/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)){ 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/control/Garages.cpp b/src/control/Garages.cpp index ab7024c7..c70d9592 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; @@ -1045,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()) >= @@ -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; @@ -1260,9 +1261,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 +1272,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) @@ -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 } } } @@ -1419,34 +1422,7 @@ void CGarages::PrintMessages() 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) { -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(2.0f), TheText.Get(MessageIDString)); -#else - CFont::PrintString(SCREEN_WIDTH / 2 - 2.0f, y_offset - 2.0f, TheText.Get(MessageIDString)); -#endif - 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); -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); -#else - CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f, y_offset - 40.0f + 2.0f, gUString); -#endif - - CFont::SetColor(CRGBA(89, 115, 150, 255)); - -#ifdef FIX_BUGS - CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); -#else - CFont::PrintString(SCREEN_WIDTH / 2, y_offset - 40.0f, gUString); -#endif - } - } - else { + if (MessageNumberInString2 >= 0) { CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, MessageNumberInString2, -1, -1, -1, -1, gUString); #ifdef FIX_BUGS CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); @@ -1460,6 +1436,31 @@ void CGarages::PrintMessages() CFont::PrintString(SCREEN_WIDTH / 2, y_offset - 40.0f, gUString); #endif } + else if (MessageNumberInString >= 0) { + CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, -1, -1, -1, -1, -1, gUString); +#ifdef FIX_BUGS + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); +#else + CFont::PrintString(SCREEN_WIDTH / 2 + 2.0f, y_offset - 40.0f + 2.0f, gUString); +#endif + + CFont::SetColor(CRGBA(89, 115, 150, 255)); + +#ifdef FIX_BUGS + CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); +#else + CFont::PrintString(SCREEN_WIDTH / 2, y_offset - 40.0f, gUString); +#endif + } + else { +#ifdef FIX_BUGS + CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(2.0f), TheText.Get(MessageIDString)); +#else + CFont::PrintString(SCREEN_WIDTH / 2 - 2.0f, y_offset - 2.0f, TheText.Get(MessageIDString)); +#endif + CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::PrintString(SCREEN_WIDTH / 2, y_offset, TheText.Get(MessageIDString)); + } } } @@ -1534,41 +1535,54 @@ void CGarage::UpdateCrusherShake(float X, float Y) m_pDoor2->GetMatrix().GetPosition().y -= Y; } -// This is dumb but there is no way to avoid goto. What was there originally even? -static bool DoINeedToRefreshPointer(CEntity * pDoor, bool bIsDummy, uint8 nIndex) -{ - bool bNeedToFindDoorEntities = false; - if (pDoor) { - if (bIsDummy) { - if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex((CDummy*)pDoor))) - return true; - if (nIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)pDoor) & 0x7F)) - bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return true; - } - else { - if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex((CObject*)pDoor))) - return true; - if (nIndex != (CPools::GetObjectPool()->GetIndex((CObject*)pDoor) & 0x7F)) - bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return true; - } - } - return bNeedToFindDoorEntities; -} - void CGarage::RefreshDoorPointers(bool bCreate) { - bool bNeedToFindDoorEntities = true; - if (!bCreate && !m_bRecreateDoorOnNextRefresh) - bNeedToFindDoorEntities = false; + bool bNeedToFindDoorEntities = bCreate || m_bRecreateDoorOnNextRefresh; m_bRecreateDoorOnNextRefresh = false; - if (DoINeedToRefreshPointer(m_pDoor1, m_bDoor1IsDummy, m_bDoor1PoolIndex)) - bNeedToFindDoorEntities = true; - if (DoINeedToRefreshPointer(m_pDoor2, m_bDoor2IsDummy, m_bDoor2PoolIndex)) - bNeedToFindDoorEntities = true; + if (m_pDoor1) { + if (m_bDoor1IsDummy) { + if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor1PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor1) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor1->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + else { + if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor1PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor1) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor1->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + } + if (m_pDoor2) { + if (m_bDoor2IsDummy) { + if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor2PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor2) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor2->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + else { + if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor2PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor2) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor2->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + } if (bNeedToFindDoorEntities) FindDoorsEntities(); } diff --git a/src/control/Garages.h b/src/control/Garages.h index 00020eb3..41b2afb7 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -198,7 +198,6 @@ class CGarages static CStoredCar aCarsInSafeHouse1[NUM_GARAGE_STORED_CARS]; static CStoredCar aCarsInSafeHouse2[NUM_GARAGE_STORED_CARS]; static CStoredCar aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; - static int32 AudioEntity; static bool bCamShouldBeOutisde; public: @@ -208,7 +207,7 @@ public: #endif static void Update(void); - static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId); + static int16 AddOne(CVector pos1, CVector pos2, eGarageType type, int32 targetId); static void ChangeGarageType(int16, eGarageType, int32); static void PrintMessages(void); static void TriggerMessage(const char* text, int16, uint16 time, int16); diff --git a/src/control/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/control/PathFind.cpp b/src/control/PathFind.cpp index fb60250c..49e43c81 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; @@ -1633,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/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 950612ca..a6166554 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(); @@ -1013,7 +1013,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); @@ -1436,3 +1436,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/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/control/Restart.cpp b/src/control/Restart.cpp index a6482d04..4ca18c3b 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 @@ -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 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/control/Script.cpp b/src/control/Script.cpp index 6bde6b87..dbd477e2 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]; @@ -1327,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 @@ -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 @@ -2696,8 +2641,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; @@ -4367,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) { @@ -13335,3 +4428,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..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 @@ -376,6 +399,11 @@ private: #ifdef FIX_BUGS friend void RetryMission(int, int); #endif + +#ifdef MISSION_SWITCHER +public: + static void SwitchToMission(int32 mission); +#endif }; @@ -514,6 +542,8 @@ private: return false; } } + + friend class CTheScripts; }; #ifdef MISSION_REPLAY diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp new file mode 100644 index 00000000..562125c6 --- /dev/null +++ b/src/control/Script2.cpp @@ -0,0 +1,1555 @@ +#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); +#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: + script_assert(0); + } + return -1; +} diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp new file mode 100644 index 00000000..23ab453c --- /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(CVector(infX, infY, infZ), CVector(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(CVector(infX, infY, infZ), CVector(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..78da2d96 --- /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..164ca036 --- /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_NoFreeAssert((CTreadable*)pBuilding) + 1; + } else { + type = 2; + handle = CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(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_NoFreeAssert((CTreadable*)pEntity) + 1; + } else { + type = 2; + handle = CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)pEntity) + 1; + } + break; + case ENTITY_TYPE_OBJECT: + type = 3; + handle = CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)pEntity) + 1; + break; + case ENTITY_TYPE_DUMMY: + type = 4; + handle = CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((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..acd9e424 --- /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 +#if GTA_VERSION < GTA3_PC_11 + 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; +} 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/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 3e016667..b20e6db3 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); @@ -2570,7 +2572,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 +2607,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; @@ -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) { @@ -3997,6 +4000,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) @@ -4010,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; diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 13d03213..4551e36f 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,15 +88,15 @@ 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 #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; @@ -104,15 +104,13 @@ 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 m_pRwCamera = nil; -#ifdef PS2_MENU } -#endif m_1rstPersonRunCloseToAWall = false; m_fPositionAlongSpline = 0.0f; @@ -123,7 +121,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; @@ -237,7 +235,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 @@ -715,14 +713,18 @@ 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 + 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; - // missing on PS2 +#if GTA_VERSION > GTA3_PS2_160 GenerationDistMultiplier = LODDistMultiplier; LODDistMultiplier *= CRenderer::ms_lodDistScale; - // +#endif // Keep track of speed if(m_bJustInitalised || m_bJust_Switched){ @@ -1574,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){ @@ -3398,10 +3402,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..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); @@ -348,7 +350,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; diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index c11fb72a..f987dea5 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 "MemoryMgr.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) @@ -242,8 +243,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..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__) @@ -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/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/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 576a58b1..cadba7f2 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2316,8 +2316,252 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act return num; } +#ifdef BIND_VEHICLE_FIREWEAPON +#define VFB(b) b, +#else +#define VFB(b) +#endif + +#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 */ \ + }} + + +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"); +#endif + + +#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" +#define PS2_CROSS "CROSS" +#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"); +#endif + +#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 + if (CPad::GetPad(0)->IsAffectedByController) { + wchar wstr[16]; + + // TODO: INI and/or menu setting for Xbox/PS switch +#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); + + CMessages::WideStringCopy(text, wstr, leight); + return; + } +#endif + int32 nums = GetNumOfSettingsForAction((e_ControllerAction)action); int32 sets = 0; diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index aadafc29..b9d475b8 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" @@ -25,6 +24,7 @@ #include "ZoneCull.h" #include "CdStream.h" #include "FileLoader.h" +#include "MemoryHeap.h" char CFileLoader::ms_line[256]; @@ -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)){ @@ -72,11 +78,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); @@ -95,12 +103,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); @@ -189,6 +201,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"); @@ -212,6 +226,8 @@ CFileLoader::LoadCollisionFile(const char *filename) } CFileMgr::CloseFile(fd); + + POP_MEMID(); } void @@ -233,6 +249,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; @@ -244,6 +261,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; @@ -255,6 +273,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; @@ -266,6 +285,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 || @@ -281,6 +301,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; @@ -332,6 +353,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 +374,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 +400,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 +426,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 +457,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 +478,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 +842,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/Frontend.cpp b/src/core/Frontend.cpp index 89b5ba3d..5597b358 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,31 +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_DisplayIslandLoading = ISLAND_LOADING_LOW; -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; @@ -254,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) \ @@ -290,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))); \ @@ -341,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; @@ -357,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; @@ -375,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; @@ -434,30 +438,26 @@ CMenuManager::ThingsToDoBeforeGoingBack() m_nTotalListRow = 0; } -#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; - } +#ifdef SCROLLABLE_PAGES + if (m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen)) { + m_nSelectedListRow = 0; + m_nFirstVisibleRowOnList = 0; + m_nScrollbarTopMargin = 0; } +#endif - 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; - } - } +#ifdef CUSTOM_FRONTEND_OPTIONS + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; + + 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,21 +476,248 @@ 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 } +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 @@ -782,19 +1009,21 @@ 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(); 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); 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)); + CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(MENU_X_MARGIN - 2.0f)); switch (m_nCurrScreen) { case MENUPAGE_STATS: @@ -854,13 +1083,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; } @@ -873,7 +1095,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; @@ -959,30 +1185,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) @@ -1043,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; @@ -1066,28 +1295,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 @@ -1095,14 +1318,14 @@ 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); + 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); - 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 @@ -1270,21 +1493,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"); @@ -1336,29 +1544,24 @@ CMenuManager::Draw() rightText = TheText.Get(CVehicle::m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON"); break; #ifdef CUSTOM_FRONTEND_OPTIONS - case MENUACTION_TRIGGERFUNC: - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu]; - if (m_nCurrScreen == option.screen && i == option.screenOptionOrder) { - if (option.type == FEOPTION_SELECT) { - // To whom manipulate option.value of static options externally (like RestoreDef functions) - if (*option.value != option.lastSavedValue) - option.displayedValue = option.lastSavedValue = *option.value; + case MENUACTION_CFO_DYNAMIC: + case MENUACTION_CFO_SELECT: + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[i]; + if (option.m_Action == MENUACTION_CFO_SELECT) { + // To whom manipulate option.m_CFO->value of static options externally (like RestoreDef functions) + if (*option.m_CFO->value != option.m_CFOSelect->lastSavedValue) + option.m_CFOSelect->displayedValue = option.m_CFOSelect->lastSavedValue = *option.m_CFO->value; - if (option.displayedValue >= option.numRightTexts || option.displayedValue < 0) - option.displayedValue = 0; + if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts || option.m_CFOSelect->displayedValue < 0) + option.m_CFOSelect->displayedValue = 0; - rightText = (wchar*)option.rightTexts[option.displayedValue]; + rightText = TheText.Get(option.m_CFOSelect->rightTexts[option.m_CFOSelect->displayedValue]); - } else if (option.type == FEOPTION_DYNAMIC) { - if (option.drawFunc) { - rightText = option.drawFunc(&isOptionDisabled, m_nCurrOption == i); - } + } else if (option.m_Action == MENUACTION_CFO_DYNAMIC) { + if (option.m_CFODynamic->drawFunc) { + rightText = option.m_CFODynamic->drawFunc(&isOptionDisabled, m_nCurrOption == i); } - } else { - debug("A- screen:%d option:%d - totalCo: %d, coId: %d, coScreen:%d, coOption:%d\n", m_nCurrScreen, i, numCustomFrontendOptions, aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu, option.screen, option.screenOptionOrder); - assert(0 && "Custom frontend options is borked"); } - break; #endif } @@ -1368,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) @@ -1469,12 +1683,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); @@ -1483,12 +1691,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. @@ -1535,6 +1737,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); @@ -1559,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) { @@ -1573,13 +1810,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; @@ -2047,7 +2280,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 @@ -2236,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; } } @@ -2264,6 +2498,7 @@ CMenuManager::DrawFrontEnd() bottomBarActive = true; curBottomBarOption = 0; } + #undef setBbItem #else if (m_nCurrScreen == MENUPAGE_NONE) { if (m_bGameNotLoaded) { @@ -2354,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) { @@ -2394,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 || @@ -2438,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); @@ -2463,7 +2676,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) { @@ -2612,17 +2825,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 +2884,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 @@ -2794,7 +2994,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 @@ -2986,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 { @@ -3004,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))); @@ -3301,10 +3501,6 @@ CMenuManager::InitialiseChangedLanguageSettings() default: break; } - -#ifdef CUSTOM_FRONTEND_OPTIONS - CustomFrontendOptionsPopulate(); -#endif } } @@ -3342,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 @@ -3372,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 @@ -3387,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; @@ -3494,6 +3690,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 @@ -3575,8 +3774,8 @@ 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)); // 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_SCALE_X(380.0f)); @@ -3670,7 +3869,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 @@ -3683,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 @@ -3958,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 @@ -3982,235 +4191,10 @@ CMenuManager::ProcessButtonPresses(void) if (m_nMousePosY < 0) m_nMousePosY = 0; if (m_nMousePosY > SCREEN_HEIGHT) m_nMousePosY = SCREEN_HEIGHT; - if (m_nCurrScreen == MENUPAGE_MULTIPLAYER_FIND_GAME || m_nCurrScreen == MENUPAGE_SKIN_SELECT - || m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { + if (hasNativeList(m_nCurrScreen)) { + // Not split to seperate function in III as in VC, but we need it for scrollable pages :) + ProcessList(goBack, optionSelected); - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - m_nTotalListRow = m_nSkinsTotal; - } - if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - m_nTotalListRow = m_ControlMethod == CONTROL_CLASSIC ? 30 : 25; - if (m_nSelectedListRow > m_nTotalListRow) - m_nSelectedListRow = m_nTotalListRow - 1; - } - -#ifndef TIDY_UP_PBP - if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) { - m_bShowMouse = 0; - optionSelected = true; - } -#endif - if (CPad::GetPad(0)->GetBackspaceJustDown() && m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && !field_535) { - if (m_nCurrExLayer == HOVEROPTION_LIST) { - m_nHoverOption = HOVEROPTION_NOT_HOVERING; - m_bWaitingForNewKeyBind = true; - m_bStartWaitingForKeyBind = true; - m_bKeyChangeNotProcessed = true; - pControlEdit = &m_KeyPressedCode; - } - } else { - field_535 = false; - } - - static uint32 lastTimeClickedScrollButton = 0; - - if (CTimer::GetTimeInMillisecondsPauseMode() - lastTimeClickedScrollButton >= 200) { - m_bPressedPgUpOnList = false; - m_bPressedPgDnOnList = false; - m_bPressedUpOnList = false; - m_bPressedDownOnList = false; - m_bPressedScrollButton = false; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - } - - if (CPad::GetPad(0)->GetTabJustDown()) { - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - m_bShowMouse = false; - switch (m_nCurrExLayer) { - case HOVEROPTION_BACK: - default: - m_nCurrExLayer = HOVEROPTION_LIST; - break; - case HOVEROPTION_LIST: - m_nCurrExLayer = HOVEROPTION_USESKIN; - break; - case HOVEROPTION_USESKIN: - m_nCurrExLayer = HOVEROPTION_BACK; - } - if (((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) && strcmp(m_aSkinName, m_PrefsSkinFile) == 0) { - m_nCurrExLayer = HOVEROPTION_BACK; - } - if ((m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) { - m_nCurrExLayer = HOVEROPTION_BACK; - } - } - - bool pressed = false; - if (CPad::GetPad(0)->GetUp() || CPad::GetPad(0)->GetAnaloguePadUp() || CPad::GetPad(0)->GetDPadUpJustDown()) { - m_bShowMouse = false; - pressed = true; - } else if (CPad::GetPad(0)->GetMouseWheelUpJustUp()) { - m_bShowMouse = true; - pressed = true; - } - - // Up - if (pressed) { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedUpOnList) { - m_bPressedUpOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - ScrollUpListByOne(); - } - } else { - m_bPressedUpOnList = false; - } - - pressed = false; - if (CPad::GetPad(0)->GetDown() || CPad::GetPad(0)->GetAnaloguePadDown() || CPad::GetPad(0)->GetDPadDownJustDown()) { - m_bShowMouse = false; - pressed = true; - } else if (CPad::GetPad(0)->GetMouseWheelDownJustDown()) { - m_bShowMouse = true; - pressed = true; - } - - // Down - if (pressed) { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedDownOnList) { - m_bPressedDownOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - ScrollDownListByOne(); - } - } else { - m_bPressedDownOnList = false; - } - - if (m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { - if (!CPad::GetPad(0)->GetPageUp()) { - m_bPressedPgUpOnList = false; - } else { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedPgUpOnList) { - m_bPressedPgUpOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - PageUpList(false); - } - } - if (!CPad::GetPad(0)->GetPageDown()) { - m_bPressedPgDnOnList = false; - } else { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedPgDnOnList) { - m_bPressedPgDnOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - PageDownList(false); - } - } - if (CPad::GetPad(0)->GetHome()) { - m_nCurrExLayer = HOVEROPTION_LIST; - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) { - m_nFirstVisibleRowOnList = 0; - } - m_nSelectedListRow = 0; - m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; - } - if (CPad::GetPad(0)->GetEnd()) { - m_nCurrExLayer = HOVEROPTION_LIST; - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) { - m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; - } - m_nSelectedListRow = m_nTotalListRow - 1; - m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; - } - } - -#ifndef TIDY_UP_PBP - if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustDown()) { - m_bShowMouse = false; - goBack = true; - } -#endif - - if (CPad::GetPad(0)->GetLeftMouseJustDown()) { - switch (m_nHoverOption) { - case HOVEROPTION_BACK: - goBack = true; - break; - case HOVEROPTION_PAGEUP: - PageUpList(true); - break; - case HOVEROPTION_PAGEDOWN: - PageDownList(true); - break; - case HOVEROPTION_USESKIN: - if (m_nSkinsTotal > 0) { - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); - m_pSelectedSkin = m_pSkinListHead.nextSkin; - strcpy(m_PrefsSkinFile, m_aSkinName); - CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile); - SaveSettings(); - } - } - } - - if (CPad::GetPad(0)->GetLeftMouseJustDown()) { - switch (m_nHoverOption) { - case HOVEROPTION_OVER_SCROLL_UP: - m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_UP; - break; - case HOVEROPTION_OVER_SCROLL_DOWN: - m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_DOWN; - break; - case HOVEROPTION_LIST: - m_nHoverOption = HOVEROPTION_SKIN; - } - } else if ((CPad::GetPad(0)->GetLeftMouseJustUp()) - && ((m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_UP || (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_DOWN)))) { - m_nHoverOption = HOVEROPTION_NOT_HOVERING; - } - - if (!CPad::GetPad(0)->GetLeftMouse()) { - holdingScrollBar = false; - } else { - if ((m_nHoverOption == HOVEROPTION_HOLDING_SCROLLBAR) || holdingScrollBar) { - holdingScrollBar = true; - // TODO: This part is a bit hard to reverse. Not much code tho - assert(0 && "Holding scrollbar isn't done yet"); - } else { - switch (m_nHoverOption) { - case HOVEROPTION_OVER_SCROLL_UP: - case HOVEROPTION_CLICKED_SCROLL_UP: - if (!m_bPressedScrollButton) { - m_bPressedScrollButton = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - ScrollUpListByOne(); - } - break; - case HOVEROPTION_OVER_SCROLL_DOWN: - case HOVEROPTION_CLICKED_SCROLL_DOWN: - if (!m_bPressedScrollButton) { - m_bPressedScrollButton = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - ScrollDownListByOne(); - } - break; - default: - m_bPressedScrollButton = false; - } - } - } } else if (isPlainTextScreen(m_nCurrScreen)) { #ifndef TIDY_UP_PBP if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown() || CPad::GetPad(0)->GetLeftMouseJustDown()) { @@ -4449,7 +4433,7 @@ CMenuManager::ProcessButtonPresses(void) TheCamera.m_fMouseAccelVertical = TheCamera.m_fMouseAccelHorzntl; SaveSettings(); break; - } + } #else switch (m_nHoverOption) { case HOVEROPTION_INCREASE_BRIGHTNESS: @@ -4468,7 +4452,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() @@ -4483,6 +4486,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) { @@ -4502,7 +4506,7 @@ CMenuManager::ProcessButtonPresses(void) goBack = false; } #endif - } + } // Centralized enter/back (except some conditions) #ifdef TIDY_UP_PBP @@ -4555,16 +4559,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; @@ -4573,9 +4571,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; @@ -4606,6 +4601,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)) { @@ -4879,45 +4880,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; @@ -4974,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(); @@ -4992,40 +4954,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(); @@ -5086,29 +5014,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 +5043,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) { @@ -5213,23 +5132,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) @@ -5294,15 +5217,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; @@ -5326,32 +5240,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 @@ -5527,6 +5443,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(); } @@ -5623,8 +5543,14 @@ CMenuManager::SwitchMenuOnAndOff() gMusicPlaying = 0; } */ - if (m_bMenuActive != menuWasActive) + if (m_bMenuActive != menuWasActive) { m_bMenuStateChanged = true; + + // 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 + } m_bStartUpFrontEndRequested = false; m_bShutDownFrontEndRequested = false; @@ -5662,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/Frontend.h b/src/core/Frontend.h index 848148e7..21124fdb 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 @@ -156,9 +155,6 @@ enum eSaveSlot SAVESLOT_7, SAVESLOT_8, SAVESLOT_LABEL = 36, -#ifdef CUSTOM_FRONTEND_OPTIONS - SAVESLOT_CFO -#endif }; #ifdef MENU_MAP @@ -239,18 +235,31 @@ enum eMenuScreen MENUPAGE_MOUSE_CONTROLS = 56, MENUPAGE_MISSION_RETRY = 57, #ifdef MENU_MAP - MENUPAGE_MAP, + MENUPAGE_MAP = 58, #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, @@ -370,12 +379,6 @@ enum eMenuAction // MENUACTION_MIPMAPS, // MENUACTION_TEXTURE_FILTERING, //#endif -//#ifdef NO_ISLAND_LOADING -// MENUACTION_ISLANDLOADING, -//#endif -#ifdef CUSTOM_FRONTEND_OPTIONS - MENUACTION_TRIGGERFUNC -#endif }; enum eCheckHover @@ -458,6 +461,7 @@ struct BottomBarOption int32 screenId; }; +#ifndef CUSTOM_FRONTEND_OPTIONS struct CMenuScreen { char m_ScreenName[8]; @@ -470,9 +474,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 { @@ -628,7 +714,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) @@ -696,6 +781,7 @@ public: void PageUpList(bool); void PageDownList(bool); int8 GetPreviousPageOption(); + void ProcessList(bool &goBack, bool &optionSelected); }; #ifndef IMPROVED_VIDEOMODE @@ -703,6 +789,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/Frontend_PS2.cpp b/src/core/Frontend_PS2.cpp index a76ac279..1cb944d1 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) @@ -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; @@ -3044,4 +3030,4 @@ CMenuManager::FilterOutColorMarkersFromString(wchar *string, CRGBA &color) *dst = '\0'; } -#endif \ No newline at end of file +#endif 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/Game.cpp b/src/core/Game.cpp index ef4800c5..33302653 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -86,10 +86,14 @@ #include "ZoneCull.h" #include "Zones.h" #include "debugmenu.h" -#include "frontendoption.h" #include "postfx.h" #include "custompipes.h" +#include "screendroplets.h" #include "crossplatform.h" +#include "MemoryHeap.h" +#ifdef USE_TEXTURE_POOL +#include "TexturePools.h" +#endif eLevelName CGame::currLevel; bool CGame::bDemoMode = true; @@ -129,7 +133,7 @@ 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 @@ -172,19 +176,33 @@ 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); @@ -207,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 @@ -224,14 +246,22 @@ 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); } +// missing altogether on PS2 void CGame::ShutdownRenderWare(void) { CMBlur::MotionBlurClose(); @@ -241,7 +271,8 @@ void CGame::ShutdownRenderWare(void) for ( int32 i = 0; i < NUMPLAYERS; i++ ) CWorld::Players[i].DeletePlayerSkin(); - + + // TODO: define CPlayerSkin::Shutdown(); DestroyDebugFont(); @@ -264,16 +295,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; @@ -314,19 +348,10 @@ 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; } +// missing altogether on PS2 void CGame::FinalShutdown(void) { @@ -337,21 +362,40 @@ CGame::FinalShutdown(void) bool CGame::Initialise(const char* datFile) { +#ifdef GTA_PS2 + // TODO: upload VU0 collision code here +#endif + +#if GTA_VERSION > GTA3_PS2_160 ResetLoadingScreenBar(); strcpy(aDatFile, datFile); - CPools::Initialise(); + CPools::Initialise(); // done in CWorld on PS2 +#endif + +#ifndef GTA_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(); @@ -362,32 +406,72 @@ 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(); + + PUSH_MEMID(MEMID_WORLD); 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(); -#ifdef PS2 + POP_MEMID(); + +#if GTA_VERSION <= GTA3_PS2_160 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(); + +#if GTA_VERSION > GTA3_PS2_160 InitModelIndices(); +#endif + + PUSH_MEMID(MEMID_DEF_MODELS); CModelInfo::Initialise(); +#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(); @@ -396,17 +480,30 @@ bool CGame::Initialise(const char* datFile) CVehicleModelInfo::LoadVehicleColours(); CVehicleModelInfo::LoadEnvironmentMaps(); CTheZones::PostZoneCreation(); + POP_MEMID(); + +#if GTA_VERSION <= GTA3_PS2_160 + TestModelIndices(); +#endif LoadingScreen("Loading the Game", "Setup paths", GetRandomSplashScreen()); ThePaths.PreparePathData(); +#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; + LoadingScreen("Loading the Game", "Setup streaming", nil); CStreaming::Init(); CStreaming::LoadInitialVehicles(); @@ -414,22 +511,37 @@ 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(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#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(); +#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(); @@ -438,44 +550,74 @@ bool CGame::Initialise(const char* datFile) CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); +#ifdef GTA_SCENE_EDIT 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); +#if GTA_VERSION <= GTA3_PS2_160 + CTimer::Initialise(); +#endif CClock::Initialise(1000); +#if GTA_VERSION <= GTA3_PS2_160 + CTheCarGenerators::Init(); +#endif CHeli::InitHelis(); CCranes::InitCranes(); CMovingThings::Init(); CDarkel::Init(); CStats::Init(); +#if GTA_VERSION <= GTA3_PS2_160 + CPickups::Init(); +#endif CPacManPickups::Init(); +#if GTA_VERSION <= GTA3_PS2_160 + CGarages::Init(); +#endif CRubbish::Init(); CClouds::Init(); +#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(); - LoadingScreen("Loading the Game", "Initialise vehicle paths", nil); +#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(); CReplay::Init(); + #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - LoadingScreen("Loading the Game", "Start script", nil); - CTheScripts::StartTestScript(); - CTheScripts::Process(); - TheCamera.Process(); -#ifdef PS2_MENU + LoadingScreen("Loading the Game", "Start script", nil); + CTheScripts::StartTestScript(); + CTheScripts::Process(); + TheCamera.Process(); } -#endif + LoadingScreen("Loading the Game", "Load scene", nil); CModelInfo::RemoveColModelsFromOtherLevels(currLevel); CCollision::ms_collisionInMemory = currLevel; @@ -490,7 +632,7 @@ bool CGame::ShutDown(void) CPlane::Shutdown(); CTrain::Shutdown(); CSpecialFX::Shutdown(); -#ifndef PS2 +#if GTA_VERSION > GTA3_PS2_160 CGarages::Shutdown(); #endif CMovingThings::Shutdown(); @@ -531,7 +673,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; @@ -542,13 +686,11 @@ void CGame::ReInitGameObjectVariables(void) CGameLogic::InitAtStartOfGame(); #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - TheCamera.Init(); - TheCamera.SetRwCamera(Scene.camera); -#ifdef PS2_MENU + TheCamera.Init(); + TheCamera.SetRwCamera(Scene.camera); } -#endif CDebug::DebugInitTextBuffer(); CWeather::Init(); CUserDisplay::Init(); @@ -557,7 +699,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::bDoingCarCollisions = false; CHud::ReInitialise(); CRadar::Initialise(); -#ifdef PS2 +#if GTA_VERSION <= GTA3_PS2_160 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -570,6 +712,9 @@ void CGame::ReInitGameObjectVariables(void) CStreaming::LoadAllRequestedModels(false); CPed::Initialise(); CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif CWeapon::InitialiseWeapons(); CPopulation::Initialise(); @@ -577,15 +722,19 @@ void CGame::ReInitGameObjectVariables(void) CWorld::Players[i].Clear(); CWorld::PlayerInFocus = 0; -#ifdef PS2 +#if GTA_VERSION <= GTA3_PS2_160 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(); @@ -596,7 +745,7 @@ void CGame::ReInitGameObjectVariables(void) CPickups::Init(); CPacManPickups::Init(); CGarages::Init(); -#ifdef PS2 +#if GTA_VERSION <= GTA3_PS2_160 CClouds::Init(); CRemote::Init(); #endif @@ -666,7 +815,7 @@ void CGame::ShutDownForRestart(void) CRadar::RemoveRadarSections(); FrontEndMenuManager.UnloadTextures(); CParticleObject::RemoveAllParticleObjects(); -#ifndef PS2 +#if GTA_VERSION >= GTA3_PS2_160 CPedType::Shutdown(); CSpecialFX::Shutdown(); #endif @@ -745,10 +894,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_X(480.0f)); CFont::SetJustifyOff(); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::SetBackGroundOnlyTextOff(); @@ -811,7 +960,7 @@ void CGame::InitialiseWhenRestarting(void) void CGame::Process(void) { CPad::UpdatePads(); -#ifdef GTA_PS2 +#ifdef USE_CUSTOM_ALLOCATOR ProcessTidyUpMemory(); #endif TheCamera.SetMotionBlurAlpha(0); @@ -821,8 +970,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()) { @@ -835,7 +988,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(); @@ -844,7 +1001,9 @@ void CGame::Process(void) CSkidmarks::Update(); CAntennas::Update(); CGlass::Update(); +#ifdef GTA_SCENE_EDIT CSceneEdit::Update(); +#endif CEventList::Update(); CParticle::Update(); gFireManager.Update(); @@ -859,7 +1018,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(); @@ -880,33 +1043,370 @@ 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 USE_CUSTOM_ALLOCATOR + +int32 gNumMemMoved; + +bool +MoveMem(void **ptr) { -#ifdef PS2 - // meow + if(*ptr){ + gNumMemMoved++; + void *newPtr = gMainHeap.MoveMemory(*ptr); + if(*ptr != newPtr){ + *ptr = newPtr; + return true; + } + } + return false; +} + +// 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) +{ +#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 +MoveAtomicMemory(RpAtomic *atomic, bool onlyOne) +{ + 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; +} +#endif + +void CGame::DrasticTidyUpMemory(bool flushDraw) +{ +#ifdef USE_CUSTOM_ALLOCATOR + 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 PS2 - // meow +#ifdef USE_CUSTOM_ALLOCATOR + 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 PS2 - // meow +#ifdef USE_CUSTOM_ALLOCATOR + 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/MenuScreens.cpp b/src/core/MenuScreens.cpp index 533fc755..9eff09e6 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, }, @@ -390,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,10 +441,10 @@ CMenuScreen aScreens[MENUPAGES] = { #ifdef MENU_MAP // MENUPAGE_MAP - { "FEG_MAP", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2, + { "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 @@ -449,4 +454,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..ae08f5f5 --- /dev/null +++ b/src/core/MenuScreensCustom.cpp @@ -0,0 +1,878 @@ +#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" +#include "Text.h" +#include "Streaming.h" +#include "FileLoader.h" +#include "Collision.h" +#include "ModelInfo.h" +#include "Pad.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 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) }, \ + 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_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 + +#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" }; + +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 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; + CMenuManager::m_PrefsVsync = true; + CMenuManager::m_PrefsUseWideScreen = false; + FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode; + #if GTA_VERSION >= GTA3_PC_11 + 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 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) +{ + 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 }, + INVERT_PAD_SELECTOR + 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 + 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 }, + }, +#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, + + ISLAND_LOADING_SELECTOR + 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/Pad.cpp b/src/core/Pad.cpp index 0e2f06a6..b971f3ec 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]; @@ -934,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(); @@ -1281,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 ) { @@ -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) ) @@ -2593,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_SCALE_X(SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); @@ -2610,7 +2627,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_SCALE_X(SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); 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/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 3c5689fd..03b49fd6 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -33,6 +33,9 @@ #endif #include "main.h" #include "Frontend.h" +#include "Font.h" +#include "MemoryMgr.h" +#include "MemoryHeap.h" bool CStreaming::ms_disableStreaming; bool CStreaming::ms_bLoadingBigModel; @@ -289,6 +292,11 @@ CStreaming::Shutdown(void) } } +#ifndef MASTER +uint64 timeProcessingTXD; +uint64 timeProcessingDFF; +#endif + void CStreaming::Update(void) { @@ -296,6 +304,11 @@ CStreaming::Update(void) CStreamingInfo *si, *prev; bool requestedSubway = false; +#ifndef MASTER + timeProcessingTXD = 0; + timeProcessingDFF = 0; +#endif + UpdateMemoryUsed(); if(ms_channelError != -1){ @@ -331,6 +344,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; @@ -390,6 +411,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; @@ -436,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) { @@ -469,10 +520,14 @@ 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()); 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(); @@ -481,7 +536,12 @@ 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(); // Txd no longer needed unless we only read part of the file @@ -505,12 +565,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){ @@ -560,7 +622,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,31 +664,42 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) if(streamId < STREAM_OFFSET_TXD){ // Model 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()); }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; @@ -741,7 +816,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 @@ -855,7 +932,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){ @@ -877,6 +958,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; @@ -2041,19 +2125,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 @@ -2633,3 +2723,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(); }; diff --git a/src/core/World.cpp b/src/core/World.cpp index d65d57dd..0bc564ff 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -53,6 +53,9 @@ bool CWorld::bIncludeCarTyres; void CWorld::Initialise() { +#if GTA_VERSION <= GTA3_PS2_160 + CPools::Initialise(); +#endif pIgnoreEntity = nil; bDoingCarCollisions = false; bSecondShift = false; @@ -919,24 +922,24 @@ CEntity * CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects) { - static CColModel sphereCol; + static CColModel OurColModel; - sphereCol.boundingSphere.center.x = 0.0f; - sphereCol.boundingSphere.center.y = 0.0f; - sphereCol.boundingSphere.center.z = 0.0f; - sphereCol.boundingSphere.radius = radius; - sphereCol.boundingBox.min.x = -radius; - sphereCol.boundingBox.min.y = -radius; - sphereCol.boundingBox.min.z = -radius; - sphereCol.boundingBox.max.x = radius; - sphereCol.boundingBox.max.y = radius; - sphereCol.boundingBox.max.z = radius; - sphereCol.numSpheres = 1; - sphereCol.spheres = &sphereCol.boundingSphere; - sphereCol.numLines = 0; - sphereCol.numBoxes = 0; - sphereCol.numTriangles = 0; - sphereCol.ownsCollisionVolumes = false; + OurColModel.boundingSphere.center.x = 0.0f; + OurColModel.boundingSphere.center.y = 0.0f; + OurColModel.boundingSphere.center.z = 0.0f; + OurColModel.boundingSphere.radius = radius; + OurColModel.boundingBox.min.x = -radius; + OurColModel.boundingBox.min.y = -radius; + OurColModel.boundingBox.min.z = -radius; + OurColModel.boundingBox.max.x = radius; + OurColModel.boundingBox.max.y = radius; + OurColModel.boundingBox.max.z = radius; + OurColModel.numSpheres = 1; + OurColModel.spheres = &OurColModel.boundingSphere; + OurColModel.numLines = 0; + OurColModel.numBoxes = 0; + OurColModel.numTriangles = 0; + OurColModel.ownsCollisionVolumes = false; CMatrix sphereMat; sphereMat.SetTranslate(spherePos); @@ -959,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 || @@ -1735,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) { @@ -1750,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(); @@ -1780,6 +1791,9 @@ CWorld::ShutDown(void) } } ms_listMovingEntityPtrs.Flush(); +#if GTA_VERSION <= GTA3_PS2_160 + CPools::Shutdown(); +#endif } void diff --git a/src/core/ZoneCull.cpp b/src/core/ZoneCull.cpp index c376e11f..075a13bc 100644 --- a/src/core/ZoneCull.cpp +++ b/src/core/ZoneCull.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "General.h" #include "Building.h" #include "Treadable.h" #include "Train.h" @@ -11,6 +12,9 @@ #include "ZoneCull.h" #include "Zones.h" +#include "Debug.h" +#include "Renderer.h" + int32 CCullZones::NumCullZones; CCullZone CCullZones::aZones[NUMCULLZONES]; int32 CCullZones::NumAttributeZones; @@ -27,6 +31,8 @@ int32 CCullZones::EntityIndicesUsed; bool CCullZones::bCurrentSubwayIsInvisible; bool CCullZones::bCullZonesDisabled; +#define NUMUNCOMPRESSED (6000) +#define NUMTEMPINDICES (140000) void CCullZones::Init(void) @@ -48,26 +54,6 @@ CCullZones::Init(void) aPointersToBigBuildingsForTreadables[i] = -1; } -bool CCullZone::TestLine(CVector vec1, CVector vec2) -{ - CColPoint colPoint; - CEntity *entity; - - if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false)) - return true; - return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false); -} - uint16* pTempArrayIndices; int TempEntityIndicesUsed; @@ -89,19 +75,25 @@ CCullZones::ResolveVisibilities(void) CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); CFileMgr::CloseFile(fd); }else{ -#if 0 - // TODO: implement code from mobile to generate data here +#ifndef MASTER EntityIndicesUsed = 0; BuildListForBigBuildings(); - pTempArrayIndices = new uint16[140000]; + pTempArrayIndices = new uint16[NUMTEMPINDICES]; TempEntityIndicesUsed = 0; - for (int i = 0; i < NumCullZones; i++) { - DoVisibilityTestCullZone(i, true); +// if(!LoadTempFile()) // not in final game + { + for (int i = 0; i < NumCullZones; i++) { +//printf("testing zone %d (%d indices)\n", i, TempEntityIndicesUsed); + DoVisibilityTestCullZone(i, true); + } + +// SaveTempFile(); // not in final game } CompressIndicesArray(); delete[] pTempArrayIndices; + pTempArrayIndices = nil; fd = CFileMgr::OpenFileForWriting("data\\cullzone.dat"); if (fd != 0) { @@ -118,16 +110,53 @@ CCullZones::ResolveVisibilities(void) } } +bool +CCullZones::LoadTempFile(void) +{ + int fd = CFileMgr::OpenFile("cullzone.tmp"); + if (fd != 0) { + CFileMgr::Read(fd, (char*)&NumCullZones, sizeof(NumCullZones)); + CFileMgr::Read(fd, (char*)aZones, sizeof(aZones)); + CFileMgr::Read(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones)); + CFileMgr::Read(fd, (char*)&aAttributeZones, sizeof(aAttributeZones)); + CFileMgr::Read(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16)); + CFileMgr::Read(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed)); + CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings)); + CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); + CFileMgr::CloseFile(fd); + return true; + } + return false; +} + +void +CCullZones::SaveTempFile(void) +{ + int fd = CFileMgr::OpenFileForWriting("cullzone.tmp"); + if (fd != 0) { + CFileMgr::Write(fd, (char*)&NumCullZones, sizeof(NumCullZones)); + CFileMgr::Write(fd, (char*)aZones, sizeof(aZones)); + CFileMgr::Write(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones)); + CFileMgr::Write(fd, (char*)&aAttributeZones, sizeof(aAttributeZones)); + CFileMgr::Write(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16)); + CFileMgr::Write(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed)); + CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings)); + CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); + CFileMgr::CloseFile(fd); + } +} + + void CCullZones::BuildListForBigBuildings() { for (int i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--) { CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); if (building == nil || !building->bIsBIGBuilding) continue; - CSimpleModelInfo *nonlod = (CSimpleModelInfo*)((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->m_atomics[2]; + CSimpleModelInfo *nonlod = ((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->GetRelatedModel(); if (nonlod == nil) continue; - for (int j = i; j >= 0; j--) { + for (int j = CPools::GetBuildingPool()->GetSize()-1; j >= 0; j--) { CBuilding *building2 = CPools::GetBuildingPool()->GetSlot(j); if (building2 == nil || building2->bIsBIGBuilding) continue; if (CModelInfo::GetModelInfo(building2->GetModelIndex()) == nonlod) { @@ -150,7 +179,7 @@ CCullZones::BuildListForBigBuildings() } void -CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) +CCullZones::DoVisibilityTestCullZone(int zoneId, bool findIndices) { aZones[zoneId].m_groupIndexCount[0] = 0; aZones[zoneId].m_groupIndexCount[1] = 0; @@ -158,16 +187,17 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) aZones[zoneId].m_indexStart = TempEntityIndicesUsed; aZones[zoneId].FindTestPoints(); - if (!doIt) return; + if (!findIndices) return; for (int i = CPools::GetBuildingPool()->GetSize() - 1; i >= 0; i--) { CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); if (building != nil && !building->bIsBIGBuilding && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForBuildings[i] != -1)) { - CBuilding *building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForBuildings[i] != -1) - building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]); + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) { + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[0]++; } @@ -175,13 +205,14 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) } for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) { - CTreadable* building = CPools::GetTreadablePool()->GetSlot(i); + CBuilding* building = CPools::GetTreadablePool()->GetSlot(i); if (building != nil && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForTreadables[i] != -1)) { - CTreadable* building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForTreadables[i] != -1) - building2 = CPools::GetTreadablePool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, building2)) { + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[1]++; } @@ -189,23 +220,28 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) } for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) { - CTreadable *building = CPools::GetTreadablePool()->GetSlot(i); - if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < 40000.0f) { + CBuilding *building = CPools::GetTreadablePool()->GetSlot(i); + if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < SQR(200.0f)) { int start = aZones[zoneId].m_groupIndexCount[0] + aZones[zoneId].m_indexStart; int end = aZones[zoneId].m_groupIndexCount[1] + start; bool alreadyAdded = false; for (int k = start; k < end; k++) { +#ifdef FIX_BUGS + if (pTempArrayIndices[k] == i) +#else if (aIndices[k] == i) +#endif alreadyAdded = true; } if (!alreadyAdded) { - CBuilding *building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForTreadables[i] != -1) - building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) { + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[2]++; } @@ -353,7 +389,9 @@ CCullZones::AddCullZone(CVector const &position, if((flag & ATTRZONE_NOTCULLZONE) == 0){ cull = &aZones[NumCullZones++]; v = position; - // WTF is this? + // reposition start point to the start/end of the + // alley next to the big building in the industrial district. + // probably isn't analyzed correctly otherwise?s if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f) v = CVector(1061.7f, -613.0f, 19.0f); if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f) @@ -385,6 +423,208 @@ CCullZones::AddCullZone(CVector const &position, } } +uint16 *pExtraArrayIndices; + +void +CCullZones::CompressIndicesArray() +{ + uint16 set[3]; + + // These are used to hold the compressed groups in sets of 3 + int numExtraIndices = 0; + pExtraArrayIndices = new uint16[NUMTEMPINDICES]; + + for(int numOccurrences = 6; numOccurrences > 1; numOccurrences--){ + if(NumCullZones == 0) + break; + +//printf("checking occurrences %d\n", numOccurrences); + int attempt = 0; + while(attempt < 10000){ + for(;;){ + attempt++; + + int zone = CGeneral::GetRandomNumber() % NumCullZones; + int group = CGeneral::GetRandomNumber() % 3; + if(!PickRandomSetForGroup(zone, group, set)) + break; + if(!DoWeHaveMoreThanXOccurencesOfSet(numOccurrences, set)) + break; + + // add this set + attempt = 1; + int setId = numExtraIndices + NUMUNCOMPRESSED; + pExtraArrayIndices[numExtraIndices++] = set[0]; + pExtraArrayIndices[numExtraIndices++] = set[1]; + pExtraArrayIndices[numExtraIndices++] = set[2]; + ReplaceSetForAllGroups(set, setId); + } + } + } + + TidyUpAndMergeLists(pExtraArrayIndices, numExtraIndices); + + delete[] pExtraArrayIndices; +} + +// Get three random indices for this group of a zone +bool +CCullZones::PickRandomSetForGroup(int32 zone, int32 group, uint16 *set) +{ + int32 start; + int32 size; + + aZones[zone].GetGroupStartAndSize(group, start, size); + if(size <= 0) + return false; + + int numIndices = 0; + for(int i = 0; i < size; i++) + if(pTempArrayIndices[start + i] != 0xFFFF) + numIndices++; + if(numIndices < 3) + return false; + + int first = CGeneral::GetRandomNumber() % (numIndices-2); + + numIndices = 0; + int n = 0; + for(int i = 0; i < size; i++) + if(pTempArrayIndices[start + i] != 0xFFFF){ + if(n++ < first) continue; + + set[numIndices++] = pTempArrayIndices[start + i]; + if(numIndices == 3) + break; + } + return true; +} + +bool +CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set) +{ + int32 curCount; + int32 start; + int32 size; + + curCount = 0; + for (int i = 0; i < NumCullZones; i++) { + for (int group = 0; group < 3; group++) { + aZones[i].GetGroupStartAndSize(group, start, size); + if(size <= 0) continue; + + // check if the set is a subset of the group + int n = 0; + for (int j = 0; j < size; j++) { + for (int k = 0; k < 3; k++) { + if (pTempArrayIndices[start+j] == set[k]) + n++; + } + } + // yes it is + if(n == 3){ + curCount++; + // check if we have seen this set often enough + if(curCount >= count) + return true; + } + } + } + return false; +} + +void +CCullZones::ReplaceSetForAllGroups(uint16 *set, uint16 setid) +{ + int32 start; + int32 size; + + for(int i = 0; i < NumCullZones; i++) + for(int group = 0; group < 3; group++){ + aZones[i].GetGroupStartAndSize(group, start, size); + if(size <= 0) continue; + + // check if the set is a subset of the group + int n = 0; + for(int j = 0; j < size; j++){ + for(int k = 0; k < 3; k++){ + if(pTempArrayIndices[start+j] == set[k]) + n++; + } + } + + // yes it is, so replace it + if(n == 3){ + bool insertedSet = false; + for(int j = 0; j < size; j++){ + for(int k = 0; k < 3; k++){ + // replace first element by set, invalidate others + if(pTempArrayIndices[start+j] == set[k]){ + if(!insertedSet) + pTempArrayIndices[start+j] = setid; + else + pTempArrayIndices[start+j] = 0xFFFF; + insertedSet = true; + } + } + } + } + } +} + +void +CCullZones::TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices) +{ + int numTempIndices = 0; + for(int i = 0; i < TempEntityIndicesUsed; i++) + if(pTempArrayIndices[i] != 0xFFFF) + numTempIndices++; + + // Fix up zone ranges such that there are no holes + for(int i = 0; i < NumCullZones; i++){ + int j; + int start = 0; + for(j = 0; j < aZones[i].m_indexStart; j++) + if(pTempArrayIndices[j] != 0xFFFF) + start++; + + aZones[i].m_indexStart = start; + aZones[i].m_numBuildings = 0; + aZones[i].m_numTreadablesPlus10m = 0; + aZones[i].m_numTreadables = 0; + + for(int k = 0; k < aZones[i].m_groupIndexCount[0]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numBuildings++; + for(int k = 0; k < aZones[i].m_groupIndexCount[1]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numTreadablesPlus10m++; + for(int k = 0; k < aZones[i].m_groupIndexCount[2]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numTreadables++; + } + + // Now copy the actually used indices + EntityIndicesUsed = 0; + for(int i = 0; i < TempEntityIndicesUsed; i++) + if(pTempArrayIndices[i] != 0xFFFF){ + assert(EntityIndicesUsed < NUMZONEINDICES); + if(pTempArrayIndices[i] < NUMUNCOMPRESSED) + aIndices[EntityIndicesUsed++] = pTempArrayIndices[i]; + else + aIndices[EntityIndicesUsed++] = pTempArrayIndices[i] + numTempIndices; + } + for(int i = 0; i < numExtraIndices; i++) + if(extraIndices[i] != 0xFFFF){ + assert(EntityIndicesUsed < NUMZONEINDICES); + if(extraIndices[i] < NUMUNCOMPRESSED) + aIndices[EntityIndicesUsed++] = extraIndices[i]; + else + aIndices[EntityIndicesUsed++] = extraIndices[i] + numTempIndices; + } +} + + void CCullZone::DoStuffLeavingZone(void) @@ -403,13 +643,14 @@ CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i) int16 bb; int j; - if(i < 6000){ + + if(i < NUMUNCOMPRESSED){ CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false; bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); } @@ -421,14 +662,14 @@ CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false; CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]); } @@ -453,13 +694,13 @@ CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true; bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[i+j]); } @@ -471,14 +712,14 @@ CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true; CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[i+j]); } @@ -490,13 +731,13 @@ CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[i+j]); } @@ -518,6 +759,68 @@ CCullZone::CalcDistToCullZoneSquared(float x, float y) return rx + ry; } +bool +CCullZone::TestLine(CVector vec1, CVector vec2) +{ + CColPoint colPoint; + CEntity *entity; + + if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false)) + return true; + return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false); +} + +bool +CCullZone::DoThoroughLineTest(CVector start, CVector end, CEntity *testEntity) +{ + CColPoint colPoint; + CEntity *entity; + + if(CWorld::ProcessLineOfSight(start, end, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + + CVector side; +#ifdef FIX_BUGS + if(start.x != end.x || start.y != end.y) +#else + if(start.x != end.x && start.y != end.y) +#endif + side = CVector(0.0f, 0.0f, 1.0f); + else + side = CVector(1.0f, 0.0f, 0.0f); + CVector up = CrossProduct(side, end - start); + side = CrossProduct(up, end - start); + side.Normalise(); + up.Normalise(); + side *= 0.1f; + up *= 0.1f; + + if(CWorld::ProcessLineOfSight(start+side, end+side, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start-side, end-side, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start+up, end+up, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start-up, end-up, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + return true; +} + bool CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) { @@ -526,10 +829,10 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) CSimpleModelInfo *minfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex()); float distToZone = CalcDistToCullZone(pos.x, pos.y); float lodDist; - if (minfo->m_isSubway) - lodDist = minfo->GetLargestLodDistance() + 30.0f; + if (minfo->m_noFade) + lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE; else - lodDist = minfo->GetLargestLodDistance() + 50.0f; + lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE + FADE_DISTANCE; if (lodDist > distToZone) return true; if (!checkLevel) return false; @@ -538,27 +841,749 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) } bool -CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set) +CCullZone::PointFallsWithinZone(CVector pos, float radius) { - int32 curCount; - int32 start; - int32 size; + if(minx - radius > pos.x || + maxx + radius < pos.x || + miny - radius > pos.y || + maxy + radius < pos.y || + minz - radius > pos.z || + maxz + radius < pos.z) + return false; + return true; +} - for (int i = 0; i < NumCullZones; i++) { - curCount = 0; - for (int group = 0; group < 3; group++) { - aZones[i].GetGroupStartAndSize(group, start, size); - int unk = 0; // TODO: figure out - for (int j = 0; j < size; j++) { - for (int k = 0; k < 3; k++) { - if (set[k] == pTempArrayIndices[start+j]) - unk++; +CVector ExtraFudgePointsCoors[] = { + CVector(978.0, -394.0, 18.0), + CVector(1189.7, -414.6, 27.0), + CVector(978.8, -391.0, 19.0), + CVector(1199.0, -502.3, 28.0), + CVector(1037.0, -391.9, 18.4), + CVector(1140.0, -608.7, 16.0), + CVector(1051.0, -26.0, 11.0), + CVector(951.5, -345.1, 12.0), + CVector(958.2, -394.6, 16.0), + CVector(1036.5, -390.0, 15.2), + CVector(960.6, -390.5, 20.9), + CVector(1061.0, -640.6, 16.3), + CVector(1034.5, -388.96, 14.78), + CVector(1038.4, -13.98, 12.2), + CVector(1047.2, -16.7, 10.6), + CVector(1257.9, -333.3, 40.0), + CVector(885.6, -424.9, 17.0), + CVector(1127.5, -795.8, 17.7), + CVector(1133.0, -716.0, 19.0), + CVector(1125.0, -694.0, 18.5), + CVector(1125.0, -670.0, 16.3), + CVector(1051.6, 36.3, 17.9), + CVector(1054.6, -11.4, 15.0), + CVector(1058.9, -278.0, 15.0), + CVector(1059.4, -261.0, 10.9), + CVector(1051.5, -638.5, 16.5), + CVector(1058.2, -643.4, 15.5), + CVector(1058.2, -643.4, 18.0), + CVector(826.0, -260.0, 7.0), + CVector(826.0, -260.0, 11.0), + CVector(833.0, -603.6, 16.4), + CVector(833.0, -603.6, 20.0), + CVector(1002.0, -318.5, 10.5), + CVector(998.0, -318.0, 9.8), + CVector(1127.0, -183.0, 18.1), + CVector(1123.0, -331.5, 23.8), + CVector(1123.8, -429.0, 24.0), + CVector(1197.0, -30.0, 13.7), + CVector(1117.5, -230.0, 17.3), + CVector(1117.5, -230.0, 20.0), + CVector(1120.0, -281.6, 21.5), + CVector(1120.0, -281.6, 24.0), + CVector(1084.5, -1022.7, 17.0), + CVector(1071.5, 5.4, 4.6), + CVector(1177.2, -215.7, 27.6), + CVector(841.6, -460.0, 19.7), + CVector(874.8, -456.6, 16.6), + CVector(918.3, -451.8, 17.8), + CVector(844.0, -495.7, 16.7), + CVector(842.0, -493.4, 21.0), + CVector(1433.5, -774.4, 16.9), + CVector(1051.0, -205.0, 7.5), + CVector(885.5, -425.6, 15.6), + CVector(182.6, -470.4, 27.8), + CVector(132.5, -930.2, 29.0), + CVector(124.7, -904.0, 28.0), + CVector(-50.0, -686.0, 22.0), + CVector(-49.1, -694.5, 22.5), + CVector(1063.8, -404.45, 16.2), + CVector(1062.2, -405.5, 17.0) +}; +int32 NumTestPoints; +int32 aTestPointsX[100]; +int32 aTestPointsY[100]; +int32 aTestPointsZ[100]; +CVector aTestPoints[100]; +int32 ElementsX, ElementsY, ElementsZ; +float StepX, StepY, StepZ; +int32 Memsize; +uint8 *pMem; +#define MEM(x, y, z) pMem[((x)*ElementsY + (y))*ElementsZ + (z)] +#define FLAG_FREE 1 +#define FLAG_PROCESSED 2 + +int32 MinValX, MaxValX; +int32 MinValY, MaxValY; +int32 MinValZ, MaxValZ; +int32 Point1, Point2; +int32 NewPointX, NewPointY, NewPointZ; + + +void +CCullZone::FindTestPoints() +{ + static int CZNumber; + + NumTestPoints = 0; + ElementsX = (maxx-minx) < 1.0f ? 2 : (maxx-minx)+1.0f; + ElementsY = (maxy-miny) < 1.0f ? 2 : (maxy-miny)+1.0f; + ElementsZ = (maxz-minz) < 1.0f ? 2 : (maxz-minz)+1.0f; + if(ElementsX > 32) ElementsX = 32; + if(ElementsY > 32) ElementsY = 32; + if(ElementsZ > 32) ElementsZ = 32; + Memsize = ElementsX * ElementsY * ElementsZ; + StepX = (maxx-minx)/(ElementsX-1); + StepY = (maxy-miny)/(ElementsY-1); + StepZ = (maxz-minz)/(ElementsZ-1); + + pMem = new uint8[Memsize]; + memset(pMem, 0, Memsize); + + // indices of center + int x = ElementsX * (position.x-minx)/(maxx-minx); + x = clamp(x, 0, ElementsX-1); + int y = ElementsY * (position.y-miny)/(maxy-miny); + y = clamp(y, 0, ElementsY-1); + int z = ElementsZ * (position.z-minz)/(maxz-minz); + z = clamp(z, 0, ElementsZ-1); + + // Mark which test points inside the zone are not occupied by buildings. + // To do this, mark the start point as free and do a food fill. + + // NB: we just assume the start position is free here! + MEM(x, y, z) |= FLAG_FREE; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + NumTestPoints++; + + bool notDoneYet; + do{ + notDoneYet = false; + for(x = 0; x < ElementsX; x++){ + for(y = 0; y < ElementsY; y++){ + for(z = 0; z < ElementsZ; z++){ + if(!(MEM(x, y, z) & FLAG_FREE) || MEM(x, y, z) & FLAG_PROCESSED) + continue; + + float pX = x*StepX + minx; + float pY = y*StepY + miny; + float pZ = z*StepZ + minz; + + if(x > 0 && !(MEM(x-1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX-StepX, pY, pZ))) + MEM(x-1, y, z) |= FLAG_FREE; + if(x < ElementsX-1 && !(MEM(x+1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX+StepX, pY, pZ))) + MEM(x+1, y, z) |= FLAG_FREE; + + if(y > 0 && !(MEM(x, y-1, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY-StepY, pZ))) + MEM(x, y-1, z) |= FLAG_FREE; + if(y < ElementsY-1 && !(MEM(x, y+1, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY+StepY, pZ))) + MEM(x, y+1, z) |= FLAG_FREE; + + if(z > 0 && !(MEM(x, y, z-1) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ-StepZ))) + MEM(x, y, z-1) |= FLAG_FREE; + if(z < ElementsZ-1 && !(MEM(x, y, z+1) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ+StepZ))) + MEM(x, y, z+1) |= FLAG_FREE; + + notDoneYet = true; + MEM(x, y, z) |= FLAG_PROCESSED; } } - if (unk == 3 && ++curCount >= count) - return true; + } + }while(notDoneYet); + + bool done; + + // Find bound planes of free space + + // increase x, bounds in y and z + x = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(y + z < minA){ + minA = y + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(y + z > maxA){ + maxA = y + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(y - z < minB){ + minB = y - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(y - z > maxB){ + maxB = y - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + x++; + }while(!done); + NumTestPoints += 4; + + // decrease x, bounds in y and z + x = ElementsX-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(y + z < minA){ + minA = y + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(y + z > maxA){ + maxA = y + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(y - z < minB){ + minB = y - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(y - z > maxB){ + maxB = y - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + x--; + }while(!done); + NumTestPoints += 4; + + // increase y, bounds in x and z + y = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + z < minA){ + minA = x + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + z > maxA){ + maxA = x + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - z < minB){ + minB = x - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - z > maxB){ + maxB = x - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + y++; + }while(!done); + NumTestPoints += 4; + + // decrease y, bounds in x and z + y = ElementsY-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + z < minA){ + minA = x + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + z > maxA){ + maxA = x + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - z < minB){ + minB = x - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - z > maxB){ + maxB = x - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + y--; + }while(!done); + NumTestPoints += 4; + + // increase z, bounds in x and y + z = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + y < minA){ + minA = x + y; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + y > maxA){ + maxA = x + y; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - y < minB){ + minB = x - y; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - y > maxB){ + maxB = x - y; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + z++; + }while(!done); + NumTestPoints += 4; + + // decrease z, bounds in x and y + z = ElementsZ-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + y < minA){ + minA = x + y; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + y > maxA){ + maxA = x + y; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - y < minB){ + minB = x - y; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - y > maxB){ + maxB = x - y; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + z--; + }while(!done); + NumTestPoints += 4; + + // divide the axis aligned bounding planes into 4 and place some test points + + // x = 0 plane + MinValY = 999999; + MinValZ = 999999; + MaxValY = 0; + MaxValZ = 0; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(0, y, z) & FLAG_FREE){ + if(y < MinValY) MinValY = y; + if(z < MinValZ) MinValZ = z; + if(y > MaxValY) MaxValY = y; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValY != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(0, NewPointY, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = 0; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // x = ElementsX-1 plane + MinValY = 999999; + MinValZ = 999999; + MaxValY = 0; + MaxValZ = 0; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(ElementsX-1, y, z) & FLAG_FREE){ + if(y < MinValY) MinValY = y; + if(z < MinValZ) MinValZ = z; + if(y > MaxValY) MaxValY = y; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValY != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(ElementsX-1, NewPointY, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = ElementsX-1; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // y = 0 plane + MinValX = 999999; + MinValZ = 999999; + MaxValX = 0; + MaxValZ = 0; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, 0, z) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(z < MinValZ) MinValZ = z; + if(x > MaxValX) MaxValX = x; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(NewPointX, 0, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = 0; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // y = ElementsY-1 plane + MinValX = 999999; + MinValZ = 999999; + MaxValX = 0; + MaxValZ = 0; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, ElementsY-1, z) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(z < MinValZ) MinValZ = z; + if(x > MaxValX) MaxValX = x; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(NewPointX, ElementsY-1, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = ElementsY-1; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // z = 0 plane + MinValX = 999999; + MinValY = 999999; + MaxValX = 0; + MaxValY = 0; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, 0) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(y < MinValY) MinValY = y; + if(x > MaxValX) MaxValX = x; + if(y > MaxValY) MaxValY = y; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValY != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + if(MEM(NewPointX, NewPointY, 0) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = 0; + NumTestPoints++; + } + } + + // z = ElementsZ-1 plane + MinValX = 999999; + MinValY = 999999; + MaxValX = 0; + MaxValY = 0; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, ElementsZ-1) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(y < MinValY) MinValY = y; + if(x > MaxValX) MaxValX = x; + if(y > MaxValY) MaxValY = y; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValY != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + if(MEM(NewPointX, NewPointY, ElementsZ-1) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = ElementsZ-1; + NumTestPoints++; + } + } + + // add some hardcoded test points + for(int i = 0; i < ARRAY_SIZE(ExtraFudgePointsCoors); i++) + if(PointFallsWithinZone(ExtraFudgePointsCoors[i], 0.0f)){ + x = ElementsX * (ExtraFudgePointsCoors[i].x-minx)/(maxx-minx); + y = ElementsY * (ExtraFudgePointsCoors[i].y-miny)/(maxy-miny); + z = ElementsZ * (ExtraFudgePointsCoors[i].z-minz)/(maxz-minz); + if(MEM(x, y, z) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + NumTestPoints++; + } + } + + // remove duplicate points + for(int i = 0; i < NumTestPoints; i++) + for(int j = i+1; j < NumTestPoints; j++) + if(aTestPointsX[j] == aTestPointsX[i] && + aTestPointsY[j] == aTestPointsY[i] && + aTestPointsZ[j] == aTestPointsZ[i]){ + // get rid of [j] + for(int k = j; k < NumTestPoints-1; k++){ + aTestPointsX[k] = aTestPointsX[k+1]; + aTestPointsY[k] = aTestPointsY[k+1]; + aTestPointsZ[k] = aTestPointsZ[k+1]; + } + NumTestPoints--; + } + + // convert points to floating point + for(int i = 0; i < NumTestPoints; i++){ + aTestPoints[i].x = aTestPointsX[i]*StepX + minx; + aTestPoints[i].y = aTestPointsY[i]*StepY + miny; + aTestPoints[i].z = aTestPointsZ[i]*StepZ + minz; + } + + CZNumber++; + + delete[] pMem; + pMem = nil; +} + +bool +CCullZone::TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity) +{ + CColModel *colmodel = entity->GetColModel(); + float boundMaxX = colmodel->boundingBox.max.x; + float boundMaxY = colmodel->boundingBox.max.y; + float boundMaxZ = colmodel->boundingBox.max.z; + float boundMinX = colmodel->boundingBox.min.x; + float boundMinY = colmodel->boundingBox.min.y; + float boundMinZ = colmodel->boundingBox.min.z; + if(LODentity){ + colmodel = LODentity->GetColModel(); + boundMaxX = Max(boundMaxX, colmodel->boundingBox.max.x); + boundMaxY = Max(boundMaxY, colmodel->boundingBox.max.y); + boundMaxZ = Max(boundMaxZ, colmodel->boundingBox.max.z); + boundMinX = Min(boundMinX, colmodel->boundingBox.min.x); + boundMinY = Min(boundMinY, colmodel->boundingBox.min.y); + boundMinZ = Min(boundMinZ, colmodel->boundingBox.min.z); + } + + if(boundMaxZ-boundMinZ + extraDist < 0.5f) + boundMaxZ = boundMinZ + 0.5f; + else + boundMaxZ += extraDist; + + CVector vecMin = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMinZ); + CVector vecMaxX = entity->GetMatrix() * CVector(boundMaxX, boundMinY, boundMinZ); + CVector vecMaxY = entity->GetMatrix() * CVector(boundMinX, boundMaxY, boundMinZ); + CVector vecMaxZ = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMaxZ); + CVector dirx = vecMaxX - vecMin; + CVector diry = vecMaxY - vecMin; + CVector dirz = vecMaxZ - vecMin; + + // If building intersects zone at all, it's visible + int x, y, z; + for(x = 0; x < 9; x++){ + CVector posX = vecMin + x/8.0f*dirx; + for(y = 0; y < 9; y++){ + CVector posY = posX + y/8.0f*diry; + for(z = 0; z < 9; z++){ + CVector posZ = posY + z/8.0f*dirz; + if(PointFallsWithinZone(posZ, 2.0f)) + return true; + } } } + + float distToZone = CalcDistToCullZone(entity->GetPosition().x, entity->GetPosition().y)/15.0f; + distToZone = Max(distToZone, 7.0f); + int numX = (boundMaxX - boundMinX)/distToZone + 2.0f; + int numY = (boundMaxY - boundMinY)/distToZone + 2.0f; + int numZ = (boundMaxZ - boundMinZ)/distToZone + 2.0f; + + float stepX = 1.0f/(numX-1); + float stepY = 1.0f/(numY-1); + float stepZ = 1.0f/(numZ-1); + float midX = (boundMaxX + boundMinX)/2.0f; + float midY = (boundMaxY + boundMinY)/2.0f; + float midZ = (boundMaxZ + boundMinZ)/2.0f; + + // check both xy planes + for(int i = 0; i < NumTestPoints; i++){ + CVector testPoint = aTestPoints[i]; + CVector mid = entity->GetMatrix() * CVector(midX, midY, midZ); + mid.z += 0.1f; + if(DoThoroughLineTest(testPoint, mid, entity)) + return true; + + CVector ray = entity->GetPosition() - testPoint; + + float dotX = DotProduct(ray, dirx); + float dotY = DotProduct(ray, diry); + float dotZ = DotProduct(ray, dirz); + + for(x = 0; x < numX; x++){ + CVector pMinZ = vecMin + x*stepX*dirx; + CVector pMaxZ = vecMin + x*stepX*dirx + dirz; + for(y = 0; y < numY; y++) + if(dotZ > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinZ + y*stepY*diry, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxZ + y*stepY*diry, entity)) + return true; + } + } + + for(x = 0; x < numX; x++){ + CVector pMinY = vecMin + x*stepX*dirx; + CVector pMaxY = vecMin + x*stepX*dirx + diry; + for(z = 1; z < numZ-1; z++) // edge cases already handled + if(dotY > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinY + z*stepZ*dirz, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxY + z*stepZ*dirz, entity)) + return true; + } + } + + for(y = 1; y < numY-1; y++){ // edge cases already handled + CVector pMinX = vecMin + y*stepY*diry; + CVector pMaxX = vecMin + y*stepY*diry + dirx; + for(z = 1; z < numZ-1; z++) // edge cases already handled + if(dotX > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinX + z*stepZ*dirz, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxX + z*stepZ*dirz, entity)) + return true; + } + } + } + return false; } diff --git a/src/core/ZoneCull.h b/src/core/ZoneCull.h index 9bc07b8c..10742ffb 100644 --- a/src/core/ZoneCull.h +++ b/src/core/ZoneCull.h @@ -12,7 +12,7 @@ public: float maxz; int32 m_indexStart; - int16 m_groupIndexCount[3]; + int16 m_groupIndexCount[3]; // only useful during resolution stage int16 m_numBuildings; int16 m_numTreadablesPlus10m; int16 m_numTreadables; @@ -26,30 +26,35 @@ public: static void DoStuffEnteringZone_OneTreadable(uint16 i); - static bool TestLine(CVector a1, CVector a2); + static bool TestLine(CVector vec1, CVector vec2); + static bool DoThoroughLineTest(CVector vec1, CVector vec2, CEntity *testEntity); float CalcDistToCullZoneSquared(float x, float y); float CalcDistToCullZone(float x, float y) { return Sqrt(CalcDistToCullZoneSquared(x, y)); }; bool IsEntityCloseEnoughToZone(CEntity* entity, bool checkLevel); + bool PointFallsWithinZone(CVector pos, float radius); + bool TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity); + void FindTestPoints(); void GetGroupStartAndSize(int32 groupid, int32 &start, int32 &size) { switch (groupid) { + case 0: + default: + // buildings + start = m_indexStart; + size = m_groupIndexCount[0]; + break; case 1: + // treadables + 10m start = m_groupIndexCount[0] + m_indexStart; size = m_groupIndexCount[1]; break; case 2: + // treadables start = m_groupIndexCount[0] + m_groupIndexCount[1] + m_indexStart; size = m_groupIndexCount[2]; break; - default: - start = m_indexStart; - size = m_groupIndexCount[0]; - break; } } - - void FindTestPoints() {}; // todo - bool TestEntityVisibilityFromCullZone(CEntity*, float, CEntity*) { return false; }; // todo }; enum eZoneAttribs @@ -121,5 +126,12 @@ public: static void DoVisibilityTestCullZone(int zoneId, bool doIt); static bool DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set); - static void CompressIndicesArray() {};// todo + static void CompressIndicesArray(); + static bool PickRandomSetForGroup(int32 zone, int32 group, uint16 *set); + static void ReplaceSetForAllGroups(uint16 *set, uint16 setid); + static void TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices); + + // debug + static bool LoadTempFile(void); + static void SaveTempFile(void); }; diff --git a/src/core/config.h b/src/core/config.h index a87b1850..d64cca40 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 @@ -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 @@ -156,30 +152,68 @@ 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 + +// 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 + +// those infamous texts +#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 # define PS2_MATFX # endif +# define GTA_REPLAY +# define GTA_SCENE_EDIT #elif defined GTA_XBOX #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 // only in master builds + #undef DRAW_GAME_VERSION_TEXT #else // not in master builds #define VALIDATE_SAVE_SIZE + + #define NO_MOVIES // disable intro videos + #define DEBUGMENU #endif #ifdef FINAL @@ -187,18 +221,19 @@ 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 -#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 + +// Just debug menu entries +#ifdef DEBUGMENU +#define MISSION_SWITCHER // from debug menu +#endif // Rendering/display //#define EXTRA_MODEL_FLAGS // from mobile to optimize rendering @@ -209,17 +244,20 @@ enum Config { #define USE_TXD_CDIMAGE // generate and load textures from txd.img #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 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 -#define CUTSCENE_BORDERS_SWITCH +#ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) //#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) -#define MULTISAMPLING // adds MSAA option +//#define SCREEN_DROPLETS // neo water droplets +#endif -#ifdef LIBRW -// these are not supported with librw yet -# undef MULTISAMPLING +#ifndef EXTENDED_COLOURFILTER +#undef SCREEN_DROPLETS // we need the backbuffer for this effect +#endif +#ifndef EXTENDED_PIPELINES +#undef SCREEN_DROPLETS // we need neo.txd #endif // Particle @@ -239,12 +277,14 @@ 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 PS2_HUD #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 @@ -258,7 +298,14 @@ 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 +# define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC +# endif #endif // Script @@ -270,7 +317,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 @@ -307,6 +354,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 @@ -315,3 +364,7 @@ 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 +#endif diff --git a/src/core/main.cpp b/src/core/main.cpp index 171d0a57..cc7f3259 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -63,7 +63,11 @@ #include "SceneEdit.h" #include "debugmenu.h" #include "Clock.h" +#include "postfx.h" #include "custompipes.h" +#include "screendroplets.h" +#include "frontendoption.h" +#include "MemoryHeap.h" GlobalScene Scene; @@ -88,7 +92,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]; @@ -102,6 +110,18 @@ void TheGame(void); void DebugMenuPopulate(void); #endif +#ifndef FINAL +bool gbPrintMemoryUsage; +#endif + +#ifdef PS2_MENU +#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() { @@ -404,9 +424,19 @@ 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 +#endif +#ifdef SCREEN_DROPLETS + ScreenDroplets::InitDraw(); #endif return ret; } @@ -417,6 +447,9 @@ Initialise3D(void *param) static void Terminate3D(void) { +#ifdef SCREEN_DROPLETS + ScreenDroplets::Shutdown(); +#endif #ifdef EXTENDED_PIPELINES CustomPipes::CustomPipeShutdown(); #endif @@ -634,18 +667,18 @@ LoadingIslandScreen(const char *levelName) CFont::SetColor(CRGBA(243, 237, 71, 255)); CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f)); #ifdef FIX_BUGS - CFont::PrintString(SCREEN_STRETCH_FROM_RIGHT(20.0f), SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); #else - CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); + CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_SCALE_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); #endif TextCopy(wstr, name); TheText.UpperCase(wstr); CFont::SetColor(CRGBA(243, 237, 71, 255)); CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f)); #ifdef FIX_BUGS - CFont::PrintString(SCREEN_STRETCH_FROM_RIGHT(20.0f), SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(80.0f), wstr); #else - CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); + CFont::PrintString(SCREEN_WIDTH-20, SCREEN_SCALE_FROM_BOTTOM(80.0f), wstr); #endif CFont::DrawFonts(); DoRWStuffEndOfFrame(); @@ -768,6 +801,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() { @@ -779,11 +976,15 @@ DisplayGameDebugText() TWEAKBOOL(bDisplayPosn); TWEAKBOOL(bDisplayRate); } -#endif + if(gbPrintMemoryUsage) + PrintMemoryUsage(); +#endif char str[200]; wchar ustr[200]; + +#ifdef DRAW_GAME_VERSION_TEXT wchar ver[200]; AsciiToUnicode(version_name, ver); @@ -803,6 +1004,7 @@ DisplayGameDebugText() #else CFont::PrintString(10.0f, 10.0f, ver); #endif +#endif // #ifdef DRAW_GAME_VERSION_TEXT FrameSamples++; FramesPerSecondCounter += 1000.0f / (CTimer::GetTimeStepNonClippedInSeconds() * 1000.0f); @@ -989,9 +1191,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(); @@ -1010,13 +1214,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(); } } @@ -1055,24 +1255,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(); @@ -1080,21 +1285,12 @@ Idle(void *arg) #endif if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){ -#ifdef PS2_MENU - TheMemoryCard.m_bWantToLoad = false; + WANT_TO_LOAD = false; FrontEndMenuManager.m_bWantToRestart = true; -#else - FrontEndMenuManager.m_bWantToRestart = true; - FrontEndMenuManager.m_bWantToLoad = false; -#endif return; } -#ifdef PS2_MENU - if ( FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad ) -#else - if(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad) -#endif + if(FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD) { return; } @@ -1104,18 +1300,22 @@ Idle(void *arg) if(arg == nil) return; + PUSH_MEMID(MEMID_RENDER); + if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) && TheCamera.GetScreenFadeStatus() != FADE_2) { -#if defined(GTA_PC) && defined(FIX_BUGS) +#if defined(GTA_PC) && !defined(RW_GL3) && defined(FIX_BUGS) + // This is from SA, but it's nice for windowed mode 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; RsMouseSetPos(&pos); } #endif + + PUSH_MEMID(MEMID_RENDERLIST); tbStartTimer(0, "CnstrRenderList"); CRenderer::ConstructRenderList(); tbEndTimer("CnstrRenderList"); @@ -1123,6 +1323,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 @@ -1133,12 +1334,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(); @@ -1159,10 +1360,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"); @@ -1178,7 +1386,7 @@ Idle(void *arg) CVisibilityPlugins::SetRenderWareCamera(Scene.camera); RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); if(!RsCameraBeginUpdate(Scene.camera)) - return; + goto popret; } #ifdef PS2_SAVE_DIALOG @@ -1191,7 +1399,7 @@ Idle(void *arg) #ifdef PS2_MENU if ( TheMemoryCard.m_bWantToLoad ) - return; + goto popret; #endif tbStartTimer(0, "DoFade"); @@ -1210,8 +1418,13 @@ Idle(void *arg) DoRWStuffEndOfFrame(); + POP_MEMID(); // MEMID_RENDER + if(g_SlowMode) ProcessSlowMode(); + return; + +popret: POP_MEMID(); // MEMID_RENDER } void @@ -1377,14 +1590,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(); @@ -1422,77 +1634,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); @@ -1528,15 +1712,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; } @@ -1553,9 +1731,7 @@ void TheGame(void) CTimer::Update(); -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(): // MEMID_RENDER if (g_SlowMode) ProcessSlowMode(); @@ -1567,24 +1743,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(); @@ -1607,7 +1771,7 @@ void SystemInit() mwInit(); #endif -#ifdef GTA_PS2 +#ifdef USE_CUSTOM_ALLOCATOR InitMemoryMgr(); #endif @@ -1637,7 +1801,7 @@ void SystemInit() #ifdef GTA_PS2 CFileMgr::InitCd(); - Char modulepath[256]; + char modulepath[256]; strcpy(modulepath, "cdrom0:\\"); strcat(modulepath, "SYSTEM\\"); @@ -1724,7 +1888,7 @@ void SystemInit() // #endif -#ifdef PS2 +#ifdef GTA_PS2 TheMemoryCard.Init(); #endif } @@ -1753,7 +1917,7 @@ void GameInit() #endif CdStreamInit(MAX_CDCHANNELS); -#ifdef PS2 +#ifdef GTA_PS2 Initialise3D(); //no params #else //TODO @@ -1860,21 +2024,18 @@ 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); 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(); @@ -1902,11 +2063,10 @@ 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 - && r != CMemoryCard::ERR_OPENNOENTRY && r != CMemoryCard::ERR_NONE ) + if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT ) { GameInit(); @@ -1916,6 +2076,8 @@ main(int argc, char *argv[]) CFont::Initialise(); FrontEndMenuManager.DrawMemoryCardStartUpMenus(); + }else if(r == CMemoryCard::ERR_OPENNOENTRY || r == CMemoryCard::ERR_NONE){ + // eh? } #endif @@ -1926,12 +2088,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/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 a06762f5..5974175a 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,12 +24,12 @@ #include "Radar.h" #include "debugmenu.h" #include "Frontend.h" -#include "Text.h" #include "WaterLevel.h" #include "main.h" -#include "MBlur.h" +#include "Script.h" #include "postfx.h" #include "custompipes.h" +#include "MemoryHeap.h" #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS #include "FileMgr.h" @@ -76,388 +74,61 @@ mysrand(unsigned int seed) #ifdef CUSTOM_FRONTEND_OPTIONS #include "frontendoption.h" -#include "Font.h" -void ReloadFrontendOptions(void) -{ - CustomFrontendOptionsPopulate(); -} - -void RestoreDefGraphics(int8 action) { - if (action != FEOPTION_ACTION_SELECT) - return; - - #ifdef PS2_ALPHA_TEST - gPS2alphaTest = false; - #endif - #ifdef MULTISAMPLING - FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0; - #endif - #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those - CMenuManager::m_PrefsFrameLimiter = true; - CMenuManager::m_PrefsVsyncDisp = true; - CMenuManager::m_PrefsVsync = true; - CMenuManager::m_PrefsUseWideScreen = false; - FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode; - #ifdef GTA3_1_1_PATCH - if (_dwOperatingSystemVersion == OS_WIN98) { - CMBlur::BlurOn = false; - CMBlur::MotionBlurClose(); - } else { - CMBlur::BlurOn = true; - CMBlur::MotionBlurOpen(Scene.camera); - } - #else - CMBlur::BlurOn = true; - #endif - FrontEndMenuManager.SaveSettings(); - #endif -} - -void RestoreDefDisplay(int8 action) { - if (action != FEOPTION_ACTION_SELECT) - return; - - #ifdef CUTSCENE_BORDERS_SWITCH - CMenuManager::m_PrefsCutsceneBorders = true; - #endif - #ifdef FREE_CAM - TheCamera.bFreeCam = false; - #endif - #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those - CMenuManager::m_PrefsBrightness = 256; - CMenuManager::m_PrefsLOD = 1.2f; - CRenderer::ms_lodDistScale = 1.2f; - CMenuManager::m_PrefsShowSubtitles = true; - FrontEndMenuManager.SaveSettings(); - #endif -} - -#ifdef MULTISAMPLING -void MultiSamplingGoBack() { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; -} - -void MultiSamplingButtonPress(int8 action) { - if (action == FEOPTION_ACTION_SELECT) { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel; - _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); - FrontEndMenuManager.SetHelperText(0); - FrontEndMenuManager.SaveSettings(); - } - } else if (action == FEOPTION_ACTION_LEFT || action == FEOPTION_ACTION_RIGHT) { - if (FrontEndMenuManager.m_bGameNotLoaded) { - FrontEndMenuManager.m_nDisplayMSAALevel += (action == FEOPTION_ACTION_RIGHT ? 1 : -1); - - int i = 0; - int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels(); - while (maxAA != 1) { - i++; - maxAA >>= 1; - } - - if (FrontEndMenuManager.m_nDisplayMSAALevel < 0) - FrontEndMenuManager.m_nDisplayMSAALevel = i; - else if (FrontEndMenuManager.m_nDisplayMSAALevel > i) - FrontEndMenuManager.m_nDisplayMSAALevel = 0; - } - } else if (action == FEOPTION_ACTION_FOCUSLOSS) { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; - FrontEndMenuManager.SetHelperText(3); - } - } -} - -wchar* MultiSamplingDraw(bool *disabled, bool userHovering) { - static wchar unicodeTemp[64]; - if (userHovering) { - if (FrontEndMenuManager.m_nDisplayMSAALevel == FrontEndMenuManager.m_nPrefsMSAALevel) { - if (FrontEndMenuManager.m_nHelperTextMsgId == 1) // Press enter to apply - FrontEndMenuManager.ResetHelperText(); - } else { - FrontEndMenuManager.SetHelperText(1); - } - } else { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; - } - } - - if (!FrontEndMenuManager.m_bGameNotLoaded) - *disabled = true; - - switch (FrontEndMenuManager.m_nDisplayMSAALevel) { - case 0: - return TheText.Get("FEM_OFF"); - default: - sprintf(gString, "%iX", 1 << (FrontEndMenuManager.m_nDisplayMSAALevel)); - AsciiToUnicode(gString, unicodeTemp); - return unicodeTemp; - } -} -const char* multisamplingKey = "MultiSampling"; -#endif - -#ifdef MORE_LANGUAGES -void LangPolSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_POLISH; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} - -void LangRusSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_RUSSIAN; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} - -void LangJapSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_JAPANESE; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} -#endif - -#ifdef IMPROVED_VIDEOMODE -void ScreenModeChange(int8 displayedValue) -{ - if (displayedValue != FrontEndMenuManager.m_nPrefsWindowed) { - FrontEndMenuManager.m_nPrefsWindowed = displayedValue; - _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution - FrontEndMenuManager.SetHelperText(0); - FrontEndMenuManager.SaveSettings(); - } -} -#endif - -#ifdef FREE_CAM -void FreeCamChange(int8 displayedValue) -{ - TheCamera.bFreeCam = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* freeCamKey = "FreeCam"; -#endif - -#ifdef CUTSCENE_BORDERS_SWITCH -void BorderModeChange(int8 displayedValue) -{ - CMenuManager::m_PrefsCutsceneBorders = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* cutsceneBordersKey = "CutsceneBorders"; -#endif - -#ifdef PS2_ALPHA_TEST -void PS2AlphaTestChange(int8 displayedValue) -{ - gPS2alphaTest = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* ps2alphaKey = "PS2AlphaTest"; -#endif - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS -wchar selectedJoystickUnicode[128]; - -wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { - int numButtons; - int found = -1; - const char *joyname; - if (userHovering) { - for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { - if ((joyname = glfwGetJoystickName(i))) { - const uint8* buttons = glfwGetJoystickButtons(i, &numButtons); - for (int j = 0; j < numButtons; j++) { - if (buttons[j]) { - found = i; - break; - } - } - if (found != -1) - break; - } - } - - if (found != -1 && PSGLOBAL(joy1id) != found) { - if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found) - PSGLOBAL(joy2id) = PSGLOBAL(joy1id); - else - PSGLOBAL(joy2id) = -1; - - strcpy(gSelectedJoystickName, joyname); - PSGLOBAL(joy1id) = found; - } - } - if (PSGLOBAL(joy1id) == -1) - AsciiToUnicode("Not found", selectedJoystickUnicode); - else - AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode); - - return selectedJoystickUnicode; -} -#endif - -// Important: Make sure to read the warnings/informations in frontendoption.h!! -// If you will hardcode any text, please use AllocUnicode! wchar_t size differs between platforms void CustomFrontendOptionsPopulate(void) { - RemoveCustomFrontendOptions(); // if exist - - // -- Graphics/display seperation preperation starts - don't add options in here! -#ifdef GRAPHICS_MENU_OPTIONS - int graphicsMenu = FrontendScreenAdd("FET_GRA", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - - int newDisplayMenu = FrontendScreenAdd("FET_DIS", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - - FrontendOptionSetCursor(MENUPAGE_OPTIONS, 2, true); - FrontendOptionAddRedirect(TheText.Get("FET_DIS"), newDisplayMenu, 0); - FrontendOptionSetCursor(MENUPAGE_OPTIONS, 3); - FrontendOptionAddRedirect(TheText.Get("FET_GRA"), graphicsMenu, 0); - -#define SWITCH_TO_GRAPHICS_MENU FrontendOptionSetCursor(graphicsMenu, -1); -#define SWITCH_TO_DISPLAY_MENU FrontendOptionSetCursor(newDisplayMenu, -1); -#define CLONE_OPTION(a, b, c, d) FrontendOptionAddBuiltinAction(a, b, c, d); -#define ADD_BACK FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); -#define ADD_RESTORE_DEFAULTS(a) FrontendOptionAddDynamic(TheText.Get("FET_DEF"), nil, nil, a, nil); -#else - int advancedDisplayMenu = FrontendScreenAdd("FET_ADV", MENUSPRITE_MAINMENU, MENUPAGE_DISPLAY_SETTINGS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - bool movedToAdvMenu = false; - -#define SWITCH_TO_GRAPHICS_MENU \ - if (GetNumberOfMenuOptions(MENUPAGE_DISPLAY_SETTINGS) >= 12) { \ - FrontendOptionSetCursor(advancedDisplayMenu, -1); \ - movedToAdvMenu = true; \ - } else { \ - FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3); \ - } - -#define SWITCH_TO_DISPLAY_MENU SWITCH_TO_GRAPHICS_MENU -#define CLONE_OPTION(a, b, c, d) -#define ADD_BACK -#define ADD_RESTORE_DEFAULTS(a) -#endif - // -- Graphics/display seperation preperation end - - const wchar* off_on[] = { TheText.Get("FEM_OFF"), TheText.Get("FEM_ON") }; - -#ifdef MORE_LANGUAGES - FrontendOptionSetCursor(MENUPAGE_LANGUAGE_SETTINGS, -2); - FrontendOptionAddDynamic(TheText.Get("FEL_POL"), nil, nil, LangPolSelect, nil); - FrontendOptionAddDynamic(TheText.Get("FEL_RUS"), nil, nil, LangRusSelect, nil); - FrontendOptionAddDynamic(TheText.Get("FEL_JAP"), nil, nil, LangJapSelect, nil); -#endif - -#ifdef MENU_MAP - FrontendOptionSetCursor(MENUPAGE_PAUSE_MENU, 2); - FrontendOptionAddRedirect(TheText.Get("FEG_MAP"), MENUPAGE_MAP); -#endif - - // -- Start of graphics menu - add options in display order! - - SWITCH_TO_GRAPHICS_MENU - CLONE_OPTION(TheText.Get("FED_RES"), MENUACTION_SCREENRES, nil, nil); - CLONE_OPTION(TheText.Get("FED_WIS"), MENUACTION_WIDESCREEN, nil, nil) - -#ifdef IMPROVED_VIDEOMODE - const wchar* screenModes[] = { TheText.Get("FED_FLS"), TheText.Get("FED_WND") }; - // Storing isn't enabled because it's handled in Frontend - FrontendOptionAddSelect(TheText.Get("FEM_SCF"), screenModes, 2, (int8*)&FrontEndMenuManager.m_nPrefsWindowed, true, ScreenModeChange, nil); -#endif - - CLONE_OPTION(TheText.Get("FEM_VSC"), MENUACTION_FRAMESYNC, nil, nil); - CLONE_OPTION(TheText.Get("FEM_FRM"), MENUACTION_FRAMELIMIT, nil, nil); - -#ifdef MULTISAMPLING - SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, multisamplingKey); -#endif - - CLONE_OPTION(TheText.Get("FED_TRA"), MENUACTION_TRAILS, nil, nil); - -#ifdef PS2_ALPHA_TEST - SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, ps2alphaKey); -#endif - - ADD_RESTORE_DEFAULTS(RestoreDefGraphics) - ADD_BACK - - // ---- End of Graphics Menu ---- - - // -- Start of Display menu - add options in display order! - - SWITCH_TO_DISPLAY_MENU - CLONE_OPTION(TheText.Get("FED_BRI"), MENUACTION_BRIGHTNESS, nil, nil); - CLONE_OPTION(TheText.Get("FEM_LOD"), MENUACTION_DRAWDIST, nil, nil); - -#ifdef CUTSCENE_BORDERS_SWITCH - SWITCH_TO_DISPLAY_MENU - FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, cutsceneBordersKey); -#endif - -#ifdef FREE_CAM - SWITCH_TO_DISPLAY_MENU - FrontendOptionAddSelect(TheText.Get("FEC_FRC"), off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, freeCamKey); -#endif - - CLONE_OPTION(TheText.Get("FED_SUB"), MENUACTION_SUBTITLES, nil, nil); - - // Add link to advanced graphics menu if it's filled. -#ifndef GRAPHICS_MENU_OPTIONS - if (movedToAdvMenu) { - FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3); - FrontendOptionAddRedirect(TheText.Get("FET_ADV"), advancedDisplayMenu, 0); - - FrontendOptionSetCursor(advancedDisplayMenu, -1); - FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); - } -#endif - - ADD_RESTORE_DEFAULTS(RestoreDefDisplay) - ADD_BACK - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS - int detectJoystickMenu = FrontendScreenAdd("FEC_JOD", MENUSPRITE_MAINMENU, MENUPAGE_CONTROLLER_PC, 40, 60, 20, - FONT_BANK, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, false); - - FrontendOptionSetCursor(detectJoystickMenu, 0); - - FrontendOptionAddBuiltinAction(TheText.Get("FEC_JPR"), MENUACTION_LABEL, nil, nil); - FrontendOptionAddDynamic(TheText.Get("FEC_JDE"), DetectJoystickDraw, nil, nil, nil); - FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); - - FrontendOptionSetCursor(MENUPAGE_CONTROLLER_PC, 2); - FrontendOptionAddRedirect(TheText.Get("FEC_JOD"), detectJoystickMenu, 1); -#endif + // Moved to an array in MenuScreensCustom.cpp, but APIs are still available. see frontendoption.h } #endif #ifdef LOAD_INI_SETTINGS #include "ini_parser.hpp" + +linb::ini cfg; +int CheckAndReadIniInt(const char *cat, const char *key, int original) +{ + std::string strval = cfg.get(cat, key, ""); + const char *value = strval.c_str(); + if (value && value[0] != '\0') + return atoi(value); + + return original; +} + +float CheckAndReadIniFloat(const char *cat, const char *key, float original) +{ + std::string strval = cfg.get(cat, key, ""); + const char *value = strval.c_str(); + if (value && value[0] != '\0') + return atof(value); + + 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() { - 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 +162,38 @@ 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_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading; +#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,23 +204,29 @@ 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) { + // 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) @@ -688,6 +375,19 @@ ResetCamStatics(void) TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true; } +#ifdef MISSION_SWITCHER +int8 nextMissionToSwitch = 0; +static void +SwitchToMission(void) +{ + CTheScripts::SwitchToMission(nextMissionToSwitch); +} +#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", @@ -870,8 +570,19 @@ 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); + 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 @@ -888,9 +599,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); @@ -899,6 +607,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; diff --git a/src/core/templates.h b/src/core/templates.h index 4f7b8490..166f865c 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; @@ -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; @@ -141,8 +147,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 +162,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/entities/Physical.cpp b/src/entities/Physical.cpp index a08e68f8..04cec96b 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){ @@ -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) && @@ -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; 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/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/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/frontendoption.cpp b/src/extras/frontendoption.cpp index 88a930a9..a3c4b9e3 100644 --- a/src/extras/frontendoption.cpp +++ b/src/extras/frontendoption.cpp @@ -1,20 +1,14 @@ #include "common.h" #ifdef CUSTOM_FRONTEND_OPTIONS -#include "frontendoption.h" +#include "Frontend.h" #include "Text.h" -int numCustomFrontendOptions = 0; -FrontendOption *customFrontendOptions; - -int numCustomFrontendScreens = 0; -FrontendScreen* customFrontendScreens; - -int numFrontendOptionReplacements = 0; -CMenuScreen::CMenuEntry* frontendOptionReplacements; - int lastOgScreen = MENUPAGES; // means no new pages +int numCustomFrontendOptions = 0; +int numCustomFrontendScreens = 0; + int optionCursor = -2; int currentMenu; bool optionOverwrite = false; @@ -32,8 +26,7 @@ void GoBack(bool fadeIn) { int screen = !FrontEndMenuManager.m_bGameNotLoaded ? aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[0]; - int option = !FrontEndMenuManager.m_bGameNotLoaded ? - aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[0]; + int option = FrontEndMenuManager.GetPreviousPageOption(); FrontEndMenuManager.ThingsToDoBeforeGoingBack(); @@ -58,7 +51,7 @@ GetLastMenuScreen() { int8 page = -1; for (int i = 0; i < MENUPAGES; i++) { - if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].unk == 0) + if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].m_PreviousPage[0] == MENUPAGE_NONE) break; ++page; @@ -66,89 +59,23 @@ GetLastMenuScreen() return page; } -// Used before populating options, but effective in InitialiseChangedLanguageSettings and debugmenu -void -RemoveCustomFrontendOptions() -{ - if (numCustomFrontendOptions != 0) { - - for (int i = 0; i < MENUPAGES; i++) { - for (int j = 0; j < NUM_MENUROWS; j++) { - if (aScreens[i].m_aEntries[j].m_SaveSlot == SAVESLOT_CFO) { - int ogOptionId = customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].ogOptionId; - - if (customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].type == FEOPTION_SELECT) - free(customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].rightTexts); - - if (ogOptionId == -1) { - int k; - for (k = j; k < NUM_MENUROWS - 1; k++) { - memcpy(&aScreens[i].m_aEntries[k], &aScreens[i].m_aEntries[k + 1], sizeof(CMenuScreen::CMenuEntry)); - } - aScreens[i].m_aEntries[k].m_Action = MENUACTION_NOTHING; - aScreens[i].m_aEntries[k].m_SaveSlot = SAVESLOT_NONE; - aScreens[i].m_aEntries[k].m_EntryName[0] = '\0'; - j--; - } else { - memcpy(&aScreens[i].m_aEntries[j], &frontendOptionReplacements[ogOptionId], sizeof(CMenuScreen::CMenuEntry)); - } - } - } - } - free(customFrontendOptions); - numCustomFrontendOptions = 0; - - if (numFrontendOptionReplacements != 0) { - free(frontendOptionReplacements); - numFrontendOptionReplacements = 0; - } - } - - if (numCustomFrontendScreens == 0) - return; - - for (int i = 0; i < MENUPAGES; i++) { - if (i > lastOgScreen) { - aScreens[i].m_ScreenName[0] = '\0'; - aScreens[i].unk = 0; - } - } - free(customFrontendScreens); - numCustomFrontendScreens = 0; - lastOgScreen = MENUPAGES; -} - -int8 RegisterNewScreen(const char *name, int prevPage) +int8 RegisterNewScreen(const char *name, int prevPage, ReturnPrevPageFunc returnPrevPageFunc) { if (lastOgScreen == MENUPAGES) lastOgScreen = GetLastMenuScreen(); numCustomFrontendScreens++; - if (numCustomFrontendScreens == 1) - customFrontendScreens = (FrontendScreen*)malloc(5 * sizeof(FrontendScreen)); - else if (numCustomFrontendScreens % 5 == 1) - customFrontendScreens = (FrontendScreen*)realloc(customFrontendScreens, (numCustomFrontendScreens + 4) * sizeof(FrontendScreen)); - - assert(customFrontendScreens != nil && "Custom frontend screens can't be allocated"); - int id = lastOgScreen + numCustomFrontendScreens; assert(id < MENUPAGES && "No room for new custom frontend screens! Increase MENUPAGES"); strncpy(aScreens[id].m_ScreenName, name, 8); aScreens[id].m_PreviousPage[0] = aScreens[id].m_PreviousPage[1] = prevPage; - aScreens[id].unk = 1; + aScreens[id].returnPrevPageFunc = returnPrevPageFunc; return id; } int8 RegisterNewOption() { numCustomFrontendOptions++; - if (numCustomFrontendOptions == 1) - customFrontendOptions = (FrontendOption*)malloc(5 * sizeof(FrontendOption)); - else if (numCustomFrontendOptions % 5 == 1) - customFrontendOptions = (FrontendOption*)realloc(customFrontendOptions, (numCustomFrontendOptions + 4) * sizeof(FrontendOption)); - - assert(customFrontendOptions != nil && "Custom frontend options can't be allocated"); - uint8 numOptions = GetNumberOfMenuOptions(currentMenu); uint8 curIdx; if (optionCursor < 0) { @@ -159,30 +86,11 @@ int8 RegisterNewOption() if (!optionOverwrite) { if (aScreens[currentMenu].m_aEntries[curIdx].m_Action != MENUACTION_NOTHING) { for (int i = numOptions - 1; i >= curIdx; i--) { - memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreen::CMenuEntry)); + memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreenCustom::CMenuEntry)); } } } optionCursor++; - - if (optionOverwrite) { - numFrontendOptionReplacements++; - if (numFrontendOptionReplacements == 1) - frontendOptionReplacements = (CMenuScreen::CMenuEntry*)malloc(5 * sizeof(CMenuScreen::CMenuEntry)); - else if (numFrontendOptionReplacements % 5 == 1) - frontendOptionReplacements = (CMenuScreen::CMenuEntry*)realloc(frontendOptionReplacements, (numFrontendOptionReplacements + 4) * sizeof(CMenuScreen::CMenuEntry)); - - memcpy(&frontendOptionReplacements[numFrontendOptionReplacements - 1], &aScreens[currentMenu].m_aEntries[curIdx], sizeof(CMenuScreen::CMenuEntry)); - customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = numFrontendOptionReplacements - 1; - } else { - customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = -1; - } - customFrontendOptions[numCustomFrontendOptions - 1].screen = currentMenu; - - aScreens[currentMenu].m_aEntries[curIdx].m_Action = MENUACTION_TRIGGERFUNC; - aScreens[currentMenu].m_aEntries[curIdx].m_SaveSlot = SAVESLOT_CFO; - aScreens[currentMenu].m_aEntries[curIdx].m_TargetMenu = numCustomFrontendOptions - 1; - aScreens[currentMenu].m_aEntries[curIdx].m_EntryName[0] = 1; // just something to fool it return curIdx; } @@ -193,110 +101,78 @@ void FrontendOptionSetCursor(int screen, int8 option, bool overwrite) optionOverwrite = overwrite; } -void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc) { +void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu, int saveSlot) { int8 screenOptionOrder = RegisterNewOption(); - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; - // To fool the Frontend, we will still display the text passed via first param. + // We can't use custom text on those :shrug: switch (action) { case MENUACTION_SCREENRES: - strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FED_RES"); + strcpy(option.m_EntryName, "FED_RES"); break; case MENUACTION_AUDIOHW: - strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FEA_3DH"); + strcpy(option.m_EntryName, "FEA_3DH"); + break; + default: + strncpy(option.m_EntryName, gxtKey, 8); break; } - aScreens[currentMenu].m_aEntries[screenOptionOrder].m_Action = action; - option.type = FEOPTION_BUILTIN_ACTION; - option.buttonPressFunc = buttonPressFunc; - TextCopy(option.leftText, leftText); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; - option.save = nil; + option.m_Action = action; + option.m_SaveSlot = saveSlot; + option.m_TargetMenu = targetMenu; } -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName) +{ + int8 screenOptionOrder = RegisterNewOption(); + + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; + option.m_Action = MENUACTION_CFO_SELECT; + strncpy(option.m_EntryName, gxtKey, 8); + option.m_CFOSelect = new CCFOSelect(); + option.m_CFOSelect->rightTexts = (char**)malloc(numRightTexts * sizeof(char*)); + memcpy(option.m_CFOSelect->rightTexts, rightTexts, numRightTexts * sizeof(char*)); + option.m_CFOSelect->numRightTexts = numRightTexts; + option.m_CFOSelect->value = var; + if (var) { + option.m_CFOSelect->displayedValue = *var; + option.m_CFOSelect->lastSavedValue = *var; + } + option.m_CFOSelect->save = saveName; + option.m_CFOSelect->onlyApplyOnEnter = onlyApplyOnEnter; + option.m_CFOSelect->changeFunc = changeFunc; +} + +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName) { int8 screenOptionOrder = RegisterNewOption(); - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_SELECT; - TextCopy(option.leftText, leftText); - option.rightTexts = (wchar**)malloc(numRightTexts * sizeof(wchar*)); - memcpy(option.rightTexts, rightTexts, numRightTexts * sizeof(wchar*)); - option.numRightTexts = numRightTexts; - option.value = var; - option.displayedValue = *var; - option.lastSavedValue = *var; - option.save = saveName; - option.onlyApplyOnEnter = onlyApplyOnEnter; - option.changeFunc = changeFunc; - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; -} - -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_DYNAMIC; - option.drawFunc = drawFunc; - option.buttonPressFunc = buttonPressFunc; - TextCopy(option.leftText, leftText); - option.value = var; - option.save = saveName; - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; -} - -void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, bool fadeIn) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption &option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_REDIRECT; - option.to = to; - option.option = selectedOption; - option.fadeIn = fadeIn; - TextCopy(option.leftText, text); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = nil; - option.save = nil; -} - -void FrontendOptionAddBackButton(const wchar* text, bool fadeIn) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_GOBACK; - option.fadeIn = fadeIn; - TextCopy(option.leftText, text); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = nil; - option.save = nil; + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; + option.m_Action = MENUACTION_CFO_DYNAMIC; + strncpy(option.m_EntryName, gxtKey, 8); + option.m_CFODynamic = new CCFODynamic(); + option.m_CFODynamic->drawFunc = drawFunc; + option.m_CFODynamic->buttonPressFunc = buttonPressFunc; + option.m_CFODynamic->value = var; + option.m_CFODynamic->save = saveName; } uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc) { - uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage); + uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage, returnPrevPageFunc); - FrontendScreen &screen = customFrontendScreens[numCustomFrontendScreens - 1]; - screen.id = screenOrder; - screen.sprite = sprite; - screen.prevPage = prevPage; - strncpy(screen.name, gxtKey, 8); - screen.columnWidth = columnWidth; - screen.headerHeight = headerHeight; - screen.lineHeight = lineHeight; - screen.font = font; - screen.fontScaleX = fontScaleX; - screen.fontScaleY = fontScaleY; - screen.alignment = alignment; - screen.returnPrevPageFunc = returnPrevPageFunc; + CCustomScreenLayout *screen = new CCustomScreenLayout(); + aScreens[screenOrder].layout = screen; + screen->sprite = sprite; + screen->columnWidth = columnWidth; + screen->headerHeight = headerHeight; + screen->lineHeight = lineHeight; + screen->font = font; + screen->fontScaleX = fontScaleX; + screen->fontScaleY = fontScaleY; + screen->alignment = alignment; return screenOrder; } diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h index dac6be62..19340b20 100644 --- a/src/extras/frontendoption.h +++ b/src/extras/frontendoption.h @@ -2,47 +2,23 @@ #include "common.h" #ifdef CUSTOM_FRONTEND_OPTIONS -#include "Frontend.h" - -// Warning: -// All of the code relies on that you won't use more then NUM_MENUROWS(18) options on one page. -// Also congrats if you can make 18 options visible at once. - -// About texts: -// All text parameters accept wchar(including hardcoded wchar* and TheText.Get) -// except FrontendScreenAdd(it's char[8] GXT key by the design of Frontend). -// All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu! - -// Execute direction: -// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order, -// i.e. don't set cursor to 8 first and then 3. - -// Live reload: -// You can add/change/undo the new options in-game if you use VS. Change what you want, build the changed bits via "Edit and Continue", -// and hit the "Reload custom frontend options" from debug menu. Or call CustomFrontendOptionsPopulate() from somewhere else. +// ! There are 2 ways to use CFO, +// 1st; by adding a new option to the array in MenuScreensCustom.cpp and passing attributes/CBs to it +// 2nd; by calling the functions listed at the bottom of this file. // -- Option types // // Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function, -// then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately) -// and ReturnPrevPageFunc optionally. You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter. +// optionally you can add post-change event via ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately) +// You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter. // // Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do // all the operations with ButtonPressFunc, this includes allocating the variable. // Left-side text is passed while creating and static, but ofc right-side text is dynamic - -// you should return it in DrawFunc, which is called on every draw. ReturnPrevPageFunc is also here if needed. -// -// Redirect: Redirection to another screen. selectedOption parameter is the highlighted option user will see after the redirection. +// you should return it in DrawFunc, which is called on every draw. // // Built-in action: As the name suggests, any action that game has built-in. But as an extra you can set the option text, -// and can be informed on button press/focus loss via buttonPressFunc. ReturnPrevPageFunc is also here. - -#define FEOPTION_SELECT 0 -#define FEOPTION_DYNAMIC 1 -#define FEOPTION_REDIRECT 2 -#define FEOPTION_GOBACK 3 -#define FEOPTION_BUILTIN_ACTION 4 // -- Returned via ButtonPressFunc() action param. #define FEOPTION_ACTION_LEFT 0 @@ -61,7 +37,7 @@ typedef void (*ReturnPrevPageFunc)(); // for static options -typedef void (*ChangeFunc)(int8 displayedValue); // called before updating the value. +typedef void (*ChangeFunc)(int8 before, int8 after); // called after updating the value. // only called on enter if onlyApplyOnEnter set, otherwise called on every value change // for dynamic options @@ -69,71 +45,11 @@ typedef wchar* (*DrawFunc)(bool* disabled, bool userHovering); // you must retur // you can also set *disabled if you want to gray it out. typedef void (*ButtonPressFunc)(int8 action); // see FEOPTION_ACTIONs above -struct FrontendScreen -{ - int id; - char name[8]; - eMenuSprites sprite; - int prevPage; - int columnWidth; - int headerHeight; - int lineHeight; - int8 font; - float fontScaleX; - float fontScaleY; - int8 alignment; - bool showLeftRightHelper; - ReturnPrevPageFunc returnPrevPageFunc; -}; - -struct FrontendOption -{ - int8 type; - int8 screenOptionOrder; - int32 screen; - wchar leftText[128]; - ReturnPrevPageFunc returnPrevPageFunc; - int8* value; - int8 displayedValue; // only if onlyApplyOnEnter enabled for now - const char* save; - int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor - - union { - // Only for dynamic / built-in action - struct { - DrawFunc drawFunc; - ButtonPressFunc buttonPressFunc; - }; - - // Only for static/select - struct { - wchar** rightTexts; - int8 numRightTexts; - bool onlyApplyOnEnter; - ChangeFunc changeFunc; - int8 lastSavedValue; // only if onlyApplyOnEnter enabled - }; - - // Only for redirect - struct { - int to; - int8 option; - bool fadeIn; - }; - }; -}; - // -- Internal things -void RemoveCustomFrontendOptions(); void CustomFrontendOptionsPopulate(); - extern int lastOgScreen; // for reloading - extern int numCustomFrontendOptions; -extern FrontendOption* customFrontendOptions; - extern int numCustomFrontendScreens; -extern FrontendScreen* customFrontendScreens; // -- To be used in ButtonPressFunc / ChangeFunc(this one would be weird): void ChangeScreen(int screen, int option = 0, bool fadeIn = true); @@ -141,6 +57,21 @@ void GoBack(bool fadeIn = true); uint8 GetNumberOfMenuOptions(int screen); +// !!! We're now moved to MenuScreensCustom.cpp, which houses an array that keeps all original+custom options. +// But you can still use the APIs below, and manipulate aScreens while in game. + +// Limits: +// The code relies on that you won't use more then NUM_MENUROWS(18) options on one page, and won't exceed the MENUPAGES of pages. +// Also congrats if you can make 18 options visible at once. + +// Texts: +// All text parameters accept char[8] GXT key. + +// Execute direction: +// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order, +// i.e. don't set cursor to 8 first and then 3. + + // -- Placing the cursor to append/overwrite option // // Done via FrontendOptionSetCursor(screen, position, overwrite = false), parameters explained below: @@ -152,11 +83,9 @@ uint8 GetNumberOfMenuOptions(int screen); void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false); // var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to saveName param. obv), otherwise pass nil/0 -void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc); -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); -void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true); -void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true); +void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu = MENUPAGE_NONE, int saveSlot = SAVESLOT_NONE); +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil); +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName = nil); uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil); #endif diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp index 6355dfb1..d3b8b8ac 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 @@ -373,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) { @@ -415,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/inttypes.h b/src/extras/re3_inttypes.h similarity index 100% rename from src/extras/inttypes.h rename to src/extras/re3_inttypes.h 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 6cbbf237..51e009d6 100644 --- a/src/extras/shaders/Makefile +++ b/src/extras/shaders/Makefile @@ -1,68 +1,79 @@ -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_UV2_gl.inc screenDroplet_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 + +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/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_gl3.inc b/src/extras/shaders/colourfilterIII_fs_gl.inc similarity index 79% rename from src/extras/shaders/colourfilterIII_fs_gl3.inc rename to src/extras/shaders/colourfilterIII_fs_gl.inc index 5530a4fa..6fd1935b 100644 --- a/src/extras/shaders/colourfilterIII_fs_gl3.inc +++ b/src/extras/shaders/colourfilterIII_fs_gl.inc @@ -2,11 +2,9 @@ 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" +"FSIN vec4 v_color;\n" +"FSIN vec2 v_tex0;\n" +"FSIN float v_fog;\n" "void\n" "main(void)\n" @@ -18,8 +16,11 @@ const char *colourfilterIII_frag_src = " 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_gl3.inc b/src/extras/shaders/contrast_fs_gl.inc similarity index 74% rename from src/extras/shaders/contrast_fs_gl3.inc rename to src/extras/shaders/contrast_fs_gl.inc index 58aaf079..97f78194 100644 --- a/src/extras/shaders/contrast_fs_gl3.inc +++ b/src/extras/shaders/contrast_fs_gl.inc @@ -3,18 +3,19 @@ const char *contrast_frag_src = "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" +"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_gl3.inc b/src/extras/shaders/default_UV2_gl.inc similarity index 63% rename from src/extras/shaders/default_UV2_gl3.inc rename to src/extras/shaders/default_UV2_gl.inc index 14106b29..450f3d9a 100644 --- a/src/extras/shaders/default_UV2_gl3.inc +++ b/src/extras/shaders/default_UV2_gl.inc @@ -1,14 +1,10 @@ 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" +"VSIN(ATTRIB_POS) vec3 in_pos;\n" -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out vec2 v_tex1;\n" -"out float v_fog;\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" 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_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/im2d_gl3.inc b/src/extras/shaders/im2d_gl.inc similarity index 63% rename from src/extras/shaders/im2d_gl3.inc rename to src/extras/shaders/im2d_gl.inc index 68341b39..d11f5d33 100644 --- a/src/extras/shaders/im2d_gl3.inc +++ b/src/extras/shaders/im2d_gl.inc @@ -1,13 +1,11 @@ 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" +"VSIN(ATTRIB_POS) vec4 in_pos;\n" -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" "void\n" "main(void)\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_gl3.inc b/src/extras/shaders/neoGloss_fs_gl.inc similarity index 68% rename from src/extras/shaders/neoGloss_fs_gl3.inc rename to src/extras/shaders/neoGloss_fs_gl.inc index 736b0c5d..67e9724e 100644 --- a/src/extras/shaders/neoGloss_fs_gl3.inc +++ b/src/extras/shaders/neoGloss_fs_gl.inc @@ -5,17 +5,15 @@ const char *neoGloss_frag_src = "#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" +"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" -" color = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\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" @@ -23,6 +21,8 @@ const char *neoGloss_frag_src = " 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_gl3.inc b/src/extras/shaders/neoGloss_vs_gl.inc similarity index 67% rename from src/extras/shaders/neoGloss_vs_gl3.inc rename to src/extras/shaders/neoGloss_vs_gl.inc index 4adc9cb2..dffb423f 100644 --- a/src/extras/shaders/neoGloss_vs_gl3.inc +++ b/src/extras/shaders/neoGloss_vs_gl.inc @@ -1,16 +1,12 @@ const char *neoGloss_vert_src = "uniform vec3 u_eye;\n" +"VSIN(ATTRIB_POS) vec3 in_pos;\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" +"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" diff --git a/src/extras/shaders/neoRim.vert b/src/extras/shaders/neoRim.vert index 4a2b545f..81ee1090 100644 --- a/src/extras/shaders/neoRim.vert +++ b/src/extras/shaders/neoRim.vert @@ -3,14 +3,11 @@ uniform vec4 u_rampStart; uniform vec4 u_rampEnd; uniform vec3 u_rimData; -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/neoRimSkin.vert b/src/extras/shaders/neoRimSkin.vert index f16f2310..1515ad71 100644 --- a/src/extras/shaders/neoRimSkin.vert +++ b/src/extras/shaders/neoRimSkin.vert @@ -5,16 +5,11 @@ uniform vec4 u_rampStart; uniform vec4 u_rampEnd; uniform vec3 u_rimData; -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; -layout(location = 11) in vec4 in_weights; -layout(location = 12) in vec4 in_indices; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/neoRimSkin_gl3.inc b/src/extras/shaders/neoRimSkin_gl.inc similarity index 78% rename from src/extras/shaders/neoRimSkin_gl3.inc rename to src/extras/shaders/neoRimSkin_gl.inc index 70948e1f..01b739b2 100644 --- a/src/extras/shaders/neoRimSkin_gl3.inc +++ b/src/extras/shaders/neoRimSkin_gl.inc @@ -6,16 +6,11 @@ const char *neoRimSkin_vert_src = "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" +"VSIN(ATTRIB_POS) vec3 in_pos;\n" -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" "void\n" "main(void)\n" diff --git a/src/extras/shaders/neoRim_gl3.inc b/src/extras/shaders/neoRim_gl.inc similarity index 77% rename from src/extras/shaders/neoRim_gl3.inc rename to src/extras/shaders/neoRim_gl.inc index 7e36e95a..7cd199d0 100644 --- a/src/extras/shaders/neoRim_gl3.inc +++ b/src/extras/shaders/neoRim_gl.inc @@ -4,14 +4,11 @@ const char *neoRim_vert_src = "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" +"VSIN(ATTRIB_POS) vec3 in_pos;\n" -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" "void\n" "main(void)\n" diff --git a/src/extras/shaders/neoVehicle.frag b/src/extras/shaders/neoVehicle.frag index 96d4a632..2ac24f70 100644 --- a/src/extras/shaders/neoVehicle.frag +++ b/src/extras/shaders/neoVehicle.frag @@ -1,13 +1,11 @@ uniform sampler2D tex0; uniform sampler2D tex1; -in vec4 v_color; -in vec4 v_reflcolor; -in vec2 v_tex0; -in vec2 v_tex1; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec4 v_reflcolor; +FSIN vec2 v_tex0; +FSIN vec2 v_tex1; +FSIN float v_fog; void main(void) @@ -20,9 +18,12 @@ main(void) vec3 pass2 = v_reflcolor.rgb * v_fog; + vec4 color; color.rgb = pass1.rgb*pass1.a + pass2; color.a = pass1.a; // color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog); DoAlphaTest(color.a); + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/neoVehicle.vert b/src/extras/shaders/neoVehicle.vert index f2f54d6d..f0224ddb 100644 --- a/src/extras/shaders/neoVehicle.vert +++ b/src/extras/shaders/neoVehicle.vert @@ -8,16 +8,13 @@ uniform vec4 u_specColor[5]; #define shininess (u_reflProps.z) #define specularity (u_reflProps.w) -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec4 v_reflcolor; -out vec2 v_tex0; -out vec2 v_tex1; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec4 v_reflcolor; +VSOUT vec2 v_tex0; +VSOUT vec2 v_tex1; +VSOUT float v_fog; vec3 DoDirLightSpec(vec3 Ldir, vec3 Lcol, vec3 N, vec3 V, float power) { diff --git a/src/extras/shaders/neoVehicle_fs_gl3.inc b/src/extras/shaders/neoVehicle_fs_gl.inc similarity index 80% rename from src/extras/shaders/neoVehicle_fs_gl3.inc rename to src/extras/shaders/neoVehicle_fs_gl.inc index c75ba717..20537440 100644 --- a/src/extras/shaders/neoVehicle_fs_gl3.inc +++ b/src/extras/shaders/neoVehicle_fs_gl.inc @@ -2,13 +2,11 @@ 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" +"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" @@ -21,10 +19,13 @@ const char *neoVehicle_frag_src = " 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_gl3.inc b/src/extras/shaders/neoVehicle_vs_gl.inc similarity index 83% rename from src/extras/shaders/neoVehicle_vs_gl3.inc rename to src/extras/shaders/neoVehicle_vs_gl.inc index 268180e1..b7b42622 100644 --- a/src/extras/shaders/neoVehicle_vs_gl3.inc +++ b/src/extras/shaders/neoVehicle_vs_gl.inc @@ -9,16 +9,13 @@ const char *neoVehicle_vert_src = "#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" +"VSIN(ATTRIB_POS) vec3 in_pos;\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" +"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" 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_gl3.inc b/src/extras/shaders/neoWorldIII_fs_gl.inc similarity index 70% rename from src/extras/shaders/neoWorldIII_fs_gl3.inc rename to src/extras/shaders/neoWorldIII_fs_gl.inc index 5145f9cd..afd75f57 100644 --- a/src/extras/shaders/neoWorldIII_fs_gl3.inc +++ b/src/extras/shaders/neoWorldIII_fs_gl.inc @@ -4,12 +4,10 @@ const char *neoWorldIII_frag_src = "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" +"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" @@ -17,11 +15,13 @@ const char *neoWorldIII_frag_src = " 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" +" 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/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/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_gl3.inc b/src/extras/shaders/simple_fs_gl.inc similarity index 69% rename from src/extras/shaders/simple_fs_gl3.inc rename to src/extras/shaders/simple_fs_gl.inc index 47d89971..614d79a0 100644 --- a/src/extras/shaders/simple_fs_gl3.inc +++ b/src/extras/shaders/simple_fs_gl.inc @@ -1,18 +1,19 @@ 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" +"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 b9ff0144..2e04aed2 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); @@ -294,32 +299,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; } @@ -462,6 +447,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; @@ -509,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; @@ -550,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; } @@ -749,6 +803,9 @@ RwBool RpWorldPluginAttach(void) { registerNativeDataPlugin(); registerAtomicRightsPlugin(); registerMaterialRightsPlugin(); + + // not sure if this goes here + rw::xbox::registerVertexFormatPlugin(); return true; } @@ -905,14 +962,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 - return '3LGO'; -#endif - return flags & 0xF00; -} 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/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/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/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/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/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/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index a024bb40..17754211 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)) @@ -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 } @@ -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/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/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 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 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/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/peds/Ped.cpp b/src/peds/Ped.cpp index fcfd9bce..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,1649 +283,72 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) CPopulation::UpdatePedCount((ePedType)m_nPedType, false); } -uint32 -CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) +CPed::~CPed(void) { - CWeapon &weapon = GetWeapon(weaponType); - - if (HasWeapon(weaponType)) { - if (weapon.m_nAmmoTotal + ammo > 99999) - weapon.m_nAmmoTotal = 99999; - else - weapon.m_nAmmoTotal += ammo; - - weapon.Reload(); - } else { - weapon.Initialise(weaponType, ammo); - // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. - m_maxWeaponTypeAllowed++; - } - if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) - weapon.m_eWeaponState = WEAPONSTATE_READY; - - return weaponType; -} - -static RwObject* -RemoveAllModelCB(RwObject *object, void *data) -{ - RpAtomic *atomic = (RpAtomic*)object; - if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { - RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); - RpAtomicDestroy(atomic); - } - return object; -} - -static PedOnGroundState -CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround) -{ - PedOnGroundState stateToReturn; - float angleToFace; - CPed *currentPed = nil; - PedState currentPedState; - CPed *pedOnTheFloor = nil; - CPed *deadPed = nil; - CPed *pedBelow = nil; - bool foundDead = false; - bool foundOnTheFloor = false; - bool foundBelow = false; - float angleDiff; - float distance; - - if (!CGame::nastyGame) - return NO_PED; - - for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) { - - currentPed = attacker->m_nearPeds[currentPedId]; - - CVector posDifference = currentPed->GetPosition() - attacker->GetPosition(); - distance = posDifference.Magnitude(); - - if (distance < 2.0f) { - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - currentPed->GetPosition().x, currentPed->GetPosition().y, - attacker->GetPosition().x, attacker->GetPosition().y); - - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur); - - angleDiff = Abs(angleToFace - attacker->m_fRotationCur); - - if (angleDiff > PI) - angleDiff = 2 * PI - angleDiff; - - currentPedState = currentPed->m_nPedState; - - if (currentPed->OnGroundOrGettingUp()) { - if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { - if (currentPedState == PED_DEAD) { - foundDead = 1; - if (!deadPed) - deadPed = currentPed; - } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { - foundOnTheFloor = 1; - if (!pedOnTheFloor) - pedOnTheFloor = currentPed; - } - } - } else if ((distance < 0.8f && angleDiff < DEGTORAD(75.0f)) - || (distance < 1.3f && angleDiff < DEGTORAD(55.0f)) - || (distance < 1.7f && angleDiff < DEGTORAD(35.0f)) - || (distance < 2.0f && angleDiff < DEGTORAD(30.0f))) { - - // Either this condition or below one was probably returning 4 early in development. See Fight(). - foundBelow = 1; - pedBelow = currentPed; - break; - } else { - if (angleDiff < DEGTORAD(75.0f)) { - foundBelow = 1; - if (!pedBelow) - pedBelow = currentPed; - } - } + CWorld::Remove(this); + CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); + if (InVehicle()){ + uint8 door_flag = GetCarDoorFlag(m_vehEnterType); + if (m_pMyVehicle->pDriver == this) + m_pMyVehicle->pDriver = nil; + else { + // FIX: Passenger counter now decreasing after removing ourself from vehicle. + m_pMyVehicle->RemovePassenger(this); } + if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) + m_pMyVehicle->m_nGettingOutFlags &= ~door_flag; + bInVehicle = false; + m_pMyVehicle = nil; + } else if (EnteringCar()) { + QuitEnteringCar(); } - - if (foundOnTheFloor) { - currentPed = pedOnTheFloor; - stateToReturn = PED_ON_THE_FLOOR; - } else if (foundDead) { - currentPed = deadPed; - stateToReturn = PED_DEAD_ON_THE_FLOOR; - } else if (foundBelow) { - currentPed = pedBelow; - stateToReturn = PED_IN_FRONT_OF_ATTACKER; - } else { - currentPed = nil; - stateToReturn = NO_PED; - } - - if (pedOnGround) - *pedOnGround = currentPed; - - return stateToReturn; -} - -bool -CPed::IsPlayer(void) -{ - return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType == PEDTYPE_PLAYER2 || - m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; -} - -bool -CPed::UseGroundColModel(void) -{ - return m_nPedState == PED_FALL || - m_nPedState == PED_DIVE_AWAY || - m_nPedState == PED_DIE || - m_nPedState == PED_DEAD; -} - -bool -CPed::CanSetPedState(void) -{ - return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; -} - -bool -CPed::IsPedInControl(void) -{ - return m_nPedState <= PED_STATES_NO_AI - && !bIsInTheAir && !bIsLanding - && m_fHealth > 0.0f; -} - -bool -CPed::CanStrafeOrMouseControl(void) -{ -#ifdef FREE_CAM - if (CCamera::bFreeCam) - return false; -#endif - return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || - m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; + if (m_pFire) + m_pFire->Extinguish(); + CPopulation::UpdatePedCount((ePedType)m_nPedType, true); + DMAudio.DestroyEntity(m_audioEntityId); } void -CPed::AddWeaponModel(int id) +CPed::Initialise(void) { - RpAtomic *atm; + debug("Initialising CPed...\n"); + CPedType::Initialise(); + LoadFightData(); + SetAnimOffsetForEnterOrExitVehicle(); + debug("CPed ready\n"); +} + +void +CPed::SetModelIndex(uint32 mi) +{ + CEntity::SetModelIndex(mi); + RpAnimBlendClumpInit(GetClump()); + RpAnimBlendClumpFillFrameArray(GetClump(), m_pFrames); + CPedModelInfo *modelInfo = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); + SetPedStats(modelInfo->m_pedStatType); + m_headingRate = m_pedStats->m_headingChangeRate; + m_animGroup = (AssocGroupId) modelInfo->m_animGroup; + CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE); + + // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; - if (id != -1) { #ifdef PED_SKIN - if (IsClumpSkinned(GetClump())) { - if (m_pWeaponModel) - RemoveWeaponModel(-1); - - m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - } else -#endif - { - atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - RwFrameDestroy(RpAtomicGetFrame(atm)); - RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); - RpClumpAddAtomic(GetClump(), atm); - } - m_wepModelID = id; - } -} - -void -CPed::AimGun(void) -{ - RwV3d pos; - CVector vector; - - if (m_pSeekTarget) { - if (m_pSeekTarget->IsPed()) { - ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID); - vector = pos; - } else { - vector = m_pSeekTarget->GetPosition(); - } - Say(SOUND_PED_ATTACK); - - bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(vector); - if (m_pLookTarget != m_pSeekTarget) { - SetLookFlag(m_pSeekTarget, true); - } - - } else { - if (IsPlayer()) { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); - } else { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); - } - } -} - -void -CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) -{ - CVector pos2 = CVector( - pos.x, - pos.y, - pos.z + 0.1f - ); - - if (!IsPlayer() || evenOnPlayer) { - ++CStats::HeadsPopped; - - // BUG: This condition will always return true. Even fixing it won't work, because these states are unused. - // if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { - SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - // } - - bBodyPartJustCameOff = true; - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; - - CParticle::AddParticle(PARTICLE_TEST, pos2, - CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); - - if (CEntity::GetIsOnScreen()) { - for(int i=0; i < 32; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos2, CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_DEBRIS2, - pos2, - CVector(0.0f, 0.0f, 0.01f), - nil, 0.0f, 0, 0, 0, 0); - } - } - } -} - -static RwObject* -SetPedAtomicVisibilityCB(RwObject* object, void* data) -{ - if (data == nil) - RpAtomicSetFlags((RpAtomic*)object, 0); - return object; -} - -static RwFrame* -RecurseFrameChildrenVisibilityCB(RwFrame* frame, void* data) -{ - RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); - RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); - return frame; -} - -void -CPed::RemoveBodyPart(PedNode nodeId, int8 direction) -{ - RwFrame *frame; - CVector pos; - - frame = m_pFrames[nodeId]->frame; - if (frame) { - if (CGame::nastyGame) { -#ifdef PED_SKIN - if(!IsClumpSkinned(GetClump())) -#endif - { -#ifdef DEBUGMENU - if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) -#else - if (nodeId != PED_HEAD) -#endif - SpawnFlyingComponent(nodeId, direction); - - RecurseFrameChildrenVisibilityCB(frame, nil); - } - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - TransformToNode(pos, PED_HEAD); - - if (CEntity::GetIsOnScreen()) { - CParticle::AddParticle(PARTICLE_TEST, pos, - CVector(0.0f, 0.0f, 0.0f), - nil, 0.1f, 0, 0, 0, 0); - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos, - CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - } - bBodyPartJustCameOff = true; - m_bodyPartBleeding = nodeId; - } - } else { - printf("Trying to remove ped component"); - } -} - -void -CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = target; - m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - m_fLookDirection = 999999.0f; - m_lookTimer = 0; - bKeepTryingToLook = keepTryingToLook; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - } - } -} - -void -CPed::SetLookFlag(float direction, bool keepTryingToLook) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = nil; - m_fLookDirection = direction; - m_lookTimer = 0; - bKeepTryingToLook = keepTryingToLook; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - } - } -} - -void -CPed::SetLookTimer(int time) -{ - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + time; - } -} - -bool -CPed::OurPedCanSeeThisOne(CEntity *target) -{ - CColPoint colpoint; - CEntity *ent; - - CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(GetPosition()); - - // Check if target is behind ped - if (DotProduct2D(dist, CVector2D(GetForward())) < 0.0f) - return false; - - // Check if target is too far away - if (dist.Magnitude() >= 40.0f) - return false; - - // Check line of sight from head - CVector headPos = this->GetPosition(); - headPos.z += 1.0f; - return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); -} - -void -CPed::Avoid(void) -{ - CPed *nearestPed; - - if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) - return; - - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { - - if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { - nearestPed = m_nearPeds[0]; - - if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { - - // Check if this ped wants to avoid the nearest one - if (CPedType::GetAvoid(m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { - - // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. - // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. - - // Game converts from radians to degress and back again here, doesn't make much sense - CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); - forward.Normalise(); // this is kinda pointless - - // Move forward 1.25 meters - CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; - - // Get distance to ped we want to avoid - CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; - - if (distToPed.Magnitude() <= 1.0f && OurPedCanSeeThisOne((CEntity*)nearestPed)) { - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() - + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) - % 1000 / 5; - - m_fRotationDest += DEGTORAD(45.0f); - if (!bIsLooking) { - SetLookFlag(nearestPed, false); - SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); - } - } - } - } - } - } -} - -void -CPed::ClearAimFlag(void) -{ - if (bIsAimingGun) { - bIsAimingGun = false; - bIsRestoringGun = true; - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; -#if defined VC_PED_PORTS || defined FIX_BUGS - m_lookTimer = 0; -#endif - } - - if (IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; -} - -void -CPed::ClearLookFlag(void) { - if (bIsLooking) { - bIsLooking = false; - bIsRestoringLook = true; - bShakeFist = false; - - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - if (IsPlayer()) - m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; - else - m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; - - if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { - ClearLook(); - } - } -} - -bool -CPed::IsPedHeadAbovePos(float zOffset) -{ - return zOffset + GetPosition().z < GetNodePosition(PED_HEAD).z; -} - -void -CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) -{ - CWeaponInfo *currentWeapon; - CAnimBlendAssociation *newAnim; - CPed *ped = (CPed*)arg; - - if (attackAssoc) { - switch (attackAssoc->animId) { - case ANIM_WEAPON_START_THROW: - // what?! - if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->m_bHaveTargetSelected) && ped->IsPlayer()) { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU); - } else { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROW); - } - - newAnim->SetFinishCallback(FinishedAttackCB, ped); - return; - - case ANIM_FIGHT_PPUNCH: - attackAssoc->blendDelta = -8.0f; - attackAssoc->flags |= ASSOC_DELETEFADEDOUT; - ped->ClearAttack(); - return; - - case ANIM_WEAPON_THROW: - case ANIM_WEAPON_THROWU: - if (ped->GetWeapon()->m_nAmmoTotal > 0) { - currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); - ped->AddWeaponModel(currentWeapon->m_nModelId); - } - break; - default: - break; - } - } - - if (!ped->bIsAttacking) - ped->ClearAttack(); -} - -void -CPed::Attack(void) -{ - CAnimBlendAssociation *weaponAnimAssoc; - int32 weaponAnim; - float animStart; - eWeaponType ourWeaponType; - float weaponAnimTime; - eWeaponFire ourWeaponFire; - float animLoopEnd; - CWeaponInfo *ourWeapon; - bool attackShouldContinue; - AnimationId reloadAnim; - CAnimBlendAssociation *reloadAnimAssoc; - float delayBetweenAnimAndFire; - CVector firePos; - - ourWeaponType = GetWeapon()->m_eWeaponType; - ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); - ourWeaponFire = ourWeapon->m_eWeaponFire; - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay); - attackShouldContinue = bIsAttacking; - reloadAnimAssoc = nil; - reloadAnim = NUM_ANIMS; - delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; - weaponAnim = ourWeapon->m_AnimToPlay; - - if (weaponAnim == ANIM_WEAPON_HGUN_BODY) - reloadAnim = ANIM_HGUN_RELOAD; - else if (weaponAnim == ANIM_WEAPON_AK_BODY) - reloadAnim = ANIM_AK_RELOAD; - - if (reloadAnim != NUM_ANIMS) - reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), reloadAnim); - - if (bIsDucking) - return; - - if (reloadAnimAssoc) { - if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) - ClearAttack(); - - return; - } - - if (CTimer::GetTimeInMilliseconds() < m_shootTimer) - attackShouldContinue = true; - - if (!weaponAnimAssoc) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay); - delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; - - // Long throw granade, molotov - if (!weaponAnimAssoc && ourWeapon->m_bThrow) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); - delayBetweenAnimAndFire = 0.2f; - } - - if (!weaponAnimAssoc) { - if (attackShouldContinue) { - if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { - if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { - weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } - else { - weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } - - weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); - weaponAnimAssoc->SetRun(); - - if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) - weaponAnimAssoc->SetCurrentTime(0.0f); - - if (IsPlayer()) { - ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f; - ((CPlayerPed*)this)->m_bHaveTargetSelected = false; - } - } - } else - FinishedAttackCB(nil, this); - - return; - } - } - - animStart = ourWeapon->m_fAnimLoopStart; - weaponAnimTime = weaponAnimAssoc->currentTime; - if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { - if (ourWeapon->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; - else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; - } - - if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { - if (weaponAnimAssoc->speed < 1.0f) - weaponAnimAssoc->speed = 1.0f; - - } else { - firePos = ourWeapon->m_vecFireOffset; - if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { - if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; - - firePos = GetMatrix() * firePos; - } else if (ourWeaponType != WEAPONTYPE_UNARMED) { - TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR); - } else { - firePos = GetMatrix() * firePos; - } - - GetWeapon()->Fire(this, &firePos); - - if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { - RemoveWeaponModel(ourWeapon->m_nModelId); - } - if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { - SelectGunIfArmed(); - } - - if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { - // If reloading just began, start the animation - // Last condition will always return true, even IDA hides it - if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS /* && !reloadAnimAssoc*/) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f); - ClearLookFlag(); - ClearAimFlag(); - bIsAttacking = false; - bIsPointingGunAt = false; - m_shootTimer = CTimer::GetTimeInMilliseconds(); - return; - } - } else { - if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); - } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); - } - - weaponAnimAssoc->speed = 0.5f; - - if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) { - weaponAnimAssoc->callbackType = 0; - } - } - - attackShouldContinue = false; - } - - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { - weaponAnimTime = weaponAnimAssoc->currentTime; - firePos = ourWeapon->m_vecFireOffset; - - if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - TransformToNode(firePos, PED_HANDR); - - CVector gunshellPos( - firePos.x - 0.6f * GetForward().x, - firePos.y - 0.6f * GetForward().y, - firePos.z - 0.15f * GetUp().z - ); - - CVector2D gunshellRot( - GetRight().x, - GetRight().y - ); - - gunshellRot.Normalise(); - GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); - } - } -#ifdef VC_PED_PORTS - if (IsPlayer()) { - if (CPad::GetPad(0)->GetSprint()) { - // animBreakout is a member of WeaponInfo in VC, so it's me that added the below line. - float animBreakOut = ((ourWeaponType == WEAPONTYPE_FLAMETHROWER || ourWeaponType == WEAPONTYPE_UZI || ourWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f); - if (!attackShouldContinue && weaponAnimAssoc->currentTime > animBreakOut) { - weaponAnimAssoc->blendDelta = -4.0f; - FinishedAttackCB(nil, this); - return; - } - } - } -#endif - animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - animLoopEnd = 3.4f/6.0f; - - weaponAnimTime = weaponAnimAssoc->currentTime; - - // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { - - if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd - && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) - && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - - weaponAnim = weaponAnimAssoc->animId; - if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { - if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { - weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); - } else { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } - } else { - if (weaponAnim == ourWeapon->m_Anim2ToPlay) - weaponAnimAssoc->SetCurrentTime(0.1f); - else - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } -#ifdef VC_PED_PORTS - } else if (IsPlayer() && m_pPointGunAt && bIsAimingGun && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - weaponAnimAssoc->SetCurrentTime(ourWeapon->m_fAnimLoopEnd); - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - SetPointGunAt(m_pPointGunAt); -#endif - } else { - ClearAimFlag(); - - // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) - if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { - switch (ourWeaponType) { - case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_M16: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); - break; - default: - break; - } - } - - // Fun fact: removing this part leds to reloading flamethrower - if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { - weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - weaponAnimAssoc->blendDelta = -4.0f; - } - } - } - if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) - attackShouldContinue = false; - - bIsAttacking = attackShouldContinue; -} - -void -CPed::RemoveWeaponModel(int modelId) -{ - // modelId is not used!! This function just removes the current weapon. -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - if(m_pWeaponModel){ - RwFrame *frm = RpAtomicGetFrame(m_pWeaponModel); - RpAtomicDestroy(m_pWeaponModel); - RwFrameDestroy(frm); - m_pWeaponModel = nil; - } - }else -#endif - RwFrameForAllObjects(m_pFrames[PED_HANDR]->frame,RemoveAllModelCB,nil); - m_wepModelID = -1; -} - -void -CPed::SetCurrentWeapon(uint32 weaponType) -{ - CWeaponInfo *weaponInfo; - if (HasWeapon(weaponType)) { - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(weaponInfo->m_nModelId); - - m_currentWeapon = weaponType; - - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(weaponInfo->m_nModelId); - } -} - -// Only used while deciding which gun ped should switch to, if no ammo left. -bool -CPed::SelectGunIfArmed(void) -{ - for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { - if (GetWeapon(i).m_nAmmoTotal > 0) { - eWeaponType weaponType = GetWeapon(i).m_eWeaponType; - if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { - SetCurrentWeapon(i); - return true; - } - } - } - SetCurrentWeapon(WEAPONTYPE_UNARMED); - return false; -} - -void -CPed::Duck(void) -{ - if (CTimer::GetTimeInMilliseconds() > m_duckTimer) - ClearDuck(); -} - -void -CPed::ClearDuck(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); - - if (!animAssoc) { - bIsDucking = false; - return; - } - } - - if (!bCrouchWhenShooting) - return; - - if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN) - return; - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); - } -} - -void -CPed::ClearPointGunAt(void) -{ - CAnimBlendAssociation *animAssoc; - CWeaponInfo *weaponInfo; - - ClearLookFlag(); - ClearAimFlag(); - bIsPointingGunAt = false; -#ifndef VC_PED_PORTS - if (m_nPedState == PED_AIM_GUN) { - RestorePreviousState(); -#else - if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { - m_nPedState = PED_IDLE; - RestorePreviousState(); - } -#endif - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); - } - if (animAssoc) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->blendDelta = -4.0f; - } -#ifndef VC_PED_PORTS - } + if(modelInfo->GetHitColModel() == nil) + modelInfo->CreateHitColModelSkinned(GetClump()); #endif } void -CPed::BeingDraggedFromCar(void) +CPed::SetPedStats(ePedStats pedStat) { - CAnimBlendAssociation *animAssoc; - AnimationId enterAnim; - bool dontRunAnim = false; - PedLineUpPhase lineUpType; - - if (!m_pVehicleAnim) { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO); - } - } - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - if (bWillBeQuickJacked) { - enterAnim = ANIM_CAR_QJACKED; - } else if (m_pMyVehicle->bLowVehicle) { - enterAnim = ANIM_CAR_LJACKED_LHS; - } else { - enterAnim = ANIM_CAR_JACKED_LHS; - } - } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - if (m_pMyVehicle->bLowVehicle) - enterAnim = ANIM_CAR_LJACKED_RHS; - else - enterAnim = ANIM_CAR_JACKED_RHS; - } else - dontRunAnim = true; - - - if (!dontRunAnim) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, enterAnim); - - m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this); - lineUpType = LINE_UP_TO_CAR_START; - } else if (m_pVehicleAnim->currentTime <= 1.4f) { - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - lineUpType = LINE_UP_TO_CAR_START; - } else { - lineUpType = LINE_UP_TO_CAR_2; - } - - LineUpPedWithCar(lineUpType); -#ifdef VC_PED_PORTS - if (m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - if (m_pMyVehicle) { - m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); - } - } -#endif -} - -void -CPed::RestartNonPartialAnims(void) -{ - CAnimBlendAssociation *assoc; - - for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->SetRun(); - } -} - -void -CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) -{ - CAnimBlendAssociation *quickJackedAssoc; - CVehicle *vehicle; - CPed *ped = (CPed*)arg; - - quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED); - if (ped->m_nPedState != PED_ARRESTED) { - ped->m_nLastPedState = PED_NONE; - if (dragAssoc) - dragAssoc->blendDelta = -1000.0f; - } - ped->RestartNonPartialAnims(); - ped->m_pVehicleAnim = nil; - ped->m_pSeekTarget = nil; - vehicle = ped->m_pMyVehicle; - - if (vehicle) { - vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - - if (vehicle->pDriver == ped) { - vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - vehicle->m_nDoorLock = CARLOCK_UNLOCKED; - - if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) - vehicle->ChangeLawEnforcerState(false); - } else { - vehicle->RemovePassenger(ped); - } - } - ped->bInVehicle = false; - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); - -#ifdef VC_PED_PORTS - if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - ped->m_fHealth = 0.0f; - ped->SetDie(ANIM_FLOOR_HIT, 1000.0f, 0.5f); - return; - } -#endif - - if (quickJackedAssoc) { - dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); - } else { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - if (ped->CanSetPedState()) - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - } - - ped->ReplaceWeaponWhenExitingVehicle(); - - ped->m_nStoredMoveState = PEDMOVE_NONE; - ped->bVehExitWillBeInstant = false; -} - -CVector -CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult) -{ - CVehicleModelInfo *vehModel; - CVector vehDoorPos; - CVector vehDoorOffset; - float seatOffset; - - vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); - if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) { - seatOffset = 0.0f; - vehDoorOffset = vecPedVanRearDoorAnimOffset; - } else { - seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult; - if (veh->bLowVehicle) { - vehDoorOffset = vecPedCarDoorLoAnimOffset; - } else { - vehDoorOffset = vecPedCarDoorAnimOffset; - } - } - - switch (component) { - case CAR_DOOR_RF: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case CAR_DOOR_RR: - vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case CAR_DOOR_LF: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - case CAR_DOOR_LR: - vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - default: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); - } - return vehDoorPos - vehDoorOffset; -} - -// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. -CVector -CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component) -{ - CVector localPos; - CVector vehDoorPos; - - localPos = GetLocalPositionToOpenCarDoor(veh, component, 1.0f); - vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); - -/* - // Not used. - CVector localVehDoorOffset; - - if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) { - localVehDoorOffset = vecPedVanRearDoorAnimOffset; - } else { - if (veh->bIsLow) { - localVehDoorOffset = vecPedCarDoorLoAnimOffset; - } else { - localVehDoorOffset = vecPedCarDoorAnimOffset; - } - } - - vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); -*/ - return vehDoorPos; -} - -CVector -CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset) -{ - CVector doorPos; - CMatrix vehMat(veh->GetMatrix()); - - doorPos = Multiply3x3(vehMat, GetLocalPositionToOpenCarDoor(veh, component, offset)); - - return veh->GetPosition() + doorPos; -} - -void -CPed::LineUpPedWithCar(PedLineUpPhase phase) -{ - bool vehIsUpsideDown = false; - int vehAnim; - float seatPosMult = 0.0f; - float currentZ; - float adjustedTimeStep; - - if (CReplay::IsPlayingBack()) - return; - - if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) { - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO)) { - SetPedPositionInCar(); - return; - } - bChangedSeat = true; - } - if (phase == LINE_UP_TO_CAR_START) { - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } - CVehicle *veh = m_pMyVehicle; - - // Not quite right, IsUpsideDown func. checks for <= -0.9f. - if (veh->GetUp().z <= -0.8f) - vehIsUpsideDown = true; - - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - if (vehIsUpsideDown) { - m_fRotationDest = -PI + veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - if (vehIsUpsideDown) { - m_fRotationDest = veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = -0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } else { - // I don't know will this part ever run(maybe boats?), but the game also handles that. I don't know is it intentional. - - if (vehIsUpsideDown) { - m_fRotationDest = veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } - - if (!bInVehicle) - seatPosMult = 1.0f; - -#ifdef VC_PED_PORTS - bool multExtractedFromAnim = false; - bool multExtractedFromAnimBus = false; - float zBlend; -#endif - if (m_pVehicleAnim) { - vehAnim = m_pVehicleAnim->animId; - - switch (vehAnim) { - case ANIM_CAR_JACKED_RHS: - case ANIM_CAR_LJACKED_RHS: - case ANIM_CAR_JACKED_LHS: - case ANIM_CAR_LJACKED_LHS: - case ANIM_VAN_GETIN_L: - case ANIM_VAN_GETIN: -#ifdef VC_PED_PORTS - multExtractedFromAnim = true; - zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.3f, 0.0f) / (1.0f - 0.3f); - // fall through -#endif - case ANIM_CAR_QJACKED: - case ANIM_CAR_GETOUT_LHS: - case ANIM_CAR_GETOUT_LOW_LHS: - case ANIM_CAR_GETOUT_RHS: - case ANIM_CAR_GETOUT_LOW_RHS: -#ifdef VC_PED_PORTS - if (!multExtractedFromAnim) { - multExtractedFromAnim = true; - zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.5f, 0.0f) / (1.0f - 0.5f); - } - // fall through -#endif - case ANIM_CAR_CRAWLOUT_RHS: - case ANIM_CAR_CRAWLOUT_RHS2: - case ANIM_VAN_GETOUT_L: - case ANIM_VAN_GETOUT: - seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; - break; - case ANIM_CAR_GETIN_RHS: - case ANIM_CAR_GETIN_LHS: -#ifdef VC_PED_PORTS - if (veh && veh->IsCar() && veh->bIsBus) { - multExtractedFromAnimBus = true; - zBlend = Min(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength, 0.5f) / 0.5f; - } - // fall through -#endif - case ANIM_CAR_QJACK: - case ANIM_CAR_GETIN_LOW_LHS: - case ANIM_CAR_GETIN_LOW_RHS: - case ANIM_DRIVE_BOAT: - seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; - break; - case ANIM_CAR_CLOSEDOOR_LHS: - case ANIM_CAR_CLOSEDOOR_LOW_LHS: - case ANIM_CAR_CLOSEDOOR_RHS: - case ANIM_CAR_CLOSEDOOR_LOW_RHS: - case ANIM_CAR_SHUFFLE_RHS: - case ANIM_CAR_LSHUFFLE_RHS: - seatPosMult = 0.0f; - break; - case ANIM_CAR_CLOSE_LHS: - case ANIM_CAR_CLOSE_RHS: - case ANIM_COACH_OPEN_L: - case ANIM_COACH_OPEN_R: - case ANIM_COACH_IN_L: - case ANIM_COACH_IN_R: - case ANIM_COACH_OUT_L: - seatPosMult = 1.0f; - break; - default: - break; - } - } - - CVector neededPos; - - if (phase == LINE_UP_TO_CAR_2) { - neededPos = GetPosition(); - } else { - neededPos = GetPositionToOpenCarDoor(veh, m_vehEnterType, seatPosMult); - } - - CVector autoZPos = neededPos; - - if (veh->bIsInWater) { - if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) - autoZPos.z += 1.0f; - } else { - CPedPlacement::FindZCoorForPed(&autoZPos); - } - - if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { - neededPos.z = GetPosition().z; - - // Getting out - if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { - float nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); - - // If we're not in ground at next step, apply animation - if (neededPos.z + nextZSpeed >= autoZPos.z) { - m_vecMoveSpeed.z = nextZSpeed; - ApplyMoveSpeed(); - // Removing below line breaks the animation - neededPos.z = GetPosition().z; - } else { - neededPos.z = autoZPos.z; - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } - } - } - - if (autoZPos.z > neededPos.z) { -#ifdef VC_PED_PORTS - if (multExtractedFromAnim) { - neededPos.z += (autoZPos.z - neededPos.z) * zBlend; - } else { -#endif - currentZ = GetPosition().z; - if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { - neededPos.z = autoZPos.z; - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { - adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); - - // Smoothly change ped position - neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); - } -#ifdef VC_PED_PORTS - } -#endif - } else { - // We may need to raise up the ped - if (phase == LINE_UP_TO_CAR_START) { - currentZ = GetPosition().z; - - if (neededPos.z > currentZ) { -#ifdef VC_PED_PORTS - if (multExtractedFromAnimBus) { - neededPos.z = (neededPos.z - currentZ) * zBlend + currentZ; - } else { -#endif - if (m_pVehicleAnim && - (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS - || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { - adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); - - // Smoothly change ped position - neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; - } else if (EnteringCar()) { - neededPos.z = Max(currentZ, autoZPos.z); - } -#ifdef VC_PED_PORTS - } -#endif - } - } - } - - bool stillGettingInOut = false; - if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) - stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; - - if (!stillGettingInOut) { - m_fRotationCur = m_fRotationDest; - } else { - float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); - float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; - - if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0f; - m_vecOffsetSeek.y = 0.0f; - } - m_vecOffsetSeek.z = 0.0f; - - neededPos -= timeUntilStateChange * m_vecOffsetSeek; - - if (PI + m_fRotationCur < limitedDest) { - limitedDest -= 2 * PI; - } else if (m_fRotationCur - PI > limitedDest) { - limitedDest += 2 * PI; - } - m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); - } - - if (seatPosMult > 0.2f || vehIsUpsideDown) { - SetPosition(neededPos); - SetHeading(m_fRotationCur); - } else { - CMatrix vehDoorMat(veh->GetMatrix()); - vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); - // VC couch anims are inverted, so they're fixing it here. - GetMatrix() = vehDoorMat; - } - -} - -static void -particleProduceFootDust(CPed *ped, CVector const &pos, float size, int times) -{ - switch (ped->m_nSurfaceTouched) - { - case SURFACE_TARMAC: - case SURFACE_GRAVEL: - case SURFACE_PAVEMENT: - case SURFACE_SAND: - for (int i = 0; i < times; ++i) { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); - } - break; - default: - break; - } -} - -static void -particleProduceFootSplash(CPed *ped, CVector const &pos, float size, int times) -{ -#ifdef PC_PARTICLE - for (int i = 0; i < times; i++) { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - - CVector direction = ped->GetForward() * -0.05f; - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumber() & 1, 200); - } -#else - for ( int32 i = 0; i < times; i++ ) - { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); - - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, CGeneral::GetRandomNumber() & 1, 200); - } -#endif -} - -void -CPed::PlayFootSteps(void) -{ - if (bDoBloodyFootprints) { - if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { - m_bloodyFootprintCountOrDeathTime--; - - if (m_bloodyFootprintCountOrDeathTime == 0) - bDoBloodyFootprints = false; - } - } - - if (!bIsStanding) - return; - - CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); - CAnimBlendAssociation *walkRunAssoc = nil; - float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; - - for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (assoc->flags & ASSOC_WALK) { - walkRunAssoc = assoc; - walkRunAssocBlend += assoc->blendAmount; - } else if ((assoc->flags & ASSOC_NOWALK) == 0) { - idleAssocBlend += assoc->blendAmount; - } - } - -#ifdef GTA_PS2_STUFF - CAnimBlendAssociation *runStopAsoc = NULL; - - if ( IsPlayer() ) - { - runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - - if ( runStopAsoc == NULL ) - runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); - } - - if ( runStopAsoc != NULL && runStopAsoc->blendAmount > 0.1f ) - { - { - CVector pos(0.0f, 0.0f, 0.0f); - TransformToNode(pos, PED_FOOTL); - - pos.z -= 0.1f; - pos += GetForward()*0.2f; - particleProduceFootDust(this, pos, 0.02f, 1); - } - - { - CVector pos(0.0f, 0.0f, 0.0f); - TransformToNode(pos, PED_FOOTR); - - pos.z -= 0.1f; - pos += GetForward()*0.2f; - particleProduceFootDust(this, pos, 0.02f, 1); - } - } -#endif - - - if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { - float stepStart = 1 / 15.0f; - float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; - float currentTime = walkRunAssoc->currentTime; - int stepPart = 0; - - if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) - stepPart = 1; - else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) - stepPart = 2; - - if (stepPart != 0) { - DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); - CVector footPos(0.0f, 0.0f, 0.0f); - TransformToNode(footPos, stepPart == 1 ? PED_FOOTL : PED_FOOTR); - - CVector forward = GetForward(); - - footPos.z -= 0.1f; - footPos += 0.2f * forward; - - if (bDoBloodyFootprints) { - CVector2D top(forward * 0.26f); - CVector2D right(GetRight() * 0.14f); - - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos, - top.x, top.y, - right.x, right.y, - 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); - - if (m_bloodyFootprintCountOrDeathTime <= 20) { - m_bloodyFootprintCountOrDeathTime = 0; - bDoBloodyFootprints = false; - } else { - m_bloodyFootprintCountOrDeathTime -= 20; - } - } - if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { - if(IsPlayer()) - particleProduceFootDust(this, footPos, 0.0f, 4); - } -#ifdef PC_PARTICLE - else if(stepPart == 2) -#else - else -#endif - { - particleProduceFootSplash(this, footPos, 0.15f, 4); - } - } - } - - if (m_nSurfaceTouched == SURFACE_WATER) { - float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); - if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { -#ifdef PC_PARTICLE - float particleSize = pedSpeed * 2.0f; - - if (particleSize < 0.25f) - particleSize = 0.25f; - - if (particleSize > 0.75f) - particleSize = 0.75f; - - CVector particlePos = GetPosition() + GetForward() * 0.3f; - particlePos.z -= 1.2f; - - CVector particleDir = m_vecMoveSpeed * -0.75f; - - particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); - CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); - - particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); - CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); -#else - CVector particlePos = (GetPosition() - 0.3f * GetUp()) + GetForward()*0.3f; - CVector particleDir = m_vecMoveSpeed * 0.45f; - particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); - CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos-CVector(0.0f, 0.0f, 1.2f), particleDir, nil, 0.0f, CRGBA(155, 185, 155, 255)); -#endif - } - } -} - -bool -CPed::IsPointerValid(void) -{ - int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; - if (pedIndex < 0 || pedIndex >= NUMPEDS) - return false; - - if (m_entryInfoList.first || FindPlayerPed() == this) - return true; - - return false; -} - -// Some kind of binary sort -void -CPed::SortPeds(CPed **list, int min, int max) -{ - if (min >= max) - return; - - CVector leftDiff, rightDiff; - CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); - float middleDist = middleDiff.Magnitude(); - - int left = max; - int right; - for(right = min; right <= left; ){ - float rightDist, leftDist; - do { - rightDiff = GetPosition() - list[right]->GetPosition(); - rightDist = rightDiff.Magnitude(); - } while (middleDist > rightDist && ++right); - - do { - leftDiff = GetPosition() - list[left]->GetPosition(); - leftDist = leftDiff.Magnitude(); - } while (middleDist < leftDist && left--); - - if (right <= left) { - CPed *ped = list[right]; - list[right] = list[left]; - list[left] = ped; - right++; - left--; - } - } - SortPeds(list, min, left); - SortPeds(list, right, max); + m_pedStats = CPedStats::ms_apPedStats[pedStat]; } void 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,110 +386,919 @@ 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++; + } } } -void -CPed::SetPedStats(ePedStats pedStat) -{ - m_pedStats = CPedStats::ms_apPedStats[pedStat]; -} - -void -CPed::SetModelIndex(uint32 mi) -{ - CEntity::SetModelIndex(mi); - RpAnimBlendClumpInit(GetClump()); - RpAnimBlendClumpFillFrameArray(GetClump(), m_pFrames); - CPedModelInfo *modelInfo = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); - SetPedStats(modelInfo->m_pedStatType); - m_headingRate = m_pedStats->m_headingChangeRate; - m_animGroup = (AssocGroupId) modelInfo->m_animGroup; - CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE); - - // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; - -#ifdef PED_SKIN - if(modelInfo->GetHitColModel() == nil) - modelInfo->CreateHitColModelSkinned(GetClump()); -#endif -} - -void -CPed::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} - bool -CPed::SetupLighting(void) +CPed::OurPedCanSeeThisOne(CEntity *target) { - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); + CColPoint colpoint; + CEntity *ent; -#ifndef MASTER - // Originally this was being called through iteration of Sectors, but putting it here is better. - if (GetDebugDisplay() != 0 && !IsPlayer()) - DebugRenderOnePedText(); -#endif + CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(GetPosition()); - if (bRenderScorched) { - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - } else { - // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. - float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); - if (!bHasBlip && lightMult != 1.0f) { - SetAmbientAndDirectionalColours(lightMult); - return true; - } - } - return false; + // Check if target is behind ped + if (DotProduct2D(dist, CVector2D(GetForward())) < 0.0f) + return false; + + // Check if target is too far away + if (dist.Magnitude() >= 40.0f) + return false; + + // Check line of sight from head + CVector headPos = this->GetPosition(); + headPos.z += 1.0f; + return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); } +// Some kind of binary sort void -CPed::Teleport(CVector pos) +CPed::SortPeds(CPed **list, int min, int max) { - CWorld::Remove(this); - SetPosition(pos); - bIsStanding = false; - m_nPedStateTimer = 0; - m_actionX = 0.0f; - m_actionY = 0.0f; - m_pDamageEntity = nil; - CWorld::Add(this); -} - -void -CPed::CalculateNewOrientation(void) -{ - if (CReplay::IsPlayingBack() || !IsPedInControl()) + if (min >= max) return; - SetHeading(m_fRotationCur); + CVector leftDiff, rightDiff; + CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); + float middleDist = middleDiff.Magnitude(); + + int left = max; + int right = min; + while(right <= left){ + float rightDist, leftDist; + do { + rightDiff = GetPosition() - list[right]->GetPosition(); + rightDist = rightDiff.Magnitude(); + } while (middleDist > rightDist && ++right); + + do { + leftDiff = GetPosition() - list[left]->GetPosition(); + leftDist = leftDiff.Magnitude(); + } while (middleDist < leftDist && left--); + + if (right <= left) { + CPed *ped = list[right]; + list[right] = list[left]; + list[left] = ped; + right++; + left--; + } + } + SortPeds(list, min, left); + SortPeds(list, right, max); } -float -CPed::WorkOutHeadingForMovingFirstPerson(float offset) +void +CPed::SetMoveState(eMoveState state) { - if (!IsPlayer()) - return 0.0f; + m_nMoveState = state; +} - CPad *pad0 = CPad::GetPad(0); - float leftRight = pad0->GetPedWalkLeftRight(); - float upDown = pad0->GetPedWalkUpDown(); - float &angle = ((CPlayerPed*)this)->m_fWalkAngle; +void +CPed::SetMoveAnim(void) +{ + if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) + return; - 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_nMoveState == PEDMOVE_NONE) { + m_nStoredMoveState = PEDMOVE_NONE; + return; } - return CGeneral::LimitRadianAngle(offset + angle); + AssocGroupId animGroupToUse; + if (m_leader && m_leader->IsPlayer()) + animGroupToUse = ASSOCGRP_PLAYER; + else + animGroupToUse = m_animGroup; + + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_BLOCK); + if (!animAssoc) { + CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); + animAssoc = fightIdleAssoc; + if (fightIdleAssoc && m_nPedState == PED_FIGHT) + return; + + if (fightIdleAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); + } + } + } + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) + if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) + return; + + if (animAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + } + } + } + if (!animAssoc) { + m_nStoredMoveState = m_nMoveState; + if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { + for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); + assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { + + if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { + assoc->blendDelta = -2.0f; + assoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + + ClearAimFlag(); + ClearLookFlag(); + } + + switch (m_nMoveState) { + case PEDMOVE_STILL: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + 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 (animAssoc) { + if (m_leader) { + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); + + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); + + if (walkAssoc) { + animAssoc->speed = walkAssoc->speed; + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + + } + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + } + } + } +} + +void +CPed::StopNonPartialAnims(void) +{ + CAnimBlendAssociation *assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->flags &= ~ASSOC_RUNNING; + } +} + +void +CPed::RestartNonPartialAnims(void) +{ + CAnimBlendAssociation *assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->SetRun(); + } +} + +void +CPed::SetStoredState(void) +{ + if (m_nLastPedState != PED_NONE || !CanPedReturnToState()) + return; + + 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::RestorePreviousState(void) +{ + if(!CanSetPedState() || m_nPedState == PED_FALL) + return; + + if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) + return; + + 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; + } + + 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; + } +} + +uint32 +CPed::ScanForThreats(void) +{ + int fearFlags = m_fearFlags; + CVector ourPos = GetPosition(); + float closestPedDist = 60.0f; + CVector2D explosionPos = GetPosition(); + if (fearFlags & PED_FLAG_EXPLOSION && CheckForExplosions(explosionPos)) { + m_eventOrThreat = explosionPos; + return PED_FLAG_EXPLOSION; + } + + 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 (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { + m_threatEntity = shooter; + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + return CPedType::GetFlag(shooter->m_nPedType); + } + } + + 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; + + CPed *pedToFearFrom = nil; +#ifndef VC_PED_PORTS + for (int i = 0; i < m_numNearPeds; i++) { + if (CharCreatedBy != RANDOM_CHAR || m_nearPeds[i]->CharCreatedBy != MISSION_CHAR || m_nearPeds[i]->IsPlayer()) { + CPed *nearPed = m_nearPeds[i]; + + // BUG: WTF Rockstar?! Putting this here will result in returning the flags of farthest ped to us, since m_nearPeds is sorted by distance. + // Fixed at the bottom of the function. + flagsOfSomePed = CPedType::GetFlag(nearPed->m_nPedType); + + if (CPedType::GetFlag(nearPed->m_nPedType) & fearFlags) { + if (nearPed->m_fHealth > 0.0f && OurPedCanSeeThisOne(m_nearPeds[i])) { + // FIX: Taken from VC +#ifdef FIX_BUGS + float nearPedDistSqr = (nearPed->GetPosition() - ourPos).MagnitudeSqr2D(); +#else + float nearPedDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); +#endif + if (sq(closestPedDist) > nearPedDistSqr) { + closestPedDist = Sqrt(nearPedDistSqr); + pedToFearFrom = m_nearPeds[i]; + } + } + } + } + } +#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)) { + + if (nearPed->m_pedInObjective == this) { + float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestEnemyDist) > enemyDistSqr) { + float enemyDist = Sqrt(enemyDistSqr); + weMaySeeOurEnemy = true; + closestPedDist = enemyDist; + closestEnemyDist = enemyDist; + pedToFearFrom = m_nearPeds[i]; + } + } else if (!nearPed->GetWeapon()->IsTypeMelee() && !weMaySeeOurEnemy) { + float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestPedDist) > nearPedDistSqr) { + weMaySeeOurEnemy = true; + closestPedDist = Sqrt(nearPedDistSqr); + pedToFearFrom = m_nearPeds[i]; + } + } + } + } + } + } + } + } + } +#endif + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(ourPos, 20.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle* foundVeh = nil; + for (int i = 0; i < lastVehicle; i++) { + CVehicle* nearVeh = (CVehicle*)vehicles[i]; + + CPed *driver = nearVeh->pDriver; + if (driver) { + + // BUG: Same bug as above. Fixed at the bottom of function. + flagsOfSomePed = CPedType::GetFlag(driver->m_nPedType); + if (CPedType::GetFlag(driver->m_nPedType) & fearFlags) { + if (driver->m_fHealth > 0.0f && OurPedCanSeeThisOne(nearVeh->pDriver)) { + // FIX: Taken from VC +#ifdef FIX_BUGS + float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); +#else + float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); +#endif + if (sq(closestPedDist) > driverDistSqr) { + closestPedDist = Sqrt(driverDistSqr); + pedToFearFrom = nearVeh->pDriver; + } + } + } + } + } + m_threatEntity = pedToFearFrom; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + +#ifdef FIX_BUGS + if (pedToFearFrom) + flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); + else + flagsOfSomePed = 0; +#endif + + return flagsOfSomePed; + } +} + +void +CPed::SetLookFlag(float direction, bool keepTryingToLook) +{ + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = nil; + m_fLookDirection = direction; + m_lookTimer = 0; + bKeepTryingToLook = keepTryingToLook; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + } + } +} + +void +CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) +{ + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = target; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + m_fLookDirection = 999999.0f; + m_lookTimer = 0; + bKeepTryingToLook = keepTryingToLook; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + } + } +} + +void +CPed::ClearLookFlag(void) { + if (bIsLooking) { + bIsLooking = false; + bIsRestoringLook = true; + bShakeFist = false; + + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + if (IsPlayer()) + m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; + else + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + + if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { + ClearLook(); + } + } +} + +void +FinishFuckUCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (animAssoc->animId == ANIM_FUCKU && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) + ped->RemoveWeaponModel(0); +} + +void +CPed::MoveHeadToLook(void) +{ + 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 +CPed::RestoreHeadPosition(void) +{ + if (m_pedIK.RestoreLookAt()) { + bIsRestoringLook = false; + } +} + +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::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::ClearAimFlag(void) +{ + if (bIsAimingGun) { + bIsAimingGun = false; + bIsRestoringGun = true; + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; +#if defined VC_PED_PORTS || defined FIX_BUGS + m_lookTimer = 0; +#endif + } + + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; +} + +void +CPed::AimGun(void) +{ + CVector vector; + + if (m_pSeekTarget) { + if (m_pSeekTarget->IsPed()) { + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(vector, PED_MID); + } else { + vector = m_pSeekTarget->GetPosition(); + } + Say(SOUND_PED_ATTACK); + + bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(vector); + if (m_pLookTarget != m_pSeekTarget) { + SetLookFlag(m_pSeekTarget, true); + } + + } else { + if (IsPlayer()) { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); + } else { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); + } + } +} + +void +CPed::RestoreGunPosition(void) +{ + if (bIsLooking) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + bIsRestoringGun = false; + } else if (m_pedIK.RestoreGunPosn()) { + bIsRestoringGun = false; + } else { + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; + } +} + +void +CPed::ScanForInterestingStuff(void) +{ + if (!IsPedInControl()) + return; + + if (m_objective != OBJECTIVE_NONE) + return; + + if (CharCreatedBy == MISSION_CHAR) + return; + + LookForSexyPeds(); + LookForSexyCars(); + if (LookForInterestingNodes()) + return; + + if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + if (CGeneral::GetRandomNumber() % 100 < 10) { + int mostExpensiveVehAround = -1; + int bestMonetaryValue = 0; + + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->VehicleCreatedBy != MISSION_VEHICLE) { + if (veh->m_vecMoveSpeed.Magnitude() <= 0.1f && veh->IsVehicleNormal() + && veh->IsCar() && bestMonetaryValue < veh->pHandling->nMonetaryValue) { + mostExpensiveVehAround = i; + bestMonetaryValue = veh->pHandling->nMonetaryValue; + } + } + } + if (bestMonetaryValue > 2000 && mostExpensiveVehAround != -1 && vehicles[mostExpensiveVehAround]) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, vehicles[mostExpensiveVehAround]); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + return; + } + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { + CPed *charToMug = nil; + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) + break; + + if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE + || nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->m_nPedType == PEDTYPE_UNUSED1 + || nearPed->m_nPedType == PEDTYPE_PROSTITUTE) + && nearPed->CharCreatedBy != MISSION_CHAR + && nearPed->IsPedShootable() + && nearPed->m_objective != OBJECTIVE_MUG_CHAR) { + charToMug = nearPed; + break; + } + } + if (charToMug) + SetObjective(OBJECTIVE_MUG_CHAR, charToMug); + + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } + } + + if (m_nPedState == PED_WANDER_PATH) { +#ifndef VC_PED_PORTS + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + // += 2 is weird + for (int i = 0; i < m_numNearPeds; i += 2) { + if (m_nearPeds[i]->m_nPedState == PED_WANDER_PATH && WillChat(m_nearPeds[i])) { + if (CGeneral::GetRandomNumberInRange(0, 100) >= 100) + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + else { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() >= 1.8f) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + } else if (CanSeeEntity(m_nearPeds[i])) { + int time = CGeneral::GetRandomNumber() % 4000 + 10000; + SetChat(m_nearPeds[i], time); + m_nearPeds[i]->SetChat(this, time); + return; + } + } + } + } + } +#else + if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.5f) { + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + for (int i = 0; i < m_numNearPeds; i ++) { + if (m_nearPeds[i] && m_nearPeds[i]->m_nPedState == PED_WANDER_PATH) { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 1.8f + && CanSeeEntity(m_nearPeds[i]) + && m_nearPeds[i]->CanSeeEntity(this) + && WillChat(m_nearPeds[i])) { + + int time = CGeneral::GetRandomNumber() % 4000 + 10000; + SetChat(m_nearPeds[i], time); + m_nearPeds[i]->SetChat(this, time); + return; + } + } + } + } + } else { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; + } +#endif + } + + // Parts below aren't there in VC, they're in somewhere else. + if (!CGame::noProstitutes && m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy != MISSION_CHAR + && m_objectiveTimer < CTimer::GetTimeInMilliseconds() && !CTheScripts::IsPlayerOnAMission()) { + + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->IsVehicleNormal()) { + if (veh->IsCar()) { + if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil)) { + SetObjective(OBJECTIVE_SOLICIT_VEHICLE, veh); + Say(SOUND_PED_SOLICIT); + return; + } + } + } + } + } + if (m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->GetModelIndex() == MI_MRWHOOP) { + if (veh->GetStatus() != STATUS_ABANDONED && veh->GetStatus() != STATUS_WRECKED) { + if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f) { + SetObjective(OBJECTIVE_BUY_ICE_CREAM, veh); + return; + } + } + } + } + } +} + +bool +CPed::WillChat(CPed *stranger) +{ + if (m_pNextPathNode && m_pLastPathNode) { + if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { + return false; + } + } + if (m_nSurfaceTouched == SURFACE_TARMAC) + return false; + if (stranger == this) + return false; + if (m_nPedType == stranger->m_nPedType) + return true; + if (m_nPedType == PEDTYPE_CRIMINAL) + return false; + if ((IsGangMember() || stranger->IsGangMember()) && m_nPedType != stranger->m_nPedType) + return false; + return true; } void @@ -2288,1115 +1406,103 @@ CPed::CalculateNewVelocity(void) } } -bool -CPed::CanBeDeleted(void) +float +CPed::WorkOutHeadingForMovingFirstPerson(float offset) { - if (bInVehicle) - return false; + if (!IsPlayer()) + return 0.0f; - switch (CharCreatedBy) { - case RANDOM_CHAR: - return true; - case MISSION_CHAR: - return false; - default: - return true; + CPad *pad0 = CPad::GetPad(0); + float leftRight = pad0->GetPedWalkLeftRight(); + float upDown = pad0->GetPedWalkUpDown(); + float &angle = ((CPlayerPed*)this)->m_fWalkAngle; + + if (upDown != 0.0f) { + angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); + } else { + if (leftRight < 0.0f) + angle = 0.5f * PI; + else if (leftRight > 0.0f) + angle = -0.5f * PI; } + + return CGeneral::LimitRadianAngle(offset + angle); } -bool -CPed::CanPedDriveOff(void) +void +CPed::UpdatePosition(void) { - if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) - return false; + if (CReplay::IsPlayingBack() || !bIsStanding) + return; - 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; -} + CVector2D velocityChange; -#ifdef VC_PED_PORTS -bool -CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil) -{ - if (m_nSurfaceTouched == SURFACE_WATER) - return true; + SetHeading(m_fRotationCur); + if (m_pCurrentPhysSurface) { + CVector2D velocityOfSurface; + if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { - CVector pos = GetPosition(); - CVector forwardOffset = GetForward(); - if (damageNormal && damageNormal->z > 0.17f) { - if (damageNormal->z > 0.9f) - return false; + // It seems R* didn't like m_vecOffsetFromPhysSurface for boats + CVector offsetToSurface = GetPosition() - m_pCurrentPhysSurface->GetPosition(); + offsetToSurface.z -= FEET_OFFSET; - 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) { - forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; + 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 { - 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); + velocityOfSurface = m_pCurrentPhysSurface->GetSpeed(m_vecOffsetFromPhysSurface); + } + // Reminder: m_moved is displacement from walking/running. + velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed; + m_fRotationCur += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + m_fRotationDest += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + } else if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF && (m_vecDamageNormal.x != 0.0f || m_vecDamageNormal.y != 0.0f)) { + // Ped got damaged by steep slope + m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f); + // some kind of + CVector2D reactionForce = m_vecDamageNormal; + reactionForce.Normalise(); + + velocityChange = 0.02f * reactionForce + m_moved; + + float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); + // they're in same direction + if (reactionAndVelocityDotProd < 0.0f) { + velocityChange -= reactionAndVelocityDotProd * reactionForce; } } else { - pos.z -= 0.15f; + velocityChange = m_moved - m_vecMoveSpeed; } - - CVector forwardPos = pos + forwardOffset; - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} -#else -bool -CPed::CanPedJumpThis(CEntity *unused) -{ - CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); - CVector pos = GetPosition(); - CVector forwardPos( - forward.x + pos.x, - forward.y + pos.y, - pos.z); - - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} -#endif - -bool -CPed::CanPedReturnToState(void) -{ - return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && - m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; -} - -bool -CPed::CanSeeEntity(CEntity *entity, float threshold = CAN_SEE_ENTITY_ANGLE_THRESHOLD) -{ - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - entity->GetPosition().x, - entity->GetPosition().y, - GetPosition().x, - GetPosition().y); - - if (neededAngle < 0.0f) - neededAngle += TWOPI; - else if (neededAngle > TWOPI) - neededAngle -= TWOPI; - - float ourAngle = m_fRotationCur; - if (ourAngle < 0.0f) - ourAngle += TWOPI; - else if (ourAngle > TWOPI) - ourAngle -= TWOPI; - - float neededTurn = Abs(neededAngle - ourAngle); - - return neededTurn < threshold || TWOPI - threshold < neededTurn; -} - -bool -CPed::IsTemporaryObjective(eObjective objective) -{ - return objective == OBJECTIVE_LEAVE_CAR || objective == OBJECTIVE_SET_LEADER || -#ifdef VC_PED_PORTS - objective == OBJECTIVE_LEAVE_CAR_AND_DIE || -#endif - objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; -} - -void -CPed::SetMoveState(eMoveState state) -{ - m_nMoveState = state; -} - -void -CPed::SetObjectiveTimer(int time) -{ - if (time == 0) { - m_objectiveTimer = 0; - } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; - } -} - -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; - } -} - -void -CPed::SetStoredObjective(void) -{ - if (m_objective == m_prevObjective) - return; - - switch (m_objective) - { - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - return; - default: - m_prevObjective = m_objective; - } -} - -void -CPed::RestorePreviousObjective(void) -{ - if (m_objective == OBJECTIVE_NONE) - return; - - if (m_objective != OBJECTIVE_LEAVE_CAR && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - && m_nPedState != PED_CARJACK -#endif - ) - m_pedInObjective = nil; - - if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { - m_objective = OBJECTIVE_NONE; - if (m_pMyVehicle) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - - } else { - m_objective = m_prevObjective; - m_prevObjective = OBJECTIVE_NONE; - } - bObjectiveCompleted = false; -} - -void -CPed::SetLeader(CEntity *leader) -{ - m_leader = (CPed*)leader; - - if(m_leader) - m_leader->RegisterReference((CEntity **)&m_leader); -} - -void -CPed::SetObjective(eObjective newObj, void *entity) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective == newObj) { - // Why? - if (m_prevObjective != OBJECTIVE_NONE) - return; - } - - if (entity == this) - return; - - SetObjectiveTimer(0); - if (m_objective == newObj) { - switch (newObj) { - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GUARD_ATTACK: - if (m_pedInObjective == entity) - return; - - break; - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_FLEE_CAR: -#ifdef VC_PED_PORTS - case OBJECTIVE_LEAVE_CAR_AND_DIE: -#endif - 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)) { - if (m_objective != newObj) { - if (IsTemporaryObjective(newObj)) - ForceStoredObjective(newObj); - else - SetStoredObjective(); - } - m_objective = newObj; - } else { - m_prevObjective = 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) - break; - - 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::SetIdle(void) -{ - if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { -#ifdef VC_PED_PORTS - if (m_nPedState == PED_AIM_GUN) - ClearPointGunAt(); - - m_nLastPedState = PED_NONE; -#endif - m_nPedState = PED_IDLE; - SetMoveState(PEDMOVE_STILL); - } - if (m_nWaitState == WAITSTATE_FALSE) { - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); - } -} - -void -CPed::SetObjective(eObjective newObj) -{ - if (DyingOrDead()) - return; - - if (newObj == OBJECTIVE_NONE) { - if ((m_objective == OBJECTIVE_LEAVE_CAR || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER -#ifdef VC_PED_PORTS - || m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) - && !IsPlayer() -#else - ) -#endif - && !IsPedInControl()) { - - bStartWanderPathOnFoot = true; - return; - } - // Unused code from assembly... - /* - else if(m_objective == OBJECTIVE_FLEE_CAR) { - - } else { - - } - */ - m_objective = OBJECTIVE_NONE; - m_prevObjective = OBJECTIVE_NONE; - } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { - SetObjectiveTimer(0); - - if (m_objective == newObj) - return; - - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - bObjectiveCompleted = false; - - switch (newObj) { - case OBJECTIVE_NONE: - m_prevObjective = OBJECTIVE_NONE; - break; - case OBJECTIVE_HAIL_TAXI: - m_nWaitTimer = 0; - SetIdle(); - SetMoveState(PEDMOVE_STILL); - break; - default: - break; - } - } -} - -// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode -// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... -void -CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) - return; - - SetObjectiveTimer(0); - - if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) - return; - - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - - if (newObj == OBJECTIVE_FOLLOW_ROUTE) { - SetFollowRoute(routePoint, routeType); - } -} - -void -CPed::ClearChat(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - bIsTalking = false; - ClearLookFlag(); - RestorePreviousState(); -} - -bool -CPed::IsGangMember(void) -{ - return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; -} - -void -CPed::InformMyGangOfAttack(CEntity *attacker) -{ - CPed *attackerPed; - - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) - return; - - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; - - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } - - if (attackerPed->m_nPedType == PEDTYPE_COP) - return; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed && nearPed != this) { - CPed *leader = nearPed->m_leader; - if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) - { - nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); - nearPed->SetObjectiveTimer(30000); - } - } - } -} - -void -CPed::QuitEnteringCar(void) -{ - CAnimBlendAssociation *animAssoc = m_pVehicleAnim; - CVehicle *veh = m_pMyVehicle; - if (animAssoc) - animAssoc->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()) { - animAssoc = m_pVehicleAnim; - if (animAssoc) { - animAssoc->blendDelta = -4.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->flags &= ~ASSOC_RUNNING; + // 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(); } - } 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; + if (speedChange > changeMult) { + velocityChange = velocityChange * (changeMult / speedChange); + } } + m_vecMoveSpeed.x += velocityChange.x; + m_vecMoveSpeed.y += velocityChange.y; } void -CPed::ReactToAttack(CEntity *attacker) +CPed::CalculateNewOrientation(void) { - 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); - } - } - } -} - -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, - GetPosition().x, - GetPosition().y); - } else - lookDir = m_fLookDirection; - - float limitedLookDir = CGeneral::LimitRadianAngle(lookDir); - float currentRot = m_fRotationCur; - - if (currentRot - PI > limitedLookDir) - limitedLookDir += 2 * PI; - else if (PI + currentRot < limitedLookDir) - limitedLookDir -= 2 * PI; - - float neededTurn = currentRot - limitedLookDir; - m_fRotationDest = limitedLookDir; - - if (Abs(neededTurn) > 0.05f) { - turnDone = false; - currentRot -= neededTurn * 0.2f; - } - - m_fRotationCur = currentRot; - m_fLookDirection = limitedLookDir; - return turnDone; -} - -void -CPed::Chat(void) -{ - // We're already looking to our partner - if (bIsLooking && TurnBody()) - ClearLookFlag(); - - if (!m_pLookTarget || !m_pLookTarget->IsPed()) { - ClearChat(); - return; - } - - CPed *partner = (CPed*) m_pLookTarget; - - if (partner->m_nPedState != PED_CHAT) { - ClearChat(); - if (partner->m_pedInObjective) { - if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || - partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) - ReactToAttack(partner->m_pedInObjective); - } - return; - } - if (bIsTalking) { - if (CGeneral::GetRandomNumber() < 512) { - CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (chatAssoc) { - chatAssoc->blendDelta = -4.0f; - chatAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - bIsTalking = false; - } else - Say(SOUND_PED_CHAT); - - } else if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG_XPRESS)) { - - if (CGeneral::GetRandomNumber() < 20) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); - } - if (!bIsTalking) { - 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) + if (CReplay::IsPlayingBack() || !IsPedInControl()) return; - GetBoundCentre(ourCentre); - - CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false); - for (int i = 0; i < maxObject; i++) { - CEntity *object = objects[i]; - if (bRunningToPhone) { - if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition())) - break; - } - object->GetBoundCentre(objCentre); - float radius = object->GetBoundRadius(); - if (radius > 4.5f || radius < 1.0f) - radius = 1.0f; - - // Developers gave up calculating Z diff. later according to asm. - float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); - - if (sq(radius + 1.0f) > diff) - m_fRotationDest += DEGTORAD(22.5f); - } -} - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE -void -ReportPhonePickUpCB(CAnimBlendAssociation* assoc, void* arg) -{ - CPed* ped = (CPed*)arg; - ped->m_nMoveState = PEDMOVE_STILL; - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); - - if (assoc->blendAmount > 0.5f && ped) { - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); - } -} - -void -ReportPhonePutDownCB(CAnimBlendAssociation* assoc, void* arg) -{ - assoc->flags |= ASSOC_DELETEFADEDOUT; - assoc->blendDelta = -1000.0f; - CPed* ped = (CPed*)arg; - - if (ped->m_phoneId != -1 && crimeReporters[ped->m_phoneId] == ped) { - crimeReporters[ped->m_phoneId] = nil; - gPhoneInfo.m_aPhones[ped->m_phoneId].m_nState = PHONE_STATE_FREE; - ped->m_phoneId = -1; - } - - if (assoc->blendAmount > 0.5f) - ped->bUpdateAnimHeading = true; - - ped->SetWanderPath(CGeneral::GetRandomNumber() & 7); -} -#endif - -bool -CPed::MakePhonecall(void) -{ -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { - - FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), - (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (uintptr)m_threatEntity : (uintptr)m_victimOfPlayerCrime), false); - - if (m_crimeToReportOnPhone != CRIME_POSSESSION_GUN) - FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1); - - bRunningToPhone = false; - } -#endif - if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) - return false; - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - CAnimBlendAssociation* talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_PHONE_TALK); - if (talkAssoc && talkAssoc->blendAmount > 0.5f) { - CAnimBlendAssociation* endAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_OUT, 8.0f); - endAssoc->flags &= ~ASSOC_DELETEFADEDOUT; - endAssoc->SetFinishCallback(ReportPhonePutDownCB, this); - } -#endif - SetIdle(); - - gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - m_phoneId = -1; -#endif - - // Because SetWanderPath is now done async in ReportPhonePutDownCB -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - return false; -#else - return true; -#endif -} - -bool -CPed::FacePhone(void) -{ - // This function was broken since it's left unused early in development. -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - float phoneDir = CGeneral::GetRadianAngleBetweenPoints( - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, - GetPosition().x, GetPosition().y); - - if (m_facePhoneStart) { - m_lookTimer = 0; - SetLookFlag(phoneDir, true); - m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; - m_facePhoneStart = false; - } - - if (bIsLooking && TurnBody()) { - ClearLookFlag(); - SetIdle(); - m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; - CAnimBlendAssociation* assoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_IN, 4.0f); - assoc->SetFinishCallback(ReportPhonePickUpCB, this); - return true; - } - - return false; -#else - float currentRot = RADTODEG(m_fRotationCur); - float phoneDir = CGeneral::GetRadianAngleBetweenPoints( - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, - GetPosition().x, - GetPosition().y); - - SetLookFlag(phoneDir, false); - phoneDir = CGeneral::LimitAngle(phoneDir); - m_moved = CVector2D(0.0f, 0.0f); - - if (currentRot - 180.0f > phoneDir) - phoneDir += 2 * 180.0f; - else if (180.0f + currentRot < phoneDir) - phoneDir -= 2 * 180.0f; - - float neededTurn = currentRot - phoneDir; - - if (Abs(neededTurn) <= 0.75f) { - SetIdle(); - ClearLookFlag(); - m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; - return true; - } else { - m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); - return false; - } -#endif -} - -CPed * -CPed::CheckForDeadPeds(void) -{ - int event; - if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) { - int pedHandle = gaEvent[event].entityRef; - if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { - bGonnaInvestigateEvent = true; - return CPools::GetPed(pedHandle); - } - } - bGonnaInvestigateEvent = false; - return nil; -} - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE -// returns event id, parameter is optional -int32 -CPed::CheckForPlayerCrimes(CPed *victim) -{ - int i; - float dist; - float mindist = 60.0f; - CPlayerPed *player = FindPlayerPed(); - int32 victimRef = (victim ? CPools::GetPedRef(victim) : 0); - int event = -1; - - for (i = 0; i < NUMEVENTS; i++) { - if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) - continue; - - // those are already handled in game, also DEAD_PED isn't registered alone, most of the time there is SHOOT_PED etc. - if (gaEvent[i].type == EVENT_DEAD_PED || gaEvent[i].type == EVENT_GUNSHOT || gaEvent[i].type == EVENT_EXPLOSION) - continue; - - if (victim && gaEvent[i].entityRef != victimRef) - continue; - - if (gaEvent[i].criminal != player) - continue; - - dist = (GetPosition() - gaEvent[i].posn).Magnitude(); - if (dist < mindist) { - mindist = dist; - event = i; - } - } - - if (event != -1) { - if (victim) { - m_victimOfPlayerCrime = victim; - } else { - switch (gaEvent[event].entityType) { - case EVENT_ENTITY_PED: - m_victimOfPlayerCrime = CPools::GetPed(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_VEHICLE: - m_victimOfPlayerCrime = CPools::GetVehicle(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_OBJECT: - m_victimOfPlayerCrime = CPools::GetObject(gaEvent[event].entityRef); - break; - default: - break; - } - } - } - - return event; -} -#endif - -bool -CPed::CheckForExplosions(CVector2D &area) -{ - int event = 0; - if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { - area.x = gaEvent[event].posn.x; - area.y = gaEvent[event].posn.y; - CEntity *actualEntity = nil; - - switch (gaEvent[event].entityType) { - case EVENT_ENTITY_PED: - actualEntity = CPools::GetPed(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_VEHICLE: - actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_OBJECT: - actualEntity = CPools::GetObject(gaEvent[event].entityRef); - break; - default: - break; - } - - if (actualEntity) { - m_pEventEntity = actualEntity; - m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); - bGonnaInvestigateEvent = true; - } else - bGonnaInvestigateEvent = false; - - CEventList::ClearEvent(event); - return true; - } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { - area.x = gaEvent[event].posn.x; - area.y = gaEvent[event].posn.y; - CEventList::ClearEvent(event); - bGonnaInvestigateEvent = false; - return true; - } - - bGonnaInvestigateEvent = false; - return false; -} - -CPed * -CPed::CheckForGunShots(void) -{ - int event; - if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { - if (gaEvent[event].entityType == EVENT_ENTITY_PED) { - // Probably due to we don't want peds to go gunshot area? (same on VC) - bGonnaInvestigateEvent = false; - return CPools::GetPed(gaEvent[event].entityRef); - } - } - bGonnaInvestigateEvent = false; - return nil; -} - -PointBlankNecessity -CPed::CheckForPointBlankPeds(CPed *pedToVerify) -{ - float pbDistance = 1.1f; - if (GetWeapon()->IsType2Handed()) - pbDistance = 1.6f; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - - if (!pedToVerify || pedToVerify == nearPed) { - - CVector diff = nearPed->GetPosition() - GetPosition(); - if (diff.Magnitude() < pbDistance) { - - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - nearPed->GetPosition().x, nearPed->GetPosition().y, - GetPosition().x, GetPosition().y); - neededAngle = CGeneral::LimitRadianAngle(neededAngle); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - - float neededTurn = Abs(neededAngle - m_fRotationCur); - - if (neededTurn > PI) - neededTurn = 2*PI - neededTurn; - - if (nearPed->OnGroundOrGettingUp() || nearPed->m_nPedState == PED_DIVE_AWAY) - return NO_POINT_BLANK_PED; - - if (neededTurn < CAN_SEE_ENTITY_ANGLE_THRESHOLD) { - if (pedToVerify == nearPed) - return POINT_BLANK_FOR_WANTED_PED; - else - return POINT_BLANK_FOR_SOMEONE_ELSE; - } - } - } - } - return NO_POINT_BLANK_PED; -} - -bool -CPed::CheckIfInTheAir(void) -{ - if (bInVehicle) - return false; - - CVector pos = GetPosition(); - CColPoint foundColPoint; - CEntity *foundEntity; - - float startZ = pos.z - 1.54f; - bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); - if (!foundGround && m_nPedState != PED_JUMP) - { - pos.z -= FEET_OFFSET; - if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) - foundGround = true; - } - return !foundGround; + SetHeading(m_fRotationCur); } void @@ -3427,5690 +1533,154 @@ CPed::ClearAll(void) } void -CPed::ClearAttack(void) +CPed::ProcessBuoyancy(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::StopNonPartialAnims(void) -{ - CAnimBlendAssociation *assoc; - - for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->flags &= ~ASSOC_RUNNING; - } -} - -void -CPed::SetStoredState(void) -{ - if (m_nLastPedState != PED_NONE || !CanPedReturnToState()) - return; - - 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::SetDie(AnimationId animId, float delta, float speed) -{ - CPlayerPed *player = FindPlayerPed(); - if (player == this) { - if (!player->m_bCanBeDamaged) - return; - } - - m_threatEntity = nil; - if (DyingOrDead()) - return; - - if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) - delta *= 0.5f; - - SetStoredState(); - ClearAll(); - m_fHealth = 0.0f; - if (m_nPedState == PED_DRIVING) { - if (!IsPlayer()) - FlagToDestroyWhenNextProcessed(); - } else if (bInVehicle) { - if (m_pVehicleAnim) - m_pVehicleAnim->blendDelta = -1000.0f; - } else if (EnteringCar()) { - QuitEnteringCar(); - } - - m_nPedState = PED_DIE; - if (animId == NUM_ANIMS) { - bIsPedDieAnimPlaying = false; - } else { - CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, delta); - if (speed > 0.0f) - dieAssoc->speed = speed; - - dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - if (dieAssoc->IsRunning()) { - dieAssoc->SetFinishCallback(FinishDieAnimCB, this); - bIsPedDieAnimPlaying = true; - } - } - - Say(SOUND_PED_DEATH); - if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) - QuitEnteringCar(); - if (!bInVehicle) - StopNonPartialAnims(); - - m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); -} - -bool -CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) -{ - CPlayerPed *player = FindPlayerPed(); - float dieDelta = 4.0f; - float dieSpeed = 0.0f; - AnimationId dieAnim = ANIM_KO_SHOT_FRONT1; - bool headShot = false; - bool willLinger = false; - int random; - - if (player == this) { - if (!player->m_bCanBeDamaged) - return false; - - player->AnnoyPlayerPed(false); - } - - if (DyingOrDead()) - return false; - - if (!bUsesCollision && method != WEAPONTYPE_DROWNING) - return false; - - if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() && - method != WEAPONTYPE_DROWNING && method != WEAPONTYPE_EXPLOSION) - return false; - - float healthImpact; - if (IsPlayer()) - healthImpact = damage * 0.33f; - else - healthImpact = damage * m_pedStats->m_defendWeakness; - - bool detectDieAnim = true; - if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) { - if (!IsPedHeadAbovePos(-0.3f)) { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta *= 2.0f; - dieSpeed = 0.5f; - detectDieAnim = false; - } else if (m_nPedState == PED_FALL) { - dieAnim = NUM_ANIMS; - detectDieAnim = false; - } - } - if (detectDieAnim) { - switch (method) { - case WEAPONTYPE_UNARMED: - if (bMeleeProof) - return false; - - if (m_nPedState == PED_FALL) { - if (IsPedHeadAbovePos(-0.3f)) { - dieAnim = NUM_ANIMS; - } else { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta = dieDelta * 2.0f; - dieSpeed = 0.5f; - } - } else { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } - break; - case WEAPONTYPE_BASEBALLBAT: - if (bMeleeProof) - return false; - - if (m_nPedState == PED_FALL) { - if (IsPedHeadAbovePos(-0.3f)) { - dieAnim = NUM_ANIMS; - } else { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta = dieDelta * 2.0f; - dieSpeed = 0.5f; - } - } else { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } - break; - case WEAPONTYPE_COLT45: - case WEAPONTYPE_UZI: - case WEAPONTYPE_SHOTGUN: - case WEAPONTYPE_AK47: - case WEAPONTYPE_M16: - case WEAPONTYPE_SNIPERRIFLE: - if (bBulletProof) - return false; - - bool dontRemoveLimb; - if (IsPlayer() || bNoCriticalHits) - dontRemoveLimb = true; - else { - switch (method) { - case WEAPONTYPE_SNIPERRIFLE: - dontRemoveLimb = false; - break; - case WEAPONTYPE_M16: - dontRemoveLimb = false; - break; - case WEAPONTYPE_SHOTGUN: - dontRemoveLimb = CGeneral::GetRandomNumber() & 7; - break; - default: - dontRemoveLimb = CGeneral::GetRandomNumber() & 15; - break; - } - } - - if (dontRemoveLimb) { - if (method == WEAPONTYPE_SHOTGUN) { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } else - dieAnim = ANIM_KO_SHOT_FRONT1; - - willLinger = false; - } else { - switch (pedPiece) { - case PEDPIECE_TORSO: - willLinger = false; - dieAnim = ANIM_KO_SHOT_FRONT1; - break; - case PEDPIECE_MID: - willLinger = false; - dieAnim = ANIM_KO_SHOT_STOM; - break; - case PEDPIECE_LEFTARM: - dieAnim = ANIM_KO_SHOT_ARML; - RemoveBodyPart(PED_UPPERARML, direction); - willLinger = true; - break; - case PEDPIECE_RIGHTARM: - dieAnim = ANIM_KO_SHOT_ARMR; - RemoveBodyPart(PED_UPPERARMR, direction); - willLinger = true; - break; - case PEDPIECE_LEFTLEG: - dieAnim = ANIM_KO_SHOT_LEGL; - RemoveBodyPart(PED_UPPERLEGL, direction); - willLinger = true; - break; - case PEDPIECE_RIGHTLEG: - dieAnim = ANIM_KO_SHOT_LEGR; - RemoveBodyPart(PED_UPPERLEGR, direction); - willLinger = true; - break; - case PEDPIECE_HEAD: - dieAnim = ANIM_KO_SHOT_FACE; - RemoveBodyPart(PED_HEAD, direction); - headShot = true; - willLinger = true; - break; - default: - break; - } - } - break; - case WEAPONTYPE_ROCKETLAUNCHER: - case WEAPONTYPE_GRENADE: - case WEAPONTYPE_EXPLOSION: - if (bExplosionProof) - return false; - - if (CGame::nastyGame && !IsPlayer() && !bInVehicle && - 1.0f + healthImpact > m_fArmour + m_fHealth) { - - random = CGeneral::GetRandomNumber(); - if (random & 1) - RemoveBodyPart(PED_UPPERARML, direction); - if (random & 2) - RemoveBodyPart(PED_UPPERLEGR, direction); - if (random & 4) - RemoveBodyPart(PED_HEAD, direction); - if (random & 8) - RemoveBodyPart(PED_UPPERARMR, direction); - if (random & 0x10) - RemoveBodyPart(PED_UPPERLEGL, direction); - if (bBodyPartJustCameOff) - willLinger = true; - } - // fall through - case WEAPONTYPE_MOLOTOV: - if (bExplosionProof) - return false; - - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - break; - case WEAPONTYPE_FLAMETHROWER: - if (bFireProof) - return false; - - dieAnim = ANIM_KO_SHOT_FRONT1; - break; - case WEAPONTYPE_RAMMEDBYCAR: - case WEAPONTYPE_RUNOVERBYCAR: - if (bCollisionProof) - return false; - - random = CGeneral::GetRandomNumber() & 3; - switch (random) { - case 0: - if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 1)) { - if (pedPiece == PEDPIECE_RIGHTARM && random > 1 - || pedPiece == PEDPIECE_MID && random == 2) - - dieAnim = ANIM_KO_SPIN_L; - else - dieAnim = ANIM_KO_SKID_FRONT; - } else - dieAnim = ANIM_KO_SPIN_R; - - break; - case 1: - if (m_nPedState == PED_DIVE_AWAY) - dieAnim = ANIM_KD_LEFT; - else - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 1)) { - if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 2)) { - dieAnim = ANIM_KO_SKID_BACK; - } else { - dieAnim = ANIM_KD_RIGHT; - } - } else - dieAnim = ANIM_KD_LEFT; - break; - case 3: - if (m_nPedState == PED_DIVE_AWAY) - dieAnim = ANIM_KD_RIGHT; - else - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - if (damagedBy) { - CVehicle *vehicle = (CVehicle*)damagedBy; - if (method == WEAPONTYPE_RAMMEDBYCAR) { - float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); - dieDelta = 8.0f * vehSpeed + 4.0f; - } else { - float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); - dieDelta = 12.0f * vehSpeed + 4.0f; - dieSpeed = 16.0f * vehSpeed + 1.0f; - } - } - break; - case WEAPONTYPE_DROWNING: - dieAnim = ANIM_DROWN; - break; - case WEAPONTYPE_FALL: - if (bCollisionProof) - return false; - - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - break; - default: - break; - } - } - - if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); - - if (healthImpact < m_fArmour) { - m_fArmour = m_fArmour - healthImpact; - healthImpact = 0.0f; - } else { - healthImpact = healthImpact - m_fArmour; - m_fArmour = 0.0f; - } - } - - if (healthImpact != 0.0f) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); - - m_lastWepDam = method; - } - - if (m_fHealth - healthImpact >= 1.0f && !willLinger) { - m_fHealth -= healthImpact; - return false; - } - - if (bInVehicle) { - if (method != WEAPONTYPE_DROWNING) { -#ifdef VC_PED_PORTS - if (m_pMyVehicle) { - if (m_pMyVehicle->IsCar() && m_pMyVehicle->pDriver == this) { - if (m_pMyVehicle->GetStatus() == STATUS_SIMPLE) { - m_pMyVehicle->SetStatus(STATUS_PHYSICS); - CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); - } - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - m_pMyVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; - m_pMyVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000; - } - if (m_pMyVehicle->CanPedExitCar()) { - SetObjective(OBJECTIVE_LEAVE_CAR_AND_DIE, m_pMyVehicle); - } else { - m_fHealth = 0.0f; - if (m_pMyVehicle && m_pMyVehicle->pDriver == this) { - SetRadioStation(); - m_pMyVehicle->SetStatus(STATUS_ABANDONED); - } - SetDie(dieAnim, dieDelta, dieSpeed); - /* - if (damagedBy == FindPlayerPed() && damagedBy != this) { - // PlayerInfo stuff - } - */ - } - for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) { - CPed* passenger = m_pMyVehicle->pPassengers[i]; - if (passenger && passenger != this && damagedBy) - passenger->ReactToAttack(damagedBy); - } - - CPed *driverOfVeh = m_pMyVehicle->pDriver; - if (driverOfVeh && driverOfVeh != this && damagedBy) - driverOfVeh->ReactToAttack(damagedBy); - - if (damagedBy == FindPlayerPed() || damagedBy && damagedBy == FindPlayerVehicle()) { - CDarkel::RegisterKillByPlayer(this, method, headShot); - m_threatEntity = FindPlayerPed(); - } else { - CDarkel::RegisterKillNotByPlayer(this, method); - } - } -#endif - m_fHealth = 1.0f; - return false; - } - m_fHealth = 0.0f; - if (player == this) - m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED); - - SetDie(NUM_ANIMS, 4.0f, 0.0f); - return true; - } else { - m_fHealth = 0.0f; - SetDie(dieAnim, dieDelta, dieSpeed); - - if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { - - // There are PlayerInfo stuff here in VC - CDarkel::RegisterKillByPlayer(this, method, headShot); - m_threatEntity = player; - } else { - CDarkel::RegisterKillNotByPlayer(this, method); - } - if (method == WEAPONTYPE_DROWNING) - bIsInTheAir = false; - - return true; - } -} - -void -CPed::ClearFlee(void) -{ - RestorePreviousState(); - bUsePedNodeSeek = false; - m_standardTimer = 0; - m_fleeTimer = 0; -} - -void -CPed::ClearFall(void) -{ - SetGetUp(); -} - -void -CPed::SetGetUp(void) -{ - if (m_nPedState == PED_GETUP && bGetUpAnimStarted) - return; - - if (!CanSetPedState()) - return; - - if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) { - if (bUpdateAnimHeading) { - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - m_fRotationCur -= HALFPI; - bUpdateAnimHeading = false; - } - if (m_nPedState != PED_GETUP) { - SetStoredState(); - m_nPedState = PED_GETUP; - } - - CVehicle *collidingVeh = (CVehicle*)m_pCollidingEntity; - CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition()); - if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE || - collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE - && ((uint8)(CTimer::GetFrameCounter() + m_randomSeed + 5) % 8 || - CCollision::ProcessColModels(GetMatrix(), *GetColModel(), collidingVeh->GetMatrix(), *collidingVeh->GetColModel(), - aTempPedColPts, nil, nil) > 0)) { - - bGetUpAnimStarted = false; - if (IsPlayer()) - InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); - else { - if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) - return; - - InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0); - } - return; - } - bGetUpAnimStarted = true; - m_pCollidingEntity = nil; - bKnockedUpIntoAir = false; - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); - if (animAssoc) { - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN)) { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_RUN, 8.0f); - } else { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); - } - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f); - else - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - - animAssoc->SetFinishCallback(PedGetupCB,this); - } else { - m_fHealth = 0.0f; - SetDie(NUM_ANIMS, 4.0f, 0.0f); - } -} - -void -CPed::ClearInvestigateEvent(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - if (m_eventType > EVENT_EXPLOSION) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; - - bGonnaInvestigateEvent = false; - m_pEventEntity = nil; - ClearLookFlag(); - RestorePreviousState(); - if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_WALK); -} - -void -CPed::ClearLeader(void) -{ - if (!m_leader) - return; - - m_leader = nil; - if (IsPedInControl()) { - SetObjective(OBJECTIVE_NONE); - if (CharCreatedBy == MISSION_CHAR) { - SetIdle(); - } else { - SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); - } - } else if (m_objective != OBJECTIVE_NONE) { - bClearObjective = true; - } -} - -void -CPed::ClearLook(void) -{ - RestorePreviousState(); - ClearLookFlag(); -} - -void -CPed::ClearObjective(void) -{ - if (IsPedInControl() || m_nPedState == PED_DRIVING) { - m_objective = OBJECTIVE_NONE; -#ifdef VC_PED_PORTS - m_pedInObjective = nil; - m_carInObjective = nil; -#endif - if (m_nPedState == PED_DRIVING && m_pMyVehicle) { - - if (m_pMyVehicle->pDriver != this) { -#if defined VC_PED_PORTS || defined FIX_BUGS - if(!IsPlayer()) -#endif - bWanderPathAfterExitingCar = true; - - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } -#ifdef VC_PED_PORTS - m_nLastPedState = PED_NONE; -#endif - } else { - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - } else { - bClearObjective = true; - } -} - -void -CPed::ClearPause(void) -{ - RestorePreviousState(); -} - -void -CPed::ClearSeek(void) -{ - SetIdle(); - bRunningToPhone = false; -} - -bool -CPed::SetWanderPath(int8 pathStateDest) -{ - uint8 nextPathState; - - if (IsPedInControl()) { - if (bKindaStayInSamePlace) { - SetIdle(); - return false; - } else { - m_nPathDir = pathStateDest; - if (pathStateDest == 0) - pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); - - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); - - // Circular loop until we find a node for current m_nPathDir - while (!m_pNextPathNode) { - m_nPathDir = (m_nPathDir+1) % 8; - - // We're at where we started and couldn't find any node - if (m_nPathDir == pathStateDest) { - ClearAll(); - SetIdle(); - return false; - } - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); - } - - // We did it, save next path state and return true - m_nPathDir = nextPathState; - m_nPedState = PED_WANDER_PATH; - SetMoveState(PEDMOVE_WALK); - bIsRunning = false; - return true; - } - } else { - m_nPathDir = pathStateDest; - bStartWanderPathOnFoot = true; - return false; - } -} - -void -CPed::ClearWeapons(void) -{ - CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(currentWeapon->m_nModelId); - - m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; - m_currentWeapon = WEAPONTYPE_UNARMED; - - currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(currentWeapon->m_nModelId); - for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { - CWeapon &weapon = GetWeapon(i); - weapon.m_eWeaponType = WEAPONTYPE_UNARMED; - weapon.m_eWeaponState = WEAPONSTATE_READY; - weapon.m_nAmmoInClip = 0; - weapon.m_nAmmoTotal = 0; - weapon.m_nTimer = 0; - } -} - -void -CPed::RestoreGunPosition(void) -{ - if (bIsLooking) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - bIsRestoringGun = false; - } else if (m_pedIK.RestoreGunPosn()) { - bIsRestoringGun = false; - } else { - if (IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; - } -} - -void -CPed::RestoreHeadingRate(void) -{ - m_headingRate = m_pedStats->m_headingChangeRate; -} - -void -CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) -{ - ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; -} - -void -CPed::RestorePreviousState(void) -{ - if(!CanSetPedState() || m_nPedState == PED_FALL) - return; - - if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) - return; - - 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; - } - - 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::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 = HALFPI + vehDirection; - 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] <= ' '; 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 %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) -{ - float direction; - - for (direction = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); direction < 0.0f; direction += TWOPI); - - for (direction = (int)RADTODEG(direction) / 90; 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 skin = GetModelIndex(); - if ((skin >= MI_COP && skin <= 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; + static uint32 nGenerateRaindrops = 0; + static uint32 nGenerateWaterCircles = 0; + CRGBA color(((0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed()) * 127.5f), + ((0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue()) * 127.5f), + ((0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen()) * 127.5f), + (CGeneral::GetRandomNumber() % 256 * 48.0f) + 48); if (bInVehicle) return; - for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + CVector buoyancyPoint; + CVector buoyancyImpulse; - 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; +#ifndef VC_PED_PORTS + float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.5f : 1.3f); #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; + float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f); #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) { - CAnimBlendAssociation *enterAssoc = m_pVehicleAnim; - if (enterAssoc) - veh->ProcessOpenDoor(m_vehEnterType, enterAssoc->animId, enterAssoc->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((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); - else - LineUpPedWithCar(LINE_UP_TO_CAR_END); - } 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; + 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; } - - 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, false, false); - - 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) -{ - CPed *referencePed = m_pedInObjective; - - if (referencePed->m_nPedState == PED_DEAD) { - CPed *referencePedOfReference = referencePed->m_pedInObjective; - if (!referencePedOfReference) { - m_pedInObjective = nil; - return GetPosition(); - } - m_pedInObjective = referencePed = referencePedOfReference; - } - - 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 + referencePed->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); - - // Right front door is closer - if ((lfPos - GetPosition()).MagnitudeSqr2D() >= (rfPos - GetPosition()).MagnitudeSqr2D()) { - - 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; - } - } - } else { - if (!veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) - return; - } - 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; - } -} - -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) { + bIsInWater = true; + ApplyMoveForce(buoyancyImpulse); 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); - } - } - } - } -} + 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); -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; + if (bIsInTheAir) { + RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); + bIsInTheAir = false; } - - 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; + 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 - if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; + CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, CRGBA(0, 0, 0, 0), true); #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; - } - } + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_nPedState = PED_IDLE; + 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; - } - } - } + 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()); } - } - 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; + 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 { - 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; - } + 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; - 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; - } - - if (999999.0f == m_fLookDirection) { - ClearLookFlag(); - return; - } - - if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { - if (!bKeepTryingToLook) { - ClearLookFlag(); - return; - } - } -} - -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) + 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 - 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); + } else + return; + } else + bTouchingWater = false; + + if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; + + if (pos.z != 0.0f) { + nGenerateWaterCircles = 0; + for(int i = 0; i < 4; i++) { +#ifdef PC_PARTICLE + pos.x += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); + pos.y += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); + CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, 0, 0, 0, 0); +#else + pos.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); + pos.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); + CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos+CVector(0.0f, 0.0f, 1.0f), CVector(0.0f, 0.0f, 0.0f)); +#endif + } } - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + } - } else { - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_LHS); + if (nGenerateRaindrops && CTimer::GetTimeInMilliseconds() >= nGenerateRaindrops) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; - ped->bCancelEnteringCar = true; - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + 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 + } } } @@ -10455,3351 +3025,458 @@ CPed::ProcessControl(void) } } -void -CPed::SetInTheAir(void) +int32 +CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) { - if (bIsInTheAir) - return; + bool collidedWithBoat = false; + bool belowTorsoCollided = false; + float gravityEffect = -0.15f * CTimer::GetTimeStep(); + CColPoint intersectionPoint; + CColLine ourLine; - bIsInTheAir = true; - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_GLIDE, 4.0f); + CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); - if (m_nPedState == PED_ATTACK) { - ClearAttack(); - ClearPointGunAt(); - } else if (m_nPedState == PED_FIGHT) { - EndFight(ENDFIGHT_FAST); - } + if (!bUsesCollision) + return false; -} + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) + collidedWithBoat = true; -void -CPed::RestoreHeadPosition(void) -{ - if (m_pedIK.RestoreLookAt()) { - bIsRestoringLook = false; - } -} - -void -CPed::PointGunAt(void) -{ - CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); - if (!weaponAssoc || weaponAssoc->blendDelta < 0.0f) - weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); - - if (weaponAssoc && weaponAssoc->currentTime > weaponInfo->m_fAnimLoopStart) { - weaponAssoc->SetCurrentTime(weaponInfo->m_fAnimLoopStart); - weaponAssoc->flags &= ~ASSOC_RUNNING; - - if (weaponInfo->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; - else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; - } -} - -void -CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CAutomobile *veh = (CAutomobile*)(ped->m_pMyVehicle); - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - if (ped->EnteringCar()) { - bool isLow = !!veh->bLowVehicle; - - if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); - - eDoors door; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; - case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; - case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; - case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break; - default: assert(0); - } - - if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SMASHED) - veh->Damage.SetDoorStatus(door, DOOR_STATUS_OK); - - if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { - PedSetInCarCB(nil, ped); - } else if (ped->m_vehEnterType == CAR_DOOR_RF - && (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF || - (veh->pDriver != nil && - (veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR + // ofc we're not vehicle + if (!m_bIsVehicleBeingShifted && !bSkipLineCol #ifdef VC_PED_PORTS - && veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE + && !collidingEnt->IsPed() #endif - || !veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil))))) { - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - || ped->m_nPedState == PED_CARJACK -#endif - ) - veh->bIsBeingCarJacked = false; - - ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; - PedSetInCarCB(nil, ped); - - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - if (!ped->IsPlayer()) - ped->bFleeAfterExitingCar = true; - - ped->bUsePedNodeSeek = true; - ped->m_pNextPathNode = nil; - - } else { - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSHUFFLE_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SHUFFLE_RHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, ped); - } - } else { + ) { + if (!bCollisionProcessed) { #ifdef VC_PED_PORTS - if (ped->m_nPedState != PED_DRIVING) + m_pCurrentPhysSurface = nil; #endif - ped->QuitEnteringCar(); - } -} - -void -CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CAutomobile* veh = (CAutomobile*)(ped->m_pMyVehicle); - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (veh->bLowVehicle) { - veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR_LOW, 1.0f); - } else { - veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, 1.0f); - } - - veh->m_nGettingOutFlags &= ~CAR_DOOR_FLAG_LF; - - if (veh->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) - veh->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_OK); -} - -void -CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!ped->IsNotInWreckedVehicle()) - return; - - if (!ped->EnteringCar()) { + if (bIsStanding) { + bIsStanding = false; + bWasStanding = true; + } + bCollisionProcessed = true; + m_fCollisionSpeed += m_vecMoveSpeed.Magnitude2D() * CTimer::GetTimeStep(); + bStillOnValidPoly = false; + if (IsPlayer() || m_fCollisionSpeed >= 1.0f + && (m_fCollisionSpeed >= 2.0f || m_nPedState != PED_WANDER_PATH)) { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; + } else { + CVector pos = GetPosition(); + float potentialGroundZ = GetPosition().z - FEET_OFFSET; + if (bWasStanding) { + pos.z += -0.25f; + potentialGroundZ += gravityEffect; + } + if (CCollision::IsStoredPolyStillValidVerticalLine(pos, potentialGroundZ, intersectionPoint, &m_collPoly)) { + bStillOnValidPoly = true; #ifdef VC_PED_PORTS - if (ped->m_nPedState != PED_DRIVING) + if(!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + if (bSomeVCflag1) + bSomeVCflag1 = false; + } +#else + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; #endif - ped->QuitEnteringCar(); - return; - } - - eDoors door; - CPed *pedInSeat = nil; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; pedInSeat = veh->pPassengers[0]; break; - case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; pedInSeat = veh->pPassengers[2]; break; - case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; pedInSeat = veh->pDriver; break; - case CAR_DOOR_LR: door = DOOR_REAR_LEFT; pedInSeat = veh->pPassengers[1]; break; - default: assert(0); - } - - if (ped->m_fHealth == 0.0f || CPad::GetPad(0)->ArePlayerControlsDisabled() && pedInSeat && pedInSeat->IsPlayer()) { - ped->QuitEnteringCar(); - return; - } - - bool isVan = veh->bIsVan; - bool isBus = veh->bIsBus; - bool isLow = veh->bLowVehicle; - bool vehUpsideDown = veh->IsUpsideDown(); - if (ped->bCancelEnteringCar) { - if (ped->IsPlayer()) { - if (veh->pDriver) { - if (veh->pDriver->m_nPedType == PEDTYPE_COP) { - FindPlayerPed()->SetWantedLevelNoDrop(1); + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; + } else { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; } } } -#ifdef CANCELLABLE_CAR_ENTER - if (!veh->IsDoorMissing(door) && veh->CanPedOpenLocks(ped) && veh->IsCar()) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); - } + + if (!bStillOnValidPoly) { + CVector potentialCenter = GetPosition(); + potentialCenter.z = GetPosition().z - 0.52f; + + // 0.52f should be a ped's approx. radius + float totalRadiusWhenCollided = collidingEnt->GetBoundRadius() + 0.52f - gravityEffect; + if (bWasStanding) { + if (collidedWithBoat) { + potentialCenter.z += 2.0f * gravityEffect; + totalRadiusWhenCollided += Abs(gravityEffect); + } else { + potentialCenter.z += gravityEffect; + } + } + if (sq(totalRadiusWhenCollided) > (potentialCenter - collidingEnt->GetBoundCentre()).MagnitudeSqr()) { + ourLine.p0 = GetPosition(); + ourLine.p1 = GetPosition(); + ourLine.p1.z = GetPosition().z - FEET_OFFSET; + if (bWasStanding) { + ourLine.p1.z = ourLine.p1.z + gravityEffect; + ourLine.p0.z = ourLine.p0.z + -0.25f; + } + float minDist = 1.0f; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + + if (collidedWithBoat && bWasStanding && !belowTorsoCollided) { + ourLine.p0.z = ourLine.p1.z; + ourLine.p1.z = ourLine.p1.z + gravityEffect; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + } + if (belowTorsoCollided) { +#ifndef VC_PED_PORTS + if (!collidingEnt->IsPed()) { #endif - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - ped->bCancelEnteringCar = false; - return; - } - if (!veh->IsDoorMissing(door) && veh->IsCar()) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + if (!bIsStanding + || FEET_OFFSET + intersectionPoint.point.z > GetPosition().z + || collidedWithBoat && 3.12f + intersectionPoint.point.z > GetPosition().z) { + + if (!collidingEnt->IsVehicle() && !collidingEnt->IsObject()) { + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + bTryingToReachDryLand = false; + bOnBoat = false; + } else { + m_pCurrentPhysSurface = (CPhysical*)collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface); + m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + m_collPoly.valid = false; + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) { + bOnBoat = true; + } else { + bOnBoat = false; + } + } +#ifdef VC_PED_PORTS + if (!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + if (bSomeVCflag1) + bSomeVCflag1 = false; + } +#else + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; +#endif + m_nSurfaceTouched = intersectionPoint.surfaceB; + if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF) { + bHitSteepSlope = true; + m_vecDamageNormal = intersectionPoint.normal; + } + } +#ifdef VC_PED_PORTS + float upperSpeedLimit = 0.33f; + float lowerSpeedLimit = -0.25f; + float speed = m_vecMoveSpeed.Magnitude2D(); + if (m_nPedState == PED_IDLE) { + upperSpeedLimit *= 2.0f; + lowerSpeedLimit *= 1.5f; + } + CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + if (!bWasStanding && speed > upperSpeedLimit && (/*!bPushedAlongByCar ||*/ m_vecMoveSpeed.z < lowerSpeedLimit) + && m_pCollidingEntity != collidingEnt) { + + float damage = 100.0f * Max(speed - 0.25f, 0.0f); + float damage2 = damage; + if (m_vecMoveSpeed.z < -0.25f) + damage += (-0.25f - m_vecMoveSpeed.z) * 150.0f; + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + + InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); + if (IsPlayer() && damage2 > 5.0f) + Say(SOUND_PED_LAND); + + } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); + } +#else + float speedSqr = 0.0f; + CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + if (!bWasStanding && (m_vecMoveSpeed.z < -0.25f || (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) > sq(0.5f))) { + if (speedSqr == 0.0f) + speedSqr = sq(m_vecMoveSpeed.z); + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir); + + } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); + } +#endif + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; +#ifndef VC_PED_PORTS + } else { + bOnBoat = false; + } +#endif + } else { + bOnBoat = false; + } + } + } } - if (veh->m_vecMoveSpeed.Magnitude() > 0.2f) { - ped->QuitEnteringCar(); - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) - ped->SetFall(1000, ANIM_KO_SPIN_R, false); - else - ped->SetFall(1000, ANIM_KO_SPIN_L, false); + int ourCollidedSpheres = CCollision::ProcessColModels(GetMatrix(), *ourCol, collidingEnt->GetMatrix(), *hisCol, collidingPoints, nil, nil); + if (ourCollidedSpheres > 0 || belowTorsoCollided) { + AddCollisionRecord(collidingEnt); + if (!collidingEnt->IsBuilding()) + ((CPhysical*)collidingEnt)->AddCollisionRecord(this); + + if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic())) { + bHasHitWall = true; + } + } + if (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic()) { + + if (bWasStanding) { + CVector sphereNormal; + float normalLength; + for(int sphere = 0; sphere < ourCollidedSpheres; sphere++) { + sphereNormal = collidingPoints[sphere].normal; +#ifdef VC_PED_PORTS + if (sphereNormal.z >= -1.0f || !IsPlayer()) { +#endif + normalLength = sphereNormal.Magnitude2D(); + if (normalLength != 0.0f) { + sphereNormal.x = sphereNormal.x / normalLength; + sphereNormal.y = sphereNormal.y / normalLength; + } +#ifdef VC_PED_PORTS + } else { + float speed = m_vecMoveSpeed.Magnitude2D(); + sphereNormal.x = -m_vecMoveSpeed.x / Max(0.001f, speed); + sphereNormal.y = -m_vecMoveSpeed.y / Max(0.001f, speed); + GetMatrix().GetPosition().z -= 0.05f; + bSomeVCflag1 = true; + } +#endif + sphereNormal.Normalise(); + collidingPoints[sphere].normal = sphereNormal; + if (collidingPoints[sphere].surfaceB == SURFACE_STEEP_CLIFF) + bHitSteepSlope = true; + } + } + } + return ourCollidedSpheres; +} + +static void +particleProduceFootSplash(CPed *ped, CVector const &pos, float size, int times) +{ +#ifdef PC_PARTICLE + for (int i = 0; i < times; i++) { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + + CVector direction = ped->GetForward() * -0.05f; + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumber() & 1, 200); + } +#else + for ( int32 i = 0; i < times; i++ ) + { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); + + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, CGeneral::GetRandomNumber() & 1, 200); + } +#endif +} + +static void +particleProduceFootDust(CPed *ped, CVector const &pos, float size, int times) +{ + switch (ped->m_nSurfaceTouched) + { + case SURFACE_TARMAC: + case SURFACE_GRAVEL: + case SURFACE_PAVEMENT: + case SURFACE_SAND: + for (int i = 0; i < times; ++i) { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); + } + break; + default: + break; + } +} + +void +CPed::PlayFootSteps(void) +{ + if (bDoBloodyFootprints) { + if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { + m_bloodyFootprintCountOrDeathTime--; + + if (m_bloodyFootprintCountOrDeathTime == 0) + bDoBloodyFootprints = false; + } + } + + if (!bIsStanding) + return; + + CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); + CAnimBlendAssociation *walkRunAssoc = nil; + float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; + + for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (assoc->flags & ASSOC_WALK) { + walkRunAssoc = assoc; + walkRunAssocBlend += assoc->blendAmount; + } else if ((assoc->flags & ASSOC_NOWALK) == 0) { + idleAssocBlend += assoc->blendAmount; + } + } + +#ifdef GTA_PS2_STUFF + CAnimBlendAssociation *runStopAsoc = NULL; + + if ( IsPlayer() ) + { + runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - return; + if ( runStopAsoc == NULL ) + runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); } - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_OPEN_LHS, 1.0f); - - if (ped->m_vehEnterType == CAR_DOOR_LF || ped->m_vehEnterType == CAR_DOOR_RF) - isVan = false; - - if (ped->m_nPedState != PED_CARJACK || isBus) { - AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - - if (isVan) { - animToPlay = ANIM_VAN_GETIN; - } else if (isBus) { - animToPlay = ANIM_COACH_IN_R; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_RHS; - } else { - animToPlay = ANIM_CAR_GETIN_RHS; - } - } else if (isVan) { - animToPlay = ANIM_VAN_GETIN_L; - } else if (isBus) { - animToPlay = ANIM_COACH_IN_L; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_LHS; - } else { - animToPlay = ANIM_CAR_GETIN_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } else { - CPed *pedToDragOut = nil; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: pedToDragOut = veh->pPassengers[0]; break; - case CAR_DOOR_RR: pedToDragOut = veh->pPassengers[2]; break; - case CAR_DOOR_LF: pedToDragOut = veh->pDriver; break; - case CAR_DOOR_LR: pedToDragOut = veh->pPassengers[1]; break; - default: assert(0); - } - - if (vehUpsideDown) { - ped->QuitEnteringCar(); - if (ped->m_nPedType == PEDTYPE_COP) - ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); - } - - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - if (pedToDragOut && !pedToDragOut->bDontDragMeOutCar) { - if (pedToDragOut->m_nPedState != PED_DRIVING) { - ped->QuitEnteringCar(); - pedToDragOut = nil; - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_RHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); - } - } else if (ped->m_nPedType == PEDTYPE_COP) { - ped->QuitEnteringCar(); - if (ped->m_pedInObjective && ped->m_pedInObjective->m_nPedState == PED_DRIVING) { - veh->SetStatus(STATUS_PLAYER_DISABLED); - ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); - } else if (!veh->IsDoorMissing(DOOR_FRONT_RIGHT)) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING); - } - } else { - // BUG: Probably we will sit on top of the passenger if his m_ped_flagF4 is true. - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } - } else { - if (pedToDragOut) { - if (pedToDragOut->m_nPedState != PED_DRIVING || pedToDragOut->bDontDragMeOutCar) { - - // BUG: Player freezes in that condition due to its objective isn't restored. It's an unfinished feature, used in VC. - ped->QuitEnteringCar(); - pedToDragOut = nil; - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); - } - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } - } - - if (pedToDragOut) { - pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, false); - if (pedToDragOut->IsGangMember()) - pedToDragOut->RegisterThreatWithGangPeds(ped); - } - } - - if (veh->pDriver && ped) { - veh->pDriver->SetLookFlag(ped, true); - veh->pDriver->SetLookTimer(1000); - } - return; -} - -void -CPed::SetJump(void) -{ - if (!bInVehicle && -#if defined VC_PED_PORTS || defined FIX_BUGS - m_nPedState != PED_JUMP && !RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_LAUNCH) && -#endif - (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { - SetStoredState(); - m_nPedState = PED_JUMP; - CAnimBlendAssociation *jumpAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAUNCH, 8.0f); - jumpAssoc->SetFinishCallback(FinishLaunchCB, this); - m_fRotationDest = m_fRotationCur; - } -} - -void -CPed::RemoveInCarAnims(void) -{ - if (!IsPlayer()) - return; - - CAnimBlendAssociation *animAssoc; - - if (m_pMyVehicle && m_pMyVehicle->bLowVehicle) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - } else { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - } - -#ifdef VC_PED_PORTS - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; -#endif - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; -} - -void -CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*) arg; - - CVehicle *veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - if (!ped->EnteringCar()) { -#ifdef VC_PED_PORTS - if(ped->m_nPedState != PED_DRIVING) -#endif - ped->QuitEnteringCar(); - return; - } - - if (ped->IsPlayer() && ped->bGonnaKillTheCarJacker && ((CPlayerPed*)ped)->m_pArrestingCop) { - PedSetInCarCB(nil, ped); - ped->m_nLastPedState = ped->m_nPedState; - ped->m_nPedState = PED_ARRESTED; - ped->bGonnaKillTheCarJacker = false; - if (veh) { - veh->m_nNumGettingIn = 0; - veh->m_nGettingInFlags = 0; - veh->bIsHandbrakeOn = true; - veh->SetStatus(STATUS_PLAYER_DISABLED); - } - return; - } - if (ped->IsPlayer() && ped->m_vehEnterType == CAR_DOOR_LF - && (Pads[0].GetAccelerate() >= 255.0f || Pads[0].GetBrake() >= 255.0f) - && veh->IsCar()) { - if (((CAutomobile*)veh)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != DOOR_STATUS_MISSING) - ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); - - PedSetInCarCB(nil, ped); - return; - } - bool isVan = !!veh->bIsVan; - bool isBus = !!veh->bIsBus; - bool isLow = !!veh->bLowVehicle; - eDoors enterDoor; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - isVan = false; - enterDoor = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - enterDoor = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - isVan = false; - enterDoor = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - enterDoor = DOOR_REAR_LEFT; - break; - default: - break; - } - if (!veh->IsDoorMissing(enterDoor)) { - if (veh->IsCar()) - ((CAutomobile*)veh)->Damage.SetDoorStatus(enterDoor, DOOR_STATUS_SWINGING); - } - CPed *driver = veh->pDriver; - if (driver && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { - if (veh->bIsBus) { - driver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - if (driver->IsPlayer()) { - veh->bIsHandbrakeOn = true; - veh->SetStatus(STATUS_PLAYER_DISABLED); - } - driver->bBusJacked = true; - veh->bIsBeingCarJacked = false; - PedSetInCarCB(nil, ped); - if (ped->m_nPedType == PEDTYPE_COP - || ped->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT - || ped->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - } - ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 400; - return; - } - if (driver != ped && ped->m_vehEnterType != CAR_DOOR_LF) { - if (!driver->IsPlayer()) { - driver->bUsePedNodeSeek = true; - driver->m_pLastPathNode = nil; - if (driver->m_pedStats->m_temper <= driver->m_pedStats->m_fear - || driver->CharCreatedBy == MISSION_CHAR - || veh->VehicleCreatedBy == MISSION_VEHICLE) { - driver->bFleeAfterExitingCar = true; - } else { - driver->bGonnaKillTheCarJacker = true; - veh->pDriver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped); - - if (veh->pDriver->m_nPedType == PEDTYPE_COP && ped->IsPlayer()) { - FindPlayerPed()->SetWantedLevelNoDrop(1); - } - } - } - if ((ped->m_nPedType != PEDTYPE_EMERGENCY || veh->pDriver->m_nPedType != PEDTYPE_EMERGENCY) - && (ped->m_nPedType != PEDTYPE_COP || veh->pDriver->m_nPedType != PEDTYPE_COP)) { - veh->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - veh->pDriver->Say(SOUND_PED_CAR_JACKED); -#ifdef VC_PED_PORTS - veh->pDriver->SetRadioStation(); -#endif - } else { - ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; - } - } - } - if (veh->IsDoorMissing(enterDoor) || isBus) { - PedAnimDoorCloseCB(nil, ped); - } else { - AnimationId animToPlay; - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { - if (isVan) { - animToPlay = ANIM_VAN_CLOSE; - } else if (isLow) { - animToPlay = ANIM_CAR_CLOSEDOOR_LOW_RHS; - } else { - animToPlay = ANIM_CAR_CLOSEDOOR_RHS; - } - } else if (isVan) { - animToPlay = ANIM_VAN_CLOSE_L; - } else if (isLow) { - animToPlay = ANIM_CAR_CLOSEDOOR_LOW_LHS; - } else { - animToPlay = ANIM_CAR_CLOSEDOOR_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorCloseCB, ped); - } -} - -void -CPed::SetPedPositionInTrain(void) -{ - LineUpPedWithTrain(); -} - -void -CPed::PedAnimPullPedOutCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (ped->EnteringCar()) { - if (!ped->IsNotInWreckedVehicle()) - return; - -#ifdef CANCELLABLE_CAR_ENTER - if (ped->bCancelEnteringCar) { - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - ped->bCancelEnteringCar = false; - return; - } -#endif - - bool isLow = !!veh->bLowVehicle; - - int padNo; - if (ped->IsPlayer()) { - - // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads - switch (ped->m_nPedType) { - case PEDTYPE_PLAYER1: - padNo = 0; - break; - case PEDTYPE_PLAYER2: - padNo = 1; - break; - case PEDTYPE_PLAYER3: - padNo = 2; - break; - case PEDTYPE_PLAYER4: - padNo = 3; - break; - } - CPad *pad = CPad::GetPad(padNo); - - if (!pad->ArePlayerControlsDisabled()) { - - if (pad->GetTarget() - || pad->NewState.LeftStickX - || pad->NewState.LeftStickY - || pad->NewState.DPadUp - || pad->NewState.DPadDown - || pad->NewState.DPadLeft - || pad->NewState.DPadRight) { - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - return; - } - } - } - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - if (isLow) - animToPlay = ANIM_CAR_GETIN_LOW_RHS; - else - animToPlay = ANIM_CAR_GETIN_RHS; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_LHS; - } else { - animToPlay = ANIM_CAR_GETIN_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } else { - ped->QuitEnteringCar(); - } - } else { - ped->QuitEnteringCar(); - } -} - -void -CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!veh) { - PedSetOutCarCB(nil, ped); - return; - } -#ifdef VC_PED_PORTS - CVector posForZ = ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posForZ); - if (ped->GetPosition().z - 0.5f > posForZ.z) { - PedSetOutCarCB(nil, ped); - return; - } -#endif - veh->m_nStaticFrames = 0; - veh->m_vecMoveSpeed += CVector(0.001f, 0.001f, 0.001f); - veh->m_vecTurnSpeed += CVector(0.001f, 0.001f, 0.001f); - if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); - - /* - // Duplicate and only in PC for some reason - if (!veh) { - PedSetOutCarCB(nil, ped); - return; - } - */ - eDoors door; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - door = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - door = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - door = DOOR_REAR_LEFT; - break; - default: - break; - } - bool closeDoor = false; - if (!veh->IsDoorMissing(door)) - closeDoor = true; - - 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 = false; - if (veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225) { - engineIsIntact = true; - } - 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) - return; - - ped->RestorePreviousState(); - } else if (animAssoc->animId == ANIM_EV_DIVE) { - ped->bUpdateAnimHeading = true; - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY) + + if ( runStopAsoc != NULL && runStopAsoc->blendAmount > 0.1f ) + { { - ped->m_getUpTimer = CTimer::GetTimeInMilliseconds() + 1; - ped->m_nPedState = PED_FALL; - } - animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } else if (animAssoc->flags & ASSOC_FADEOUTWHENDONE) { - ped->ClearLookFlag(); - if (ped->m_nPedState != PED_DIVE_AWAY && ped->m_nPedState != PED_STEP_AWAY) - return; - - ped->RestorePreviousState(); - } else if (ped->m_nPedState != PED_ARRESTED) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (animAssoc->blendDelta >= 0.0f) - animAssoc->blendDelta = -4.0f; - - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) { - ped->RestorePreviousState(); - } - } -} - -void -CPed::PedGetupCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - if (ped->m_nPedState == PED_GETUP) - RpAnimBlendClumpSetBlendDeltas(ped->GetClump(), ASSOC_PARTIAL, -1000.0f); - - ped->bFallenDown = false; - animAssoc->blendDelta = -1000.0f; - if (ped->m_nPedState == PED_GETUP) - ped->RestorePreviousState(); - - if (ped->m_nPedState != PED_FLEE_POS && ped->m_nPedState != PED_FLEE_ENTITY) - ped->SetMoveState(PEDMOVE_STILL); - else - ped->SetMoveState(PEDMOVE_RUN); - - ped->SetMoveAnim(); - ped->bGetUpAnimStarted = false; -} - -void -CPed::PedLandCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - animAssoc->blendDelta = -1000.0f; - ped->bIsLanding = false; - - if (ped->m_nPedState == PED_JUMP) - ped->RestorePreviousState(); -} - -void -CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed *ped = (CPed*)arg; - - ped->bUsesCollision = true; - ped->RestartNonPartialAnims(); - bool itsRearDoor = false; - - if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) - itsRearDoor = true; - - CMatrix pedMat(ped->GetMatrix()); - CVector posAfterBeingDragged = Multiply3x3(pedMat, (itsRearDoor ? -vecPedDraggedOutCarAnimOffset : vecPedDraggedOutCarAnimOffset)); - posAfterBeingDragged += ped->GetPosition(); -#ifndef VC_PED_PORTS - posAfterBeingDragged.z += 1.0f; -#endif - CPedPlacement::FindZCoorForPed(&posAfterBeingDragged); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posAfterBeingDragged); - - if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedDraggedOutCarAnimOffset)) { - ped->PositionPedOutOfCollision(); - } - - if (!ped->CanSetPedState()) - return; - - if (!ped->m_pMyVehicle) { - ped->SetIdle(); - ped->SetGetUp(); - return; - } - - CPed *driver = ped->m_pMyVehicle->pDriver; - - if (ped->IsPlayer()) { - ped->SetIdle(); - - } else if (ped->bFleeAfterExitingCar) { - ped->bFleeAfterExitingCar = false; - ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); - - } else if (ped->bWanderPathAfterExitingCar) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - ped->bWanderPathAfterExitingCar = false; - - } else if (ped->bGonnaKillTheCarJacker) { - // Kill objective is already set at this point. - - ped->bGonnaKillTheCarJacker = false; - if (!ped->m_pedInObjective || !(CGeneral::GetRandomNumber() & 1)) { - if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { - ped->m_nPedState = PED_NONE; - ped->m_nLastPedState = PED_NONE; - ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); - } else { - ped->ClearObjective(); - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - } - } - - } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR - && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && driver - && driver->IsPlayer() && !CTheScripts::IsPlayerOnAMission()) { - -#ifndef VC_PED_PORTS - if (CGeneral::GetRandomNumber() & 1) - ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); - else -#endif - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - - } else { -#ifdef VC_PED_PORTS - if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR - && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && !driver - && FindPlayerPed()->m_carInObjective == ped->m_pMyVehicle && !CTheScripts::IsPlayerOnAMission()) - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - else -#endif - { - ped->m_nPedState = PED_NONE; - ped->m_nLastPedState = PED_NONE; - ped->SetFindPathAndFlee(ped->m_pMyVehicle->GetPosition(), 10000); - } - } - ped->SetGetUp(); -} - -void -CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - // Pointless code - if (!veh) - return; - -#ifdef VC_PED_PORTS - // Situation of entering car as a driver while there is already a driver exiting atm. - CPed *driver = veh->pDriver; - if (driver && driver->m_nPedState == PED_DRIVING && !veh->bIsBus && driver->m_objective == OBJECTIVE_LEAVE_CAR - && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { - - if (!ped->IsPlayer() && (ped->CharCreatedBy != MISSION_CHAR || driver->IsPlayer())) { - ped->QuitEnteringCar(); - return; - } - if (driver->CharCreatedBy == MISSION_CHAR) { - PedSetOutCarCB(nil, veh->pDriver); - if (driver->m_pMyVehicle) { - driver->PositionPedOutOfCollision(); - } else { - driver->m_pMyVehicle = veh; - driver->PositionPedOutOfCollision(); - driver->m_pMyVehicle = nil; - } - veh->pDriver = nil; - } else { - driver->SetDead(); - driver->FlagToDestroyWhenNextProcessed(); - veh->pDriver = nil; - } - } -#endif - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - ped->bInVehicle = true; - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { - if (veh->pDriver) { - if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { - CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1000; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; - CWorld::Players[CWorld::PlayerInFocus].m_pHooker = (CCivilianPed*)ped; - } - } - } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - || ped->m_nPedState == PED_CARJACK -#endif - ) - veh->bIsBeingCarJacked = false; - - if (veh->m_nNumGettingIn) - --veh->m_nNumGettingIn; - - if (ped->IsPlayer() && ((CPlayerPed*)ped)->m_bAdrenalineActive) - ((CPlayerPed*)ped)->ClearAdrenaline(); - - if (veh->IsBoat()) { - if (ped->IsPlayer()) { -#if defined VC_PED_PORTS || defined FIX_BUGS - CCarCtrl::RegisterVehicleOfInterest(veh); -#endif - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PLAYER); - AudioManager.PlayerJustGotInCar(); - } - veh->SetDriver(ped); - if (!veh->bEngineOn) - veh->bEngineOn = true; - - ped->m_nPedState = PED_DRIVING; - ped->StopNonPartialAnims(); - return; - } - - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; - - ped->bDoBloodyFootprints = false; - if (veh->m_nAlarmState == -1) - veh->m_nAlarmState = 15000; - - if (ped->IsPlayer()) { - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PLAYER); - } - AudioManager.PlayerJustGotInCar(); - } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PHYSICS); - } - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { - CPed *passenger = veh->pPassengers[i]; - if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { - passenger->SetObjective(OBJECTIVE_LEAVE_CAR, veh); -#ifdef VC_PED_PORTS - passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); -#endif - } - } - } - // This shouldn't happen at all. Passengers can't enter with PED_CARJACK. Even though they did, we shouldn't call AddPassenger in here and SetDriver in below. -#if !defined VC_PED_PORTS && !defined FIX_BUGS - else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (ped->m_nPedState == PED_CARJACK) { - veh->AddPassenger(ped, 0); - ped->m_nPedState = PED_DRIVING; - ped->RestorePreviousObjective(); - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - } else if (veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) { - veh->AutoPilot.m_nCruiseSpeed = 17; - } - } -#endif - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK) { - veh->SetDriver(ped); - if (veh->VehicleCreatedBy == PARKED_VEHICLE) { - veh->VehicleCreatedBy = RANDOM_VEHICLE; - ++CCarCtrl::NumRandomCars; - --CCarCtrl::NumParkedCars; - } - if (veh->bIsAmbulanceOnDuty) { - veh->bIsAmbulanceOnDuty = false; - --CCarCtrl::NumAmbulancesOnDuty; - } - if (veh->bIsFireTruckOnDuty) { - veh->bIsFireTruckOnDuty = false; - --CCarCtrl::NumFiretrucksOnDuty; - } - if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) - veh->ChangeLawEnforcerState(true); - - if (!veh->bEngineOn) { - veh->bEngineOn = true; - DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); - } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR - && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { - - CCarCtrl::JoinCarWithRoadSystem(veh); - veh->AutoPilot.m_nCarMission = MISSION_CRUISE; - veh->AutoPilot.m_nTempAction = TEMPACT_NONE; - veh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - veh->AutoPilot.m_nCruiseSpeed = 25; - } - ped->m_nPedState = PED_DRIVING; - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - - if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) - ped->m_prevObjective = OBJECTIVE_NONE; - - ped->RestorePreviousObjective(); - } - - } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (veh->bIsBus) { - veh->AddPassenger(ped); - } else { - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - veh->AddPassenger(ped, 0); - break; - case CAR_DOOR_RR: - veh->AddPassenger(ped, 2); - break; - case CAR_DOOR_LR: - veh->AddPassenger(ped, 1); - break; - default: - veh->AddPassenger(ped); - break; - } - } - ped->m_nPedState = PED_DRIVING; - if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) - ped->m_prevObjective = OBJECTIVE_NONE; - - ped->RestorePreviousObjective(); -#ifdef VC_PED_PORTS - if(veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) - veh->AutoPilot.m_nCruiseSpeed = 17; -#endif - } - - veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - - if (veh->bIsBus && !veh->m_nGettingInFlags) - ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); - - switch (ped->m_objective) { - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - break; - default: - ped->SetObjective(OBJECTIVE_NONE); - } - - if (veh->pDriver == ped) { - if (veh->bLowVehicle) { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); - } else { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); - } - } else if (veh->bLowVehicle) { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITPLO, 100.0f); - } else { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITP, 100.0f); - } - - ped->StopNonPartialAnims(); - if (veh->bIsBus) - ped->bRenderPedInCar = false; - - // FIX: RegisterVehicleOfInterest not just registers the vehicle, but also updates register time. So remove the IsThisVehicleInteresting check. -#ifndef FIX_BUGS - if (ped->IsPlayer() && !CCarCtrl::IsThisVehicleInteresting(veh) && veh->VehicleCreatedBy != MISSION_VEHICLE) { -#else - if (ped->IsPlayer() && veh->VehicleCreatedBy != MISSION_VEHICLE) { -#endif - CCarCtrl::RegisterVehicleOfInterest(veh); - - if (!veh->bHasBeenOwnedByPlayer && veh->VehicleCreatedBy != MISSION_VEHICLE) - CEventList::RegisterEvent(EVENT_STEAL_CAR, EVENT_ENTITY_VEHICLE, veh, ped, 1500); - - veh->bHasBeenOwnedByPlayer = true; - } - ped->bChangedSeat = true; -} - -void -CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed *ped = (CPed*)arg; - CTrain *veh = (CTrain*)ped->m_pMyVehicle; - - if (!veh) - return; - - ped->bInVehicle = true; - ped->m_nPedState = PED_DRIVING; - ped->RestorePreviousObjective(); - ped->SetMoveState(PEDMOVE_STILL); - veh->AddPassenger(ped); -} - -void -CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - /* - CPed *ped = (CPed*)arg; - - if (ped->m_nPedState == PED_STAGGER) - // nothing - */ -} - -// It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB but that's not true, someone made it up. -bool -CPed::RunToReportCrime(eCrimeType crimeToReport) -{ -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - if (bRunningToPhone) { - if (!isPhoneAvailable(m_phoneId)) { - m_phoneId = -1; - bIsRunning = false; - ClearSeek(); // clears bRunningToPhone - return false; - } - - return true; - } -#else - // They changed true into false to make this function unusable. So running to phone actually starts but first frame after that cancels it. - if (m_nPedState == PED_SEEK_POS) - return false; -#endif - - CVector pos = GetPosition(); - int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); - - if (phoneId == -1) - return false; - - CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - if (phone->m_nState != PHONE_STATE_FREE) - return false; -#endif - - bRunningToPhone = true; - SetSeek(phone->m_pEntity->GetMatrix() * -phone->m_pEntity->GetForward(), 1.0f); // original: phone.m_vecPos, 0.3f - SetMoveState(PEDMOVE_RUN); - bIsRunning = true; // not there in original - m_phoneId = phoneId; - m_crimeToReportOnPhone = crimeToReport; - return true; -} - -void -CPed::RegisterThreatWithGangPeds(CEntity *attacker) -{ - CPed *attackerPed = nil; - if (attacker) { - if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; - - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } - - if (attackerPed && (attackerPed->IsPlayer() || attackerPed->IsGangMember())) { - for (int i = 0; i < m_numNearPeds; ++i) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed->IsPointerValid()) { - if (nearPed != this && nearPed->m_nPedType == m_nPedType) - nearPed->m_fearFlags |= CPedType::GetFlag(attackerPed->m_nPedType); - } - } - } - } - } - - if (attackerPed && attackerPed->IsPlayer() && (attackerPed->m_nPedState == PED_CARJACK || attackerPed->bInVehicle)) { - if (!attackerPed->m_pMyVehicle || attackerPed->m_pMyVehicle->GetModelIndex() != MI_TOYZ) { - int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), ENTER_CAR_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - if (lastVehicle > 8) - lastVehicle = 8; - - for (int j = 0; j < lastVehicle; ++j) { - CVehicle *nearVeh = (CVehicle*) vehicles[j]; - - if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { - CPed *nearVehDriver = nearVeh->pDriver; - - if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { - - if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { - nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; - nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; - nearVeh->SetStatus(STATUS_PHYSICS); - nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; - nearVeh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - } - } - } - } - } - } -} - -void -CPed::ReactToPointGun(CEntity *entWithGun) -{ - CPed *pedWithGun = (CPed*)entWithGun; - int waitTime; - - if (IsPlayer() || !IsPedInControl() || CharCreatedBy == MISSION_CHAR) - return; - - if (m_leader == pedWithGun) - return; - - if (m_nWaitState == WAITSTATE_PLAYANIM_HANDSUP || m_nWaitState == WAITSTATE_PLAYANIM_HANDSCOWER || - (GetPosition() - pedWithGun->GetPosition()).MagnitudeSqr2D() > 225.0f) - return; - - if (m_leader) { - if (FindPlayerPed() == m_leader) - return; - - ClearLeader(); - } - if (m_pedStats->m_flags & STAT_GUN_PANIC - && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) - && m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_AIM_GUN) { - - waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); - SetWaitState(WAITSTATE_PLAYANIM_HANDSCOWER, &waitTime); - Say(SOUND_PED_HANDS_COWER); - m_pLookTarget = pedWithGun; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - SetMoveState(PEDMOVE_NONE); - - } else if (m_nPedType != pedWithGun->m_nPedType) { - if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { - RegisterThreatWithGangPeds(pedWithGun); - } - - if (m_nPedType == PEDTYPE_COP) { - if (pedWithGun->IsPlayer()) { - ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); - } - if (bCrouchWhenShooting || bKindaStayInSamePlace) { - SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); - } - - } else 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++) { - // (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)); - } - } - bRichFromMugging = false; - } - } - } -} - -void -CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - bool startedToRun = false; - ped->bUsesCollision = true; - ped->m_actionX = 0.0f; - ped->m_actionY = 0.0f; - ped->bVehExitWillBeInstant = false; - if (veh && veh->IsBoat()) - ped->ApplyMoveSpeed(); - - if (ped->m_objective == OBJECTIVE_LEAVE_CAR) - ped->RestorePreviousObjective(); -#ifdef VC_PED_PORTS - else if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - ped->m_fHealth = 0.0f; - ped->SetDie(ANIM_FLOOR_HIT, 4.0f, 0.5f); - } -#endif - - ped->bInVehicle = false; - if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { - ped->PositionPedOutOfCollision(); - } - - if (ped->m_nPedState == PED_EXIT_CAR) { - if (ped->m_nPedType == PEDTYPE_COP) - ped->SetIdle(); - else - ped->RestorePreviousState(); - - veh = ped->m_pMyVehicle; - if (ped->bFleeAfterExitingCar && veh) { - ped->bFleeAfterExitingCar = false; - ped->SetFlee(veh->GetPosition(), 12000); - ped->bUsePedNodeSeek = true; - ped->m_pNextPathNode = nil; - if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { - ped->SetMoveState(PEDMOVE_SPRINT); - ped->Say(SOUND_PED_FLEE_SPRINT); - } else { - ped->SetMoveState(PEDMOVE_RUN); - ped->Say(SOUND_PED_FLEE_RUN); - } - startedToRun = true; - - // This is not a good way to do this... - ped->m_nLastPedState = PED_WANDER_PATH; - - } else if (ped->bWanderPathAfterExitingCar) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - ped->bWanderPathAfterExitingCar = false; - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) - ped->SetObjectiveTimer(30000); - ped->m_nLastPedState = PED_NONE; - - } else if (ped->bGonnaKillTheCarJacker) { - - // Kill objective is already given at this point. - ped->bGonnaKillTheCarJacker = false; - if (ped->m_pedInObjective) { - if (!(CGeneral::GetRandomNumber() & 1) - && ped->m_nPedType != PEDTYPE_COP - && (!ped->m_pedInObjective->IsPlayer() || !CTheScripts::IsPlayerOnAMission())) { - ped->ClearObjective(); - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - } - ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1500; - } - int waitTime = 1500; - ped->SetWaitState(WAITSTATE_PLAYANIM_COWER, &waitTime); - ped->SetMoveState(PEDMOVE_RUN); - startedToRun = true; - } else if (ped->m_objective == OBJECTIVE_NONE && ped->CharCreatedBy != MISSION_CHAR && ped->m_nPedState == PED_IDLE && !ped->IsPlayer()) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - } - } -#ifdef VC_PED_PORTS - else { - ped->m_nPedState = PED_IDLE; - } -#endif - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - ped->RestartNonPartialAnims(); - ped->m_pVehicleAnim = nil; - CVector posFromZ = ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posFromZ); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posFromZ); - veh = ped->m_pMyVehicle; - if (veh) { - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { - if (veh->pDriver) { - if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = 0; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = 0; - CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; - CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= 100; - if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney < 0) - CWorld::Players[CWorld::PlayerInFocus].m_nMoney = 0; - } - } - } - veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - if (veh->pDriver == ped) { - veh->RemoveDriver(); - veh->SetStatus(STATUS_ABANDONED); - if (veh->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - veh->m_nDoorLock = CARLOCK_UNLOCKED; - if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) - veh->ChangeLawEnforcerState(false); - } else { - veh->RemovePassenger(ped); - } - - if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { - float angleAfterExit; - if (ped->m_vehEnterType == CAR_DOOR_LF) { - angleAfterExit = HALFPI + veh->GetForward().Heading(); - } else { - angleAfterExit = veh->GetForward().Heading() - HALFPI; - } - ped->SetHeading(angleAfterExit); - ped->m_fRotationDest = angleAfterExit; - ped->m_fRotationCur = angleAfterExit; - if (!ped->bBusJacked) - ped->SetMoveState(PEDMOVE_WALK); - } - if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) - veh->bLightsOn = false; - } - - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); - - ped->ReplaceWeaponWhenExitingVehicle(); - - ped->bOnBoat = false; - if (ped->bBusJacked) { - ped->SetFall(1500, ANIM_KO_SKID_BACK, false); - ped->bBusJacked = false; - } - ped->m_nStoredMoveState = PEDMOVE_NONE; - if (!ped->IsPlayer()) { - // It's a shame... -#ifdef FIX_BUGS - int createdBy = ped->CharCreatedBy; -#else - int createdBy = !ped->CharCreatedBy; -#endif - - if (createdBy == MISSION_CHAR && !startedToRun) - ped->SetMoveState(PEDMOVE_WALK); - } -} - -// It was inlined in III but not in VC. -inline void -CPed::ReplaceWeaponWhenExitingVehicle(void) -{ - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - - // If it's Uzi, we may have stored weapon. Uzi is the only gun we can use in car. - if (IsPlayer() && weaponType == WEAPONTYPE_UZI) { - if (/*IsPlayer() && */ m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { - SetCurrentWeapon(m_storedWeapon); - m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - } - } else { - AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); - } -} - -// Same, it's inlined in III. -inline void -CPed::RemoveWeaponWhenEnteringVehicle(void) -{ - if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { - if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) - m_storedWeapon = GetWeapon()->m_eWeaponType; - SetCurrentWeapon(WEAPONTYPE_UZI); - } else { - CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(ourWeapon->m_nModelId); - } -} - -void -CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; - - ped->bUsesCollision = true; - ped->m_pVehicleAnim = nil; - ped->bInVehicle = false; - ped->m_nPedState = PED_IDLE; - ped->RestorePreviousObjective(); - ped->SetMoveState(PEDMOVE_STILL); - - CMatrix pedMat(ped->GetMatrix()); - ped->m_fRotationCur = HALFPI + veh->GetForward().Heading(); - ped->m_fRotationDest = ped->m_fRotationCur; - CVector posAfterExit = Multiply3x3(pedMat, vecPedTrainDoorAnimOffset); - posAfterExit += ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posAfterExit); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posAfterExit); - ped->SetHeading(ped->m_fRotationCur); - veh->RemovePassenger(ped); -} - -bool -CPed::PlacePedOnDryLand(void) -{ - float waterLevel = 0.0f; - CEntity *foundEnt = nil; - CColPoint foundCol; - float foundColZ; - - CWaterLevel::GetWaterLevelNoWaves(GetPosition().x, GetPosition().y, GetPosition().z, &waterLevel); - - CVector potentialGround = GetPosition(); - potentialGround.z = waterLevel; - - if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) - return false; - - CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition(); - potentialGroundDist.z = 0.0f; - potentialGroundDist.Normalise(); - - CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point; - posToCheck.z = 3.0f + waterLevel; - - if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) { - foundColZ = foundCol.point.z; - if (foundColZ >= waterLevel) { - posToCheck.z = 0.8f + foundColZ; - SetPosition(posToCheck); - bIsStanding = true; - bWasStanding = true; - return true; - } - } - - posToCheck = 5.0f * potentialGroundDist + GetPosition(); - posToCheck.z = 3.0f + waterLevel; - - if (!CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) - return false; - - foundColZ = foundCol.point.z; - if (foundColZ < waterLevel) - return false; - - posToCheck.z = 0.8f + foundColZ; - SetPosition(posToCheck); - bIsStanding = true; - bWasStanding = true; - return true; -} - -void -CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - CVector finalPos; - CVector draggedOutOffset; - CVector finalLocalPos; - - 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; - - finalLocalPos = Multiply3x3(pedMat, draggedOutOffset); - finalPos = finalLocalPos + 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); - - } 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 -#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); - } - } - } - } - } - if (ped->m_nLastPedState == PED_IDLE) - ped->m_nLastPedState = PED_WANDER_PATH; -} - -bool -CPed::PositionPedOutOfCollision(void) -{ - CVehicle *veh; - CVector posNearVeh; - CVector posSomewhereClose; - bool putNearVeh = false; - bool putSomewhereClose = false; - int smallestDistNearVeh = 999; - int smallestDistSomewhereClose = 999; - - if (!m_pMyVehicle) - return false; - - CVector vehPos = m_pMyVehicle->GetPosition(); - CVector potentialPos; - potentialPos.y = GetPosition().y - 3.5f; - potentialPos.z = GetPosition().z; - - for (int yTry = 0; yTry < 15; yTry++) { - potentialPos.x = GetPosition().x - 3.5f; - - for (int xTry = 0; xTry < 15; xTry++) { - CPedPlacement::FindZCoorForPed(&potentialPos); - CVector distVec = potentialPos - vehPos; - float dist = distVec.Magnitude(); - - // Makes close distances bigger for some reason. - float mult = (0.6f + dist) / dist; - CVector adjustedPotentialPos = distVec * mult + vehPos; - if (CWorld::GetIsLineOfSightClear(vehPos, adjustedPotentialPos, true, false, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, true, false, false, true, false, false)) { - - float potentialChangeSqr = (potentialPos - GetPosition()).MagnitudeSqr(); - veh = (CVehicle*)CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, false, true, false, false, false, false); - if (veh) { - if (potentialChangeSqr < smallestDistNearVeh) { - posNearVeh = potentialPos; - putNearVeh = true; - smallestDistNearVeh = potentialChangeSqr; - } - } else if (potentialChangeSqr < smallestDistSomewhereClose) { - smallestDistSomewhereClose = potentialChangeSqr; - posSomewhereClose = potentialPos; - putSomewhereClose = true; - } - } - potentialPos.x += 0.5f; - } - potentialPos.y += 0.5f; - } - - if (!putSomewhereClose && !putNearVeh) - return false; - - // We refrain from using posNearVeh, probably because of it may be top of the vehicle. - if (putSomewhereClose) { - SetPosition(posSomewhereClose); - } else { - CVector vehSize = veh->GetModelInfo()->GetColModel()->boundingBox.max; - posNearVeh.z += vehSize.z; - SetPosition(posNearVeh); - } - return true; -} - -bool -CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) -{ - bool foundIt = false; - - CVector helperPos = GetPosition(); - helperPos.z = pos->z - 0.5f; - - CVector foundPos = *pos; - foundPos.z -= 0.5f; - - // If there is another car between target car and us. - if (CWorld::TestSphereAgainstWorld((foundPos + helperPos) / 2.0f, 0.25f, veh, false, true, false, false, false, false)) { - - CColModel *vehCol = veh->GetModelInfo()->GetColModel(); - CVector *colMin = &vehCol->boundingBox.min; - CVector *colMax = &vehCol->boundingBox.max; - - CVector leftRearPos = CVector(colMin->x - 0.5f, colMin->y - 0.5f, 0.0f); - CVector rightRearPos = CVector(0.5f + colMax->x, colMin->y - 0.5f, 0.0f); - CVector leftFrontPos = CVector(colMin->x - 0.5f, 0.5f + colMax->y, 0.0f); - CVector rightFrontPos = CVector(0.5f + colMax->x, 0.5f + colMax->y, 0.0f); - - leftRearPos = veh->GetMatrix() * leftRearPos; - rightRearPos = veh->GetMatrix() * rightRearPos; - leftFrontPos = veh->GetMatrix() * leftFrontPos; - rightFrontPos = veh->GetMatrix() * rightFrontPos; - - // Makes helperPos veh-ped distance vector. - helperPos -= veh->GetPosition(); - - // ?!? I think it's absurd to use this unless another function like SeekCar finds next pos. with it and we're trying to simulate it's behaviour. - // On every run it returns another pos. for ped, with same distance to the veh. - // Sequence of positions are not guaranteed, it depends on global pos. (So sometimes it returns positions to make ped draw circle, sometimes don't) - helperPos = veh->GetMatrix() * helperPos; - - float vehForwardHeading = veh->GetForward().Heading(); - - // I'm absolutely not sure about these namings. - // NTVF = needed turn if we're looking to vehicle front and wanna look to... - - float potentialLrHeading = Atan2(leftRearPos.x - helperPos.x, leftRearPos.y - helperPos.y); - float NTVF_LR = CGeneral::LimitRadianAngle(potentialLrHeading - vehForwardHeading); - - float potentialRrHeading = Atan2(rightRearPos.x - helperPos.x, rightRearPos.y - helperPos.y); - float NTVF_RR = CGeneral::LimitRadianAngle(potentialRrHeading - vehForwardHeading); - - float potentialLfHeading = Atan2(leftFrontPos.x - helperPos.x, leftFrontPos.y - helperPos.y); - float NTVF_LF = CGeneral::LimitRadianAngle(potentialLfHeading - vehForwardHeading); - - float potentialRfHeading = Atan2(rightFrontPos.x - helperPos.x, rightFrontPos.y - helperPos.y); - float NTVF_RF = CGeneral::LimitRadianAngle(potentialRfHeading - vehForwardHeading); - - bool canHeadToLr = NTVF_LR <= -PI || NTVF_LR >= -HALFPI; - - bool canHeadToRr = NTVF_RR <= HALFPI || NTVF_RR >= PI; - - bool canHeadToLf = NTVF_LF >= 0.0f || NTVF_LF <= -HALFPI; - - bool canHeadToRf = NTVF_RF <= 0.0f || NTVF_RF >= HALFPI; - - // Only order of conditions are different among enterTypes. - if (m_vehEnterType == CAR_DOOR_RR) { - if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } - } else if(m_vehEnterType == CAR_DOOR_RF) { - if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } - } else if (m_vehEnterType == CAR_DOOR_LF) { - if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } - } else if (m_vehEnterType == CAR_DOOR_LR) { - if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } - } - } - if (!foundIt) - return false; - - helperPos = GetPosition() - foundPos; - helperPos.z = 0.0f; - if (helperPos.MagnitudeSqr() <= sq(0.5f)) - return false; - - pos->x = foundPos.x; - pos->y = foundPos.y; - return true; -} - -void -CPed::Render(void) -{ - if (!bInVehicle || m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR || - bRenderPedInCar && sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { - CEntity::Render(); - -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - renderLimb(PED_HEAD); - renderLimb(PED_HANDL); - renderLimb(PED_HANDR); - } - if(m_pWeaponModel && IsClumpSkinned(GetClump())){ - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); - RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); - *RwFrameGetMatrix(frame) = *mat; - RwFrameUpdateObjects(frame); - RpAtomicRender(m_pWeaponModel); - } -#endif - } -} - -#ifdef PED_SKIN -static RpMaterial* -SetLimbAlphaCB(RpMaterial *material, void *data) -{ - ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; - return material; -} - -void -CPed::renderLimb(int node) -{ - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); - RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - CPedModelInfo *mi = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); - RpAtomic *atomic; - switch(node){ - case PED_HEAD: - atomic = mi->getHead(); - break; - case PED_HANDL: - atomic = mi->getLeftHand(); - break; - case PED_HANDR: - atomic = mi->getRightHand(); - break; - default: - return; - } - if(atomic == nil) - return; - - RwFrame *frame = RpAtomicGetFrame(atomic); - *RwFrameGetMatrix(frame) = *mat; - RwFrameUpdateObjects(frame); - int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); - RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetLimbAlphaCB, &alpha); - RpAtomicRender(atomic); -} -#endif - -void -CPed::ProcessObjective(void) -{ - if (bClearObjective && (IsPedInControl() || m_nPedState == PED_DRIVING)) { - ClearObjective(); - bClearObjective = false; - } - UpdateFromLeader(); - - CVector carOrOurPos; - CVector targetCarOrHisPos; - CVector distWithTarget; - - if (m_objective != OBJECTIVE_NONE && (IsPedInControl() || m_nPedState == PED_DRIVING)) { - if (bInVehicle) { - if (!m_pMyVehicle) { - bInVehicle = false; - return; - } - carOrOurPos = m_pMyVehicle->GetPosition(); - } else { - carOrOurPos = GetPosition(); - } - - if (m_pedInObjective) { - if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); - } else { - targetCarOrHisPos = m_pedInObjective->GetPosition(); - } - distWithTarget = targetCarOrHisPos - carOrOurPos; - } else if (m_carInObjective) { - targetCarOrHisPos = m_carInObjective->GetPosition(); - distWithTarget = targetCarOrHisPos - carOrOurPos; - } - - switch (m_objective) { - case OBJECTIVE_NONE: - case OBJECTIVE_GUARD_AREA: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: - case OBJECTIVE_DESTROY_OBJECT: - case OBJECTIVE_GOTO_AREA_IN_CAR: - case OBJECTIVE_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: - case OBJECTIVE_SET_LEADER: - break; - case OBJECTIVE_WAIT_ON_FOOT: - SetIdle(); - m_objective = OBJECTIVE_NONE; - SetMoveState(PEDMOVE_STILL); - break; - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - if (InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - bFleeAfterExitingCar = true; - } else if (m_nPedState != PED_FLEE_POS) { - CVector2D fleePos = GetPosition(); - SetFlee(fleePos, 10000); - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - } - break; - case OBJECTIVE_GUARD_SPOT: - { - distWithTarget = m_vecSeekPosEx - GetPosition(); - if (m_pedInObjective) { - SetLookFlag(m_pedInObjective, true); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - float distWithTargetSc = distWithTarget.Magnitude(); - if (2.0f * m_distanceToCountSeekDoneEx >= distWithTargetSc) { - if (m_pedInObjective) { - if (distWithTargetSc <= m_distanceToCountSeekDoneEx) - SetIdle(); - else - SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); - } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - int threatType = ScanForThreats(); - SetLookTimer(CGeneral::GetRandomNumberInRange(500, 1500)); - - // Second condition is pointless and isn't there in Mobile. - if (threatType == PED_FLAG_GUN || (threatType == PED_FLAG_EXPLOSION && m_threatEntity) || m_threatEntity) { - if (m_threatEntity->IsPed()) - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); - } - } - } else { - SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); - } - break; - } - case OBJECTIVE_WAIT_IN_CAR: - m_nPedState = PED_DRIVING; - break; - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: - m_nPedState = PED_DRIVING; - break; - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - { - if (m_pedInObjective) { - if (m_pedInObjective->IsPlayer() && CharCreatedBy != MISSION_CHAR - && m_nPedType != PEDTYPE_COP && FindPlayerPed()->m_pWanted->m_CurrentCops != 0 - && !bKindaStayInSamePlace) { - - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - break; - } - if (InVehicle()) { - if (distWithTarget.Magnitude() >= 20.0f - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { - if (m_pMyVehicle->pDriver == this - && !m_pMyVehicle->m_nGettingInFlags) { - m_pMyVehicle->SetStatus(STATUS_PHYSICS); - m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; - if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); - m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); - } else { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; - } - m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - } - } else { - bool targetHasVeh = m_pedInObjective->bInVehicle; - if (!targetHasVeh - || targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar()) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - } - break; - } - if (distWithTarget.Magnitude() > 30.0f && !bKindaStayInSamePlace) { - if (m_pMyVehicle) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } else { - float closestVehDist = 60.0f; - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle *foundVeh = nil; - for(int i = 0; i < lastVehicle; i++) { - CVehicle *nearVeh = (CVehicle*)vehicles[i]; - /* - Not used. - CVector vehSpeed = nearVeh->GetSpeed(); - CVector ourSpeed = GetSpeed(); - */ - CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); - if (vehDistVec.Magnitude() < closestVehDist && m_pedInObjective->m_pMyVehicle != nearVeh - && nearVeh->CanPedOpenLocks(this)) { - - foundVeh = nearVeh; - closestVehDist = vehDistVec.Magnitude(); - } - } - m_pMyVehicle = foundVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } else if (!GetIsOnScreen()) { - CVector ourPos = GetPosition(); - int closestNode = ThePaths.FindNodeClosestToCoors(ourPos, PATH_CAR, 20.0f); - if (closestNode >= 0) { - int16 colliding; - CWorld::FindObjectsKindaColliding( - ThePaths.m_pathNodes[closestNode].GetPosition(), 10.0f, true, &colliding, 2, nil, false, true, true, false, false); - if (!colliding) { - CZoneInfo zoneInfo; - int chosenCarClass; - CTheZones::GetZoneInfoForTimeOfDay(&ourPos, &zoneInfo); - int chosenModel = CCarCtrl::ChooseModel(&zoneInfo, &ourPos, &chosenCarClass); - CAutomobile *newVeh = new CAutomobile(chosenModel, RANDOM_VEHICLE); - if (newVeh) { - newVeh->GetMatrix().GetPosition() = ThePaths.m_pathNodes[closestNode].GetPosition(); - newVeh->GetMatrix().GetPosition().z += 4.0f; - newVeh->SetHeading(DEGTORAD(200.0f)); - newVeh->SetStatus(STATUS_ABANDONED); - newVeh->m_nDoorLock = CARLOCK_UNLOCKED; - CWorld::Add(newVeh); - m_pMyVehicle = newVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } - } - } - } - } - } - break; - } - } else { - ClearLookFlag(); - bObjectiveCompleted = true; - } - } - case OBJECTIVE_KILL_CHAR_ON_FOOT: - { - bool killPlayerInNoPoliceZone = false; - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - break; - } - if (!m_pedInObjective || m_pedInObjective->DyingOrDead()) { - ClearLookFlag(); - bObjectiveCompleted = true; - SetMoveAnim(); - break; - } - if (m_pedInObjective->IsPlayer() && CCullZones::NoPolice()) - killPlayerInNoPoliceZone = true; - - if (!bNotAllowedToDuck || killPlayerInNoPoliceZone) { - if (m_nPedType == PEDTYPE_COP && !m_pedInObjective->GetWeapon()->IsTypeMelee() && !GetWeapon()->IsTypeMelee()) - bNotAllowedToDuck = true; - } else { - if (!m_pedInObjective->bInVehicle) { - if (m_pedInObjective->GetWeapon()->IsTypeMelee() || GetWeapon()->IsTypeMelee()) { - bNotAllowedToDuck = false; - bCrouchWhenShooting = false; - } else if (DuckAndCover()) { - break; - } - } else { - bNotAllowedToDuck = false; - bCrouchWhenShooting = false; - } - } - if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds() && !bKindaStayInSamePlace) { - SetMoveState(PEDMOVE_STILL); - break; - } - if (m_pedInObjective->IsPlayer()) { - CPlayerPed *player = FindPlayerPed(); - if (m_nPedType == PEDTYPE_COP && player->m_pWanted->m_bIgnoredByCops - || player->m_pWanted->m_bIgnoredByEveryone - || m_pedInObjective->bIsInWater - || m_pedInObjective->m_nPedState == PED_ARRESTED) { - - if (m_nPedState != PED_ARREST_PLAYER) - SetIdle(); - - break; - } - } - CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - float wepRange = wepInfo->m_fRange; - float wepRangeAdjusted; - if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { - wepRangeAdjusted = wepRange / 3.0f; - } else { - if (m_nPedState == PED_FIGHT) { - if (!IsPlayer() && !(m_pedStats->m_flags & STAT_CAN_KICK)) - wepRange = 2.0f; - } else { - wepRange = 1.3f; - } - wepRangeAdjusted = wepRange; - } - if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() && wepRangeAdjusted < 2.5f) { - wepRangeAdjusted = 2.5f; - } - if (m_pedInObjective->IsPlayer() && m_nPedType != PEDTYPE_COP - && CharCreatedBy != MISSION_CHAR && FindPlayerPed()->m_pWanted->m_CurrentCops) { - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - break; - } - if (m_pedInObjective->m_fHealth <= 0.0f) { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - SetMoveAnim(); - break; - } - float distWithTargetSc = distWithTarget.Magnitude(); - if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - CVehicle *vehOfTarget = m_pedInObjective->m_pMyVehicle; - if (vehOfTarget->bIsInWater || vehOfTarget->GetStatus() == STATUS_PLAYER_DISABLED - || m_pedInObjective->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled()) { - SetIdle(); - return; - } - SetLookFlag(vehOfTarget, false); - if (m_nPedState != PED_CARJACK) { - if (m_pedInObjective->m_nPedState != PED_ARRESTED) { - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE - && distWithTargetSc < wepRange && distWithTargetSc > 3.0f) { - - // I hope so - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - CVector maxShotPos = vehOfTarget->GetPosition() - ourHead; - maxShotPos.Normalise(); - maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CColPoint foundCol; - CEntity *foundEnt; - CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, - true, true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = false; - if (foundEnt == vehOfTarget) { - SetAttack(vehOfTarget); - m_pPointGunAt = vehOfTarget; - if (vehOfTarget) - vehOfTarget->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); - if (distWithTargetSc <= m_distanceToCountSeekDone) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 500)); - SetMoveState(PEDMOVE_STILL); - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); - } - } - } - else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace && !killPlayerInNoPoliceZone) { - if (vehOfTarget) { - if (m_nPedType == PEDTYPE_COP || vehOfTarget->bIsBus) { - GoToNearestDoor(vehOfTarget); - } else { - m_vehEnterType = 0; - if (m_pedInObjective == vehOfTarget->pDriver || vehOfTarget->bIsBus) { - m_vehEnterType = CAR_DOOR_LF; - } else if (m_pedInObjective == vehOfTarget->pPassengers[0]) { - m_vehEnterType = CAR_DOOR_RF; - } else if (m_pedInObjective == vehOfTarget->pPassengers[1]) { - m_vehEnterType = CAR_DOOR_LR; - } else if (m_pedInObjective == vehOfTarget->pPassengers[2]) { - m_vehEnterType = CAR_DOOR_RR; - } - // Unused - // GetPositionToOpenCarDoor(vehOfTarget, m_vehEnterType); - SetSeekCar(vehOfTarget, m_vehEnterType); - SetMoveState(PEDMOVE_RUN); - } - } - } - } - } - SetMoveAnim(); - break; - } - if (m_nMoveState == PEDMOVE_STILL && IsPedInControl()) { - SetLookFlag(m_pedInObjective, false); - TurnBody(); - } - if (m_nPedType == PEDTYPE_COP && distWithTargetSc < 1.5f && m_pedInObjective->IsPlayer()) { - if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() - || m_pedInObjective->m_nPedState == PED_DRAG_FROM_CAR) { - - ((CCopPed*)this)->SetArrestPlayer(m_pedInObjective); - return; - } - } - if (!bKindaStayInSamePlace && !bStopAndShoot && m_nPedState != PED_ATTACK && !killPlayerInNoPoliceZone) { - if (distWithTargetSc > wepRange - || m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() - || m_pedInObjective->m_nPedState == PED_ARRESTED - || m_pedInObjective->EnteringCar() && distWithTargetSc < 3.0f - || distWithTargetSc > m_distanceToCountSeekDone && !CanSeeEntity(m_pedInObjective)) { - - if (m_pedInObjective->EnteringCar()) - wepRangeAdjusted = 2.0f; - - if (bUsePedNodeSeek) { - CVector bestCoords(0.0f, 0.0f, 0.0f); - m_vecSeekPos = m_pedInObjective->GetPosition(); - - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); - - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); - - SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); - } else { - SetSeek(m_pedInObjective, wepRangeAdjusted); - } - bCrouchWhenShooting = false; - if (m_pedInObjective->m_pCurrentPhysSurface && distWithTargetSc < 5.0f) { - if (wepRange <= 5.0f) { - if (m_pedInObjective->IsPlayer() - && FindPlayerPed()->m_bSpeedTimerFlag - && (IsGangMember() || m_nPedType == PEDTYPE_COP) - && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { - GiveWeapon(WEAPONTYPE_COLT45, 1000); - SetCurrentWeapon(WEAPONTYPE_COLT45); - } - } else { - bStopAndShoot = true; - } - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - break; - } - bStopAndShoot = false; - SetMoveAnim(); - break; - } - } - if (m_attackTimer < CTimer::GetTimeInMilliseconds() - && distWithTargetSc < wepRange && m_pedInObjective->m_nPedState != PED_GETUP && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - if (bIsDucking) { - CAnimBlendAssociation *duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (duckAnim) { - duckAnim->blendDelta = -2.0f; - break; - } - bIsDucking = false; - } else if (wepRange <= 5.0f) { - SetMoveState(PEDMOVE_STILL); - SetAttack(m_pedInObjective); - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, - GetPosition().x, GetPosition().y); - SetShootTimer(CGeneral::GetRandomNumberInRange(0.0f, 500.0f)); - SetAttackTimer(CGeneral::GetRandomNumberInRange(0.0f, 1500.0f)); - bObstacleShowedUpDuringKillObjective = false; - - } else { - CVector target; - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - if (m_pedInObjective->IsPed()) - m_pedInObjective->m_pedIK.GetComponentPosition((RwV3d*)&target, PED_MID); - else - target = m_pedInObjective->GetPosition(); - - target -= ourHead; - target.Normalise(); - target = target * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CEntity *foundEnt = nil; - CColPoint foundCol; - - CWorld::ProcessLineOfSight( - ourHead, target, foundCol, foundEnt, - true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = 0; - if (foundEnt == m_pedInObjective) { - SetAttack(m_pedInObjective); - m_pPointGunAt = m_pedInObjective; - if (m_pedInObjective) - m_pedInObjective->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 2000.0f)); - - int time; - if (distWithTargetSc <= wepRangeAdjusted) - time = CGeneral::GetRandomNumberInRange(100.0f, 500.0f); - else - time = CGeneral::GetRandomNumberInRange(1500.0f, 3000.0f); - - SetAttackTimer(time); - bObstacleShowedUpDuringKillObjective = false; - - } else if (foundEnt) { - if (foundEnt->IsPed()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f)); - bObstacleShowedUpDuringKillObjective = false; - } else { - if (foundEnt->IsObject()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 400.0f)); - bObstacleShowedUpDuringKillObjective = true; - } else if (foundEnt->IsVehicle()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(400.0f, 600.0f)); - bObstacleShowedUpDuringKillObjective = true; - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(700.0f, 1200.0f)); - bObstacleShowedUpDuringKillObjective = true; - } - } - - m_fleeFrom = foundEnt; - m_fleeFrom->RegisterReference((CEntity**) &m_fleeFrom); - SetPointGunAt(m_pedInObjective); - } - } - } else { - if (!m_pedInObjective->m_pCurrentPhysSurface) - bStopAndShoot = false; - - if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { - - // This is weird... - if (bNotAllowedToDuck && bKindaStayInSamePlace) { - if (!bIsDucking) { - CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAnim || duckAnim->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); - bIsDucking = true; - } - break; - } else { - CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAnim || duckAnim->blendDelta < 0.0f) { - bIsDucking = false; - } else { - break; - } - } - } - if (bObstacleShowedUpDuringKillObjective) { - if (m_nPedType == PEDTYPE_COP) { - if (GetWeapon()->m_eWeaponType > WEAPONTYPE_COLT45 - || m_fleeFrom && m_fleeFrom->IsObject()) { - wepRangeAdjusted = 6.0f; - } else if (m_fleeFrom && m_fleeFrom->IsVehicle()) { - wepRangeAdjusted = 4.0f; - } else { - wepRangeAdjusted = 2.0f; - } - } else { - wepRangeAdjusted = 2.0f; - } - } - if (distWithTargetSc <= wepRangeAdjusted) { - SetMoveState(PEDMOVE_STILL); - bIsPointingGunAt = true; - if (m_nPedState != PED_AIM_GUN && !bDuckAndCover) { - m_attackTimer = CTimer::GetTimeInMilliseconds(); - SetIdle(); - } - } else { - if (m_nPedState != PED_SEEK_ENTITY && m_nPedState != PED_SEEK_POS - && !bStopAndShoot && !killPlayerInNoPoliceZone && !bKindaStayInSamePlace) { - Say(SOUND_PED_ATTACK); - SetSeek(m_pedInObjective, wepRangeAdjusted); - bIsRunning = true; - } - } - } - } - - if (distWithTargetSc < 2.5f && wepRange > 5.0f - && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE) { - - SetAttack(m_pedInObjective); - if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { - int time = CGeneral::GetRandomNumberInRange(500.0f, 1000.0f); - SetAttackTimer(time); - SetShootTimer(time - 500); - } - SetMoveState(PEDMOVE_STILL); - } - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, GetPosition().x, GetPosition().y); + CVector pos(0.0f, 0.0f, 0.0f); + TransformToNode(pos, PED_FOOTL); - SetMoveAnim(); - break; - } - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - { - if (InVehicle()) { - if (m_nPedState == PED_DRIVING) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } else if (m_nPedState != PED_FLEE_ENTITY) { - int time; - if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) - time = 0; - else - time = 6000; - - SetFindPathAndFlee(m_pedInObjective, time); - } - break; - } - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - { - if (m_pedInObjective) { - float safeDistance = 2.0f; - if (m_pedInObjective->bInVehicle) - safeDistance = 3.0f; - - float distWithTargetSc = distWithTarget.Magnitude(); - if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { - if (distWithTargetSc <= safeDistance) { - bScriptObjectiveCompleted = true; - if (m_nPedState != PED_ATTACK) { - SetIdle(); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - if (distWithTargetSc > 2.0f) - SetMoveState(m_pedInObjective->m_nMoveState); - else - SetMoveState(PEDMOVE_STILL); - } else { - SetSeek(m_pedInObjective, safeDistance); - if (distWithTargetSc >= 5.0f) { - if (m_leader && m_leader->m_nMoveState == PEDMOVE_SPRINT) - SetMoveState(PEDMOVE_SPRINT); - else - SetMoveState(PEDMOVE_RUN); - } else { - if (m_leader && m_leader->m_nMoveState != PEDMOVE_STILL - && m_leader->m_nMoveState != PEDMOVE_NONE) { - if (m_leader->IsPlayer()) { - if (distWithTargetSc >= 3.0f && FindPlayerPed()->m_fMoveSpeed >= 1.3f) - SetMoveState(PEDMOVE_RUN); - else - SetMoveState(PEDMOVE_WALK); - } else { - SetMoveState(m_leader->m_nMoveState); - } - } else if (distWithTargetSc <= 3.0f) { - SetMoveState(PEDMOVE_WALK); - } else { - SetMoveState(PEDMOVE_RUN); - } - } - } - } - } else { - SetObjective(OBJECTIVE_NONE); - } - break; - } - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - { - if (m_pedInObjective) { - CVector posToGo = GetFormationPosition(); - distWithTarget = posToGo - carOrOurPos; - SetSeek(posToGo, 1.0f); - if (distWithTarget.Magnitude() <= 3.0f) { - SetSeek(posToGo, 1.0f); - if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) - SetMoveState(m_pedInObjective->m_nMoveState); - } else { - SetSeek(posToGo, 1.0f); - SetMoveState(PEDMOVE_RUN); - } - } else { - SetObjective(OBJECTIVE_NONE); - } - break; - } - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - { - if (m_carInObjective) { - if (!bInVehicle && m_carInObjective->m_nNumPassengers >= m_carInObjective->m_nNumMaxPassengers) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - - break; - } - - if (m_prevObjective == OBJECTIVE_HAIL_TAXI && !((CAutomobile*)m_carInObjective)->bTaxiLight) { - RestorePreviousObjective(); - ClearObjective(); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - bIsRunning = false; - break; - } - if (m_objectiveTimer && m_objectiveTimer < CTimer::GetTimeInMilliseconds()) { - if (!EnteringCar()) { - bool foundSeat = false; - if (m_carInObjective->pPassengers[0] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { - if (m_carInObjective->pPassengers[1] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { - if (m_carInObjective->pPassengers[2] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { - foundSeat = false; - } else { - m_vehEnterType = CAR_DOOR_RR; - foundSeat = true; - } - } else { - m_vehEnterType = CAR_DOOR_LR; - foundSeat = true; - } - } else { - m_vehEnterType = CAR_DOOR_RF; - foundSeat = true; - } - for (int i = 2; i < m_carInObjective->m_nNumMaxPassengers; ++i) { - if (!m_carInObjective->pPassengers[i] && !(m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { - m_vehEnterType = CAR_DOOR_RF; - foundSeat = true; - } - } - if (foundSeat) { - SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType)); - SetEnterCar(m_carInObjective, m_vehEnterType); - } - } - m_objectiveTimer = 0; - } - } - // fall through - } - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - { - if (!m_carInObjective || bInVehicle) { -#ifdef VC_PED_PORTS - if (bInVehicle && m_pMyVehicle != m_carInObjective) { - SetExitCar(m_pMyVehicle, 0); - } else -#endif - { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - RestorePreviousState(); - } - } else { - if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) { - SetMoveState(PEDMOVE_STILL); - break; - } - if (IsPedInControl()) { - if (m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { - if (distWithTarget.Magnitude() < 20.0f) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (m_carInObjective->pDriver -#ifdef VC_PED_PORTS - && !IsPlayer() -#endif - ) { - if (m_carInObjective->pDriver->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS && m_carInObjective->pDriver != m_pedInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - m_carInObjective->bIsBeingCarJacked = false; - } - } - } - } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (m_carInObjective->pDriver -#ifdef VC_PED_PORTS - && (CharCreatedBy != MISSION_CHAR || m_carInObjective->pDriver->CharCreatedBy != RANDOM_CHAR) -#endif - ) { - if (m_carInObjective->pDriver->m_nPedType == m_nPedType) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - m_carInObjective->bIsBeingCarJacked = false; - } - } - } - if (m_carInObjective->IsUpsideDown() && m_carInObjective->m_vehType != VEHICLE_TYPE_BIKE) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - if (!m_carInObjective->IsBoat() || m_nPedState == PED_SEEK_IN_BOAT) { - if (m_nPedState != PED_SEEK_CAR) - SetSeekCar(m_carInObjective, 0); - } else { - SetSeekBoatPosition(m_carInObjective); - } - if (m_nMoveState == PEDMOVE_STILL && !bVehEnterDoorIsBlocked) - SetMoveState(PEDMOVE_RUN); - - if (m_carInObjective && m_carInObjective->m_fHealth > 0.0f) { - distWithTarget = m_carInObjective->GetPosition() - GetPosition(); - if (!bInVehicle) { - if (nEnterCarRangeMultiplier * ENTER_CAR_MAX_DIST < distWithTarget.Magnitude()) { - if (!m_carInObjective->pDriver && !m_carInObjective->GetIsOnScreen() && !GetIsOnScreen()) - WarpPedToNearEntityOffScreen(m_carInObjective); - - if (CharCreatedBy != MISSION_CHAR || m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS -#ifdef VC_PED_PORTS - || IsPlayer() && !CPad::GetPad(0)->ArePlayerControlsDisabled() -#endif - ) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } else { - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - } - } - } else if (!bInVehicle) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - } - } - break; - } - case OBJECTIVE_DESTROY_CAR: - { - if (!m_carInObjective) { - ClearLookFlag(); - bObjectiveCompleted = true; - break; - } - float distWithTargetSc = distWithTarget.Magnitude(); - CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - float wepRange = wepInfo->m_fRange; - m_pLookTarget = m_carInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - - m_pSeekTarget = m_carInObjective; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - - TurnBody(); - if (m_carInObjective->m_fHealth <= 0.0f) { - ClearLookFlag(); - bScriptObjectiveCompleted = true; - break; - } - - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE - && distWithTargetSc < wepRange) { - - // I hope so - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - CVector maxShotPos = m_carInObjective->GetPosition() - ourHead; - maxShotPos.Normalise(); - maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CColPoint foundCol; - CEntity *foundEnt; - CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, - true, true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = false; - if (foundEnt == m_carInObjective) { - SetAttack(m_carInObjective); - m_pPointGunAt = m_carInObjective; - if (m_pPointGunAt) - m_pPointGunAt->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); - if (distWithTargetSc > 10.0f && !bKindaStayInSamePlace) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(50, 300)); - SetMoveState(PEDMOVE_STILL); - } - } - } else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace) { - - float safeDistance; - if (wepRange <= 5.0f) - safeDistance = 3.0f; - else - safeDistance = wepRange * 0.25f; - - SetSeek(m_carInObjective, safeDistance); - SetMoveState(PEDMOVE_RUN); - } - SetLookFlag(m_carInObjective, false); - TurnBody(); - break; - } - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - { - distWithTarget = m_nextRoutePointPos - GetPosition(); - distWithTarget.z = 0.0f; - if (InVehicle()) { - CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); - CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); - if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - break; - } - if (distWithTarget.Magnitude() > 30.0f) { - if (m_pMyVehicle) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - } else { - float closestVehDist = SQR(60.0f); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle* foundVeh = nil; - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - /* - Not used. - CVector vehSpeed = nearVeh->GetSpeed(); - CVector ourSpeed = GetSpeed(); - */ - CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); - if (vehDistVec.MagnitudeSqr() < closestVehDist - && m_pedInObjective->m_pMyVehicle != nearVeh) - { - foundVeh = nearVeh; - closestVehDist = vehDistVec.MagnitudeSqr(); - } - } - m_pMyVehicle = foundVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } - } - break; - } - // fall through - } - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - { - if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) - && InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } else { - distWithTarget = m_nextRoutePointPos - GetPosition(); - distWithTarget.z = 0.0f; - if (sq(m_distanceToCountSeekDone) >= distWithTarget.MagnitudeSqr()) { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - SetMoveState(PEDMOVE_STILL); - } else if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer || m_nPedState != PED_SEEK_POS) { - if (bUsePedNodeSeek) { - CVector bestCoords(0.0f, 0.0f, 0.0f); - m_vecSeekPos = m_nextRoutePointPos; - - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); - - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); - } - SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); - } - } - - break; - } - case OBJECTIVE_GUARD_ATTACK: - { - if (m_pedInObjective) { - SetLookFlag(m_pedInObjective, true); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - m_lookTimer = m_attackTimer; - TurnBody(); - float distWithTargetSc = distWithTarget.Magnitude(); - if (distWithTargetSc >= 20.0f) { - RestorePreviousObjective(); - } else if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { - if (m_nPedState != PED_SEEK_ENTITY && distWithTargetSc >= 2.0f) { - SetSeek(m_pedInObjective, 1.0f); - } else { - SetAttack(m_pedInObjective); - SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1500.0f)); - } - SetAttackTimer(1000); - } - } else { - RestorePreviousObjective(); - } - break; - } - case OBJECTIVE_FOLLOW_ROUTE: - if (HaveReachedNextPointOnRoute(1.0f)) { - int nextPoint = GetNextPointOnRoute(); - m_nextRoutePointPos = CRouteNode::GetPointPosition(nextPoint); - } else { - SetSeek(m_nextRoutePointPos, 0.8f); - } - break; - case OBJECTIVE_SOLICIT_VEHICLE: - if (m_carInObjective) { - if (m_objectiveTimer <= CTimer::GetTimeInMilliseconds()) { - if (!bInVehicle) { - SetObjective(OBJECTIVE_NONE); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; - if (IsPedInControl()) - m_pMyVehicle = nil; - } - } else { - if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_SOLICIT) - SetSeekCar(m_carInObjective, 0); - } - } else { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - break; - case OBJECTIVE_HAIL_TAXI: - if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TAXI) && CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - Say(SOUND_PED_TAXI_WAIT); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TAXI, 4.0f); - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; - } - break; - case OBJECTIVE_CATCH_TRAIN: - { - if (m_carInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - } else { - CVehicle* trainToEnter = nil; - float closestCarDist = CHECK_NEARBY_THINGS_MAX_DIST; - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - - CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - if (nearVeh->IsTrain()) { - CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); - float vehDist = vehDistVec.Magnitude(); - if (vehDist < closestCarDist && m_pedInObjective->m_pMyVehicle != nearVeh) - { - trainToEnter = nearVeh; - closestCarDist = vehDist; - } - } - } - if (trainToEnter) { - m_carInObjective = trainToEnter; - m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); - } - } - break; - } - case OBJECTIVE_BUY_ICE_CREAM: - if (m_carInObjective) { - if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_BUY_ICECREAM) - SetSeekCar(m_carInObjective, 0); - } else { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - break; - case OBJECTIVE_STEAL_ANY_CAR: - { - if (bInVehicle) { - bScriptObjectiveCompleted = true; - RestorePreviousObjective(); - } else if (m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - CVehicle *carToSteal = nil; - float closestCarDist = ENTER_CAR_MAX_DIST; - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity *vehicles[8]; - - // NB: This should've been ENTER_CAR_MAX_DIST actually, and is fixed in VC. - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - for(int i = 0; i < lastVehicle; i++) { - CVehicle *nearVeh = (CVehicle*)vehicles[i]; - if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { - if (nearVeh->m_vecMoveSpeed.Magnitude() <= 0.1f) { - if (nearVeh->CanPedOpenLocks(this)) { - CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); - float vehDist = vehDistVec.Magnitude(); - if (vehDist < closestCarDist) { - carToSteal = nearVeh; - closestCarDist = vehDist; - } - } - } - } - } - if (carToSteal) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carToSteal); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } else { - RestorePreviousObjective(); - RestorePreviousState(); - } - } - break; - } - case OBJECTIVE_MUG_CHAR: - { - if (m_pedInObjective) { - if (m_pedInObjective->IsPlayer() || m_pedInObjective->bInVehicle || m_pedInObjective->m_fHealth <= 0.0f) { - ClearObjective(); - return; - } - if (m_pedInObjective->m_nMoveState > PEDMOVE_WALK) { - ClearObjective(); - return; - } - if (m_pedInObjective->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_pedInObjective->m_pedInObjective == this) { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pedInObjective); - SetMoveState(PEDMOVE_SPRINT); - return; - } - if (m_pedInObjective->m_nPedState == PED_FLEE_ENTITY && m_fleeFrom == this - || m_pedInObjective->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE && m_pedInObjective->m_pedInObjective == this) { - ClearObjective(); - SetFindPathAndFlee(m_pedInObjective, 15000, true); - return; - } - float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); - if (distWithTargetScSqr <= sq(10.0f)) { - if (distWithTargetScSqr <= sq(1.4f)) { - CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, - GetPosition().x, GetPosition().y); - - if (reloadAssoc || !m_pedInObjective->IsPedShootable()) { - if (reloadAssoc && - (!reloadAssoc->IsRunning() || reloadAssoc->currentTime / reloadAssoc->hierarchy->totalLength > 0.8f)) { - CAnimBlendAssociation *punchAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); - punchAssoc->flags |= ASSOC_DELETEFADEDOUT; - punchAssoc->flags |= ASSOC_FADEOUTWHENDONE; - CVector2D offset(distWithTarget.x, distWithTarget.y); - int dir = m_pedInObjective->GetLocalDirection(offset); - m_pedInObjective->StartFightDefend(dir, HITLEVEL_HIGH, 5); - m_pedInObjective->ReactToAttack(this); - m_pedInObjective->Say(SOUND_PED_ROBBED); - Say(SOUND_PED_MUGGING); - bRichFromMugging = true; - - // VC FIX: ClearObjective() clears m_pedInObjective in VC (also same with VC_PED_PORTS), so get it before call - CPed *victim = m_pedInObjective; - ClearObjective(); - if (victim->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT - || victim->m_pedInObjective != this) { - SetFindPathAndFlee(victim, 15000, true); - m_nLastPedState = PED_WANDER_PATH; - } else { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, victim); - SetMoveState(PEDMOVE_SPRINT); - m_nLastPedState = PED_WANDER_PATH; - } - } - } else { - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - if (weaponType != WEAPONTYPE_UNARMED && weaponType != WEAPONTYPE_BASEBALLBAT) - SetCurrentWeapon(WEAPONTYPE_UNARMED); - - CAnimBlendAssociation *newReloadAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_AK_RELOAD, 8.0f); - newReloadAssoc->flags |= ASSOC_DELETEFADEDOUT; - newReloadAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } - } else { - SetSeek(m_pedInObjective, 1.0f); - CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK); - - if (walkAssoc) - walkAssoc->speed = 1.3f; - } - } else { - ClearObjective(); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - } - } else { -#ifdef VC_PED_PORTS - m_objective = OBJECTIVE_NONE; -#endif - ClearObjective(); - } - break; - } - case OBJECTIVE_FLEE_CAR: - if (!bInVehicle && m_nPedState != PED_FLEE_ENTITY && m_pMyVehicle) { - RestorePreviousObjective(); - SetFlee(m_pMyVehicle, 6000); - break; - } - // fall through - case OBJECTIVE_LEAVE_CAR: - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (InVehicle() -#ifdef VC_PED_PORTS - && (FindPlayerPed() != this || !CPad::GetPad(0)->GetAccelerate() - || bBusJacked) -#endif - ) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN - && (m_nPedType != PEDTYPE_COP -#ifdef VC_PED_PORTS - || m_pMyVehicle->IsBoat() -#endif - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.005f))) { - if (m_pMyVehicle->IsTrain()) - SetExitTrain(m_pMyVehicle); -#ifdef VC_PED_PORTS - else if (m_pMyVehicle->IsBoat()) - SetExitBoat(m_pMyVehicle); -#endif - else - SetExitCar(m_pMyVehicle, 0); - } - } else { - RestorePreviousObjective(); - } - } - break; -#ifdef VC_PED_PORTS - case OBJECTIVE_LEAVE_CAR_AND_DIE: - { - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (InVehicle()) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { - if (m_pMyVehicle->IsBoat()) - SetExitBoat(m_pMyVehicle); - else if (m_pMyVehicle->bIsBus) - SetExitCar(m_pMyVehicle, 0); - else { - eCarNodes doorNode = CAR_DOOR_LF; - if (m_pMyVehicle->pDriver != this) { - if (m_pMyVehicle->pPassengers[0] == this) { - doorNode = CAR_DOOR_RF; - } else if (m_pMyVehicle->pPassengers[1] == this) { - doorNode = CAR_DOOR_LR; - } else if (m_pMyVehicle->pPassengers[2] == this) { - doorNode = CAR_DOOR_RR; - } - } - SetBeingDraggedFromCar(m_pMyVehicle, doorNode, false); - } - } - } - } - break; - } -#endif + pos.z -= 0.1f; + pos += GetForward()*0.2f; + particleProduceFootDust(this, pos, 0.02f, 1); } - if (bObjectiveCompleted - || m_objectiveTimer > 0 && CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - RestorePreviousObjective(); - if (m_objectiveTimer > CTimer::GetTimeInMilliseconds() || !m_objectiveTimer) - m_objectiveTimer = CTimer::GetTimeInMilliseconds() - 1; - if (CharCreatedBy != RANDOM_CHAR || bInVehicle) { - if (IsPedInControl()) - RestorePreviousState(); - } else { - SetWanderPath(CGeneral::GetRandomNumber() & 7); + { + CVector pos(0.0f, 0.0f, 0.0f); + TransformToNode(pos, PED_FOOTR); + + pos.z -= 0.1f; + pos += GetForward()*0.2f; + particleProduceFootDust(this, pos, 0.02f, 1); + } + } +#endif + + + if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { + float stepStart = 1 / 15.0f; + float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; + float currentTime = walkRunAssoc->currentTime; + int stepPart = 0; + + if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) + stepPart = 1; + else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) + stepPart = 2; + + if (stepPart != 0) { + DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); + CVector footPos(0.0f, 0.0f, 0.0f); + TransformToNode(footPos, stepPart == 1 ? PED_FOOTL : PED_FOOTR); + + CVector forward = GetForward(); + + footPos.z -= 0.1f; + footPos += 0.2f * forward; + + if (bDoBloodyFootprints) { + CVector2D top(forward * 0.26f); + CVector2D right(GetRight() * 0.14f); + + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos, + top.x, top.y, + right.x, right.y, + 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); + + if (m_bloodyFootprintCountOrDeathTime <= 20) { + m_bloodyFootprintCountOrDeathTime = 0; + bDoBloodyFootprints = false; + } else { + m_bloodyFootprintCountOrDeathTime -= 20; + } } - ClearAimFlag(); - ClearLookFlag(); + if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { + if(IsPlayer()) + particleProduceFootDust(this, footPos, 0.0f, 4); + } +#ifdef PC_PARTICLE + else if(stepPart == 2) +#else + else +#endif + { + particleProduceFootSplash(this, footPos, 0.15f, 4); + } + } + } + + if (m_nSurfaceTouched == SURFACE_WATER) { + float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); + if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { +#ifdef PC_PARTICLE + float particleSize = pedSpeed * 2.0f; + + if (particleSize < 0.25f) + particleSize = 0.25f; + + if (particleSize > 0.75f) + particleSize = 0.75f; + + CVector particlePos = GetPosition() + GetForward() * 0.3f; + particlePos.z -= 1.2f; + + CVector particleDir = m_vecMoveSpeed * -0.75f; + + particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); + CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); + + particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); + CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); +#else + CVector particlePos = (GetPosition() - 0.3f * GetUp()) + GetForward()*0.3f; + CVector particleDir = m_vecMoveSpeed * 0.45f; + particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); + CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos-CVector(0.0f, 0.0f, 1.2f), particleDir, nil, 0.0f, CRGBA(155, 185, 155, 255)); +#endif } } } -void -CPed::SetShootTimer(uint32 time) +// Actually GetLocalDirectionTo(Turn/Look) +int +CPed::GetLocalDirection(const CVector2D &posOffset) { - if (CTimer::GetTimeInMilliseconds() > m_shootTimer) { - m_shootTimer = CTimer::GetTimeInMilliseconds() + time; - } -} + int direction; + float angle; -void -CPed::SetSeekCar(CVehicle *car, uint32 doorNode) -{ - if (m_nPedState == PED_SEEK_CAR) - return; + for (angle = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); angle < 0.0f; angle += TWOPI); -#ifdef VC_PED_PORTS - if (!CanSetPedState() || m_nPedState == PED_DRIVING) - return; -#endif + for (direction = RADTODEG(angle)/90.0f; direction > 3; direction -= 4); - SetStoredState(); - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_carInObjective = car; - m_carInObjective->RegisterReference((CEntity**) &m_carInObjective); - m_pMyVehicle = car; - m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); - // m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = doorNode; - m_distanceToCountSeekDone = 0.5f; - m_nPedState = PED_SEEK_CAR; - -} - -void -CPed::SetSeekBoatPosition(CVehicle *boat) -{ - if (m_nPedState == PED_SEEK_IN_BOAT || boat->pDriver -#if defined VC_PED_PORTS || defined FIX_BUGS - || !IsPedInControl() -#endif - ) - return; - - SetStoredState(); - m_carInObjective = boat; - m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); - m_pMyVehicle = boat; - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_distanceToCountSeekDone = 0.5f; - m_nPedState = PED_SEEK_IN_BOAT; -} - -void -CPed::SetExitTrain(CVehicle* train) -{ - if (m_nPedState == PED_EXIT_TRAIN || train->GetStatus() != STATUS_TRAIN_NOT_MOVING || !((CTrain*)train)->Doors[0].IsFullyOpen()) - return; - - /* - // Not used - CVector exitPos; - GetNearestTrainPedPosition(train, exitPos); - */ - m_nPedState = PED_EXIT_TRAIN; - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETOUT, 4.0f); - m_pVehicleAnim->SetFinishCallback(PedSetOutTrainCB, this); - bUsesCollision = false; - LineUpPedWithTrain(); + // 0-forward, 1-left, 2-backward, 3-right. + return direction; } #ifdef NEW_WALK_AROUND_ALGORITHM @@ -14394,486 +4071,734 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 280.0f * dist * checkIntervalInTime; } -int32 -CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) +bool +CPed::IsPedInControl(void) { - bool collidedWithBoat = false; - bool belowTorsoCollided = false; - float gravityEffect = -0.15f * CTimer::GetTimeStep(); - CColPoint intersectionPoint; - CColLine ourLine; - - CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); - CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); - - if (!bUsesCollision) - return false; - - if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) - collidedWithBoat = true; - - // ofc we're not vehicle - if (!m_bIsVehicleBeingShifted && !bSkipLineCol -#ifdef VC_PED_PORTS - && !collidingEnt->IsPed() -#endif - ) { - if (!bCollisionProcessed) { -#ifdef VC_PED_PORTS - m_pCurrentPhysSurface = nil; -#endif - if (bIsStanding) { - bIsStanding = false; - bWasStanding = true; - } - bCollisionProcessed = true; - m_fCollisionSpeed += m_vecMoveSpeed.Magnitude2D() * CTimer::GetTimeStep(); - bStillOnValidPoly = false; - if (IsPlayer() || m_fCollisionSpeed >= 1.0f - && (m_fCollisionSpeed >= 2.0f || m_nPedState != PED_WANDER_PATH)) { - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - bHitSteepSlope = false; - } else { - CVector pos = GetPosition(); - float potentialGroundZ = GetPosition().z - FEET_OFFSET; - if (bWasStanding) { - pos.z += -0.25f; - potentialGroundZ += gravityEffect; - } - if (CCollision::IsStoredPolyStillValidVerticalLine(pos, potentialGroundZ, intersectionPoint, &m_collPoly)) { - bStillOnValidPoly = true; -#ifdef VC_PED_PORTS - if(!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; - if (bSomeVCflag1) - bSomeVCflag1 = false; - } -#else - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; -#endif - - m_vecMoveSpeed.z = 0.0f; - bIsStanding = true; - } else { - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - bHitSteepSlope = false; - } - } - } - - if (!bStillOnValidPoly) { - CVector potentialCenter = GetPosition(); - potentialCenter.z = GetPosition().z - 0.52f; - - // 0.52f should be a ped's approx. radius - float totalRadiusWhenCollided = collidingEnt->GetBoundRadius() + 0.52f - gravityEffect; - if (bWasStanding) { - if (collidedWithBoat) { - potentialCenter.z += 2.0f * gravityEffect; - totalRadiusWhenCollided += Abs(gravityEffect); - } else { - potentialCenter.z += gravityEffect; - } - } - if (sq(totalRadiusWhenCollided) > (potentialCenter - collidingEnt->GetBoundCentre()).MagnitudeSqr()) { - ourLine.p0 = GetPosition(); - ourLine.p1 = GetPosition(); - ourLine.p1.z = GetPosition().z - FEET_OFFSET; - if (bWasStanding) { - ourLine.p1.z = ourLine.p1.z + gravityEffect; - ourLine.p0.z = ourLine.p0.z + -0.25f; - } - float minDist = 1.0f; - belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, - intersectionPoint, minDist, false, &m_collPoly); - - if (collidedWithBoat && bWasStanding && !belowTorsoCollided) { - ourLine.p0.z = ourLine.p1.z; - ourLine.p1.z = ourLine.p1.z + gravityEffect; - belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, - intersectionPoint, minDist, false, &m_collPoly); - } - if (belowTorsoCollided) { -#ifndef VC_PED_PORTS - if (!collidingEnt->IsPed()) { -#endif - if (!bIsStanding - || FEET_OFFSET + intersectionPoint.point.z > GetPosition().z - || collidedWithBoat && 3.12f + intersectionPoint.point.z > GetPosition().z) { - - if (!collidingEnt->IsVehicle() && !collidingEnt->IsObject()) { - m_pCurSurface = collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); - bTryingToReachDryLand = false; - bOnBoat = false; - } else { - m_pCurrentPhysSurface = (CPhysical*)collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface); - m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); - m_pCurSurface = collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); - m_collPoly.valid = false; - if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) { - bOnBoat = true; - } else { - bOnBoat = false; - } - } -#ifdef VC_PED_PORTS - if (!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; - if (bSomeVCflag1) - bSomeVCflag1 = false; - } -#else - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; -#endif - m_nSurfaceTouched = intersectionPoint.surfaceB; - if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF) { - bHitSteepSlope = true; - m_vecDamageNormal = intersectionPoint.normal; - } - } -#ifdef VC_PED_PORTS - float upperSpeedLimit = 0.33f; - float lowerSpeedLimit = -0.25f; - float speed = m_vecMoveSpeed.Magnitude2D(); - if (m_nPedState == PED_IDLE) { - upperSpeedLimit *= 2.0f; - lowerSpeedLimit *= 1.5f; - } - CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); - if (!bWasStanding && speed > upperSpeedLimit && (/*!bPushedAlongByCar ||*/ m_vecMoveSpeed.z < lowerSpeedLimit) - && m_pCollidingEntity != collidingEnt) { - - float damage = 100.0f * Max(speed - 0.25f, 0.0f); - float damage2 = damage; - if (m_vecMoveSpeed.z < -0.25f) - damage += (-0.25f - m_vecMoveSpeed.z) * 150.0f; - - uint8 dir = 2; // from backward - if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { - CVector2D offset = -m_vecMoveSpeed; - dir = GetLocalDirection(offset); - } - - InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); - if (IsPlayer() && damage2 > 5.0f) - Say(SOUND_PED_LAND); - - } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); - } -#else - float speedSqr = 0.0f; - CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); - if (!bWasStanding && (m_vecMoveSpeed.z < -0.25f || (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) > sq(0.5f))) { - if (speedSqr == 0.0f) - speedSqr = sq(m_vecMoveSpeed.z); - - uint8 dir = 2; // from backward - if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { - CVector2D offset = -m_vecMoveSpeed; - dir = GetLocalDirection(offset); - } - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir); - - } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); - } -#endif - m_vecMoveSpeed.z = 0.0f; - bIsStanding = true; -#ifndef VC_PED_PORTS - } else { - bOnBoat = false; - } -#endif - } else { - bOnBoat = false; - } - } - } - } - - int ourCollidedSpheres = CCollision::ProcessColModels(GetMatrix(), *ourCol, collidingEnt->GetMatrix(), *hisCol, collidingPoints, nil, nil); - if (ourCollidedSpheres > 0 || belowTorsoCollided) { - AddCollisionRecord(collidingEnt); - if (!collidingEnt->IsBuilding()) - ((CPhysical*)collidingEnt)->AddCollisionRecord(this); - - if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic())) { - bHasHitWall = true; - } - } - if (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic()) { - - if (bWasStanding) { - CVector sphereNormal; - float normalLength; - for(int sphere = 0; sphere < ourCollidedSpheres; sphere++) { - sphereNormal = collidingPoints[sphere].normal; -#ifdef VC_PED_PORTS - if (sphereNormal.z >= -1.0f || !IsPlayer()) { -#endif - normalLength = sphereNormal.Magnitude2D(); - if (normalLength != 0.0f) { - sphereNormal.x = sphereNormal.x / normalLength; - sphereNormal.y = sphereNormal.y / normalLength; - } -#ifdef VC_PED_PORTS - } else { - float speed = m_vecMoveSpeed.Magnitude2D(); - sphereNormal.x = -m_vecMoveSpeed.x / Max(0.001f, speed); - sphereNormal.y = -m_vecMoveSpeed.y / Max(0.001f, speed); - GetMatrix().GetPosition().z -= 0.05f; - bSomeVCflag1 = true; - } -#endif - sphereNormal.Normalise(); - collidingPoints[sphere].normal = sphereNormal; - if (collidingPoints[sphere].surfaceB == SURFACE_STEEP_CLIFF) - bHitSteepSlope = true; - } - } - } - return ourCollidedSpheres; -} - -void -CPed::SetFormation(eFormation type) -{ - // FIX: Formations in GetFormationPosition were in range 1-8, whereas in here it's 0-7. - // To not change the behaviour, range in here tweaked by 1 with the use of enum. - - switch (m_pedFormation) { - case FORMATION_REAR: - case FORMATION_REAR_LEFT: - case FORMATION_REAR_RIGHT: - case FORMATION_FRONT_LEFT: - case FORMATION_FRONT_RIGHT: - case FORMATION_LEFT: - case FORMATION_RIGHT: - case FORMATION_FRONT: - break; - default: - Error("Unknown formation type, PedAI.cpp"); - break; - } - m_pedFormation = type; -} - -void -CPed::SetFollowRoute(int16 currentPoint, int16 routeType) -{ - m_routeLastPoint = currentPoint; - m_routeStartPoint = CRouteNode::GetRouteStart(currentPoint); - m_routePointsPassed = 0; - m_routeType = routeType; - m_routePointsBeingPassed = 1; - m_objective = OBJECTIVE_FOLLOW_ROUTE; - m_nextRoutePointPos = CRouteNode::GetPointPosition(GetNextPointOnRoute()); -} - -// "Wander range" state is unused in game, and you can't use it without SetWanderRange anyway -void -CPed::WanderRange(void) -{ - bool arrived = Seek(); - if (arrived) { - Idle(); - if ((m_randomSeed + 3 * CTimer::GetFrameCounter()) % 1000 > 997) { - CVector2D newCoords2D = m_wanderRangeBounds->GetRandomPointInRange(); - SetSeek(CVector(newCoords2D.x, newCoords2D.y, GetPosition().z), 2.5f); - } - } + return m_nPedState <= PED_STATES_NO_AI + && !bIsInTheAir && !bIsLanding + && m_fHealth > 0.0f; } bool -CPed::WillChat(CPed *stranger) +CPed::IsPedShootable(void) { - if (m_pNextPathNode && m_pLastPathNode) { - if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { - return false; - } - } - if (m_nSurfaceTouched == SURFACE_TARMAC) + return m_nPedState <= PED_STATES_NO_ST; +} + +bool +CPed::UseGroundColModel(void) +{ + return m_nPedState == PED_FALL || + m_nPedState == PED_DIVE_AWAY || + m_nPedState == PED_DIE || + m_nPedState == PED_DEAD; +} + +bool +CPed::CanPedReturnToState(void) +{ + return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && + m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; +} + +bool +CPed::CanSetPedState(void) +{ + return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; +} + +bool +CPed::CanStrafeOrMouseControl(void) +{ +#ifdef FREE_CAM + if (CCamera::bFreeCam) return false; - if (stranger == this) - return false; - if (m_nPedType == stranger->m_nPedType) - return true; - if (m_nPedType == PEDTYPE_CRIMINAL) - return false; - if ((IsGangMember() || stranger->IsGangMember()) && m_nPedType != stranger->m_nPedType) - return false; - return true; +#endif + return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || + m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; } void -CPed::SetEnterTrain(CVehicle *train, uint32 unused) +CPed::PedGetupCB(CAnimBlendAssociation* animAssoc, void* arg) { - if (m_nPedState == PED_ENTER_TRAIN || !((CTrain*)train)->Doors[0].IsFullyOpen()) - return; + CPed* ped = (CPed*)arg; + if (ped->m_nPedState == PED_GETUP) + RpAnimBlendClumpSetBlendDeltas(ped->GetClump(), ASSOC_PARTIAL, -1000.0f); + + ped->bFallenDown = false; + animAssoc->blendDelta = -1000.0f; + if (ped->m_nPedState == PED_GETUP) + ped->RestorePreviousState(); + + if (ped->m_nPedState != PED_FLEE_POS && ped->m_nPedState != PED_FLEE_ENTITY) + ped->SetMoveState(PEDMOVE_STILL); + else + ped->SetMoveState(PEDMOVE_RUN); + + ped->SetMoveAnim(); + ped->bGetUpAnimStarted = false; +} + +void +CPed::PedLandCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + animAssoc->blendDelta = -1000.0f; + ped->bIsLanding = false; + + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); +} + +void +CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) +{ /* - // Not used - CVector enterPos; - GetNearestTrainPedPosition(train, enterPos); + CPed *ped = (CPed*)arg; + + if (ped->m_nPedState == PED_STAGGER) + // nothing */ - m_fRotationCur = train->GetForward().Heading() - HALFPI; - m_pMyVehicle = train; - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); +} - m_nPedState = PED_ENTER_TRAIN; - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETIN, 4.0f); - m_pVehicleAnim->SetFinishCallback(PedSetInTrainCB, this); - bUsesCollision = false; - LineUpPedWithTrain(); - if (IsPlayer()) { - if (((CPlayerPed*)this)->m_bAdrenalineActive) - ((CPlayerPed*)this)->ClearAdrenaline(); +void +CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + bool startedToRun = false; + ped->bUsesCollision = true; + ped->m_actionX = 0.0f; + ped->m_actionY = 0.0f; + ped->bVehExitWillBeInstant = false; + if (veh && veh->IsBoat()) + ped->ApplyMoveSpeed(); + + if (ped->m_objective == OBJECTIVE_LEAVE_CAR) + ped->RestorePreviousObjective(); +#ifdef VC_PED_PORTS + else if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + ped->m_fHealth = 0.0f; + ped->SetDie(ANIM_FLOOR_HIT, 4.0f, 0.5f); } -} +#endif -void -CPed::SetDuck(uint32 time) -{ - if (bIsDucking || CTimer::GetTimeInMilliseconds() <= m_duckTimer) - return; - - if (bCrouchWhenShooting && (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN)) { - CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); - if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_LOW, 4.0f); - bIsDucking = true; - m_duckTimer = CTimer::GetTimeInMilliseconds() + time; - } - } else { - CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); - bIsDucking = true; - m_duckTimer = CTimer::GetTimeInMilliseconds() + time; - } + ped->bInVehicle = false; + if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { + ped->PositionPedOutOfCollision(); } -} -void -CPed::SeekBoatPosition(void) -{ - if (m_carInObjective && !m_carInObjective->pDriver) { - CVehicleModelInfo *boatModel = m_carInObjective->GetModelInfo(); - - CVector enterOffset; - enterOffset = boatModel->GetFrontSeatPosn(); - enterOffset.x = 0.0f; - CMatrix boatMat(m_carInObjective->GetMatrix()); - SetMoveState(PEDMOVE_WALK); - m_vecSeekPos = boatMat * enterOffset; - if (Seek()) { - // We arrived to the boat - m_vehEnterType = 0; - SetEnterCar(m_carInObjective, 0); - } - } else - RestorePreviousState(); -} - -void -CPed::SetEnterCar(CVehicle *car, uint32 unused) -{ - if (CCranes::IsThisCarBeingCarriedByAnyCrane(car)) { - RestorePreviousState(); - RestorePreviousObjective(); - } else { - uint8 doorFlag; - eDoors door; - switch (m_vehEnterType) { - case CAR_DOOR_RF: - doorFlag = CAR_DOOR_FLAG_RF; - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - doorFlag = CAR_DOOR_FLAG_RR; - door = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - doorFlag = CAR_DOOR_FLAG_LF; - door = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - doorFlag = CAR_DOOR_FLAG_LR; - door = DOOR_REAR_LEFT; - break; - default: - doorFlag = CAR_DOOR_FLAG_UNKNOWN; - break; - } - if (!IsPedInControl() || m_fHealth <= 0.0f - || doorFlag & car->m_nGettingInFlags || doorFlag & car->m_nGettingOutFlags - || car->bIsBeingCarJacked || m_pVehicleAnim - || doorFlag && !car->IsDoorReady(door) && !car->IsDoorFullyOpen(door)) - SetMoveState(PEDMOVE_STILL); + if (ped->m_nPedState == PED_EXIT_CAR) { + if (ped->m_nPedType == PEDTYPE_COP) + ped->SetIdle(); else - SetEnterCar_AllClear(car, m_vehEnterType, doorFlag); + ped->RestorePreviousState(); + + veh = ped->m_pMyVehicle; + if (ped->bFleeAfterExitingCar && veh) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 12000); + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->SetMoveState(PEDMOVE_RUN); + ped->Say(SOUND_PED_FLEE_RUN); + } + startedToRun = true; + + // This is not a good way to do this... + ped->m_nLastPedState = PED_WANDER_PATH; + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) + ped->SetObjectiveTimer(30000); + ped->m_nLastPedState = PED_NONE; + + } else if (ped->bGonnaKillTheCarJacker) { + + // Kill objective is already given at this point. + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective) { + if (!(CGeneral::GetRandomNumber() & 1) + && ped->m_nPedType != PEDTYPE_COP + && (!ped->m_pedInObjective->IsPlayer() || !CTheScripts::IsPlayerOnAMission())) { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1500; + } + int waitTime = 1500; + ped->SetWaitState(WAITSTATE_PLAYANIM_COWER, &waitTime); + ped->SetMoveState(PEDMOVE_RUN); + startedToRun = true; + } else if (ped->m_objective == OBJECTIVE_NONE && ped->CharCreatedBy != MISSION_CHAR && ped->m_nPedState == PED_IDLE && !ped->IsPlayer()) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } + } +#ifdef VC_PED_PORTS + else { + ped->m_nPedState = PED_IDLE; + } +#endif + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + CVector posFromZ = ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posFromZ); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posFromZ); + veh = ped->m_pMyVehicle; + if (veh) { + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { + if (veh->pDriver) { + if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= 100; + if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney < 0) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = 0; + } + } + } + veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + if (veh->pDriver == ped) { + veh->RemoveDriver(); + veh->SetStatus(STATUS_ABANDONED); + if (veh->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + veh->m_nDoorLock = CARLOCK_UNLOCKED; + if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) + veh->ChangeLawEnforcerState(false); + } else { + veh->RemovePassenger(ped); + } + + if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { + float angleAfterExit; + if (ped->m_vehEnterType == CAR_DOOR_LF) { + angleAfterExit = HALFPI + veh->GetForward().Heading(); + } else { + angleAfterExit = veh->GetForward().Heading() - HALFPI; + } + ped->SetHeading(angleAfterExit); + ped->m_fRotationDest = angleAfterExit; + ped->m_fRotationCur = angleAfterExit; + if (!ped->bBusJacked) + ped->SetMoveState(PEDMOVE_WALK); + } + if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) + veh->bLightsOn = false; + } + + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + + ped->ReplaceWeaponWhenExitingVehicle(); + + ped->bOnBoat = false; + if (ped->bBusJacked) { + ped->SetFall(1500, ANIM_KO_SKID_BACK, false); + ped->bBusJacked = false; + } + ped->m_nStoredMoveState = PEDMOVE_NONE; + if (!ped->IsPlayer()) { + // It's a shame... +#ifdef FIX_BUGS + int createdBy = ped->CharCreatedBy; +#else + int createdBy = !ped->CharCreatedBy; +#endif + + if (createdBy == MISSION_CHAR && !startedToRun) + ped->SetMoveState(PEDMOVE_WALK); } } void -CPed::SetRadioStation(void) +CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) { - static const uint8 radiosPerRadioCategories[10][4] = { - {JAH_RADIO, RISE_FM, GAME_FM, MSX_FM}, - {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, - {RISE_FM, GAME_FM, MSX_FM, FLASHBACK}, - {HEAD_RADIO, RISE_FM, LIPS_106, MSX_FM}, - {HEAD_RADIO, RISE_FM, MSX_FM, FLASHBACK}, - {JAH_RADIO, RISE_FM, LIPS_106, FLASHBACK}, - {HEAD_RADIO, RISE_FM, LIPS_106, FLASHBACK}, - {HEAD_RADIO, JAH_RADIO, LIPS_106, FLASHBACK}, - {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, - {CHATTERBOX, HEAD_RADIO, LIPS_106, GAME_FM} - }; - uint8 orderInCat = 0; // BUG: this wasn't initialized + CAnimBlendAssociation *quickJackedAssoc; + CVehicle *vehicle; + CPed *ped = (CPed*)arg; - if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) - return; + quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED); + if (ped->m_nPedState != PED_ARRESTED) { + ped->m_nLastPedState = PED_NONE; + if (dragAssoc) + dragAssoc->blendDelta = -1000.0f; + } + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + ped->m_pSeekTarget = nil; + vehicle = ped->m_pMyVehicle; - uint8 category = GetPedRadioCategory(GetModelIndex()); - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CGeneral::GetRandomNumber() & 15) { - for (orderInCat = 0; orderInCat < 4; orderInCat++) { - if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) - break; - } + if (vehicle) { + vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + + if (vehicle->pDriver == ped) { + vehicle->RemoveDriver(); + if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + vehicle->m_nDoorLock = CARLOCK_UNLOCKED; + + if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) + vehicle->ChangeLawEnforcerState(false); } else { - m_pMyVehicle->m_nRadioStation = USERTRACK; - } - } else { - for (orderInCat = 0; orderInCat < 4; orderInCat++) { - if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) - break; + vehicle->RemovePassenger(ped); } } - if (orderInCat == 4) { - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CGeneral::GetRandomNumber() & 15) - m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; - else - m_pMyVehicle->m_nRadioStation = USERTRACK; - } else { - m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + ped->bInVehicle = false; + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + +#ifdef VC_PED_PORTS + if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + ped->m_fHealth = 0.0f; + ped->SetDie(ANIM_FLOOR_HIT, 1000.0f, 0.5f); + return; + } +#endif + + if (quickJackedAssoc) { + dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); + } else { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + if (ped->CanSetPedState()) + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + } + + ped->ReplaceWeaponWhenExitingVehicle(); + + ped->m_nStoredMoveState = PEDMOVE_NONE; + ped->bVehExitWillBeInstant = false; +} + +void +CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + // Pointless code + if (!veh) + return; + +#ifdef VC_PED_PORTS + // Situation of entering car as a driver while there is already a driver exiting atm. + CPed *driver = veh->pDriver; + if (driver && driver->m_nPedState == PED_DRIVING && !veh->bIsBus && driver->m_objective == OBJECTIVE_LEAVE_CAR + && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { + + if (!ped->IsPlayer() && (ped->CharCreatedBy != MISSION_CHAR || driver->IsPlayer())) { + ped->QuitEnteringCar(); + return; } + if (driver->CharCreatedBy == MISSION_CHAR) { + PedSetOutCarCB(nil, veh->pDriver); + if (driver->m_pMyVehicle) { + driver->PositionPedOutOfCollision(); + } else { + driver->m_pMyVehicle = veh; + driver->PositionPedOutOfCollision(); + driver->m_pMyVehicle = nil; + } + veh->pDriver = nil; + } else { + driver->SetDead(); + driver->FlagToDestroyWhenNextProcessed(); + veh->pDriver = nil; + } + } +#endif + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + ped->bInVehicle = true; + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { + if (veh->pDriver) { + if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1000; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = (CCivilianPed*)ped; + } + } + } + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + || ped->m_nPedState == PED_CARJACK +#endif + ) + veh->bIsBeingCarJacked = false; + + if (veh->m_nNumGettingIn) + --veh->m_nNumGettingIn; + + if (ped->IsPlayer() && ((CPlayerPed*)ped)->m_bAdrenalineActive) + ((CPlayerPed*)ped)->ClearAdrenaline(); + + if (veh->IsBoat()) { + if (ped->IsPlayer()) { +#if defined VC_PED_PORTS || defined FIX_BUGS + CCarCtrl::RegisterVehicleOfInterest(veh); +#endif + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PLAYER); + AudioManager.PlayerJustGotInCar(); + } + veh->SetDriver(ped); + if (!veh->bEngineOn) + veh->bEngineOn = true; + + ped->m_nPedState = PED_DRIVING; + ped->StopNonPartialAnims(); + return; + } + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; + + ped->bDoBloodyFootprints = false; + if (veh->m_nAlarmState == -1) + veh->m_nAlarmState = 15000; + + if (ped->IsPlayer()) { + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PLAYER); + } + AudioManager.PlayerJustGotInCar(); + } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PHYSICS); + } + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { + CPed *passenger = veh->pPassengers[i]; + if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { + passenger->SetObjective(OBJECTIVE_LEAVE_CAR, veh); +#ifdef VC_PED_PORTS + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); +#endif + } + } + } + // This shouldn't happen at all. Passengers can't enter with PED_CARJACK. Even though they did, we shouldn't call AddPassenger in here and SetDriver in below. +#if !defined VC_PED_PORTS && !defined FIX_BUGS + else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (ped->m_nPedState == PED_CARJACK) { + veh->AddPassenger(ped, 0); + ped->m_nPedState = PED_DRIVING; + ped->RestorePreviousObjective(); + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + } else if (veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) { + veh->AutoPilot.m_nCruiseSpeed = 17; + } + } +#endif + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK) { + veh->SetDriver(ped); + if (veh->VehicleCreatedBy == PARKED_VEHICLE) { + veh->VehicleCreatedBy = RANDOM_VEHICLE; + ++CCarCtrl::NumRandomCars; + --CCarCtrl::NumParkedCars; + } + if (veh->bIsAmbulanceOnDuty) { + veh->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; + } + if (veh->bIsFireTruckOnDuty) { + veh->bIsFireTruckOnDuty = false; + --CCarCtrl::NumFiretrucksOnDuty; + } + if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) + veh->ChangeLawEnforcerState(true); + + if (!veh->bEngineOn) { + veh->bEngineOn = true; + DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); + } + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR + && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { + + CCarCtrl::JoinCarWithRoadSystem(veh); + veh->AutoPilot.m_nCarMission = MISSION_CRUISE; + veh->AutoPilot.m_nTempAction = TEMPACT_NONE; + veh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + veh->AutoPilot.m_nCruiseSpeed = 25; + } + ped->m_nPedState = PED_DRIVING; + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + + if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->m_prevObjective = OBJECTIVE_NONE; + + ped->RestorePreviousObjective(); + } + + } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (veh->bIsBus) { + veh->AddPassenger(ped); + } else { + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + veh->AddPassenger(ped, 0); + break; + case CAR_DOOR_RR: + veh->AddPassenger(ped, 2); + break; + case CAR_DOOR_LR: + veh->AddPassenger(ped, 1); + break; + default: + veh->AddPassenger(ped); + break; + } + } + ped->m_nPedState = PED_DRIVING; + if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->m_prevObjective = OBJECTIVE_NONE; + + ped->RestorePreviousObjective(); +#ifdef VC_PED_PORTS + if(veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) + veh->AutoPilot.m_nCruiseSpeed = 17; +#endif + } + + veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + + if (veh->bIsBus && !veh->m_nGettingInFlags) + ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); + + switch (ped->m_objective) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + break; + default: + ped->SetObjective(OBJECTIVE_NONE); + } + + if (veh->pDriver == ped) { + if (veh->bLowVehicle) { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); + } else { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + } + } else if (veh->bLowVehicle) { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITPLO, 100.0f); + } else { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITP, 100.0f); + } + + ped->StopNonPartialAnims(); + if (veh->bIsBus) + ped->bRenderPedInCar = false; + + // FIX: RegisterVehicleOfInterest not just registers the vehicle, but also updates register time. So remove the IsThisVehicleInteresting check. +#ifndef FIX_BUGS + if (ped->IsPlayer() && !CCarCtrl::IsThisVehicleInteresting(veh) && veh->VehicleCreatedBy != MISSION_VEHICLE) { +#else + if (ped->IsPlayer() && veh->VehicleCreatedBy != MISSION_VEHICLE) { +#endif + CCarCtrl::RegisterVehicleOfInterest(veh); + + if (!veh->bHasBeenOwnedByPlayer && veh->VehicleCreatedBy != MISSION_VEHICLE) + CEventList::RegisterEvent(EVENT_STEAL_CAR, EVENT_ENTITY_VEHICLE, veh, ped, 1500); + + veh->bHasBeenOwnedByPlayer = true; + } + ped->bChangedSeat = true; +} + +bool +CPed::CanBeDeleted(void) +{ + if (bInVehicle) + return false; + + switch (CharCreatedBy) { + case RANDOM_CHAR: + return true; + case MISSION_CHAR: + return false; + default: + return true; } } -inline bool -CPed::IsNotInWreckedVehicle() +void +CPed::AddWeaponModel(int id) { - return m_pMyVehicle != nil && m_pMyVehicle->GetStatus() != STATUS_WRECKED; + RpAtomic *atm; + + if (id != -1) { +#ifdef PED_SKIN + if (IsClumpSkinned(GetClump())) { + if (m_pWeaponModel) + RemoveWeaponModel(-1); + + m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + } else +#endif + { + atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atm)); + RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); + RpClumpAddAtomic(GetClump(), atm); + } + m_wepModelID = id; + } +} + +static RwObject* +RemoveAllModelCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { + RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); + RpAtomicDestroy(atomic); + } + return object; +} + +void +CPed::RemoveWeaponModel(int modelId) +{ + // modelId is not used!! This function just removes the current weapon. +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + if(m_pWeaponModel){ + RwFrame *frm = RpAtomicGetFrame(m_pWeaponModel); + RpAtomicDestroy(m_pWeaponModel); + RwFrameDestroy(frm); + m_pWeaponModel = nil; + } + }else +#endif + RwFrameForAllObjects(m_pFrames[PED_HANDR]->frame,RemoveAllModelCB,nil); + m_wepModelID = -1; +} + +uint32 +CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) +{ + CWeapon &weapon = GetWeapon(weaponType); + + if (HasWeapon(weaponType)) { + if (weapon.m_nAmmoTotal + ammo > 99999) + weapon.m_nAmmoTotal = 99999; + else + weapon.m_nAmmoTotal += ammo; + + weapon.Reload(); + } else { + weapon.Initialise(weaponType, ammo); + // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. + m_maxWeaponTypeAllowed++; + } + if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) + weapon.m_eWeaponState = WEAPONSTATE_READY; + + return weaponType; +} + +// Some kind of VC leftover I think +int +CPed::GetWeaponSlot(eWeaponType weaponType) +{ + if (HasWeapon(weaponType)) + return weaponType; + else + return -1; +} + +void +CPed::SetCurrentWeapon(uint32 weaponType) +{ + CWeaponInfo *weaponInfo; + if (HasWeapon(weaponType)) { + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weaponInfo->m_nModelId); + + m_currentWeapon = weaponType; + + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(weaponInfo->m_nModelId); + } +} + +void +CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal += ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal = ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::ClearWeapons(void) +{ + CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(currentWeapon->m_nModelId); + + m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; + m_currentWeapon = WEAPONTYPE_UNARMED; + + currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(currentWeapon->m_nModelId); + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + CWeapon &weapon = GetWeapon(i); + weapon.m_eWeaponType = WEAPONTYPE_UNARMED; + weapon.m_eWeaponState = WEAPONSTATE_READY; + weapon.m_nAmmoInClip = 0; + weapon.m_nAmmoTotal = 0; + weapon.m_nTimer = 0; + } } void @@ -14969,180 +4894,1131 @@ CPed::PreRender(void) } void -CPed::ProcessBuoyancy(void) +CPed::Render(void) { - static uint32 nGenerateRaindrops = 0; - static uint32 nGenerateWaterCircles = 0; - CRGBA color(((0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed()) * 127.5f), - ((0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue()) * 127.5f), - ((0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen()) * 127.5f), - (CGeneral::GetRandomNumber() % 256 * 48.0f) + 48); + if (bInVehicle && m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR) { + if (!bRenderPedInCar) + return; - if (bInVehicle) + float camDistSq = (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr(); + if (camDistSq > SQR(25.0f * TheCamera.LODDistMultiplier)) + return; + } + + CEntity::Render(); + +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + renderLimb(PED_HEAD); + renderLimb(PED_HANDL); + renderLimb(PED_HANDR); + } + if(m_pWeaponModel && IsClumpSkinned(GetClump())){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + RpAtomicRender(m_pWeaponModel); + } +#endif +} + +void +CPed::CheckAroundForPossibleCollisions(void) +{ + CVector ourCentre, objCentre; + CEntity *objects[8]; + int16 maxObject; + + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) return; - CVector buoyancyPoint; - CVector buoyancyImpulse; + GetBoundCentre(ourCentre); -#ifndef VC_PED_PORTS - float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.5f : 1.3f); -#else - float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f); -#endif - - if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) { - bTouchingWater = true; - CEntity *entity; - CColPoint point; - if (CWorld::ProcessVerticalLine(GetPosition(), GetPosition().z - 3.0f, point, entity, false, true, false, false, false, false, nil) - && entity->IsVehicle() && ((CVehicle*)entity)->IsBoat()) { - bIsInWater = false; - return; + CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false); + for (int i = 0; i < maxObject; i++) { + CEntity *object = objects[i]; + if (bRunningToPhone) { + if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition())) + break; } - bIsInWater = true; - ApplyMoveForce(buoyancyImpulse); - if (!DyingOrDead()) { - if (bTryingToReachDryLand) { - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.4f * CTimer::GetTimeStep()) { - bTryingToReachDryLand = false; - CVector pos = GetPosition(); - if (PlacePedOnDryLand()) { - if (m_fHealth > 20.0f) - InflictDamage(nil, WEAPONTYPE_DROWNING, 15.0f, PEDPIECE_TORSO, false); + object->GetBoundCentre(objCentre); + float radius = object->GetBoundRadius(); + if (radius > 4.5f || radius < 1.0f) + radius = 1.0f; - if (bIsInTheAir) { - RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); - bIsInTheAir = false; - } - pos.z = pos.z - 0.8f; -#ifdef PC_PARTICLE - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, color, true); -#else - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, CRGBA(0, 0, 0, 0), true); + // Developers gave up calculating Z diff. later according to asm. + float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); + + if (sq(radius + 1.0f) > diff) + m_fRotationDest += DEGTORAD(22.5f); + } +} + +void +CPed::SetIdle(void) +{ + if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { +#ifdef VC_PED_PORTS + if (m_nPedState == PED_AIM_GUN) + ClearPointGunAt(); + + m_nLastPedState = PED_NONE; #endif - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_nPedState = PED_IDLE; - return; - } - } - } - float speedMult = 0.0f; - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.75f * CTimer::GetTimeStep() - || mod_Buoyancy.m_waterlevel > GetPosition().z) { - speedMult = pow(0.9f, CTimer::GetTimeStep()); - m_vecMoveSpeed.x *= speedMult; - m_vecMoveSpeed.y *= speedMult; - m_vecMoveSpeed.z *= speedMult; - bIsStanding = false; - InflictDamage(nil, WEAPONTYPE_DROWNING, 3.0f * CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); - } - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.25f * CTimer::GetTimeStep()) { - if (speedMult == 0.0f) { - speedMult = pow(0.9f, CTimer::GetTimeStep()); - } - m_vecMoveSpeed.x *= speedMult; - m_vecMoveSpeed.y *= speedMult; - if (m_vecMoveSpeed.z >= -0.1f) { - if (m_vecMoveSpeed.z < -0.04f) - m_vecMoveSpeed.z = -0.02f; - } else { - m_vecMoveSpeed.z = -0.01f; - DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLASH, 0.0f); -#ifdef PC_PARTICLE - CVector aBitForward = 2.2f * m_vecMoveSpeed + GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) - aBitForward.z = level; + m_nPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + } + if (m_nWaitState == WAITSTATE_FALSE) { + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); + } +} - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, CVector(0.0f, 0.0f, 0.1f), 0.0f, 200, color, true); - nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 80; - nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 100; -#else - CVector aBitForward = 1.6f * m_vecMoveSpeed + GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) - aBitForward.z = level + 0.5f; - - CVector vel = m_vecMoveSpeed * 0.1f; - vel.z = 0.18f; - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, vel, 0.0f, 350, CRGBA(0, 0, 0, 0), true); - nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300; - nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60; -#endif +void +CPed::Idle(void) +{ + CVehicle *veh = m_pMyVehicle; + if (veh && veh->m_nGettingOutFlags && m_vehEnterType) { + + if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) { + + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + + CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); + CVector doorDist = GetPosition() - doorPos; + + if (doorDist.MagnitudeSqr() < sq(0.5f)) { + SetMoveState(PEDMOVE_WALK); + return; } } - } else - return; - } else - bTouchingWater = false; - - if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) { - CVector pos = GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(pos, &level, false)) - pos.z = level; - - if (pos.z != 0.0f) { - nGenerateWaterCircles = 0; - for(int i = 0; i < 4; i++) { -#ifdef PC_PARTICLE - pos.x += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); - pos.y += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); - CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, 0, 0, 0, 0); -#else - pos.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); - pos.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); - CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos+CVector(0.0f, 0.0f, 1.0f), CVector(0.0f, 0.0f, 0.0f)); -#endif - } } } - if (nGenerateRaindrops && CTimer::GetTimeInMilliseconds() >= nGenerateRaindrops) { - CVector pos = GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(pos, &level, false)) - pos.z = level; + CAnimBlendAssociation *armedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); + CAnimBlendAssociation *unarmedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + int waitTime; - if (pos.z >= 0.0f) { -#ifdef PC_PARTICLE - pos.z += 0.25f; -#else - pos.z += 0.5f; + if (m_nMoveState == PEDMOVE_STILL) { + + eWeaponType curWeapon = GetWeapon()->m_eWeaponType; + if (!armedIdleAssoc || + CTimer::GetTimeInMilliseconds() <= m_nWaitTimer && curWeapon != WEAPONTYPE_UNARMED && curWeapon != WEAPONTYPE_MOLOTOV && curWeapon != WEAPONTYPE_GRENADE) { + + if ((!GetWeapon()->IsType2Handed() || curWeapon == WEAPONTYPE_SHOTGUN) && curWeapon != WEAPONTYPE_BASEBALLBAT + || !unarmedIdleAssoc || unarmedIdleAssoc->blendAmount <= 0.95f || m_nWaitState != WAITSTATE_FALSE || CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + + m_moved = CVector2D(0.0f, 0.0f); + return; + } + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_ARMED, 3.0f); + waitTime = CGeneral::GetRandomNumberInRange(4000, 7500); + } else { + armedIdleAssoc->blendDelta = -2.0f; + armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; + waitTime = CGeneral::GetRandomNumberInRange(3000, 8500); + } + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + waitTime; + } else { + if (armedIdleAssoc) { + armedIdleAssoc->blendDelta = -8.0f; + armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; + m_nWaitTimer = 0; + } + if (!IsPlayer()) + SetMoveState(PEDMOVE_STILL); + } + m_moved = CVector2D(0.0f, 0.0f); +} + +void +CPed::ClearPause(void) +{ + RestorePreviousState(); +} + +void +CPed::Pause(void) +{ + m_moved = CVector2D(0.0f, 0.0f); + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) + ClearPause(); +} + +void +CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl) +{ + if (!IsPedInControl() && (!evenIfNotInControl || DyingOrDead())) + return; + + ClearLookFlag(); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_FALL; + CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), animId); + + if (fallAssoc) { + fallAssoc->SetCurrentTime(0.0f); + fallAssoc->blendAmount = 0.0f; + fallAssoc->blendDelta = 8.0f; + fallAssoc->SetRun(); + } else { + fallAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, 8.0f); + } + + if (extraTime == -1) { + m_getUpTimer = UINT32_MAX; + } else if (fallAssoc) { + if (IsPlayer()) { + m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength + + CTimer::GetTimeInMilliseconds() + + 500.0f; + } else { + m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength + + CTimer::GetTimeInMilliseconds() + + extraTime + + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); + } + } else { + m_getUpTimer = extraTime + + CTimer::GetTimeInMilliseconds() + + 1000 + + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); + } + bFallenDown = true; +} + +void +CPed::ClearFall(void) +{ + SetGetUp(); +} + +void +CPed::Fall(void) +{ + if (m_getUpTimer != UINT32_MAX && CTimer::GetTimeInMilliseconds() > m_getUpTimer +#ifdef VC_PED_PORTS + && bIsStanding #endif - nGenerateRaindrops = 0; -#ifdef PC_PARTICLE - CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 1500, CRGBA(0,0,0,0), true); -#else - CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 2500, CRGBA(0,0,0,0), true); + ) + ClearFall(); + + // VC plays animations ANIM_STD_FALL_ONBACK and ANIM_STD_FALL_ONFRONT in here, which doesn't exist in III. +} + +bool +CPed::CheckIfInTheAir(void) +{ + if (bInVehicle) + return false; + + CVector pos = GetPosition(); + CColPoint foundColPoint; + CEntity *foundEntity; + + float startZ = pos.z - 1.54f; + bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); + if (!foundGround && m_nPedState != PED_JUMP) + { + pos.z -= FEET_OFFSET; + if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) + foundGround = true; + } + return !foundGround; +} + +void +CPed::SetInTheAir(void) +{ + if (bIsInTheAir) + return; + + bIsInTheAir = true; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_GLIDE, 4.0f); + + if (m_nPedState == PED_ATTACK) { + ClearAttack(); + ClearPointGunAt(); + } else if (m_nPedState == PED_FIGHT) { + EndFight(ENDFIGHT_FAST); + } + +} + +void +CPed::InTheAir(void) +{ + CColPoint foundCol; + CEntity *foundEnt; + + CVector ourPos = GetPosition(); + CVector bitBelow = GetPosition(); + bitBelow.z -= 4.04f; + + if (m_vecMoveSpeed.z < 0.0f && !bIsPedDieAnimPlaying) { + if (!DyingOrDead()) { + if (CWorld::ProcessLineOfSight(ourPos, bitBelow, foundCol, foundEnt, true, true, false, true, false, false, false)) { + if (GetPosition().z - foundCol.point.z < 1.3f +#ifdef VC_PED_PORTS + || bIsStanding #endif + ) + SetLanding(); + } else { + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL)) { + if (m_vecMoveSpeed.z < -0.1f) + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_FALL, 4.0f); + } + } } } } void -CPed::SetSolicit(uint32 time) +CPed::SetLanding(void) { - if (m_nPedState == PED_SOLICIT || !IsPedInControl() || !m_carInObjective) + if (DyingOrDead()) return; - if (CharCreatedBy != MISSION_CHAR && m_carInObjective->m_nNumGettingIn == 0 - && CTimer::GetTimeInMilliseconds() < m_objectiveTimer) { - if (m_vehEnterType == CAR_DOOR_LF) { - m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; - } else { - m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; + CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + CAnimBlendAssociation *landAssoc; + + RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); + if (fallAssoc) { + landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_COLLAPSE); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_COLLAPSE, 1.0f); + + if (IsPlayer()) + Say(SOUND_PED_LAND); + + } else { + landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_LAND, 1.0f); + } + + landAssoc->SetFinishCallback(PedLandCB, this); + bIsInTheAir = false; + bIsLanding = true; +} + +void +CPed::SetGetUp(void) +{ + if (m_nPedState == PED_GETUP && bGetUpAnimStarted) + return; + + if (!CanSetPedState()) + return; + + if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) { + if (bUpdateAnimHeading) { + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + m_fRotationCur -= HALFPI; + bUpdateAnimHeading = false; + } + if (m_nPedState != PED_GETUP) { + SetStoredState(); + m_nPedState = PED_GETUP; } - if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + CVehicle *collidingVeh = (CVehicle*)m_pCollidingEntity; + CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition()); + if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE || + collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE + && ((uint8)(CTimer::GetFrameCounter() + m_randomSeed + 5) % 8 || + CCollision::ProcessColModels(GetMatrix(), *GetColModel(), collidingVeh->GetMatrix(), *collidingVeh->GetColModel(), + aTempPedColPts, nil, nil) > 0)) { - if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); + bGetUpAnimStarted = false; + if (IsPlayer()) + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); + else { + if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) + return; - m_nPedState = PED_SOLICIT; + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0); + } + return; + } + bGetUpAnimStarted = true; + m_pCollidingEntity = nil; + bKnockedUpIntoAir = false; + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); + if (animAssoc) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN)) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_RUN, 8.0f); + } else { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); + } + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f); + else + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + + animAssoc->SetFinishCallback(PedGetupCB,this); + } else { + m_fHealth = 0.0f; + SetDie(NUM_ANIMS, 4.0f, 0.0f); + } +} + +void +CPed::Mug(void) +{ + if (m_pSeekTarget && m_pSeekTarget->IsPed()) { + + if (CTimer::GetTimeInMilliseconds() <= m_attackTimer - 2000) { + if ((m_pSeekTarget->GetPosition() - GetPosition()).Magnitude() > 3.0f) + m_wepSkills = 50; + + Say(SOUND_PED_MUGGING); + ((CPed*)m_pSeekTarget)->Say(SOUND_PED_ROBBED); + } else { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + SetFlee(m_pSeekTarget, 20000); + } + + } else { + SetIdle(); + } +} + +void +CPed::SetLookTimer(int time) +{ + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::SetAttackTimer(uint32 time) +{ + if (CTimer::GetTimeInMilliseconds() > m_attackTimer) + m_attackTimer = Max(m_shootTimer, CTimer::GetTimeInMilliseconds()) + time; +} + +void +CPed::SetShootTimer(uint32 time) +{ + if (CTimer::GetTimeInMilliseconds() > m_shootTimer) { + m_shootTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::ClearLook(void) +{ + RestorePreviousState(); + ClearLookFlag(); +} + +void +CPed::Look(void) +{ + // UNUSED: This is a perfectly empty function. +} + +bool +CPed::TurnBody(void) +{ + bool turnDone = true; + + if (m_pLookTarget) + m_fLookDirection = CGeneral::GetRadianAngleBetweenPoints( + m_pLookTarget->GetPosition().x, + m_pLookTarget->GetPosition().y, + GetPosition().x, + GetPosition().y); + + float limitedLookDir = CGeneral::LimitRadianAngle(m_fLookDirection); + float currentRot = m_fRotationCur; + + if (currentRot - PI > limitedLookDir) + limitedLookDir += 2 * PI; + else if (PI + currentRot < limitedLookDir) + limitedLookDir -= 2 * PI; + + float neededTurn = currentRot - limitedLookDir; + m_fRotationDest = limitedLookDir; + + if (Abs(neededTurn) > 0.05f) { + turnDone = false; + currentRot -= neededTurn * 0.2f; + } + + m_fRotationCur = currentRot; + m_fLookDirection = limitedLookDir; + return turnDone; +} + +void +CPed::SetSeek(CVector pos, float distanceToCountDone) +{ + if (!IsPedInControl() + || (m_nPedState == PED_SEEK_POS && m_vecSeekPos.x == pos.x && m_vecSeekPos.y == pos.y)) + return; + + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_M16 + || GetWeapon()->m_eWeaponType == WEAPONTYPE_AK47 + || GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE + || GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER + || GetWeapon()->m_eWeaponType == WEAPONTYPE_SHOTGUN) { + ClearPointGunAt(); + } + + if (m_nPedState != PED_SEEK_POS) + SetStoredState(); + + m_nPedState = PED_SEEK_POS; + m_distanceToCountSeekDone = distanceToCountDone; + m_vecSeekPos = pos; +} + +void +CPed::SetSeek(CEntity *seeking, float distanceToCountDone) +{ + if (!IsPedInControl()) + return; + + if (m_nPedState == PED_SEEK_ENTITY && m_pSeekTarget == seeking) + return; + + if (!seeking) + return; + + if (m_nPedState != PED_SEEK_ENTITY) + SetStoredState(); + + m_nPedState = PED_SEEK_ENTITY; + m_distanceToCountSeekDone = distanceToCountDone; + m_pSeekTarget = seeking; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + SetMoveState(PEDMOVE_STILL); +} + +void +CPed::ClearSeek(void) +{ + SetIdle(); + bRunningToPhone = false; +} + +bool +CPed::Seek(void) +{ + float distanceToCountItDone = m_distanceToCountSeekDone; + eMoveState nextMove = PEDMOVE_NONE; + + if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + + if (m_nPedState != PED_EXIT_TRAIN && m_nPedState != PED_ENTER_TRAIN && m_nPedState != PED_SEEK_IN_BOAT && + m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_SOLICIT_VEHICLE && !bDuckAndCover) { + + if ((!m_pedInObjective || !m_pedInObjective->bInVehicle) + && !((CTimer::GetFrameCounter() + (m_randomSeed % 256) + 17) & 7)) { + + CEntity *obstacle = CWorld::TestSphereAgainstWorld(m_vecSeekPos, 0.4f, nil, + false, true, false, false, false, false); + + if (obstacle) { + if (!obstacle->IsVehicle() || ((CVehicle*)obstacle)->m_vehType == VEHICLE_TYPE_CAR) { + distanceToCountItDone = 2.5f; + } else { + CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(obstacle->GetModelIndex()); + float yLength = vehModel->GetColModel()->boundingBox.max.y + - vehModel->GetColModel()->boundingBox.min.y; + distanceToCountItDone = yLength * 0.55f; + } + } + } } } + + if (!m_pSeekTarget && m_nPedState == PED_SEEK_ENTITY) + ClearSeek(); + + float seekPosDist = (m_vecSeekPos - GetPosition()).Magnitude2D(); + if (seekPosDist < 2.0f || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT) { + + if (m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { + + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + nextMove = m_pedInObjective->m_nMoveState; + } else + nextMove = PEDMOVE_WALK; + + } else if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || m_objective == OBJECTIVE_RUN_TO_AREA || bIsRunning) + nextMove = PEDMOVE_RUN; + else + nextMove = PEDMOVE_WALK; + + } else if (seekPosDist <= 2.0f) { + + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + nextMove = m_pedInObjective->m_nMoveState; + + } else { + nextMove = PEDMOVE_RUN; + } + + if (m_nPedState == PED_SEEK_ENTITY) { + if (m_pSeekTarget->IsPed()) { + if (((CPed*)m_pSeekTarget)->bInVehicle) + distanceToCountItDone += 2.0f; + } + } + + if (seekPosDist >= distanceToCountItDone) { + if (bIsRunning) + nextMove = PEDMOVE_RUN; + + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) { + + if (m_actionX != 0.0f && m_actionY != 0.0f) { + + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_actionX, m_actionY, + GetPosition().x, GetPosition().y); + + float neededTurn = Abs(m_fRotationDest - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + if (neededTurn > HALFPI) { + if (seekPosDist >= 1.0f) { + if (seekPosDist < 2.0f) { + if (bIsRunning) + nextMove = PEDMOVE_RUN; + else + nextMove = PEDMOVE_WALK; + } + } else { + nextMove = PEDMOVE_STILL; + } + } + + CVector2D moveDist(GetPosition().x - m_actionX, GetPosition().y - m_actionY); + if (moveDist.Magnitude() < 0.5f) { + m_nPedStateTimer = 0; + m_actionX = 0; + m_actionY = 0; + } + } + } else { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_vecSeekPos.x, m_vecSeekPos.y, + GetPosition().x, GetPosition().y); + + float neededTurn = Abs(m_fRotationDest - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + if (neededTurn > HALFPI) { + if (seekPosDist >= 1.0 && neededTurn <= DEGTORAD(135.0f)) { + if (seekPosDist < 2.0f) + nextMove = PEDMOVE_WALK; + } else { + nextMove = PEDMOVE_STILL; + } + } + } + + if (((m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY) && m_nMoveState < nextMove) + || (m_nPedState != PED_FLEE_POS && m_nPedState != PED_FLEE_ENTITY && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT && m_nWaitState == WAITSTATE_FALSE)) { + + SetMoveState(nextMove); + } + + SetMoveAnim(); + return false; + } + + if ((m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION || m_pedInObjective->m_nMoveState == PEDMOVE_STILL) && m_nMoveState != PEDMOVE_STILL) { + m_nPedStateTimer = 0; + m_actionX = 0; + m_actionY = 0; + } + + if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA || m_objective == OBJECTIVE_GOTO_AREA_ANY_MEANS) { + if (m_pNextPathNode) + m_pNextPathNode = nil; + else + bScriptObjectiveCompleted = true; + + bUsePedNodeSeek = true; + } + + if (SeekFollowingPath(nil)) + m_nCurPathNode++; + + return true; +} + +void +CPed::SetFlee(CVector2D const &from, int time) +{ + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace) + return; + + if (m_nPedState != PED_FLEE_ENTITY) { + SetStoredState(); + m_nPedState = PED_FLEE_POS; + SetMoveState(PEDMOVE_RUN); + m_fleeFromPosX = from.x; + m_fleeFromPosY = from.y; + } + + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + from.x, from.y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::SetFlee(CEntity *fleeFrom, int time) +{ + if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom) + return; + + SetStoredState(); + m_nPedState = PED_FLEE_ENTITY; + bUsePedNodeSeek = true; + SetMoveState(PEDMOVE_RUN); + m_fleeFrom = fleeFrom; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + + if (time <= 0) + m_fleeTimer = 0; + else + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + fleeFrom->GetPosition().x, fleeFrom->GetPosition().y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::ClearFlee(void) +{ + RestorePreviousState(); + bUsePedNodeSeek = false; + m_standardTimer = 0; + m_fleeTimer = 0; +} + +void +CPed::Flee(void) +{ + if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) { + bool mayFinishFleeing = true; + if (m_nPedState == PED_FLEE_ENTITY) { + if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < sq(30.0f)) + mayFinishFleeing = false; + } + + if (mayFinishFleeing) { + eMoveState moveState = m_nMoveState; + ClearFlee(); + + if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE || m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) + RestorePreviousObjective(); + + if ((m_nPedState == PED_IDLE || m_nPedState == PED_WANDER_PATH) && CGeneral::GetRandomNumber() & 1) { + SetWaitState(moveState <= PEDMOVE_WALK ? WAITSTATE_CROSS_ROAD_LOOK : WAITSTATE_FINISH_FLEE, nil); + } + return; + } + m_fleeTimer = CTimer::GetTimeInMilliseconds() + 5000; + } + + if (bUsePedNodeSeek) { + CPathNode *realLastNode = nil; + uint8 nextDirection = 0; + uint8 curDirectionShouldBe = 9; // means not defined yet + + if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds() + && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) { + + if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); + if (m_nPathDir < curDirectionShouldBe) + m_nPathDir += 8; + + int dirDiff = m_nPathDir - curDirectionShouldBe; + if (dirDiff > 2 && dirDiff < 6) { + realLastNode = nil; + m_pLastPathNode = m_pNextPathNode; + m_pNextPathNode = nil; + } + } + + if (m_pNextPathNode) { + m_vecSeekPos = m_pNextPathNode->GetPosition(); + if (m_nMoveState == PEDMOVE_RUN) + bIsRunning = true; + + eMoveState moveState = m_nMoveState; + if (Seek()) { + realLastNode = m_pLastPathNode; + m_pLastPathNode = m_pNextPathNode; + m_pNextPathNode = nil; + } + bIsRunning = false; + SetMoveState(moveState); + } + } + + if (!m_pNextPathNode) { + if (curDirectionShouldBe == 9) { + curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); + } + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + curDirectionShouldBe, + &nextDirection); + + if (curDirectionShouldBe < nextDirection) + curDirectionShouldBe += 8; + + if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { + m_nPathDir = nextDirection; + m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + } else { + bUsePedNodeSeek = false; + SetMoveState(PEDMOVE_RUN); + Flee(); + } + } + return; + } + + if ((m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_ON_FIRE) && m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { + + float angleToFleeFromPos = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, + GetPosition().y, + ms_vec2DFleePosition.x, + ms_vec2DFleePosition.y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFleeFromPos); + + if (m_fRotationCur - PI > m_fRotationDest) + m_fRotationDest += TWOPI; + else if (PI + m_fRotationCur < m_fRotationDest) + m_fRotationDest -= TWOPI; + } + + if (CTimer::GetTimeInMilliseconds() & 0x20) { + //CVector forwardPos = GetPosition(); + CMatrix forwardMat(GetMatrix()); + forwardMat.GetPosition() += Multiply3x3(forwardMat, CVector(0.0f, 4.0f, 0.0f)); + CVector forwardPos = forwardMat.GetPosition(); + + CEntity *foundEnt; + CColPoint foundCol; + bool found = CWorld::ProcessVerticalLine(forwardPos, forwardMat.GetPosition().z - 100.0f, foundCol, foundEnt, 1, 0, 0, 0, 1, 0, 0); + + if (!found || Abs(forwardPos.z - forwardMat.GetPosition().z) > 1.0f) { + m_fRotationDest += DEGTORAD(112.5f); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; + } + } + + if (CTimer::GetTimeInMilliseconds() >= m_collidingThingTimer) + return; + + if (!m_collidingEntityWhileFleeing) + return; + + double collidingThingPriorityMult = (double)(m_collidingThingTimer - CTimer::GetTimeInMilliseconds()) * 2.0 / 2500; + + if (collidingThingPriorityMult <= 1.5) { + + double angleToFleeEntity = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, + GetPosition().y, + m_collidingEntityWhileFleeing->GetPosition().x, + m_collidingEntityWhileFleeing->GetPosition().y); + angleToFleeEntity = CGeneral::LimitRadianAngle(angleToFleeEntity); + + double angleToFleeCollidingThing = CGeneral::GetRadianAngleBetweenPoints( + m_vecDamageNormal.x, + m_vecDamageNormal.y, + 0.0f, + 0.0f); + angleToFleeCollidingThing = CGeneral::LimitRadianAngle(angleToFleeCollidingThing); + + if (angleToFleeEntity - PI > angleToFleeCollidingThing) + angleToFleeCollidingThing += TWOPI; + else if (PI + angleToFleeEntity < angleToFleeCollidingThing) + angleToFleeCollidingThing -= TWOPI; + + if (collidingThingPriorityMult <= 1.0f) { + // Range [0.0, 1.0] + + float angleToFleeBoth = (angleToFleeCollidingThing + angleToFleeEntity) * 0.5f; + + if (m_fRotationDest - PI > angleToFleeBoth) + angleToFleeBoth += TWOPI; + else if (PI + m_fRotationDest < angleToFleeBoth) + angleToFleeBoth -= TWOPI; + + m_fRotationDest = (1.0f - collidingThingPriorityMult) * m_fRotationDest + collidingThingPriorityMult * angleToFleeBoth; + } else { + // Range (1.0, 1.5] + + double adjustedMult = (collidingThingPriorityMult - 1.0f) * 2.0f; + m_fRotationDest = angleToFleeEntity * (1.0 - adjustedMult) + adjustedMult * angleToFleeCollidingThing; + } + } else { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_vecDamageNormal.x, + m_vecDamageNormal.y, + 0.0f, + 0.0f); + m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); + } + + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + if (m_fRotationCur - PI > m_fRotationDest) + m_fRotationDest += TWOPI; + else if (PI + m_fRotationCur < m_fRotationDest) + m_fRotationDest -= TWOPI; + +} + +// "Wander range" state is unused in game, and you can't use it without SetWanderRange anyway +void +CPed::WanderRange(void) +{ + bool arrived = Seek(); + if (arrived) { + Idle(); + if ((m_randomSeed + 3 * CTimer::GetFrameCounter()) % 1000 > 997) { + CVector2D newCoords2D = m_wanderRangeBounds->GetRandomPointInRange(); + SetSeek(CVector(newCoords2D.x, newCoords2D.y, GetPosition().z), 2.5f); + } + } +} + +bool +CPed::SetWanderPath(int8 pathStateDest) +{ + uint8 nextPathState; + + if (IsPedInControl()) { + if (bKindaStayInSamePlace) { + SetIdle(); + return false; + } else { + m_nPathDir = pathStateDest; + if (pathStateDest == 0) + pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); + + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &nextPathState); + + // Circular loop until we find a node for current m_nPathDir + while (!m_pNextPathNode) { + m_nPathDir = (m_nPathDir+1) % 8; + + // We're at where we started and couldn't find any node + if (m_nPathDir == pathStateDest) { + ClearAll(); + SetIdle(); + return false; + } + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &nextPathState); + } + + // We did it, save next path state and return true + m_nPathDir = nextPathState; + m_nPedState = PED_WANDER_PATH; + SetMoveState(PEDMOVE_WALK); + bIsRunning = false; + return true; + } + } else { + m_nPathDir = pathStateDest; + bStartWanderPathOnFoot = true; + return false; + } +} + +void +CPed::WanderPath(void) +{ + if (!m_pNextPathNode) { + printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); + SetIdle(); + return; + } + if (m_nWaitState == WAITSTATE_FALSE) { + if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) + SetMoveState(PEDMOVE_WALK); + } + m_vecSeekPos = m_pNextPathNode->GetPosition(); + m_vecSeekPos.z += 1.0f; + + // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. + if (!Seek()) + return; + + CPathNode *previousLastNode = m_pLastPathNode; + uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; + + // We don't prefer 180-degree turns in normal situations + uint8 dirWeWouldntPrefer = m_nPathDir; + if (dirWeWouldntPrefer <= 3) + dirWeWouldntPrefer += 4; + else + dirWeWouldntPrefer -= 4; + + CPathNode *nodeWeWouldntPrefer = nil; + uint8 dirToSet = 9; // means undefined + uint8 dirWeWouldntPrefer2 = 9; // means undefined + if (randVal <= 90) { + if (randVal > 80) { + m_nPathDir += 2; + m_nPathDir %= 8; + } + } else { + m_nPathDir -= 2; + if (m_nPathDir < 0) + m_nPathDir += 8; + } + + m_pLastPathNode = m_pNextPathNode; + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + + uint8 tryCount = 0; + + // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 + while (!m_pNextPathNode) { + tryCount++; + m_nPathDir = (m_nPathDir + 1) % 8; + + // We're at where we started and couldn't find any node + if (tryCount > 7) { + if (!nodeWeWouldntPrefer) { + ClearAll(); + SetIdle(); + // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. + Error("Can't find valid path node, SetWanderPath, Ped.cpp"); + return; + } + m_pNextPathNode = nodeWeWouldntPrefer; + dirToSet = dirWeWouldntPrefer2; + } else { + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + if (m_pNextPathNode) { + if (dirToSet == dirWeWouldntPrefer) { + nodeWeWouldntPrefer = m_pNextPathNode; + dirWeWouldntPrefer2 = dirToSet; + m_pNextPathNode = nil; + } + } + } + } + + m_nPathDir = dirToSet; + if (m_pLastPathNode == m_pNextPathNode) { + m_pNextPathNode = previousLastNode; + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); + } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_CROSS_ROAD, nil); + } else if (m_pNextPathNode == previousLastNode) { + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } +} + +void +CPed::Avoid(void) +{ + CPed *nearestPed; + + if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) + return; + + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + + if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { + nearestPed = m_nearPeds[0]; + + if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { + + // Check if this ped wants to avoid the nearest one + if (CPedType::GetAvoid(m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { + + // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. + // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. + + // Game converts from radians to degress and back again here, doesn't make much sense + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); + forward.Normalise(); // this is kinda pointless + + // Move forward 1.25 meters + CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; + + // Get distance to ped we want to avoid + CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; + + if (distToPed.Magnitude() <= 1.0f && OurPedCanSeeThisOne((CEntity*)nearestPed)) { + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) + % 1000 / 5; + + m_fRotationDest += DEGTORAD(45.0f); + if (!bIsLooking) { + SetLookFlag(nearestPed, false); + SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); + } + } + } + } + } + } +} + +bool +CPed::SeekFollowingPath(CVector *unused) +{ + return m_nCurPathNode <= m_nPathNodes && m_nPathNodes; } bool @@ -15177,669 +6053,613 @@ CPed::SetFollowPath(CVector dest) } void -AddYardieDoorSmoke(CVehicle *veh, uint32 doorNode) +CPed::FollowPath(void) { - eDoors door; - switch (doorNode) { - case CAR_DOOR_RF: - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_LF: - door = DOOR_FRONT_LEFT; - break; - default: - break; - } - - if (!veh->IsDoorMissing(door) && veh->IsComponentPresent(doorNode)) { - CVector pos; -#ifdef FIX_BUGS - veh->GetComponentWorldPosition(doorNode, pos); -#else - veh->GetComponentWorldPosition(CAR_DOOR_LF, pos); -#endif - CParticle::AddYardieDoorSmoke(pos, veh->GetMatrix()); - } -} - -// wantedDoorNode = 0 means that func. will determine it -void -CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) -{ - uint32 optedDoorNode = wantedDoorNode; - bool teleportNeeded = false; - bool isLow = !!veh->bLowVehicle; - if (!veh->CanPedExitCar()) { - if (veh->pDriver && !veh->pDriver->IsPlayer()) { - veh->AutoPilot.m_nCruiseSpeed = 0; - veh->AutoPilot.m_nCarMission = MISSION_NONE; - } - return; - } - - if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) - return; - - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - if (wantedDoorNode == 0) { - optedDoorNode = CAR_DOOR_LF; - if (!veh->bIsBus) { - if (veh->pDriver == this) { - optedDoorNode = CAR_DOOR_LF; - } else if (veh->pPassengers[0] == this) { - optedDoorNode = CAR_DOOR_RF; - } else if (veh->pPassengers[1] == this) { - optedDoorNode = CAR_DOOR_LR; - } else if (veh->pPassengers[2] == this) { - optedDoorNode = CAR_DOOR_RR; - } else { - for (int i = 3; i < veh->m_nNumMaxPassengers; ++i) { - if (veh->pPassengers[i] == this) { - if (i & 1) - optedDoorNode = CAR_DOOR_RR; - else - optedDoorNode = CAR_DOOR_LR; - - break; - } - } - } - } - } - bool someoneExitsFromOurExitDoor = false; - bool someoneEntersFromOurExitDoor = false; - switch (optedDoorNode) { - case CAR_DOOR_RF: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RF) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_RR: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RR) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_LF: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LF) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_LR: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LR) - someoneExitsFromOurExitDoor = true; - break; - default: - break; - } - if (someoneEntersFromOurExitDoor && m_objective == OBJECTIVE_LEAVE_CAR) { - RestorePreviousObjective(); - return; - } - if (!someoneExitsFromOurExitDoor || m_nPedType == PEDTYPE_COP && veh->bIsBus) { - // Again, unused... - // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); - bool thereIsRoom = veh->IsRoomForPedToLeaveCar(optedDoorNode, nil); - if (veh->IsOnItsSide()) { - teleportNeeded = true; - } else if (!thereIsRoom) { - bool trySideSeat = false; - CPed *pedOnSideSeat = nil; - switch (optedDoorNode) { - case CAR_DOOR_RF: - if (veh->pDriver || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) { - pedOnSideSeat = veh->pDriver; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_LF; - - break; - case CAR_DOOR_RR: - if (veh->pPassengers[1] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { - pedOnSideSeat = veh->pPassengers[1]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_LR; - - break; - case CAR_DOOR_LF: - if (veh->pPassengers[0] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { - pedOnSideSeat = veh->pPassengers[0]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_RF; - - break; - case CAR_DOOR_LR: - if (veh->pPassengers[2] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { - pedOnSideSeat = (CPed*)veh->pPassengers[2]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_RR; - - break; - default: - break; - } - if (trySideSeat) { - if (!pedOnSideSeat || !IsPlayer() && CharCreatedBy != MISSION_CHAR) - return; - - switch (optedDoorNode) { - case CAR_DOOR_RF: - optedDoorNode = CAR_DOOR_LF; - break; - case CAR_DOOR_RR: - optedDoorNode = CAR_DOOR_LR; - break; - case CAR_DOOR_LF: - optedDoorNode = CAR_DOOR_RF; - break; - case CAR_DOOR_LR: - optedDoorNode = CAR_DOOR_RR; - break; - default: - break; - } - } - // ... - // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); - if (!veh->IsRoomForPedToLeaveCar(optedDoorNode, nil)) { - if (!IsPlayer() && CharCreatedBy != MISSION_CHAR) - return; - - teleportNeeded = true; - } - } - if (m_nPedState == PED_FLEE_POS) { - m_nLastPedState = PED_FLEE_POS; - m_nPrevMoveState = PEDMOVE_RUN; - SetMoveState(PEDMOVE_SPRINT); - } else { - m_nLastPedState = PED_IDLE; - m_nPrevMoveState = PEDMOVE_STILL; - SetMoveState(PEDMOVE_STILL); - } - - ReplaceWeaponWhenExitingVehicle(); - bUsesCollision = false; - m_pSeekTarget = veh; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = optedDoorNode; - m_nPedState = PED_EXIT_CAR; - if (m_pVehicleAnim && m_pVehicleAnim->flags & ASSOC_PARTIAL) - m_pVehicleAnim->blendDelta = -1000.0f; - SetMoveState(PEDMOVE_NONE); - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - RemoveInCarAnims(); - veh->AutoPilot.m_nCruiseSpeed = 0; - if (teleportNeeded) { - PedSetOutCarCB(nil, this); - - // This is same code with CPedPlacement::FindZCoorForPed, except we start from z + 1.5 and also check vehicles. - float zForPed; - float startZ = GetPosition().z - 100.0f; - float foundColZ = -100.0f; - float foundColZ2 = -100.0f; - CColPoint foundCol; - CEntity* foundEnt; - - CVector vec = GetPosition(); - vec.z += 1.5f; - - if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) - foundColZ = foundCol.point.z; - - // Adjust coords and do a second test - vec.x += 0.1f; - vec.y += 0.1f; - - if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) - foundColZ2 = foundCol.point.z; - - zForPed = Max(foundColZ, foundColZ2); - - if (zForPed > -99.0f) - GetMatrix().GetPosition().z = FEET_OFFSET + zForPed; - } else { - if (veh->GetUp().z > -0.8f) { - bool addDoorSmoke = false; - if (veh->GetModelIndex() == MI_YARDIE) - addDoorSmoke = true; - - switch (m_vehEnterType) { - case CAR_DOOR_RF: - if (veh->bIsBus) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); - } else { - if (isLow) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); - else - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); - - if (addDoorSmoke) - AddYardieDoorSmoke(veh, CAR_DOOR_RF); - } - break; - case CAR_DOOR_RR: - if (veh->bIsVan) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT); - } else if (isLow) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); - } else { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); - } - break; - case CAR_DOOR_LF: - if (veh->bIsBus) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); - } else { - if (isLow) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); - else - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); - - if (addDoorSmoke) - AddYardieDoorSmoke(veh, CAR_DOOR_LF); - } - break; - case CAR_DOOR_LR: - if (veh->bIsVan) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT_L); - } else if (isLow) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); - } else { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); - } - break; - default: - break; - } - if (!bBusJacked) { - switch (m_vehEnterType) { - case CAR_DOOR_RF: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RF; - break; - case CAR_DOOR_RR: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RR; - break; - case CAR_DOOR_LF: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF; - break; - case CAR_DOOR_LR: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LR; - break; - default: - break; - } - } - m_pVehicleAnim->SetFinishCallback(PedAnimStepOutCarCB, this); - } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS2); - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS); - } - m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); - } - } - bChangedSeat = false; - if (veh->bIsBus) - bRenderPedInCar = true; - - SetRadioStation(); - if (veh->pDriver == this) { - if (IsPlayer()) - veh->SetStatus(STATUS_PLAYER_DISABLED); - else - veh->SetStatus(STATUS_ABANDONED); - } - } -} - -void -CPed::ScanForInterestingStuff(void) -{ - if (!IsPedInControl()) - return; - - if (m_objective != OBJECTIVE_NONE) - return; - - if (CharCreatedBy == MISSION_CHAR) - return; - - LookForSexyPeds(); - LookForSexyCars(); - if (LookForInterestingNodes()) - return; - - if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - if (CGeneral::GetRandomNumber() % 100 >= 10) { - 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 { - int mostExpensiveVehAround = -1; - int bestMonetaryValue = 0; - - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->VehicleCreatedBy != MISSION_VEHICLE) { - if (veh->m_vecMoveSpeed.Magnitude() <= 0.1f && veh->IsVehicleNormal() - && veh->IsCar() && bestMonetaryValue < veh->pHandling->nMonetaryValue) { - mostExpensiveVehAround = i; - bestMonetaryValue = veh->pHandling->nMonetaryValue; - } - } - } - if (bestMonetaryValue > 2000 && mostExpensiveVehAround != -1 && vehicles[mostExpensiveVehAround]) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, vehicles[mostExpensiveVehAround]); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - return; - } - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } - } - - if (m_nPedState == PED_WANDER_PATH) { -#ifndef VC_PED_PORTS - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { - - // += 2 is weird - for (int i = 0; i < m_numNearPeds; i += 2) { - if (m_nearPeds[i]->m_nPedState == PED_WANDER_PATH && WillChat(m_nearPeds[i])) { - if (CGeneral::GetRandomNumberInRange(0, 100) >= 100) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - else { - if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() >= 1.8f) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - } else if (CanSeeEntity(m_nearPeds[i])) { - int time = CGeneral::GetRandomNumber() % 4000 + 10000; - SetChat(m_nearPeds[i], time); - m_nearPeds[i]->SetChat(this, time); - return; - } - } - } - } - } -#else - if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) >= 0.5f) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; - } else { - 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; - } - } - } - } - } -#endif - } - - // Parts below aren't there in VC, they're in somewhere else. - if (!CGame::noProstitutes && m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy != MISSION_CHAR - && m_objectiveTimer < CTimer::GetTimeInMilliseconds() && !CTheScripts::IsPlayerOnAMission()) { - - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->IsVehicleNormal()) { - if (veh->IsCar()) { - if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil)) { - SetObjective(OBJECTIVE_SOLICIT_VEHICLE, veh); - Say(SOUND_PED_SOLICIT); - return; - } - } - } - } - } - if (m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->GetModelIndex() == MI_MRWHOOP) { - if (veh->GetStatus() != STATUS_ABANDONED && veh->GetStatus() != STATUS_WRECKED) { - if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f) { - SetObjective(OBJECTIVE_BUY_ICE_CREAM, veh); - return; - } - } - } - } - } -} - -uint32 -CPed::ScanForThreats(void) -{ - int fearFlags = m_fearFlags; - CVector ourPos = GetPosition(); - float closestPedDist = 60.0f; - CVector2D explosionPos = GetPosition(); - if (fearFlags & PED_FLAG_EXPLOSION && CheckForExplosions(explosionPos)) { - m_eventOrThreat = explosionPos; - return PED_FLAG_EXPLOSION; - } + m_vecSeekPos.x = m_stPathNodeStates[m_nCurPathNode].x; + m_vecSeekPos.y = m_stPathNodeStates[m_nCurPathNode].y; + m_vecSeekPos.z = GetPosition().z; - CPed *shooter = nil; - if ((fearFlags & PED_FLAG_GUN) && (shooter = CheckForGunShots()) && (m_nPedType != shooter->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE)) { - if (!IsGangMember()) { - m_threatEntity = shooter; - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - return PED_FLAG_GUN; + // Mysterious code +/* int v4 = 0; + int maxNodeIndex = m_nPathNodes - 1; + if (maxNodeIndex > 0) { + if (maxNodeIndex > 8) { + while (v4 < maxNodeIndex - 8) + v4 += 8; } - if (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { - m_threatEntity = shooter; - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - return CPedType::GetFlag(shooter->m_nPedType); + while (v4 < maxNodeIndex) + v4++; + + } +*/ + if (Seek()) { + m_nCurPathNode++; + if (m_nCurPathNode == m_nPathNodes) + RestorePreviousState(); + } +} + +void +CPed::SetEvasiveStep(CEntity *reason, uint8 animType) +{ + AnimationId stepAnim; + + if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) + return; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float neededTurn = Abs(angleToFace - m_fRotationCur); + bool vehPressedHorn = false; + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + CVehicle *veh = (CVehicle*)reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) { + if (veh->m_nCarHornTimer != 0) { + vehPressedHorn = true; + if (!IsPlayer()) + animType = 1; } } + if (neededTurn <= DEGTORAD(90.0f) || veh->GetModelIndex() == MI_RCBANDIT || vehPressedHorn || animType != 0) { + SetLookFlag(veh, true); + if ((CGeneral::GetRandomNumber() & 1) && veh->GetModelIndex() != MI_RCBANDIT && animType == 0) { + stepAnim = ANIM_IDLE_TAXI; + } else { - CPed *deadPed = nil; - if (fearFlags & PED_FLAG_DEADPEDS && CharCreatedBy != MISSION_CHAR - && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < sq(20.0f)) { - m_pEventEntity = deadPed; - m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); - return PED_FLAG_DEADPEDS; + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + + // Let's turn our back to the "reason" + angleToFace += PI; + + if (angleToFace > PI) + angleToFace -= TWOPI; + + // We don't want to run towards car's direction + float dangerZone = angleToFace - vehDirection; + dangerZone = CGeneral::LimitRadianAngle(dangerZone); + + // So, add or subtract 90deg (jump to left/right) according to that + if (dangerZone > 0.0f) + angleToFace = vehDirection - HALFPI; + else + angleToFace = vehDirection + HALFPI; + + stepAnim = NUM_ANIMS; + if (animType == 0 || animType == 1) + stepAnim = ANIM_EV_STEP; + else if (animType == 2) + stepAnim = ANIM_HANDSCOWER; + } + if (!RpAnimBlendClumpGetAssociation(GetClump(), stepAnim)) { + CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, stepAnim, 8.0f); + stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + stepAssoc->SetFinishCallback(PedEvadeCB, this); + + if (animType == 0) + Say(SOUND_PED_EVADE); + + m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } + } +} + +void +CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) +{ + if (!IsPedInControl() || !bRespondsToThreats) + return; + + CAnimBlendAssociation *animAssoc; + float angleToFace, neededTurn; + bool handsUp = false; + + angleToFace = m_fRotationCur; + CVehicle *veh = (CVehicle*) reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR && veh->m_nCarHornTimer != 0 && !IsPlayer()) { + onlyRandomJump = true; + } + + if (onlyRandomJump) { + if (reason) { + // Simple version of my bug fix below. Doesn't calculate "danger zone", selects jump direction randomly. + // Also doesn't include random hands up, sound etc. Only used on player ped and peds running from gun shots. + + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + angleToFace = (CGeneral::GetRandomNumber() & 1) * PI + (-0.5f*PI) + vehDirection; + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + } } else { - uint32 flagsOfSomePed = 0; - - CPed *pedToFearFrom = nil; -#ifndef VC_PED_PORTS - for (int i = 0; i < m_numNearPeds; i++) { - if (CharCreatedBy != RANDOM_CHAR || m_nearPeds[i]->CharCreatedBy != MISSION_CHAR || m_nearPeds[i]->IsPlayer()) { - CPed *nearPed = m_nearPeds[i]; - - // BUG: WTF Rockstar?! Putting this here will result in returning the flags of farthest ped to us, since m_nearPeds is sorted by distance. - // Fixed at the bottom of the function. - flagsOfSomePed = CPedType::GetFlag(nearPed->m_nPedType); - - if (CPedType::GetFlag(nearPed->m_nPedType) & fearFlags) { - if (nearPed->m_fHealth > 0.0f && OurPedCanSeeThisOne(m_nearPeds[i])) { - // FIX: Taken from VC -#ifdef FIX_BUGS - float nearPedDistSqr = (nearPed->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float nearPedDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); -#endif - if (sq(closestPedDist) > nearPedDistSqr) { - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } - } + if (IsPlayer()) { + ((CPlayerPed*)this)->m_nEvadeAmount = 5; + ((CPlayerPed*)this)->m_pEvadingFrom = reason; + reason->RegisterReference((CEntity**) &((CPlayerPed*)this)->m_pEvadingFrom); + return; } -#else - bool weSawOurEnemy = false; - bool weMaySeeOurEnemy = false; - float closestEnemyDist = 60.0f; - if ((CTimer::GetFrameCounter() + (uint8)m_randomSeed + 16) & 4) { - for (int i = 0; i < m_numNearPeds; ++i) { - if (CharCreatedBy == RANDOM_CHAR && m_nearPeds[i]->CharCreatedBy == MISSION_CHAR && !m_nearPeds[i]->IsPlayer()) { - continue; - } + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - // BUG: Explained at the same occurence of this bug above. Fixed at the bottom of the function. - flagsOfSomePed = CPedType::GetFlag(m_nearPeds[i]->m_nPedType); - - if (flagsOfSomePed & fearFlags) { - if (m_nearPeds[i]->m_fHealth > 0.0f) { - - // VC also has ability to include objects to line of sight check here (via last bit of flagsL) - if (OurPedCanSeeThisOne(m_nearPeds[i])) { - if (m_nearPeds[i]->m_nPedState == PED_ATTACK) { - if (m_nearPeds[i]->m_pedInObjective == this) { - - float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestEnemyDist) > enemyDistSqr) { - float enemyDist = Sqrt(enemyDistSqr); - weSawOurEnemy = true; - closestPedDist = enemyDist; - closestEnemyDist = enemyDist; - pedToFearFrom = m_nearPeds[i]; - } - } - } else { - float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestPedDist) > nearPedDistSqr && !weSawOurEnemy) { - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } else if (!weSawOurEnemy) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed->m_nPedState == PED_ATTACK) { - CColPoint foundCol; - CEntity *foundEnt; - - // We don't see him yet but he's behind a ped, vehicle or object - // VC also has ability to include objects to line of sight check here (via last bit of flagsL) - if (!CWorld::ProcessLineOfSight(ourPos, nearPed->GetPosition(), foundCol, foundEnt, - true, false, false, false, false, false, false)) { - - if (nearPed->m_pedInObjective == this) { - float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestEnemyDist) > enemyDistSqr) { - float enemyDist = Sqrt(enemyDistSqr); - weMaySeeOurEnemy = true; - closestPedDist = enemyDist; - closestEnemyDist = enemyDist; - pedToFearFrom = m_nearPeds[i]; - } - } else if (!nearPed->GetWeapon()->IsTypeMelee() && !weMaySeeOurEnemy) { - float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestPedDist) > nearPedDistSqr) { - weMaySeeOurEnemy = true; - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } - } - } - } - } - } - } -#endif - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(ourPos, 20.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle* foundVeh = nil; - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - - CPed *driver = nearVeh->pDriver; - if (driver) { - - // BUG: Same bug as above. Fixed at the bottom of function. - flagsOfSomePed = CPedType::GetFlag(driver->m_nPedType); - if (CPedType::GetFlag(driver->m_nPedType) & fearFlags) { - if (driver->m_fHealth > 0.0f && OurPedCanSeeThisOne(nearVeh->pDriver)) { - // FIX: Taken from VC + // FIX: Peds no more dive into cars. Taken from SetEvasiveStep, last if statement inverted #ifdef FIX_BUGS - float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); -#endif - if (sq(closestPedDist) > driverDistSqr) { - closestPedDist = Sqrt(driverDistSqr); - pedToFearFrom = nearVeh->pDriver; - } - } - } - } - } - m_threatEntity = pedToFearFrom; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); -#ifdef FIX_BUGS - if (pedToFearFrom) - flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); + // Let's turn our back to the "reason" + angleToFace += PI; + + if (angleToFace > PI) + angleToFace -= 2 * PI; + + // We don't want to dive towards car's direction + float dangerZone = angleToFace - vehDirection; + dangerZone = CGeneral::LimitRadianAngle(dangerZone); + + // So, add or subtract 90deg (jump to left/right) according to that + if (dangerZone > 0.0f) + angleToFace = 0.5f * PI + vehDirection; else - flagsOfSomePed = 0; + angleToFace = vehDirection - 0.5f * PI; #endif - return flagsOfSomePed; + neededTurn = Abs(angleToFace - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = 2 * PI - neededTurn; + + if (neededTurn <= 0.5f*PI) { + if (CGeneral::GetRandomNumber() & 1) + handsUp = true; + } else { + if (CGeneral::GetRandomNumber() & 7) + return; + } + Say(SOUND_PED_EVADE); } + + if (handsUp || !IsPlayer() && m_pedStats->m_flags & STAT_NO_DIVE) { + m_fRotationCur = angleToFace; + ClearLookFlag(); + ClearAimFlag(); + SetLookFlag(reason, true); + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP); + if (animAssoc) + return; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP, 8.0f); + animAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + animAssoc->SetFinishCallback(PedEvadeCB, this); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } else { + m_fRotationCur = angleToFace; + ClearLookFlag(); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_DIVE_AWAY; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_EV_DIVE, 8.0f); + animAssoc->SetFinishCallback(PedEvadeCB, this); + } + + if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) { + if (veh->pDriver && veh->pDriver->IsPlayer()) { + CWanted *wanted = FindPlayerPed()->m_pWanted; + wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); + wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (uintptr)this, false); + } + } +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + else if (reason->IsVehicle()) { + if (veh->pDriver && veh->pDriver->IsPlayer()) { + CWanted* wanted = FindPlayerPed()->m_pWanted; + wanted->RegisterCrime(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); + } + } +#endif +} + +void +CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + if (!animAssoc) { + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); + + } else if (animAssoc->animId == ANIM_EV_DIVE) { + ped->bUpdateAnimHeading = true; + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY) + { + ped->m_getUpTimer = CTimer::GetTimeInMilliseconds() + 1; + ped->m_nPedState = PED_FALL; + } + animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + + } else if (animAssoc->flags & ASSOC_FADEOUTWHENDONE) { + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); + + } else if (ped->m_nPedState != PED_ARRESTED) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (animAssoc->blendDelta >= 0.0f) + animAssoc->blendDelta = -4.0f; + + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) { + ped->RestorePreviousState(); + } + } +} + +void +CPed::SetDie(AnimationId animId, float delta, float speed) +{ + CPlayerPed *player = FindPlayerPed(); + if (player == this) { + if (!player->m_bCanBeDamaged) + return; + } + + m_threatEntity = nil; + if (DyingOrDead()) + return; + + if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) + delta *= 0.5f; + + SetStoredState(); + ClearAll(); + m_fHealth = 0.0f; + if (m_nPedState == PED_DRIVING) { + if (!IsPlayer()) + FlagToDestroyWhenNextProcessed(); + } else if (bInVehicle) { + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; + } else if (EnteringCar()) { + QuitEnteringCar(); + } + + m_nPedState = PED_DIE; + if (animId == NUM_ANIMS) { + bIsPedDieAnimPlaying = false; + } else { + CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, delta); + if (speed > 0.0f) + dieAssoc->speed = speed; + + dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + if (dieAssoc->IsRunning()) { + dieAssoc->SetFinishCallback(FinishDieAnimCB, this); + bIsPedDieAnimPlaying = true; + } + } + + Say(SOUND_PED_DEATH); + if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) + QuitEnteringCar(); + if (!bInVehicle) + StopNonPartialAnims(); + + m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); +} + +void +CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (ped->bIsPedDieAnimPlaying) + ped->bIsPedDieAnimPlaying = false; +} + +void +CPed::SetDead(void) +{ + bUsesCollision = false; + + m_fHealth = 0.0f; + if (m_nPedState == PED_DRIVING) + bIsVisible = false; + + m_nPedState = PED_DEAD; + m_pVehicleAnim = nil; + m_pCollidingEntity = nil; + + CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weapon->m_nModelId); + + m_currentWeapon = WEAPONTYPE_UNARMED; + CEventList::RegisterEvent(EVENT_INJURED_PED, EVENT_ENTITY_PED, this, nil, 250); + if (this != FindPlayerPed()) { + CreateDeadPedWeaponPickups(); + CreateDeadPedMoney(); + } + + m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); + m_deadBleeding = false; + bDoBloodyFootprints = false; + bVehExitWillBeInstant = false; + CEventList::RegisterEvent(EVENT_DEAD_PED, EVENT_ENTITY_PED, this, nil, 1000); +} + +void +CPed::Die(void) +{ + // UNUSED: This is a perfectly empty function. +} + +void +CPed::SetChat(CEntity *chatWith, uint32 time) +{ + if(m_nPedState != PED_CHAT) + SetStoredState(); + + m_nPedState = PED_CHAT; + SetMoveState(PEDMOVE_STILL); +#if defined VC_PED_PORTS || defined FIX_BUGS + m_lookTimer = 0; +#endif + SetLookFlag(chatWith, true); + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; +} + +void +CPed::Chat(void) +{ + // We're already looking to our partner + if (bIsLooking && TurnBody()) + ClearLookFlag(); + + if (!m_pLookTarget || !m_pLookTarget->IsPed()) { + ClearChat(); + return; + } + + CPed *partner = (CPed*) m_pLookTarget; + + if (partner->m_nPedState != PED_CHAT) { + ClearChat(); + if (partner->m_pedInObjective) { + if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || + partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) + ReactToAttack(partner->m_pedInObjective); + } + return; + } + if (bIsTalking) { + if (CGeneral::GetRandomNumber() < 512) { + CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (chatAssoc) { + chatAssoc->blendDelta = -4.0f; + chatAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + bIsTalking = false; + } else + Say(SOUND_PED_CHAT); + + } else { + + if (CGeneral::GetRandomNumber() < 20 && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + } + if (!bIsTalking && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { + CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); + float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); + chatAssoc->SetCurrentTime(chatTime); + + bIsTalking = true; + Say(SOUND_PED_CHAT); + } + } + if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + ClearChat(); + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + } +} + +void +CPed::ClearChat(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + bIsTalking = false; + ClearLookFlag(); + RestorePreviousState(); +} + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE +void +ReportPhonePickUpCB(CAnimBlendAssociation* assoc, void* arg) +{ + CPed* ped = (CPed*)arg; + ped->m_nMoveState = PEDMOVE_STILL; + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); + + if (assoc->blendAmount > 0.5f && ped) { + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); + } +} + +void +ReportPhonePutDownCB(CAnimBlendAssociation* assoc, void* arg) +{ + assoc->flags |= ASSOC_DELETEFADEDOUT; + assoc->blendDelta = -1000.0f; + CPed* ped = (CPed*)arg; + + if (ped->m_phoneId != -1 && crimeReporters[ped->m_phoneId] == ped) { + crimeReporters[ped->m_phoneId] = nil; + gPhoneInfo.m_aPhones[ped->m_phoneId].m_nState = PHONE_STATE_FREE; + ped->m_phoneId = -1; + } + + if (assoc->blendAmount > 0.5f) + ped->bUpdateAnimHeading = true; + + ped->SetWanderPath(CGeneral::GetRandomNumber() & 7); +} +#endif + +bool +CPed::FacePhone(void) +{ + // This function was broken since it's left unused early in development. +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, GetPosition().y); + + if (m_facePhoneStart) { + m_lookTimer = 0; + SetLookFlag(phoneDir, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_facePhoneStart = false; + } + + if (bIsLooking && TurnBody()) { + ClearLookFlag(); + SetIdle(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + CAnimBlendAssociation* assoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_IN, 4.0f); + assoc->SetFinishCallback(ReportPhonePickUpCB, this); + return true; + } + + return false; +#else + float currentRot = RADTODEG(m_fRotationCur); + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, + GetPosition().y); + + SetLookFlag(phoneDir, false); + phoneDir = CGeneral::LimitAngle(phoneDir); + m_moved = CVector2D(0.0f, 0.0f); + + if (currentRot - 180.0f > phoneDir) + phoneDir += 2 * 180.0f; + else if (180.0f + currentRot < phoneDir) + phoneDir -= 2 * 180.0f; + + float neededTurn = currentRot - phoneDir; + + if (Abs(neededTurn) <= 0.75f) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + return true; + } else { + m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); + return false; + } +#endif +} +bool +CPed::MakePhonecall(void) +{ +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { + + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), + (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (uintptr)m_threatEntity : (uintptr)m_victimOfPlayerCrime), false); + + if (m_crimeToReportOnPhone != CRIME_POSSESSION_GUN) + FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1); + + bRunningToPhone = false; + } +#endif + if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) + return false; + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + CAnimBlendAssociation* talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_PHONE_TALK); + if (talkAssoc && talkAssoc->blendAmount > 0.5f) { + CAnimBlendAssociation* endAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_OUT, 8.0f); + endAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + endAssoc->SetFinishCallback(ReportPhonePutDownCB, this); + } +#endif + SetIdle(); + + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; +#ifndef PEDS_REPORT_CRIMES_ON_PHONE + m_phoneId = -1; +#endif + + // Because SetWanderPath is now done async in ReportPhonePutDownCB +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + return false; +#else + return true; +#endif +} + +void +CPed::Teleport(CVector pos) +{ + CWorld::Remove(this); + SetPosition(pos); + bIsStanding = false; + m_nPedStateTimer = 0; + m_actionX = 0.0f; + m_actionY = 0.0f; + m_pDamageEntity = nil; + CWorld::Add(this); +} + +void +CPed::SetSeekCar(CVehicle *car, uint32 doorNode) +{ + if (m_nPedState == PED_SEEK_CAR) + return; + +#ifdef VC_PED_PORTS + if (!CanSetPedState() || m_nPedState == PED_DRIVING) + return; +#endif + + SetStoredState(); + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_carInObjective = car; + m_carInObjective->RegisterReference((CEntity**) &m_carInObjective); + m_pMyVehicle = car; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + // m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_distanceToCountSeekDone = 0.5f; + m_nPedState = PED_SEEK_CAR; + } void @@ -16006,488 +6826,104 @@ CPed::SeekCar(void) } } -void -CPed::StartFightDefend(uint8 direction, uint8 hitLevel, uint8 unk) +bool +CPed::CheckForExplosions(CVector2D &area) { - if (m_nPedState == PED_DEAD) { - if (CGame::nastyGame) { - if (hitLevel == HITLEVEL_GROUND) { - CAnimBlendAssociation *floorHitAssoc; - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) { - floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f); - } else { - floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[FIGHTMOVE_HITONFLOOR].animId, 8.0f); - } - if (floorHitAssoc) { - floorHitAssoc->SetCurrentTime(0.0f); - floorHitAssoc->SetRun(); - floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - } - } - if (CGame::nastyGame) { - CVector headPos = GetNodePosition(PED_HEAD); - for(int i = 0; i < 4; ++i) { - CVector bloodDir(0.0f, 0.0f, 0.1f); - CVector bloodPos = headPos - 0.2f * GetForward(); - CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); - } - } + int event = 0; + if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEntity *actualEntity = nil; + + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + actualEntity = CPools::GetPed(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_VEHICLE: + actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_OBJECT: + actualEntity = CPools::GetObject(gaEvent[event].entityRef); + break; + default: + break; } - } else if (m_nPedState == PED_FALL) { - if (hitLevel == HITLEVEL_GROUND && !IsPedHeadAbovePos(-0.3f)) { - CAnimBlendAssociation *floorHitAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL) ? - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f) : - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f); - if (floorHitAssoc) { - floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - floorHitAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - } else if (IsPedInControl()) { - if ((IsPlayer() && m_nPedState != PED_FIGHT && ((CPlayerPed*)this)->m_fMoveSpeed > 1.0f) - || (!IsPlayer() && m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE)) { -#ifndef VC_PED_PORTS - if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 3) && CGeneral::GetRandomNumber() & 7) { - if (IsPlayer() || CGeneral::GetRandomNumber() & 3) { -#else - if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 1) && CGeneral::GetRandomNumber() & 7) { - if (IsPlayer() || CGeneral::GetRandomNumber() & 1) { -#endif - AnimationId shotAnim; - switch (direction) { - case 1: - shotAnim = ANIM_SHOT_LEFT_PARTIAL; - break; - case 2: - shotAnim = ANIM_SHOT_BACK_PARTIAL; - break; - case 3: - shotAnim = ANIM_SHOT_RIGHT_PARTIAL; - break; - default: - shotAnim = ANIM_SHOT_FRONT_PARTIAL; - break; - } - CAnimBlendAssociation *shotAssoc = RpAnimBlendClumpGetAssociation(GetClump(), shotAnim); - if (!shotAssoc || shotAssoc->blendDelta < 0.0f) - shotAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, shotAnim, 8.0f); - shotAssoc->SetCurrentTime(0.0f); - shotAssoc->SetRun(); - shotAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } else { - int time = CGeneral::GetRandomNumberInRange(1000, 3000); - SetWaitState(WAITSTATE_PLAYANIM_DUCK, &time); - } - } else { -#ifndef VC_PED_PORTS - switch (direction) { - case 1: - SetFall(500, ANIM_KO_SPIN_R, false); - break; - case 2: - SetFall(500, ANIM_KO_SKID_BACK, false); - break; - case 3: - SetFall(500, ANIM_KO_SPIN_L, false); - break; - default: - SetFall(500, ANIM_KO_SHOT_STOM, false); - break; - } -#else - bool fall = true; - AnimationId hitAnim; - switch (direction) { - case 1: - hitAnim = ANIM_KO_SPIN_R; - break; - case 2: - if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_BACK; - } else { - hitAnim = ANIM_KO_SKID_BACK; - } - break; - case 3: - hitAnim = ANIM_KO_SPIN_L; - break; - default: - if (hitLevel == HITLEVEL_LOW) { - hitAnim = ANIM_KO_SHOT_STOM; - } else if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_WALK; - } else if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_HEAD; - } else { - hitAnim = ANIM_KO_SHOT_FACE; - } - break; - } - if (fall) { - SetFall(500, hitAnim, false); - } else { - CAnimBlendAssociation *hitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), hitAnim); - if (!hitAssoc || hitAssoc->blendDelta < 0.0f) - hitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, hitAnim, 8.0f); + if (actualEntity) { + m_pEventEntity = actualEntity; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + bGonnaInvestigateEvent = true; + } else + bGonnaInvestigateEvent = false; - hitAssoc->SetCurrentTime(0.0f); - hitAssoc->SetRun(); - hitAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } -#endif - } - Say(SOUND_PED_DEFEND); - } else { - Say(SOUND_PED_DEFEND); - switch (hitLevel) { - case HITLEVEL_GROUND: - m_curFightMove = FIGHTMOVE_HITONFLOOR; - break; - case HITLEVEL_LOW: -#ifndef VC_PED_PORTS - if (direction == 2) { - SetFall(1000, ANIM_KO_SKID_BACK, false); - return; - } -#else - if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) { - SetFall(1000, ANIM_KO_SKID_BACK, false); - return; - } else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) { - SetFall(1000, ANIM_KO_SHOT_STOM, false); - return; - } -#endif - m_curFightMove = FIGHTMOVE_HITBODY; - break; - case HITLEVEL_HIGH: - switch (direction) { - case 1: - m_curFightMove = FIGHTMOVE_HITLEFT; - break; - case 2: - m_curFightMove = FIGHTMOVE_HITBACK; - break; - case 3: - m_curFightMove = FIGHTMOVE_HITRIGHT; - break; - default: - if (unk <= 5) - m_curFightMove = FIGHTMOVE_HITHEAD; - else - m_curFightMove = FIGHTMOVE_HITBIGSTEP; - break; - } - break; - default: - switch (direction) { - case 1: - m_curFightMove = FIGHTMOVE_HITLEFT; - break; - case 2: - m_curFightMove = FIGHTMOVE_HITBACK; - break; - case 3: - m_curFightMove = FIGHTMOVE_HITRIGHT; - break; - default: - if (unk <= 5) - m_curFightMove = FIGHTMOVE_HITCHEST; - else - m_curFightMove = FIGHTMOVE_HITBIGSTEP; - break; - } - break; - } - if (m_nPedState == PED_GETUP && !IsPedHeadAbovePos(0.0f)) - m_curFightMove = FIGHTMOVE_HITONFLOOR; - - if (m_nPedState == PED_FIGHT) { - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); - moveAssoc->SetCurrentTime(0.0f); - moveAssoc->SetFinishCallback(FinishFightMoveCB, this); - if (IsPlayer()) - moveAssoc->speed = 1.3f; - - m_takeAStepAfterAttack = 0; - m_fightButtonPressure = 0; - } else if (IsPlayer() && m_currentWeapon != WEAPONTYPE_UNARMED) { - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); - moveAssoc->SetCurrentTime(0.0f); - moveAssoc->speed = 1.3f; - } else { - if (m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK) - SetStoredState(); - - if (m_nWaitState != WAITSTATE_FALSE) { - m_nWaitState = WAITSTATE_FALSE; - RestoreHeadingRate(); - } - m_nPedState = PED_FIGHT; - m_fightButtonPressure = 0; - RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); - CAnimBlendAssociation *walkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START); - if (walkStartAssoc) { - walkStartAssoc->flags |= ASSOC_DELETEFADEDOUT; - walkStartAssoc->blendDelta = -1000.0f; - } - CAnimBlendAssociation *walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - if (!walkStopAssoc) - walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); - if (walkStopAssoc) { - walkStopAssoc->flags |= ASSOC_DELETEFADEDOUT; - walkStopAssoc->blendDelta = -1000.0f; - RestoreHeadingRate(); - } - SetMoveState(PEDMOVE_NONE); - m_nStoredMoveState = PEDMOVE_NONE; - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f; - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); - moveAssoc->SetFinishCallback(FinishFightMoveCB, this); - m_fightState = FIGHTSTATE_NO_MOVE; - m_takeAStepAfterAttack = false; - bIsAttacking = true; - } - } + CEventList::ClearEvent(event); + return true; + } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEventList::ClearEvent(event); + bGonnaInvestigateEvent = false; + return true; } + + bGonnaInvestigateEvent = false; + return false; } -void -CPed::UpdateFromLeader(void) +CPed * +CPed::CheckForGunShots(void) { - if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) - return; - - if (!m_leader) - return; - - CVector leaderDist; - if (m_leader->InVehicle()) - leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); - else - leaderDist = m_leader->GetPosition() - GetPosition(); - - if (leaderDist.Magnitude() > 30.0f) { - if (IsPedInControl()) { - SetObjective(OBJECTIVE_NONE); - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - SetLeader(nil); - return; - } - - if (IsPedInControl()) { - if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) - WarpPedToNearLeaderOffScreen(); - - if (m_leader->m_nPedState == PED_DEAD) { - SetLeader(nil); - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - return; - } - if (!m_leader->bInVehicle) { - if (m_leader->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (bInVehicle) { - if (m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT && m_objective != OBJECTIVE_LEAVE_CAR) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - - return; - } - if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - RestorePreviousObjective(); - RestorePreviousState(); - } - } - if (m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy == RANDOM_CHAR) { - SetLeader(nil); - return; - } - } - if (bInVehicle || !m_leader->bInVehicle || m_leader->m_nPedState != PED_DRIVING) { - if (m_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; - } - } 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) { -#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_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); - } else { - SetObjective(OBJECTIVE_NONE); - } -#endif - } - if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { - if (ScanForThreats() && m_threatEntity) { - m_pLookTarget = m_threatEntity; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { - m_pPointGunAt = m_threatEntity; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); - SetAttack(m_threatEntity); - } - } - } - } - } - } 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); - } - } - } else if (bInVehicle) { - if ((!m_leader->bInVehicle || m_leader->m_nPedState == PED_EXIT_CAR) && m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { - - switch (m_leader->m_objective) { - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_pMyVehicle == m_leader->m_pMyVehicle || m_pMyVehicle == m_leader->m_carInObjective) - break; - - // fall through - default: - if (m_pMyVehicle && m_objective != OBJECTIVE_LEAVE_CAR) { -#ifdef VC_PED_PORTS - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 250; -#endif - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - - break; - } + int event; + if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { + if (gaEvent[event].entityType == EVENT_ENTITY_PED) { + // Probably due to we don't want peds to go gunshot area? (same on VC) + bGonnaInvestigateEvent = false; + return CPools::GetPed(gaEvent[event].entityRef); } } + bGonnaInvestigateEvent = false; + return nil; } -void -CPed::UpdatePosition(void) +CPed * +CPed::CheckForDeadPeds(void) { - if (CReplay::IsPlayingBack() || !bIsStanding) - return; - - CVector2D velocityChange; - - SetHeading(m_fRotationCur); - if (m_pCurrentPhysSurface) { - CVector2D velocityOfSurface; - 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(); - offsetToSurface.z -= FEET_OFFSET; - - CVector surfaceMoveVelocity = curSurface->m_vecMoveSpeed; - CVector surfaceTurnVelocity = CrossProduct(curSurface->m_vecTurnSpeed, offsetToSurface); - - // Also we use that weird formula instead of friction if it's boat - float slideMult = -curSurface->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); - } - // 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 { - // 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()); - - velocityChange = 0.02f * reactionForce + m_moved; - - float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); - // they're in same direction - if (reactionAndVelocityDotProd < 0.0f) { - velocityChange -= reactionAndVelocityDotProd * reactionForce; + 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); } } - - // 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 { - changeMult = 0.002f * CTimer::GetTimeStep(); - } + bGonnaInvestigateEvent = false; + return nil; +} - if (speedChange > changeMult) { - velocityChange = velocityChange * (changeMult / speedChange); - } - } - m_vecMoveSpeed.x += velocityChange.x; - m_vecMoveSpeed.y += velocityChange.y; +bool +CPed::IsPlayer(void) const +{ + return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType == PEDTYPE_PLAYER2 || + m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; +} + +bool +CPed::IsGangMember(void) const +{ + return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; +} + +bool +CPed::IsPointerValid(void) +{ + int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; + if (pedIndex < 0 || pedIndex >= NUMPEDS) + return false; + + if (m_entryInfoList.first || FindPlayerPed() == this) + return true; + + return false; } void @@ -16551,7 +6987,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; @@ -16564,109 +7000,1283 @@ CPed::SetPedPositionInCar(void) GetMatrix() = newMat; } -static RwObject* -CloneAtomicToFrameCB(RwObject *frame, void *data) +void +CPed::LookForSexyPeds(void) { - RpAtomic *newAtomic = RpAtomicClone((RpAtomic*)frame); - RpAtomicSetFrame(newAtomic, (RwFrame*)data); - RpClumpAddAtomic(flyingClumpTemp, newAtomic); - CVisibilityPlugins::SetAtomicRenderCallback(newAtomic, nil); - return frame; + if ((!IsPedInControl() && m_nPedState != PED_DRIVING) + || m_lookTimer >= CTimer::GetTimeInMilliseconds() || m_nPedType != PEDTYPE_CIVMALE) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + if (CanSeeEntity(m_nearPeds[i])) { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 10.0f) { + CPed *nearPed = m_nearPeds[i]; + if ((nearPed->m_pedStats->m_sexiness > m_pedStats->m_sexiness) + && nearPed->m_nPedType == PEDTYPE_CIVFEMALE) { + + SetLookFlag(nearPed, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + Say(SOUND_PED_CHAT_SEXY); + return; + } + } + } + } + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; } -static RwFrame* -RecurseFrameChildrenToCloneCB(RwFrame *frame, void *data) +void +CPed::LookForSexyCars(void) { - RwFrame *newFrame = RwFrameCreate(); - RwFrameAddChild((RwFrame*)data, newFrame); - RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE); - RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame); - RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame); - return newFrame; + CEntity *vehicles[8]; + CVehicle *veh; + int foundVehId = 0; + int bestPriceYet = 0; + int16 lastVehicle; + + if (!IsPedInControl() && m_nPedState != PED_DRIVING) + return; + + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + CWorld::FindObjectsInRange(GetPosition(), 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int vehId = 0; vehId < lastVehicle; vehId++) { + veh = (CVehicle*)vehicles[vehId]; + if (veh != m_pMyVehicle && bestPriceYet < veh->pHandling->nMonetaryValue) { + foundVehId = vehId; + bestPriceYet = veh->pHandling->nMonetaryValue; + } + } + if (lastVehicle > 0 && bestPriceYet > 40000) + SetLookFlag(vehicles[foundVehId], false); + + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; + } } -CObject* -CPed::SpawnFlyingComponent(int pedNode, int8 direction) +bool +CPed::LookForInterestingNodes(void) { - if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) - return nil; + CBaseModelInfo *model; + CPtrNode *ptrNode; + CVector effectDist; + C2dEffect *effect; + CMatrix *objMat; -#ifdef PED_SKIN - assert(!IsClumpSkinned(GetClump())); + if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { + return false; + } + bool found = false; + uint8 randVal = CGeneral::GetRandomNumber() % 256; + + int minX = CWorld::GetSectorIndexX(GetPosition().x - CHECK_NEARBY_THINGS_MAX_DIST); + if (minX < 0) minX = 0; + int minY = CWorld::GetSectorIndexY(GetPosition().y - CHECK_NEARBY_THINGS_MAX_DIST); + if (minY < 0) minY = 0; + int maxX = CWorld::GetSectorIndexX(GetPosition().x + CHECK_NEARBY_THINGS_MAX_DIST); +#ifdef FIX_BUGS + if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1; +#else + if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; #endif - CObject *obj = new CObject(); - if (!obj) - return nil; + int maxY = CWorld::GetSectorIndexY(GetPosition().y + CHECK_NEARBY_THINGS_MAX_DIST); +#ifdef FIX_BUGS + if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1; +#else + if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y; +#endif - RwFrame *frame = RwFrameCreate(); - RpClump *clump = RpClumpCreate(); - RpClumpSetFrame(clump, frame); - RwMatrix *matrix = RwFrameGetLTM(m_pFrames[pedNode]->frame); - *RwFrameGetMatrix(frame) = *matrix; + for (int curY = minY; curY <= maxY && !found; curY++) { + for (int curX = minX; curX <= maxX && !found; curX++) { + CSector *sector = CWorld::GetSector(curX, curY); - flyingClumpTemp = clump; - RwFrameForAllObjects(m_pFrames[pedNode]->frame, CloneAtomicToFrameCB, frame); - RwFrameForAllChildren(m_pFrames[pedNode]->frame, RecurseFrameChildrenToCloneCB, frame); - flyingClumpTemp = nil; - switch (pedNode) { - case PED_HEAD: - // So popping head would have wheel collision. They disabled it anyway - obj->SetModelIndexNoCreate(MI_CAR_WHEEL); + for (ptrNode = sector->m_lists[ENTITYLIST_VEHICLES].first; ptrNode && !found; ptrNode = ptrNode->next) { + CVehicle *veh = (CVehicle*)ptrNode->item; + model = veh->GetModelInfo(); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &veh->GetMatrix(); + CVector effectPos = veh->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_OBJECTS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CObject *obj = (CObject*)ptrNode->item; + model = CModelInfo::GetModelInfo(obj->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &obj->GetMatrix(); + CVector effectPos = obj->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding *building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + CVector effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding *building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + CVector effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + } + } + + if (!found) + return false; + + CVector effectFrontLocal = Multiply3x3(*objMat, effect->attractor.dir); + float angleToFace = CGeneral::GetRadianAngleBetweenPoints(effectFrontLocal.x, effectFrontLocal.y, 0.0f, 0.0f); + randVal = CGeneral::GetRandomNumber() % 256; + if (randVal <= m_randomSeed % 256) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + SetLookFlag(angleToFace, true); + SetLookTimer(1000); + return false; + } + + CVector2D effectPos = *objMat * effect->pos; + switch (effect->attractor.type) { + case ATTRACTORTYPE_ICECREAM: + SetInvestigateEvent(EVENT_ICECREAM, effectPos, 0.1f, 15000, angleToFace); break; - case PED_UPPERARML: - case PED_UPPERARMR: - obj->SetModelIndexNoCreate(MI_BODYPARTB); - obj->SetCenterOfMass(0.25f, 0.0f, 0.0f); + case ATTRACTORTYPE_STARE: + SetInvestigateEvent(EVENT_SHOPSTALL, effectPos, 1.0f, + CGeneral::GetRandomNumberInRange(8000, 10 * effect->attractor.probability + 8500), + angleToFace); break; - case PED_UPPERLEGL: - case PED_UPPERLEGR: - obj->SetModelIndexNoCreate(MI_BODYPARTA); - obj->SetCenterOfMass(0.4f, 0.0f, 0.0f); + default: + return true; + } + return true; +} + +void +CPed::SetWaitState(eWaitState state, void *time) +{ + AnimationId waitAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + + if (!IsPedInControl()) + return; + + if (state != m_nWaitState) + FinishedWaitCB(nil, this); + + switch (state) { + case WAITSTATE_TRAFFIC_LIGHTS: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; + SetMoveState(PEDMOVE_STILL); + break; + case WAITSTATE_CROSS_ROAD: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); + break; + case WAITSTATE_CROSS_ROAD_LOOK: + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f); + + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000); + + break; + case WAITSTATE_LOOK_PED: + case WAITSTATE_LOOK_SHOP: + case WAITSTATE_LOOK_ACCIDENT: + case WAITSTATE_FACEOFF_GANG: + break; + case WAITSTATE_DOUBLEBACK: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + break; + case WAITSTATE_HITWALL: + m_headingRate = 2.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f); + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + } + break; + case WAITSTATE_TURN180: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this); + break; + case WAITSTATE_SURPRISE: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + break; + case WAITSTATE_STUCK: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + } + break; + case WAITSTATE_LOOK_ABOUT: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + + break; + case WAITSTATE_PLAYANIM_COWER: + waitAnim = ANIM_HANDSCOWER; + case WAITSTATE_PLAYANIM_HANDSUP: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSUP; + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSCOWER; + m_headingRate = 0.0f; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_PLAYANIM_DUCK: + waitAnim = ANIM_DUCK_DOWN; + case WAITSTATE_PLAYANIM_TAXI: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_TAXI; + case WAITSTATE_PLAYANIM_CHAT: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_CHAT; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); + animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_FINISH_FLEE: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + break; + default: + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; + } + m_nWaitState = state; +} + +void +CPed::Wait(void) +{ + AnimationId mustHaveAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + CPed *pedWeLook; + + if (DyingOrDead()) { + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; + } + + switch (m_nWaitState) { + + case WAITSTATE_TRAFFIC_LIGHTS: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + } + } + break; + + case WAITSTATE_CROSS_ROAD: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer) + m_nWaitState = WAITSTATE_FALSE; + else + SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil); + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_CROSS_ROAD_LOOK: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_DOUBLEBACK: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + uint32 timeLeft = m_nWaitTimer - CTimer::GetTimeInMilliseconds(); + if (timeLeft < 2500 && timeLeft > 2000) { + m_nWaitTimer -= 500; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + } + } else { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + } + break; + + case WAITSTATE_HITWALL: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; + } + } else { + m_nWaitState = WAITSTATE_FALSE; + } + break; + + case WAITSTATE_TURN180: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + m_fRotationCur = m_fRotationCur + PI; + if (m_nPedState == PED_INVESTIGATE) + ClearInvestigateEvent(); + } + + if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; + } + break; + + case WAITSTATE_SURPRISE: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HIT_WALL)) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else { + m_nWaitState = WAITSTATE_FALSE; + } + } + break; + + case WAITSTATE_STUCK: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) + break; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_TURN_180); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + if (animAssoc->IsPartial()) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } else { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + } + + if (animAssoc->animId == ANIM_TURN_180) { + m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur); + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + m_nStoredMoveState = PEDMOVE_NONE; + m_panicCounter = 0; + return; + } + } + + AnimationId animToPlay; + + switch (CGeneral::GetRandomNumber() & 3) { + case 0: + animToPlay = ANIM_ROAD_CROSS; + break; + case 1: + animToPlay = ANIM_IDLE_TIRED; + break; + case 2: + animToPlay = ANIM_XPRESS_SCRATCH; + break; + case 3: + animToPlay = ANIM_TURN_180; + break; + default: + break; + } + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); + + if (animToPlay == ANIM_TURN_180) + animAssoc->SetFinishCallback(FinishedWaitCB, this); + + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000); + break; + + case WAITSTATE_LOOK_ABOUT: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_PLAYANIM_HANDSUP: + mustHaveAnim = ANIM_HANDSUP; + + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_HANDSCOWER; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + pedWeLook = (CPed*) m_pLookTarget; + + if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt) + && m_nPedState != PED_FLEE_ENTITY + && m_nPedState != PED_ATTACK + && CTimer::GetTimeInMilliseconds() <= m_nWaitTimer + && animAssoc) { + + TurnBody(); + } else { + m_nWaitState = WAITSTATE_FALSE; + m_nWaitTimer = 0; + if (m_pLookTarget && m_pLookTarget->IsPed()) { + + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_ATTACK) { + + if (m_pedStats->m_fear <= 100 - pedWeLook->m_pedStats->m_temper) { + + if (GetWeapon()->IsTypeMelee()) { +#ifdef VC_PED_PORTS + if(m_pedStats->m_flags & STAT_GUN_PANIC) { +#endif + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); + if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) { + + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + if (m_nMoveState != PEDMOVE_RUN) + SetMoveState(PEDMOVE_WALK); + + if (m_nPedType != PEDTYPE_COP) { + ProcessObjective(); + SetMoveState(PEDMOVE_WALK); + } +#ifdef VC_PED_PORTS + } else { + SetObjective(OBJECTIVE_NONE); + SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } +#endif + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_pLookTarget); + SetObjectiveTimer(20000); + } + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); + if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) + { + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + SetMoveState(PEDMOVE_RUN); + Say(SOUND_PED_FLEE_RUN); + } + } + } + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + case WAITSTATE_PLAYANIM_COWER: + mustHaveAnim = ANIM_HANDSCOWER; + + case WAITSTATE_PLAYANIM_DUCK: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_DUCK_DOWN; + + case WAITSTATE_PLAYANIM_TAXI: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_TAXI; + + case WAITSTATE_PLAYANIM_CHAT: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_CHAT; + + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + m_nWaitState = WAITSTATE_FALSE; + } +#ifdef VC_PED_PORTS + else if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) { + if (m_pedInObjective) { + if (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) { + + // VC also calls CleanUpOldReference here for old LookTarget. + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + } + } +#endif + break; + + case WAITSTATE_FINISH_FLEE: + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) { + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + int timer = 2000; + m_nWaitState = WAITSTATE_FALSE; + SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer); + } + } else { + m_nWaitState = WAITSTATE_FALSE; + } break; default: break; } - obj->RefModelInfo(GetModelIndex()); - obj->AttachToRwObject((RwObject*)clump); - obj->m_fMass = 15.0f; - obj->m_fTurnMass = 5.0f; - obj->m_fAirResistance = 0.99f; - obj->m_fElasticity = 0.03f; - obj->m_fBuoyancy = m_fMass*GRAVITY/0.75f; - obj->ObjectCreatedBy = TEMP_OBJECT; - obj->SetIsStatic(false); - obj->bIsPickup = false; - obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SMALLBOX; - // life time - the more objects the are, the shorter this one will live - CObject::nNoTempObjects++; - if (CObject::nNoTempObjects > 20) - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 12000; - else if (CObject::nNoTempObjects > 10) - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 30000; - else - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000; + if(!m_nWaitState) + RestoreHeadingRate(); +} - CVector localForcePos, forceDir; +void +CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; - if (direction == 2) { - obj->m_vecMoveSpeed = 0.03f * GetForward(); - obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; - obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - localForcePos = CVector(0.0f, 0.0f, 0.0f); - forceDir = GetForward(); - } else { - obj->m_vecMoveSpeed = -0.03f * GetForward(); - obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; - obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - localForcePos = CVector(0.0f, 0.0f, 0.0f); - forceDir = -GetForward(); + ped->m_nWaitTimer = 0; + ped->RestoreHeadingRate(); + ped->Wait(); +} + +void +CPed::RestoreHeadingRate(void) +{ + m_headingRate = m_pedStats->m_headingChangeRate; +} + +void +CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) +{ + ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; +} + +void +CPed::FlagToDestroyWhenNextProcessed(void) +{ + bRemoveFromWorld = true; + if (!InVehicle()) + return; + if (m_pMyVehicle->pDriver == this){ + m_pMyVehicle->pDriver = nil; + if (IsPlayer() && m_pMyVehicle->GetStatus() != STATUS_WRECKED) + m_pMyVehicle->SetStatus(STATUS_ABANDONED); + }else{ + m_pMyVehicle->RemovePassenger(this); } - obj->ApplyTurnForce(forceDir, localForcePos); - CWorld::Add(obj); + bInVehicle = false; + m_pMyVehicle = nil; + if (CharCreatedBy == MISSION_CHAR) + m_nPedState = PED_DEAD; + else + m_nPedState = PED_NONE; + m_pVehicleAnim = nil; +} - return obj; +void +CPed::SetSolicit(uint32 time) +{ + if (m_nPedState == PED_SOLICIT || !IsPedInControl() || !m_carInObjective) + return; + + if (CharCreatedBy != MISSION_CHAR && m_carInObjective->m_nNumGettingIn == 0 + && CTimer::GetTimeInMilliseconds() < m_objectiveTimer) { + if (m_vehEnterType == CAR_DOOR_LF) { + m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; + } else { + m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; + } + + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + + if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); + + m_nPedState = PED_SOLICIT; + } + } +} + +void +CPed::Solicit(void) +{ + if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + SetMoveState(PEDMOVE_STILL); + + // Game uses GetAngleBetweenPoints and converts it to radian + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + doorPos.x, doorPos.y, + GetPosition().x, GetPosition().y); + + if (m_fRotationDest < 0.0f) { + m_fRotationDest = m_fRotationDest + TWOPI; + } else if (m_fRotationDest > TWOPI) { + m_fRotationDest = m_fRotationDest - TWOPI; + } + + if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) + return; + CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); + if (talkAssoc) { + talkAssoc->blendDelta = -1000.0f; + talkAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (!m_carInObjective) { + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { + m_carInObjective = nil; + } else { + m_pVehicleAnim = nil; + SetLeader(m_carInObjective->pDriver); + } +} + +void +CPed::SetBuyIceCream(void) +{ + if (m_nPedState == PED_BUY_ICECREAM || !IsPedInControl()) + return; + + if (!m_carInObjective) + return; + +#ifdef FIX_ICECREAM + + // Simulating BuyIceCream + CPed* driver = m_carInObjective->pDriver; + if (driver) { + m_nPedState = PED_BUY_ICECREAM; + bFindNewNodeAfterStateRestore = true; + SetObjectiveTimer(8000); + SetChat(driver, 8000); + driver->SetChat(this, 8000); + return; + } +#endif + + // Side of the Ice Cream van + m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; + + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_nPedState = PED_BUY_ICECREAM; + } +} + +bool +CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) +{ + bool foundIt = false; + + CVector helperPos = GetPosition(); + helperPos.z = pos->z - 0.5f; + + CVector foundPos = *pos; + foundPos.z -= 0.5f; + + // If there is another car between target car and us. + if (CWorld::TestSphereAgainstWorld((foundPos + helperPos) / 2.0f, 0.25f, veh, false, true, false, false, false, false)) { + + CColModel *vehCol = veh->GetModelInfo()->GetColModel(); + CVector *colMin = &vehCol->boundingBox.min; + CVector *colMax = &vehCol->boundingBox.max; + + CVector leftRearPos = CVector(colMin->x - 0.5f, colMin->y - 0.5f, 0.0f); + CVector rightRearPos = CVector(0.5f + colMax->x, colMin->y - 0.5f, 0.0f); + CVector leftFrontPos = CVector(colMin->x - 0.5f, 0.5f + colMax->y, 0.0f); + CVector rightFrontPos = CVector(0.5f + colMax->x, 0.5f + colMax->y, 0.0f); + + leftRearPos = veh->GetMatrix() * leftRearPos; + rightRearPos = veh->GetMatrix() * rightRearPos; + leftFrontPos = veh->GetMatrix() * leftFrontPos; + rightFrontPos = veh->GetMatrix() * rightFrontPos; + + // Makes helperPos veh-ped distance vector. + helperPos -= veh->GetPosition(); + + // ?!? I think it's absurd to use this unless another function like SeekCar finds next pos. with it and we're trying to simulate it's behaviour. + // On every run it returns another pos. for ped, with same distance to the veh. + // Sequence of positions are not guaranteed, it depends on global pos. (So sometimes it returns positions to make ped draw circle, sometimes don't) + helperPos = veh->GetMatrix() * helperPos; + + float vehForwardHeading = veh->GetForward().Heading(); + + // I'm absolutely not sure about these namings. + // NTVF = needed turn if we're looking to vehicle front and wanna look to... + + float potentialLrHeading = Atan2(leftRearPos.x - helperPos.x, leftRearPos.y - helperPos.y); + float NTVF_LR = CGeneral::LimitRadianAngle(potentialLrHeading - vehForwardHeading); + + float potentialRrHeading = Atan2(rightRearPos.x - helperPos.x, rightRearPos.y - helperPos.y); + float NTVF_RR = CGeneral::LimitRadianAngle(potentialRrHeading - vehForwardHeading); + + float potentialLfHeading = Atan2(leftFrontPos.x - helperPos.x, leftFrontPos.y - helperPos.y); + float NTVF_LF = CGeneral::LimitRadianAngle(potentialLfHeading - vehForwardHeading); + + float potentialRfHeading = Atan2(rightFrontPos.x - helperPos.x, rightFrontPos.y - helperPos.y); + float NTVF_RF = CGeneral::LimitRadianAngle(potentialRfHeading - vehForwardHeading); + + bool canHeadToLr = NTVF_LR <= -PI || NTVF_LR >= -HALFPI; + + bool canHeadToRr = NTVF_RR <= HALFPI || NTVF_RR >= PI; + + bool canHeadToLf = NTVF_LF >= 0.0f || NTVF_LF <= -HALFPI; + + bool canHeadToRf = NTVF_RF <= 0.0f || NTVF_RF >= HALFPI; + + // Only order of conditions are different among enterTypes. + if (m_vehEnterType == CAR_DOOR_RR) { + if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } + } else if(m_vehEnterType == CAR_DOOR_RF) { + if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } + } else if (m_vehEnterType == CAR_DOOR_LF) { + if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } + } else if (m_vehEnterType == CAR_DOOR_LR) { + if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } + } + } + if (!foundIt) + return false; + + helperPos = GetPosition() - foundPos; + helperPos.z = 0.0f; + if (helperPos.MagnitudeSqr() <= sq(0.5f)) + return false; + + pos->x = foundPos.x; + pos->y = foundPos.y; + return true; +} + +void +CPed::SetLeader(CEntity *leader) +{ + m_leader = (CPed*)leader; + + if(m_leader) + m_leader->RegisterReference((CEntity **)&m_leader); +} + +#ifdef VC_PED_PORTS +bool +CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal) +{ + if (m_nSurfaceTouched == SURFACE_WATER) + return true; + + CVector pos = GetPosition(); + CVector forwardOffset = GetForward(); + if (damageNormal && damageNormal->z > 0.17f) { + if (damageNormal->z > 0.9f) + return false; + + CColModel *ourCol = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); + pos.z = ourCol->spheres->center.z - ourCol->spheres->radius * damageNormal->z + pos.z; + pos.z = pos.z + 0.05f; + float collPower = damageNormal->Magnitude2D(); + if (damageNormal->z > 0.5f) { + CVector invDamageNormal(-damageNormal->x, -damageNormal->y, 0.0f); + invDamageNormal *= 1.0f / collPower; + CVector estimatedJumpDist = invDamageNormal + collPower * invDamageNormal * ourCol->spheres->radius; + forwardOffset = estimatedJumpDist * Min(2.0f / collPower, 4.0f); + } else { + forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; + } + } else { + pos.z -= 0.15f; + } + + CVector forwardPos = pos + forwardOffset; + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} +#else +bool +CPed::CanPedJumpThis(CEntity *unused) +{ + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); + CVector pos = GetPosition(); + CVector forwardPos( + forward.x + pos.x, + forward.y + pos.y, + pos.z); + + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} +#endif + +void +CPed::SetJump(void) +{ + if (!bInVehicle && +#if defined VC_PED_PORTS || defined FIX_BUGS + m_nPedState != PED_JUMP && !RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_LAUNCH) && +#endif + (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { + SetStoredState(); + m_nPedState = PED_JUMP; + CAnimBlendAssociation *jumpAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAUNCH, 8.0f); + jumpAssoc->SetFinishCallback(FinishLaunchCB, this); + m_fRotationDest = m_fRotationCur; + } +} + +void +CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (ped->m_nPedState != PED_JUMP) + return; + + CVector forward(0.15f * ped->GetForward() + ped->GetPosition()); + forward.z += CModelInfo::GetModelInfo(ped->GetModelIndex())->GetColModel()->spheres->center.z + 0.25f; + + CEntity *obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); + if (!obstacle) { + // Forward of forward + forward += 0.15f * ped->GetForward(); + forward.z += 0.15f; + obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); + } + + if (obstacle) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + + // ANIM_HIT_WALL in VC (which makes more sense) + CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 8.0f); + handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped); + ped->bIsLanding = true; + return; + } + + float velocityFromAnim = 0.1f; + CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_SPRINT); + + if (sprintAssoc) { + velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f; + } else { + CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_RUN); + if (runAssoc) { + velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f; + } + } + + if (ped->IsPlayer() +#ifdef VC_PED_PORTS + || ped->m_pedInObjective && ped->m_pedInObjective->IsPlayer() +#endif + ) + ped->ApplyMoveForce(0.0f, 0.0f, 8.5f); + else + ped->ApplyMoveForce(0.0f, 0.0f, 4.5f); + + if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D() +#ifdef VC_PED_PORTS + || ped->m_pCurrentPhysSurface +#endif + ) { + +#ifdef FREE_CAM + if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) { +#else + if (TheCamera.Cams[0].Using3rdPersonMouseCam()) { +#endif + float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur); + ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle); + ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle); + } else { + ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(ped->m_fRotationCur); + ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(ped->m_fRotationCur); + } +#ifdef VC_PED_PORTS + if (ped->m_pCurrentPhysSurface) { + ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x; + ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y; + } +#endif + } + + ped->bIsStanding = false; + ped->bIsInTheAir = true; + animAssoc->blendDelta = -1000.0f; + CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE); + + if (ped->bDoBloodyFootprints) { + CVector bloodPos(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTL); + + bloodPos.z -= 0.1f; + bloodPos += 0.2f * ped->GetForward(); + + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + 0.26f * ped->GetForward().x, + 0.26f * ped->GetForward().y, + 0.14f * ped->GetRight().x, + 0.14f * ped->GetRight().y, + 255, 255, 0, 0, 4.0f, 3000, 1.0f); + + bloodPos = CVector(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTR); + + bloodPos.z -= 0.1f; + bloodPos += 0.2f * ped->GetForward(); + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + 0.26f * ped->GetForward().x, + 0.26f * ped->GetForward().y, + 0.14f * ped->GetRight().x, + 0.14f * ped->GetRight().y, + 255, 255, 0, 0, 4.0f, 3000, 1.0f); + + if (ped->m_bloodyFootprintCountOrDeathTime <= 40) { + ped->m_bloodyFootprintCountOrDeathTime = 0; + ped->bDoBloodyFootprints = false; + } else { + ped->m_bloodyFootprintCountOrDeathTime -= 40; + } + } +} + +void +CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + ped->bResetWalkAnims = true; + ped->bIsLanding = false; + + animAssoc->blendDelta = -1000.0f; +} + +void +CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); + + ped->bIsLanding = false; +} + +bool +CPed::CanPedDriveOff(void) +{ + if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + return false; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && nearPed->m_carInObjective == m_carInObjective) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; + return false; + } + } + return true; +} + +// These categories are purely random, most of ped models have no correlation. So I don't think making an enum. +uint8 +CPed::GetPedRadioCategory(uint32 modelIndex) +{ + switch (modelIndex) { + case MI_MALE01: + case MI_FEMALE03: + case MI_PROSTITUTE2: + case MI_WORKER1: + case MI_MOD_MAN: + case MI_MOD_WOM: + case MI_ST_WOM: + case MI_FAN_WOM: + return 3; + case MI_TAXI_D: + case MI_PIMP: + case MI_MALE02: + case MI_FEMALE02: + case MI_FATFEMALE01: + case MI_FATFEMALE02: + case MI_DOCKER1: + case MI_WORKER2: + case MI_FAN_MAN2: + return 9; + case MI_GANG01: + case MI_GANG02: + case MI_SCUM_MAN: + case MI_SCUM_WOM: + case MI_HOS_WOM: + case MI_CONST1: + return 1; + case MI_GANG03: + case MI_GANG04: + case MI_GANG07: + case MI_GANG08: + case MI_CT_MAN2: + case MI_CT_WOM2: + case MI_B_MAN3: + case MI_SHOPPER3: + return 4; + case MI_GANG05: + case MI_GANG06: + case MI_GANG11: + case MI_GANG12: + case MI_CRIMINAL02: + case MI_B_WOM2: + case MI_ST_MAN: + case MI_HOS_MAN: + return 5; + case MI_FATMALE01: + case MI_LI_MAN2: + case MI_SHOPPER1: + case MI_CAS_MAN: + return 6; + case MI_PROSTITUTE: + case MI_P_WOM2: + case MI_LI_WOM2: + case MI_B_WOM3: + case MI_CAS_WOM: + return 2; + case MI_P_WOM1: + case MI_DOCKER2: + case MI_STUD_MAN: + return 7; + case MI_CT_MAN1: + case MI_CT_WOM1: + case MI_LI_MAN1: + case MI_LI_WOM1: + case MI_B_MAN1: + case MI_B_MAN2: + case MI_B_WOM1: + case MI_SHOPPER2: + case MI_STUD_WOM: + return 8; + default: + return 0; + } +} + +void +CPed::SetRadioStation(void) +{ + static const uint8 radiosPerRadioCategories[10][4] = { + {JAH_RADIO, RISE_FM, GAME_FM, MSX_FM}, + {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, + {RISE_FM, GAME_FM, MSX_FM, FLASHBACK}, + {HEAD_RADIO, RISE_FM, LIPS_106, MSX_FM}, + {HEAD_RADIO, RISE_FM, MSX_FM, FLASHBACK}, + {JAH_RADIO, RISE_FM, LIPS_106, FLASHBACK}, + {HEAD_RADIO, RISE_FM, LIPS_106, FLASHBACK}, + {HEAD_RADIO, JAH_RADIO, LIPS_106, FLASHBACK}, + {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, + {CHATTERBOX, HEAD_RADIO, LIPS_106, GAME_FM} + }; + uint8 orderInCat = 0; // BUG: this wasn't initialized + + if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) + return; + + uint8 category = GetPedRadioCategory(GetModelIndex()); + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CGeneral::GetRandomNumber() & 15) { + for (orderInCat = 0; orderInCat < 4; orderInCat++) { + if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) + break; + } + } else { + m_pMyVehicle->m_nRadioStation = USERTRACK; + } + } else { + for (orderInCat = 0; orderInCat < 4; orderInCat++) { + if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) + break; + } + } + if (orderInCat == 4) { + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CGeneral::GetRandomNumber() & 15) + m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + else + m_pMyVehicle->m_nRadioStation = USERTRACK; + } else { + m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + } + } } void @@ -16754,688 +8364,104 @@ CPed::WarpPedIntoCar(CVehicle *car) bChangedSeat = true; } -void -CPed::SetObjective(eObjective newObj, CVector dest) + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE +// returns event id, parameter is optional +int32 +CPed::CheckForPlayerCrimes(CPed *victim) { - if (DyingOrDead()) - return; + int i; + float dist; + float mindist = 60.0f; + CPlayerPed *player = FindPlayerPed(); + int32 victimRef = (victim ? CPools::GetPedRef(victim) : 0); + int event = -1; - if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) - return; + for (i = 0; i < NUMEVENTS; i++) { + if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) + continue; - SetObjectiveTimer(0); - if (m_objective == newObj) { - if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - if (m_nextRoutePointPos == dest) - return; - } else if (newObj == OBJECTIVE_GUARD_SPOT) { - if (m_vecSeekPosEx == dest) - return; + // those are already handled in game, also DEAD_PED isn't registered alone, most of the time there is SHOOT_PED etc. + if (gaEvent[i].type == EVENT_DEAD_PED || gaEvent[i].type == EVENT_GUNSHOT || gaEvent[i].type == EVENT_EXPLOSION) + continue; + + if (victim && gaEvent[i].entityRef != victimRef) + continue; + + if (gaEvent[i].criminal != player) + continue; + + dist = (GetPosition() - gaEvent[i].posn).Magnitude(); + if (dist < mindist) { + mindist = dist; + event = i; } } -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - switch (newObj) { - case OBJECTIVE_GUARD_SPOT: - m_vecSeekPosEx = dest; - m_distanceToCountSeekDoneEx = 5.0f; - SetMoveState(PEDMOVE_STILL); - break; - case OBJECTIVE_GUARD_AREA: - case OBJECTIVE_WAIT_IN_CAR: - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: - case OBJECTIVE_DESTROY_OBJECT: - case OBJECTIVE_DESTROY_CAR: - break; - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - bIsRunning = false; - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - m_distanceToCountSeekDone = 0.5f; - bUsePedNodeSeek = true; - if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) - return; - break; - case OBJECTIVE_RUN_TO_AREA: - bIsRunning = true; - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - m_distanceToCountSeekDone = 0.5f; - bUsePedNodeSeek = true; - if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) - return; - break; - default: break; - } - - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } -} - -void -CPed::SetMoveAnim(void) -{ - if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) - return; - - if (m_nMoveState == PEDMOVE_NONE) { - m_nStoredMoveState = PEDMOVE_NONE; - return; - } - - AssocGroupId animGroupToUse; - if (m_leader && m_leader->IsPlayer()) - animGroupToUse = ASSOCGRP_PLAYER; - else - animGroupToUse = m_animGroup; - - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_BLOCK); - if (!animAssoc) { - CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); - animAssoc = fightIdleAssoc; - if (fightIdleAssoc && m_nPedState == PED_FIGHT) - return; - - if (fightIdleAssoc) { - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); - } - } - } - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); - if (animAssoc) - if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) - return; - - if (animAssoc) { - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); - } - } - } - if (!animAssoc) { - m_nStoredMoveState = m_nMoveState; - if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { - for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); - assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { - - if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { - assoc->blendDelta = -2.0f; - assoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - - ClearAimFlag(); - ClearLookFlag(); - } - - switch (m_nMoveState) { - case PEDMOVE_STILL: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + if (event != -1) { + if (victim) { + m_victimOfPlayerCrime = victim; + } else { + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + m_victimOfPlayerCrime = CPools::GetPed(gaEvent[event].entityRef); break; - case PEDMOVE_WALK: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); + case EVENT_ENTITY_VEHICLE: + m_victimOfPlayerCrime = CPools::GetVehicle(gaEvent[event].entityRef); break; - case PEDMOVE_RUN: - if (m_nPedState == PED_FLEE_ENTITY) { - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 3.0f); - } else { - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 1.0f); - } - break; - case PEDMOVE_SPRINT: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_SPRINT, 1.0f); + case EVENT_ENTITY_OBJECT: + m_victimOfPlayerCrime = CPools::GetObject(gaEvent[event].entityRef); break; default: break; - } - - if (animAssoc) { - if (m_leader) { - CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); - - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); - - if (walkAssoc) { - animAssoc->speed = walkAssoc->speed; - } else { - if (CharCreatedBy == MISSION_CHAR) - animAssoc->speed = 1.0f; - else - animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; - - } - } else { - if (CharCreatedBy == MISSION_CHAR) - animAssoc->speed = 1.0f; - else - animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; } } } + + return event; } - -void -CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) -{ - float zDiff = 0.0f; - RemoveWeaponWhenEnteringVehicle(); - car->m_nGettingInFlags |= doorFlag; - bVehEnterDoorIsBlocked = false; - if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) - SetStoredState(); - - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_vehEnterType = doorNode; - m_nPedState = PED_ENTER_CAR; - if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { - car->bIsBeingCarJacked = true; - } - - m_pMyVehicle = (CVehicle*)m_pSeekTarget; - m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); - ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; - bUsesCollision = false; - CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); - - // Because buses have stairs - if (!m_pMyVehicle->bIsBus) - zDiff = Max(0.0f, doorOpenPos.z - GetPosition().z); - - m_vecOffsetSeek = doorOpenPos - GetPosition(); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; - if (car->IsBoat()) { -#ifdef VC_PED_PORTS - // VC checks for handling flag, but we can't do that - if(car->GetModelIndex() == MI_SPEEDER) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); - - PedSetInCarCB(nil, this); - bVehExitWillBeInstant = true; -#else - -#ifndef FIX_BUGS - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); -#else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); #endif - m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#ifdef PED_SKIN +static RpMaterial* +SetLimbAlphaCB(RpMaterial *material, void *data) +{ + ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; + return material; +} + +void +CPed::renderLimb(int node) +{ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + CPedModelInfo *mi = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); + RpAtomic *atomic; + switch(node){ + case PED_HEAD: + atomic = mi->getHead(); + break; + case PED_HANDL: + atomic = mi->getLeftHand(); + break; + case PED_HANDR: + atomic = mi->getRightHand(); + break; + default: + return; + } + if(atomic == nil) + return; + + RwFrame *frame = RpAtomicGetFrame(atomic); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetLimbAlphaCB, &alpha); + RpAtomicRender(atomic); +} #endif - if (IsPlayer()) - CWaterLevel::AllocateBoatWakeArray(); - } else { - if (zDiff > 4.4f) { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); - - } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); - } - m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); - car->AutoPilot.m_nCruiseSpeed = 0; - } -} - -void -CPed::WanderPath(void) -{ - if (!m_pNextPathNode) { - printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); - SetIdle(); - return; - } - if (m_nWaitState == WAITSTATE_FALSE) { - if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) - SetMoveState(PEDMOVE_WALK); - } - m_vecSeekPos = m_pNextPathNode->GetPosition(); - m_vecSeekPos.z += 1.0f; - - // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. - if (!Seek()) - return; - - CPathNode *previousLastNode = m_pLastPathNode; - uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; - - // We don't prefer 180-degree turns in normal situations - uint8 dirWeWouldntPrefer = m_nPathDir; - if (dirWeWouldntPrefer <= 3) - dirWeWouldntPrefer += 4; - else - dirWeWouldntPrefer -= 4; - - CPathNode *nodeWeWouldntPrefer = nil; - uint8 dirToSet = 9; // means undefined - uint8 dirWeWouldntPrefer2 = 9; // means undefined - if (randVal <= 90) { - if (randVal > 80) { - m_nPathDir += 2; - m_nPathDir %= 8; - } - } else { - m_nPathDir -= 2; - if (m_nPathDir < 0) - m_nPathDir += 8; - } - - m_pLastPathNode = m_pNextPathNode; - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &dirToSet); - - uint8 tryCount = 0; - - // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 - while (!m_pNextPathNode) { - tryCount++; - m_nPathDir = (m_nPathDir + 1) % 8; - - // We're at where we started and couldn't find any node - if (tryCount > 7) { - if (!nodeWeWouldntPrefer) { - ClearAll(); - SetIdle(); - // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. - Error("Can't find valid path node, SetWanderPath, Ped.cpp"); - return; - } - m_pNextPathNode = nodeWeWouldntPrefer; - dirToSet = dirWeWouldntPrefer2; - } else { - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &dirToSet); - if (m_pNextPathNode) { - if (dirToSet == dirWeWouldntPrefer) { - nodeWeWouldntPrefer = m_pNextPathNode; - dirWeWouldntPrefer2 = dirToSet; - m_pNextPathNode = nil; - } - } - } - } - - m_nPathDir = dirToSet; - if (m_pLastPathNode == m_pNextPathNode) { - m_pNextPathNode = previousLastNode; - SetWaitState(WAITSTATE_DOUBLEBACK, nil); - Say(SOUND_PED_WAIT_DOUBLEBACK); - } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { - SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); - } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { - SetWaitState(WAITSTATE_CROSS_ROAD, nil); - } else if (m_pNextPathNode == previousLastNode) { - SetWaitState(WAITSTATE_DOUBLEBACK, nil); - Say(SOUND_PED_WAIT_DOUBLEBACK); - } -} - -bool -CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) -{ - bool teleported = false; - if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) - return false; - - CVector warpToPos = warpTo->GetPosition(); - CVector distVec = warpToPos - GetPosition(); - float halfOfDist = distVec.Magnitude() * 0.5f; - CVector halfNormalizedDist = distVec / halfOfDist; - - CVector appropriatePos = GetPosition(); - CVector zCorrectedPos = appropriatePos; - int tryCount = Min(10, halfOfDist); - for (int i = 0; i < tryCount; ++i) { - appropriatePos += halfNormalizedDist; - CPedPlacement::FindZCoorForPed(&zCorrectedPos); - - if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) - continue; - - appropriatePos.z = zCorrectedPos.z; - if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) - && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { - teleported = true; - Teleport(appropriatePos); - } - } - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; - return teleported; -} - -bool -CPed::WarpPedToNearLeaderOffScreen(void) -{ - bool teleported = false; - if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) - return false; - - CVector warpToPos = m_leader->GetPosition(); - CVector distVec = warpToPos - GetPosition(); - float halfOfDist = distVec.Magnitude() * 0.5f; - CVector halfNormalizedDist = distVec / halfOfDist; - - CVector appropriatePos = GetPosition(); - CVector zCorrectedPos = appropriatePos; - int tryCount = Min(10, halfOfDist); - for (int i = 0; i < tryCount; ++i) { - appropriatePos += halfNormalizedDist; - CPedPlacement::FindZCoorForPed(&zCorrectedPos); - - if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) - continue; - - appropriatePos.z = zCorrectedPos.z; - if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) - && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { - teleported = true; - Teleport(appropriatePos); - } - } - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; - return teleported; -} - -void -CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) -{ - RemoveWeaponWhenEnteringVehicle(); - if (m_nPedState != PED_SEEK_CAR) - SetStoredState(); - - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); - m_nPedState = PED_CARJACK; - car->bIsBeingCarJacked = true; - m_pMyVehicle = (CVehicle*)m_pSeekTarget; - m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); - ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; - - Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); - CVector carEnterPos; - carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); - - car->m_nGettingInFlags |= doorFlag; - m_vecOffsetSeek = carEnterPos - GetPosition(); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; - float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); - bUsesCollision = false; - - if (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); -} - -void -CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) - return; - - SetObjectiveTimer(0); - if (m_objective == newObj) { - if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) - return; - } else if (newObj == OBJECTIVE_GUARD_SPOT) { - if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) - return; - } - } - -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - - if (newObj == OBJECTIVE_GUARD_SPOT) { - m_vecSeekPosEx = dest; - m_distanceToCountSeekDoneEx = safeDist; - } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - bUsePedNodeSeek = true; - } -} - -void -CPed::SetCarJack(CVehicle* car) -{ - uint8 doorFlag; - eDoors door; - CPed *pedInSeat = nil; - - if (car->IsBoat()) - return; - - switch (m_vehEnterType) { - case CAR_DOOR_RF: - doorFlag = CAR_DOOR_FLAG_RF; - door = DOOR_FRONT_RIGHT; - if (car->pPassengers[0]) { - pedInSeat = car->pPassengers[0]; - } else if (m_nPedType == PEDTYPE_COP) { - pedInSeat = car->pDriver; - } - break; - case CAR_DOOR_RR: - doorFlag = CAR_DOOR_FLAG_RR; - door = DOOR_REAR_RIGHT; - pedInSeat = car->pPassengers[2]; - break; - case CAR_DOOR_LF: - doorFlag = CAR_DOOR_FLAG_LF; - door = DOOR_FRONT_LEFT; - pedInSeat = car->pDriver; - break; - case CAR_DOOR_LR: - doorFlag = CAR_DOOR_FLAG_LR; - door = DOOR_REAR_LEFT; - pedInSeat = car->pPassengers[1]; - break; - default: - doorFlag = CAR_DOOR_FLAG_UNKNOWN; - break; - } - - if(car->bIsBus) - pedInSeat = car->pDriver; - - if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || - (car->VehicleCreatedBy != MISSION_VEHICLE && car->GetModelIndex() != MI_DODO))) - if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) - if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) - if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) - if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) - SetCarJack_AllClear(car, m_vehEnterType, doorFlag); -} - -void -CPed::Solicit(void) -{ - if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { - CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); - SetMoveState(PEDMOVE_STILL); - - // Game uses GetAngleBetweenPoints and converts it to radian - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - doorPos.x, doorPos.y, - GetPosition().x, GetPosition().y); - - if (m_fRotationDest < 0.0f) { - m_fRotationDest = m_fRotationDest + TWOPI; - } else if (m_fRotationDest > TWOPI) { - m_fRotationDest = m_fRotationDest - TWOPI; - } - - if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) - return; - CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); - if (talkAssoc) { - talkAssoc->blendDelta = -1000.0f; - talkAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - RestorePreviousState(); - RestorePreviousObjective(); - SetObjectiveTimer(10000); - } else if (!m_carInObjective) { - RestorePreviousState(); - RestorePreviousObjective(); - SetObjectiveTimer(10000); - } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { - m_carInObjective = nil; - } else { - m_pVehicleAnim = nil; - SetLeader(m_carInObjective->pDriver); - } -} - -// Seperate function in VC, more logical. Not sure is it inlined in III. -void -CPed::SetExitBoat(CVehicle *boat) -{ -#ifndef VC_PED_PORTS - m_nPedState = PED_IDLE; - CVector firstPos = GetPosition(); - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - if (boat->GetModelIndex() == MI_SPEEDER && boat->IsUpsideDown()) { - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); - m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); - m_vehEnterType = CAR_DOOR_RF; - m_nPedState = PED_EXIT_CAR; - } else { - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - } - SetPosition(firstPos); - SetMoveState(PEDMOVE_STILL); - m_vecMoveSpeed = boat->m_vecMoveSpeed; - bTryingToReachDryLand = true; -#else - m_nPedState = PED_IDLE; - CVector newPos = GetPosition(); - RemoveInCarAnims(); - CColModel* boatCol = boat->GetColModel(); - if (boat->IsUpsideDown()) { - newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; - newPos = boat->GetMatrix() * newPos; - newPos.z += 1.0f; - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - m_pCurrentPhysSurface = boat; - } else { -/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { - if (boat->m_modelIndex == MI_SKIMMER) - newPos.z += 2.0f -*/ - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - m_pCurrentPhysSurface = boat; - CColPoint foundCol; - CEntity *foundEnt = nil; - if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) - newPos.z = FEET_OFFSET + foundCol.point.z; -/* // VC specific - } else { - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - SetMoveState(PEDMOVE_STILL); - bTryingToReachDryLand = true; - float upMult = 1.04f + boatCol->boundingBox.min.z; - float rightMult = 0.6f * boatCol->boundingBox.max.x; - newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); - GetPosition() = newPos; - if (m_pMyVehicle) { - PositionPedOutOfCollision(); - } else { - m_pMyVehicle = boat; - PositionPedOutOfCollision(); - m_pMyVehicle = nil; - } - return; - } -*/ } - SetPosition(newPos); - SetMoveState(PEDMOVE_STILL); - m_vecMoveSpeed = boat->m_vecMoveSpeed; -#endif - // Not there in VC. - CWaterLevel::FreeBoatWakeArray(); -} #ifdef COMPATIBLE_SAVES #define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipSaveBuf(buf, sizeof(data)); diff --git a/src/peds/Ped.h b/src/peds/Ped.h index dbe61572..a3d4997d 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -5,7 +5,7 @@ #include "Crime.h" #include "EventList.h" #include "PedIK.h" -#include "PedStats.h" +#include "PedType.h" #include "Physical.h" #include "Weapon.h" #include "WeaponInfo.h" @@ -13,6 +13,7 @@ #define FEET_OFFSET 1.04f #define CHECK_NEARBY_THINGS_MAX_DIST 15.0f #define ENTER_CAR_MAX_DIST 30.0f +#define CAN_SEE_ENTITY_ANGLE_THRESHOLD DEGTORAD(60.0f) struct CPathNode; class CAccident; @@ -568,7 +569,7 @@ public: void CalculateNewOrientation(void); float WorkOutHeadingForMovingFirstPerson(float); void CalculateNewVelocity(void); - bool CanSeeEntity(CEntity*, float); + bool CanSeeEntity(CEntity*, float threshold = CAN_SEE_ENTITY_ANGLE_THRESHOLD); void RestorePreviousObjective(void); void SetIdle(void); #ifdef _MSC_VER @@ -747,7 +748,7 @@ public: static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); - bool IsPlayer(void); + bool IsPlayer(void) const; bool UseGroundColModel(void); bool CanSetPedState(void); bool IsPedInControl(void); @@ -765,7 +766,7 @@ public: void SetStoredObjective(void); void SetLeader(CEntity* leader); void SetPedStats(ePedStats); - bool IsGangMember(void); + bool IsGangMember(void) const; void Die(void); void EnterTrain(void); void ExitTrain(void); @@ -788,7 +789,7 @@ public: CObject *SpawnFlyingComponent(int, int8); void SetCarJack_AllClear(CVehicle*, uint32, uint32); #ifdef VC_PED_PORTS - bool CanPedJumpThis(CEntity*, CVector*); + bool CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil); #else bool CanPedJumpThis(CEntity*); #endif @@ -809,9 +810,40 @@ public: bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state. bool EnteringCar(void) { return m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK; } - void ReplaceWeaponWhenExitingVehicle(void); - void RemoveWeaponWhenEnteringVehicle(void); - bool IsNotInWreckedVehicle(); + // It was inlined in III but not in VC. + inline void + ReplaceWeaponWhenExitingVehicle(void) + { + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + + // If it's Uzi, we may have stored weapon. Uzi is the only gun we can use in car. + if (IsPlayer() && weaponType == WEAPONTYPE_UZI) { + if (/*IsPlayer() && */ m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { + SetCurrentWeapon(m_storedWeapon); + m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; + } + } else { + AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); + } + } + + // It was inlined in III but not in VC. + inline void + RemoveWeaponWhenEnteringVehicle(void) + { + if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { + if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) + m_storedWeapon = GetWeapon()->m_eWeaponType; + SetCurrentWeapon(WEAPONTYPE_UZI); + } else { + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } + } + bool IsNotInWreckedVehicle() + { + return m_pMyVehicle != nil && ((CEntity*)m_pMyVehicle)->GetStatus() != STATUS_WRECKED; + } // My additions, because there were many, many instances of that. inline void SetFindPathAndFlee(CEntity *fleeFrom, int time, bool walk = false) { diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp new file mode 100644 index 00000000..38303473 --- /dev/null +++ b/src/peds/PedAI.cpp @@ -0,0 +1,5413 @@ +#include "common.h" + +#include "main.h" +#include "Particle.h" +#include "RpAnimBlend.h" +#include "Ped.h" +#include "Wanted.h" +#include "AnimBlendAssociation.h" +#include "DMAudio.h" +#include "General.h" +#include "HandlingMgr.h" +#include "Replay.h" +#include "Camera.h" +#include "PedPlacement.h" +#include "ZoneCull.h" +#include "Pad.h" +#include "Pickups.h" +#include "Train.h" +#include "PedRoutes.h" +#include "CopPed.h" +#include "Script.h" +#include "CarCtrl.h" +#include "WaterLevel.h" +#include "CarAI.h" +#include "Zones.h" +#include "Cranes.h" + +CVector vecPedCarDoorAnimOffset; +CVector vecPedCarDoorLoAnimOffset; +CVector vecPedVanRearDoorAnimOffset; +CVector vecPedQuickDraggedOutCarAnimOffset; +CVector vecPedDraggedOutCarAnimOffset; +CVector vecPedTrainDoorAnimOffset; + +void +CPed::SetObjectiveTimer(int time) +{ + if (time == 0) { + m_objectiveTimer = 0; + } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::SetStoredObjective(void) +{ + if (m_objective == m_prevObjective) + return; + + switch (m_objective) + { + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::ForceStoredObjective(eObjective objective) +{ + if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + m_prevObjective = m_objective; + return; + } + + switch (m_objective) + { + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +bool +CPed::IsTemporaryObjective(eObjective objective) +{ + return objective == OBJECTIVE_LEAVE_CAR || objective == OBJECTIVE_SET_LEADER || +#ifdef VC_PED_PORTS + objective == OBJECTIVE_LEAVE_CAR_AND_DIE || +#endif + objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; +} + +void +CPed::SetObjective(eObjective newObj) +{ + if (DyingOrDead()) + return; + + if (newObj == OBJECTIVE_NONE) { + if ((m_objective == OBJECTIVE_LEAVE_CAR || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER +#ifdef VC_PED_PORTS + || m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) + && !IsPlayer() +#else + ) +#endif + && !IsPedInControl()) { + + bStartWanderPathOnFoot = true; + return; + } + // Unused code from assembly... + /* + else if(m_objective == OBJECTIVE_FLEE_CAR) { + + } else { + + } + */ + m_objective = OBJECTIVE_NONE; + m_prevObjective = OBJECTIVE_NONE; + } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { + SetObjectiveTimer(0); + + if (m_objective == newObj) + return; + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + bObjectiveCompleted = false; + + switch (newObj) { + case OBJECTIVE_NONE: + m_prevObjective = OBJECTIVE_NONE; + break; + case OBJECTIVE_HAIL_TAXI: + m_nWaitTimer = 0; + SetIdle(); + SetMoveState(PEDMOVE_STILL); + break; + default: + break; + } + } +} + +void +CPed::SetObjective(eObjective newObj, void *entity) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective == newObj) { + // Why? + if (m_prevObjective != OBJECTIVE_NONE) + return; + } + + if (entity == this) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + switch (newObj) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GUARD_ATTACK: + if (m_pedInObjective == entity) + return; + + break; + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_FLEE_CAR: +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: +#endif + return; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT_VEHICLE: + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective == entity) + return; + + break; + case OBJECTIVE_SET_LEADER: + if (m_leader == entity) + return; + + break; + default: + break; + } + } else { + if ((newObj == OBJECTIVE_LEAVE_CAR +#ifdef VC_PED_PORTS + || newObj == OBJECTIVE_LEAVE_CAR_AND_DIE +#endif + ) && !bInVehicle) + return; + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective) && !IsTemporaryObjective(newObj)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) { + if (IsTemporaryObjective(newObj)) + ForceStoredObjective(newObj); + else + SetStoredObjective(); + } + m_objective = newObj; + } + + switch (newObj) { + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + + // In this special case, entity parameter isn't CEntity, but int. + SetObjectiveTimer((uintptr)entity); + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_MUG_CHAR: + m_pNextPathNode = nil; + bUsePedNodeSeek = false; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pLookTarget = (CEntity*)entity; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + break; + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_GUARD_ATTACK: + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + break; + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pedFormation = FORMATION_REAR; + break; + case OBJECTIVE_LEAVE_CAR: +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: +#endif + case OBJECTIVE_FLEE_CAR: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); + if (m_carInObjective->bIsBus && m_leaveCarTimer == 0) { + for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + break; + } + } + } + + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_RUN); + + if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { + RestorePreviousObjective(); + break; + } + // fall through + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT_VEHICLE: + case OBJECTIVE_BUY_ICE_CREAM: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity**)&m_carInObjective); + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + if (newObj == OBJECTIVE_SOLICIT_VEHICLE) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && + (m_carInObjective->GetStatus() == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) { + SetObjectiveTimer(14000); + } else { + m_objectiveTimer = 0; + } + break; + case OBJECTIVE_SET_LEADER: + SetLeader((CEntity*)entity); + RestorePreviousObjective(); + break; + default: + break; + } +} + +void +CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_GUARD_SPOT) { + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = safeDist; + } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + bUsePedNodeSeek = true; + } +} + +// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode +// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... +void +CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) + return; + + SetObjectiveTimer(0); + + if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) + return; + + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_FOLLOW_ROUTE) { + SetFollowRoute(routePoint, routeType); + } +} + +void +CPed::SetObjective(eObjective newObj, CVector dest) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + switch (newObj) { + case OBJECTIVE_GUARD_SPOT: + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = 5.0f; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJECT: + case OBJECTIVE_DESTROY_CAR: + break; + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + bIsRunning = false; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + case OBJECTIVE_RUN_TO_AREA: + bIsRunning = true; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + default: break; + } + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } +} + +void +CPed::ClearObjective(void) +{ + if (IsPedInControl() || m_nPedState == PED_DRIVING) { + m_objective = OBJECTIVE_NONE; +#ifdef VC_PED_PORTS + m_pedInObjective = nil; + m_carInObjective = nil; +#endif + if (m_nPedState == PED_DRIVING && m_pMyVehicle) { + + if (m_pMyVehicle->pDriver != this) { +#if defined VC_PED_PORTS || defined FIX_BUGS + if(!IsPlayer()) +#endif + bWanderPathAfterExitingCar = true; + + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } +#ifdef VC_PED_PORTS + m_nLastPedState = PED_NONE; +#endif + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } else { + bClearObjective = true; + } +} + +void +CPed::ClearLeader(void) +{ + if (!m_leader) + return; + + m_leader = nil; + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + if (CharCreatedBy == MISSION_CHAR) { + SetIdle(); + } else { + SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); + } + } else if (m_objective != OBJECTIVE_NONE) { + bClearObjective = true; + } +} + +void +CPed::UpdateFromLeader(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) + return; + + if (!m_leader) + return; + + CVector leaderDist; + if (m_leader->InVehicle()) + leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); + else + leaderDist = m_leader->GetPosition() - GetPosition(); + + if (leaderDist.Magnitude() > 30.0f) { + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + SetLeader(nil); + return; + } + + if (IsPedInControl()) { + if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) + WarpPedToNearLeaderOffScreen(); + + if (m_leader->m_nPedState == PED_DEAD) { + SetLeader(nil); + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + return; + } + if (!m_leader->bInVehicle) { + if (m_leader->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (bInVehicle) { + if (m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT && m_objective != OBJECTIVE_LEAVE_CAR) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + + return; + } + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + RestorePreviousObjective(); + RestorePreviousState(); + } + } + if (m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy == RANDOM_CHAR) { + SetLeader(nil); + return; + } + } + if (!bInVehicle && m_leader->bInVehicle && m_leader->m_nPedState == PED_DRIVING) { + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); + } + } else if (m_leader->m_objective == OBJECTIVE_NONE || (m_leader->IsPlayer() && m_leader->m_objective == OBJECTIVE_WAIT_ON_FOOT) + || m_objective == m_leader->m_objective) { + + if (m_leader->m_nPedState == PED_ATTACK) { + CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; + if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { + + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); + SetObjectiveTimer(8000); + SetLookFlag(m_leader->m_pLookTarget, false); + SetLookTimer(500); + } + } else { + if (IsPedInControl() && m_nPedState != PED_ATTACK) { +#ifndef VC_PED_PORTS + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); +#else + if (m_leader->m_objective == OBJECTIVE_NONE && m_objective == OBJECTIVE_NONE + && m_leader->m_nPedState == PED_CHAT && m_nPedState == PED_CHAT) { + + SetObjective(OBJECTIVE_NONE); + } else { + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + } +#endif + } + if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { + if (ScanForThreats() && m_threatEntity) { + m_pLookTarget = m_threatEntity; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { + m_pPointGunAt = m_threatEntity; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); + SetAttack(m_threatEntity); + } + } + } + } + } else { + switch (m_leader->m_objective) { + case OBJECTIVE_WAIT_ON_FOOT: + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_FOLLOW_ROUTE: + SetObjective(m_leader->m_objective); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_GUARD_SPOT: + SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + if (m_leader->m_pedInObjective) { + SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); + m_objectiveTimer = m_leader->m_objectiveTimer; + } + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_leader->m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); + return; + } + break; + case OBJECTIVE_GUARD_ATTACK: + return; + case OBJECTIVE_HAIL_TAXI: + m_leader = nil; + SetObjective(OBJECTIVE_NONE); + break; + default: + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + break; + } + } + } else if (bInVehicle) { + if ((!m_leader->bInVehicle || m_leader->m_nPedState == PED_EXIT_CAR) && m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { + + switch (m_leader->m_objective) { + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_pMyVehicle == m_leader->m_pMyVehicle || m_pMyVehicle == m_leader->m_carInObjective) + break; + + // fall through + default: + if (m_pMyVehicle && m_objective != OBJECTIVE_LEAVE_CAR) { +#ifdef VC_PED_PORTS + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 250; +#endif + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + + break; + } + } + } +} + +void +CPed::RestorePreviousObjective(void) +{ + if (m_objective == OBJECTIVE_NONE) + return; + + if (m_objective != OBJECTIVE_LEAVE_CAR && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + && m_nPedState != PED_CARJACK +#endif + ) + m_pedInObjective = nil; + + if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { + m_objective = OBJECTIVE_NONE; + if (m_pMyVehicle) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + + } else { + m_objective = m_prevObjective; + m_prevObjective = OBJECTIVE_NONE; + } + bObjectiveCompleted = false; +} + +void +CPed::ProcessObjective(void) +{ + if (bClearObjective && (IsPedInControl() || m_nPedState == PED_DRIVING)) { + ClearObjective(); + bClearObjective = false; + } + UpdateFromLeader(); + + CVector carOrOurPos; + CVector targetCarOrHisPos; + CVector distWithTarget; + + if (m_objective != OBJECTIVE_NONE && (IsPedInControl() || m_nPedState == PED_DRIVING)) { + if (bInVehicle) { + if (!m_pMyVehicle) { + bInVehicle = false; + return; + } + carOrOurPos = m_pMyVehicle->GetPosition(); + } else { + carOrOurPos = GetPosition(); + } + + if (m_pedInObjective) { + if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); + } else { + targetCarOrHisPos = m_pedInObjective->GetPosition(); + } + distWithTarget = targetCarOrHisPos - carOrOurPos; + } else if (m_carInObjective) { + targetCarOrHisPos = m_carInObjective->GetPosition(); + distWithTarget = targetCarOrHisPos - carOrOurPos; + } + + switch (m_objective) { + case OBJECTIVE_NONE: + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJECT: + case OBJECTIVE_GOTO_AREA_IN_CAR: + case OBJECTIVE_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: + case OBJECTIVE_SET_LEADER: + break; + case OBJECTIVE_WAIT_ON_FOOT: + SetIdle(); + m_objective = OBJECTIVE_NONE; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + if (InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + bFleeAfterExitingCar = true; + } else if (m_nPedState != PED_FLEE_POS) { + CVector2D fleePos = GetPosition(); + SetFlee(fleePos, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + break; + case OBJECTIVE_GUARD_SPOT: + { + distWithTarget = m_vecSeekPosEx - GetPosition(); + if (m_pedInObjective) { + SetLookFlag(m_pedInObjective, true); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + float distWithTargetSc = distWithTarget.Magnitude(); + if (2.0f * m_distanceToCountSeekDoneEx >= distWithTargetSc) { + if (m_pedInObjective) { + if (distWithTargetSc <= m_distanceToCountSeekDoneEx) + SetIdle(); + else + SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); + } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + int threatType = ScanForThreats(); + SetLookTimer(CGeneral::GetRandomNumberInRange(500, 1500)); + + // Second condition is pointless and isn't there in Mobile. + if (threatType == PED_FLAG_GUN || (threatType == PED_FLAG_EXPLOSION && m_threatEntity) || m_threatEntity) { + if (m_threatEntity->IsPed()) + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } + } else { + SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); + } + break; + } + case OBJECTIVE_WAIT_IN_CAR: + m_nPedState = PED_DRIVING; + break; + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + m_nPedState = PED_DRIVING; + break; + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer() && CharCreatedBy != MISSION_CHAR + && m_nPedType != PEDTYPE_COP && FindPlayerPed()->m_pWanted->m_CurrentCops != 0 + && !bKindaStayInSamePlace) { + + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + break; + } + if (InVehicle()) { + if (distWithTarget.Magnitude() >= 20.0f + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { + if (m_pMyVehicle->pDriver == this + && !m_pMyVehicle->m_nGettingInFlags) { + m_pMyVehicle->SetStatus(STATUS_PHYSICS); + m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; + if (m_nPedType == PEDTYPE_COP) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); + m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); + } else { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; + } + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + } else { + bool targetHasVeh = m_pedInObjective->bInVehicle; + if (!targetHasVeh + || targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar()) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + } + break; + } + if (distWithTarget.Magnitude() > 30.0f && !bKindaStayInSamePlace) { + if (m_pMyVehicle) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } else { + float closestVehDist = 60.0f; + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle *foundVeh = nil; + for(int i = 0; i < lastVehicle; i++) { + CVehicle *nearVeh = (CVehicle*)vehicles[i]; + /* + Not used. + CVector vehSpeed = nearVeh->GetSpeed(); + CVector ourSpeed = GetSpeed(); + */ + CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); + if (vehDistVec.Magnitude() < closestVehDist && m_pedInObjective->m_pMyVehicle != nearVeh + && nearVeh->CanPedOpenLocks(this)) { + + foundVeh = nearVeh; + closestVehDist = vehDistVec.Magnitude(); + } + } + m_pMyVehicle = foundVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } else if (!GetIsOnScreen()) { + CVector ourPos = GetPosition(); + int closestNode = ThePaths.FindNodeClosestToCoors(ourPos, PATH_CAR, 20.0f); + if (closestNode >= 0) { + int16 colliding; + CWorld::FindObjectsKindaColliding( + ThePaths.m_pathNodes[closestNode].GetPosition(), 10.0f, true, &colliding, 2, nil, false, true, true, false, false); + if (!colliding) { + CZoneInfo zoneInfo; + int chosenCarClass; + CTheZones::GetZoneInfoForTimeOfDay(&ourPos, &zoneInfo); + int chosenModel = CCarCtrl::ChooseModel(&zoneInfo, &ourPos, &chosenCarClass); + CAutomobile *newVeh = new CAutomobile(chosenModel, RANDOM_VEHICLE); + if (newVeh) { + newVeh->GetMatrix().GetPosition() = ThePaths.m_pathNodes[closestNode].GetPosition(); + newVeh->GetMatrix().GetPosition().z += 4.0f; + newVeh->SetHeading(DEGTORAD(200.0f)); + newVeh->SetStatus(STATUS_ABANDONED); + newVeh->m_nDoorLock = CARLOCK_UNLOCKED; + CWorld::Add(newVeh); + m_pMyVehicle = newVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + } + } + } + } + break; + } + } else { + ClearLookFlag(); + bObjectiveCompleted = true; + } + } + case OBJECTIVE_KILL_CHAR_ON_FOOT: + { + bool killPlayerInNoPoliceZone = false; + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + break; + } + if (!m_pedInObjective || m_pedInObjective->DyingOrDead()) { + ClearLookFlag(); + bObjectiveCompleted = true; + SetMoveAnim(); + break; + } + if (m_pedInObjective->IsPlayer() && CCullZones::NoPolice()) + killPlayerInNoPoliceZone = true; + + if (!bNotAllowedToDuck || killPlayerInNoPoliceZone) { + if (m_nPedType == PEDTYPE_COP && !m_pedInObjective->GetWeapon()->IsTypeMelee() && !GetWeapon()->IsTypeMelee()) + bNotAllowedToDuck = true; + } else { + if (!m_pedInObjective->bInVehicle) { + if (m_pedInObjective->GetWeapon()->IsTypeMelee() || GetWeapon()->IsTypeMelee()) { + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + } else if (DuckAndCover()) { + break; + } + } else { + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + } + } + if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds() && !bKindaStayInSamePlace) { + SetMoveState(PEDMOVE_STILL); + break; + } + if (m_pedInObjective->IsPlayer()) { + CPlayerPed *player = FindPlayerPed(); + if (m_nPedType == PEDTYPE_COP && player->m_pWanted->m_bIgnoredByCops + || player->m_pWanted->m_bIgnoredByEveryone + || m_pedInObjective->bIsInWater + || m_pedInObjective->m_nPedState == PED_ARRESTED) { + + if (m_nPedState != PED_ARREST_PLAYER) + SetIdle(); + + break; + } + } + CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + float wepRange = wepInfo->m_fRange; + float wepRangeAdjusted; + if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { + wepRangeAdjusted = wepRange / 3.0f; + } else { + if (m_nPedState == PED_FIGHT) { + if (!IsPlayer() && !(m_pedStats->m_flags & STAT_CAN_KICK)) + wepRange = 2.0f; + } else { + wepRange = 1.3f; + } + wepRangeAdjusted = wepRange; + } + if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() && wepRangeAdjusted < 2.5f) { + wepRangeAdjusted = 2.5f; + } + if (m_pedInObjective->IsPlayer() && m_nPedType != PEDTYPE_COP + && CharCreatedBy != MISSION_CHAR && FindPlayerPed()->m_pWanted->m_CurrentCops) { + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + break; + } + if (m_pedInObjective->m_fHealth <= 0.0f) { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + SetMoveAnim(); + break; + } + float distWithTargetSc = distWithTarget.Magnitude(); + if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + CVehicle *vehOfTarget = m_pedInObjective->m_pMyVehicle; + if (vehOfTarget->bIsInWater || vehOfTarget->GetStatus() == STATUS_PLAYER_DISABLED + || m_pedInObjective->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled()) { + SetIdle(); + return; + } + SetLookFlag(vehOfTarget, false); + if (m_nPedState != PED_CARJACK) { + if (m_pedInObjective->m_nPedState != PED_ARRESTED) { + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE + && distWithTargetSc < wepRange && distWithTargetSc > 3.0f) { + + // I hope so + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + CVector maxShotPos = vehOfTarget->GetPosition() - ourHead; + maxShotPos.Normalise(); + maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CColPoint foundCol; + CEntity *foundEnt; + CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, + true, true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = false; + if (foundEnt == vehOfTarget) { + SetAttack(vehOfTarget); + m_pPointGunAt = vehOfTarget; + if (vehOfTarget) + vehOfTarget->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); + if (distWithTargetSc <= m_distanceToCountSeekDone) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 500)); + SetMoveState(PEDMOVE_STILL); + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + } + } + } + else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace && !killPlayerInNoPoliceZone) { + if (vehOfTarget) { + if (m_nPedType == PEDTYPE_COP || vehOfTarget->bIsBus) { + GoToNearestDoor(vehOfTarget); + } else { + m_vehEnterType = 0; + if (m_pedInObjective == vehOfTarget->pDriver || vehOfTarget->bIsBus) { + m_vehEnterType = CAR_DOOR_LF; + } else if (m_pedInObjective == vehOfTarget->pPassengers[0]) { + m_vehEnterType = CAR_DOOR_RF; + } else if (m_pedInObjective == vehOfTarget->pPassengers[1]) { + m_vehEnterType = CAR_DOOR_LR; + } else if (m_pedInObjective == vehOfTarget->pPassengers[2]) { + m_vehEnterType = CAR_DOOR_RR; + } + // Unused + // GetPositionToOpenCarDoor(vehOfTarget, m_vehEnterType); + SetSeekCar(vehOfTarget, m_vehEnterType); + SetMoveState(PEDMOVE_RUN); + } + } + } + } + } + SetMoveAnim(); + break; + } + if (m_nMoveState == PEDMOVE_STILL && IsPedInControl()) { + SetLookFlag(m_pedInObjective, false); + TurnBody(); + } + if (m_nPedType == PEDTYPE_COP && distWithTargetSc < 1.5f && m_pedInObjective->IsPlayer()) { + if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() + || m_pedInObjective->m_nPedState == PED_DRAG_FROM_CAR) { + + ((CCopPed*)this)->SetArrestPlayer(m_pedInObjective); + return; + } + } + if (!bKindaStayInSamePlace && !bStopAndShoot && m_nPedState != PED_ATTACK && !killPlayerInNoPoliceZone) { + if (distWithTargetSc > wepRange + || m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() + || m_pedInObjective->m_nPedState == PED_ARRESTED + || m_pedInObjective->EnteringCar() && distWithTargetSc < 3.0f + || distWithTargetSc > m_distanceToCountSeekDone && !CanSeeEntity(m_pedInObjective)) { + + if (m_pedInObjective->EnteringCar()) + wepRangeAdjusted = 2.0f; + + if (bUsePedNodeSeek) { + CVector bestCoords(0.0f, 0.0f, 0.0f); + m_vecSeekPos = m_pedInObjective->GetPosition(); + + if (!m_pNextPathNode) + FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); + + if (m_pNextPathNode) + m_vecSeekPos = m_pNextPathNode->GetPosition(); + + SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); + } else { + SetSeek(m_pedInObjective, wepRangeAdjusted); + } + bCrouchWhenShooting = false; + if (m_pedInObjective->m_pCurrentPhysSurface && distWithTargetSc < 5.0f) { + if (wepRange <= 5.0f) { + if (m_pedInObjective->IsPlayer() + && FindPlayerPed()->m_bSpeedTimerFlag + && (IsGangMember() || m_nPedType == PEDTYPE_COP) + && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { + GiveWeapon(WEAPONTYPE_COLT45, 1000); + SetCurrentWeapon(WEAPONTYPE_COLT45); + } + } else { + bStopAndShoot = true; + } + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + break; + } + bStopAndShoot = false; + SetMoveAnim(); + break; + } + } + if (m_attackTimer < CTimer::GetTimeInMilliseconds() + && distWithTargetSc < wepRange && m_pedInObjective->m_nPedState != PED_GETUP && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + if (bIsDucking) { + CAnimBlendAssociation *duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (duckAnim) { + duckAnim->blendDelta = -2.0f; + break; + } + bIsDucking = false; + } else if (wepRange <= 5.0f) { + SetMoveState(PEDMOVE_STILL); + SetAttack(m_pedInObjective); + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, + GetPosition().x, GetPosition().y); + SetShootTimer(CGeneral::GetRandomNumberInRange(0.0f, 500.0f)); + SetAttackTimer(CGeneral::GetRandomNumberInRange(0.0f, 1500.0f)); + bObstacleShowedUpDuringKillObjective = false; + + } else { + CVector target; + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + if (m_pedInObjective->IsPed()) + m_pedInObjective->m_pedIK.GetComponentPosition((RwV3d*)&target, PED_MID); + else + target = m_pedInObjective->GetPosition(); + + target -= ourHead; + target.Normalise(); + target = target * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CEntity *foundEnt = nil; + CColPoint foundCol; + + CWorld::ProcessLineOfSight( + ourHead, target, foundCol, foundEnt, + true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = 0; + if (foundEnt == m_pedInObjective) { + SetAttack(m_pedInObjective); + m_pPointGunAt = m_pedInObjective; + if (m_pedInObjective) + m_pedInObjective->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 2000.0f)); + + int time; + if (distWithTargetSc <= wepRangeAdjusted) + time = CGeneral::GetRandomNumberInRange(100.0f, 500.0f); + else + time = CGeneral::GetRandomNumberInRange(1500.0f, 3000.0f); + + SetAttackTimer(time); + bObstacleShowedUpDuringKillObjective = false; + + } else if (foundEnt) { + if (foundEnt->IsPed()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f)); + bObstacleShowedUpDuringKillObjective = false; + } else { + if (foundEnt->IsObject()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 400.0f)); + bObstacleShowedUpDuringKillObjective = true; + } else if (foundEnt->IsVehicle()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(400.0f, 600.0f)); + bObstacleShowedUpDuringKillObjective = true; + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(700.0f, 1200.0f)); + bObstacleShowedUpDuringKillObjective = true; + } + } + + m_fleeFrom = foundEnt; + m_fleeFrom->RegisterReference((CEntity**) &m_fleeFrom); + SetPointGunAt(m_pedInObjective); + } + } + } else { + if (!m_pedInObjective->m_pCurrentPhysSurface) + bStopAndShoot = false; + + if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { + + // This is weird... + if (bNotAllowedToDuck && bKindaStayInSamePlace) { + if (!bIsDucking) { + CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAnim || duckAnim->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); + bIsDucking = true; + } + break; + } else { + CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAnim || duckAnim->blendDelta < 0.0f) { + bIsDucking = false; + } else { + break; + } + } + } + if (bObstacleShowedUpDuringKillObjective) { + if (m_nPedType == PEDTYPE_COP) { + if (GetWeapon()->m_eWeaponType > WEAPONTYPE_COLT45 + || m_fleeFrom && m_fleeFrom->IsObject()) { + wepRangeAdjusted = 6.0f; + } else if (m_fleeFrom && m_fleeFrom->IsVehicle()) { + wepRangeAdjusted = 4.0f; + } else { + wepRangeAdjusted = 2.0f; + } + } else { + wepRangeAdjusted = 2.0f; + } + } + if (distWithTargetSc <= wepRangeAdjusted) { + SetMoveState(PEDMOVE_STILL); + bIsPointingGunAt = true; + if (m_nPedState != PED_AIM_GUN && !bDuckAndCover) { + m_attackTimer = CTimer::GetTimeInMilliseconds(); + SetIdle(); + } + } else { + if (m_nPedState != PED_SEEK_ENTITY && m_nPedState != PED_SEEK_POS + && !bStopAndShoot && !killPlayerInNoPoliceZone && !bKindaStayInSamePlace) { + Say(SOUND_PED_ATTACK); + SetSeek(m_pedInObjective, wepRangeAdjusted); + bIsRunning = true; + } + } + } + } + + if (distWithTargetSc < 2.5f && wepRange > 5.0f + && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE) { + + SetAttack(m_pedInObjective); + if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { + int time = CGeneral::GetRandomNumberInRange(500.0f, 1000.0f); + SetAttackTimer(time); + SetShootTimer(time - 500); + } + SetMoveState(PEDMOVE_STILL); + } + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, GetPosition().x, GetPosition().y); + + SetMoveAnim(); + break; + } + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + { + if (InVehicle()) { + if (m_nPedState == PED_DRIVING) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } else if (m_nPedState != PED_FLEE_ENTITY) { + int time; + if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) + time = 0; + else + time = 6000; + + SetFindPathAndFlee(m_pedInObjective, time); + } + break; + } + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + { + if (m_pedInObjective) { + float safeDistance = 2.0f; + if (m_pedInObjective->bInVehicle) + safeDistance = 3.0f; + + float distWithTargetSc = distWithTarget.Magnitude(); + if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { + if (distWithTargetSc <= safeDistance) { + bScriptObjectiveCompleted = true; + if (m_nPedState != PED_ATTACK) { + SetIdle(); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + if (distWithTargetSc > 2.0f) + SetMoveState(m_pedInObjective->m_nMoveState); + else + SetMoveState(PEDMOVE_STILL); + } else { + SetSeek(m_pedInObjective, safeDistance); + if (distWithTargetSc >= 5.0f) { + if (m_leader && m_leader->m_nMoveState == PEDMOVE_SPRINT) + SetMoveState(PEDMOVE_SPRINT); + else + SetMoveState(PEDMOVE_RUN); + } else { + if (m_leader && m_leader->m_nMoveState != PEDMOVE_STILL + && m_leader->m_nMoveState != PEDMOVE_NONE) { + if (m_leader->IsPlayer()) { + if (distWithTargetSc >= 3.0f && FindPlayerPed()->m_fMoveSpeed >= 1.3f) + SetMoveState(PEDMOVE_RUN); + else + SetMoveState(PEDMOVE_WALK); + } else { + SetMoveState(m_leader->m_nMoveState); + } + } else if (distWithTargetSc <= 3.0f) { + SetMoveState(PEDMOVE_WALK); + } else { + SetMoveState(PEDMOVE_RUN); + } + } + } + } + } else { + SetObjective(OBJECTIVE_NONE); + } + break; + } + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + { + if (m_pedInObjective) { + CVector posToGo = GetFormationPosition(); + distWithTarget = posToGo - carOrOurPos; + SetSeek(posToGo, 1.0f); + if (distWithTarget.Magnitude() <= 3.0f) { + SetSeek(posToGo, 1.0f); + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + SetMoveState(m_pedInObjective->m_nMoveState); + } else { + SetSeek(posToGo, 1.0f); + SetMoveState(PEDMOVE_RUN); + } + } else { + SetObjective(OBJECTIVE_NONE); + } + break; + } + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + { + if (m_carInObjective) { + if (!bInVehicle && m_carInObjective->m_nNumPassengers >= m_carInObjective->m_nNumMaxPassengers) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + + break; + } + + if (m_prevObjective == OBJECTIVE_HAIL_TAXI && !((CAutomobile*)m_carInObjective)->bTaxiLight) { + RestorePreviousObjective(); + ClearObjective(); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + bIsRunning = false; + break; + } + if (m_objectiveTimer && m_objectiveTimer < CTimer::GetTimeInMilliseconds()) { + if (!EnteringCar()) { + bool foundSeat = false; + if (m_carInObjective->pPassengers[0] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { + if (m_carInObjective->pPassengers[1] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { + if (m_carInObjective->pPassengers[2] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { + foundSeat = false; + } else { + m_vehEnterType = CAR_DOOR_RR; + foundSeat = true; + } + } else { + m_vehEnterType = CAR_DOOR_LR; + foundSeat = true; + } + } else { + m_vehEnterType = CAR_DOOR_RF; + foundSeat = true; + } + for (int i = 2; i < m_carInObjective->m_nNumMaxPassengers; ++i) { + if (!m_carInObjective->pPassengers[i] && !(m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { + m_vehEnterType = CAR_DOOR_RF; + foundSeat = true; + } + } + if (foundSeat) { + SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType)); + SetEnterCar(m_carInObjective, m_vehEnterType); + } + } + m_objectiveTimer = 0; + } + } + // fall through + } + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + { + if (!m_carInObjective || bInVehicle) { +#ifdef VC_PED_PORTS + if (bInVehicle && m_pMyVehicle != m_carInObjective) { + SetExitCar(m_pMyVehicle, 0); + } else +#endif + { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + RestorePreviousState(); + } + } else { + if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) { + SetMoveState(PEDMOVE_STILL); + break; + } + if (IsPedInControl()) { + if (m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (distWithTarget.Magnitude() < 20.0f) { + RestorePreviousObjective(); + RestorePreviousState(); + return; + } + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_carInObjective->pDriver +#ifdef VC_PED_PORTS + && !IsPlayer() +#endif + ) { + if (m_carInObjective->pDriver->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS && m_carInObjective->pDriver != m_pedInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + m_carInObjective->bIsBeingCarJacked = false; + } + } + } + } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (m_carInObjective->pDriver +#ifdef VC_PED_PORTS + && (CharCreatedBy != MISSION_CHAR || m_carInObjective->pDriver->CharCreatedBy != RANDOM_CHAR) +#endif + ) { + if (m_carInObjective->pDriver->m_nPedType == m_nPedType) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + m_carInObjective->bIsBeingCarJacked = false; + } + } + } + if (m_carInObjective->IsUpsideDown() && m_carInObjective->m_vehType != VEHICLE_TYPE_BIKE) { + RestorePreviousObjective(); + RestorePreviousState(); + return; + } + if (!m_carInObjective->IsBoat() || m_nPedState == PED_SEEK_IN_BOAT) { + if (m_nPedState != PED_SEEK_CAR) + SetSeekCar(m_carInObjective, 0); + } else { + SetSeekBoatPosition(m_carInObjective); + } + if (m_nMoveState == PEDMOVE_STILL && !bVehEnterDoorIsBlocked) + SetMoveState(PEDMOVE_RUN); + + if (m_carInObjective && m_carInObjective->m_fHealth > 0.0f) { + distWithTarget = m_carInObjective->GetPosition() - GetPosition(); + if (!bInVehicle) { + if (nEnterCarRangeMultiplier * ENTER_CAR_MAX_DIST < distWithTarget.Magnitude()) { + if (!m_carInObjective->pDriver && !m_carInObjective->GetIsOnScreen() && !GetIsOnScreen()) + WarpPedToNearEntityOffScreen(m_carInObjective); + + if (CharCreatedBy != MISSION_CHAR || m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS +#ifdef VC_PED_PORTS + || IsPlayer() && !CPad::GetPad(0)->ArePlayerControlsDisabled() +#endif + ) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } + } + } else if (!bInVehicle) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + } + } + break; + } + case OBJECTIVE_DESTROY_CAR: + { + if (!m_carInObjective) { + ClearLookFlag(); + bObjectiveCompleted = true; + break; + } + float distWithTargetSc = distWithTarget.Magnitude(); + CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + float wepRange = wepInfo->m_fRange; + m_pLookTarget = m_carInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + + TurnBody(); + if (m_carInObjective->m_fHealth <= 0.0f) { + ClearLookFlag(); + bScriptObjectiveCompleted = true; + break; + } + + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE + && distWithTargetSc < wepRange) { + + // I hope so + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + CVector maxShotPos = m_carInObjective->GetPosition() - ourHead; + maxShotPos.Normalise(); + maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CColPoint foundCol; + CEntity *foundEnt; + CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, + true, true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = false; + if (foundEnt == m_carInObjective) { + SetAttack(m_carInObjective); + m_pPointGunAt = m_carInObjective; + if (m_pPointGunAt) + m_pPointGunAt->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); + if (distWithTargetSc > 10.0f && !bKindaStayInSamePlace) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(50, 300)); + SetMoveState(PEDMOVE_STILL); + } + } + } else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace) { + + float safeDistance; + if (wepRange <= 5.0f) + safeDistance = 3.0f; + else + safeDistance = wepRange * 0.25f; + + SetSeek(m_carInObjective, safeDistance); + SetMoveState(PEDMOVE_RUN); + } + SetLookFlag(m_carInObjective, false); + TurnBody(); + break; + } + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + { + distWithTarget = m_nextRoutePointPos - GetPosition(); + distWithTarget.z = 0.0f; + if (InVehicle()) { + CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); + CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); + if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + break; + } + if (distWithTarget.Magnitude() > 30.0f) { + if (m_pMyVehicle) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + } else { + float closestVehDist = SQR(60.0f); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle* foundVeh = nil; + for (int i = 0; i < lastVehicle; i++) { + CVehicle* nearVeh = (CVehicle*)vehicles[i]; + /* + Not used. + CVector vehSpeed = nearVeh->GetSpeed(); + CVector ourSpeed = GetSpeed(); + */ + CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); + if (vehDistVec.MagnitudeSqr() < closestVehDist + && m_pedInObjective->m_pMyVehicle != nearVeh) + { + foundVeh = nearVeh; + closestVehDist = vehDistVec.MagnitudeSqr(); + } + } + m_pMyVehicle = foundVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + break; + } + // fall through + } + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + { + if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) + && InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } else { + distWithTarget = m_nextRoutePointPos - GetPosition(); + distWithTarget.z = 0.0f; + if (sq(m_distanceToCountSeekDone) >= distWithTarget.MagnitudeSqr()) { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + SetMoveState(PEDMOVE_STILL); + } else if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer || m_nPedState != PED_SEEK_POS) { + if (bUsePedNodeSeek) { + CVector bestCoords(0.0f, 0.0f, 0.0f); + m_vecSeekPos = m_nextRoutePointPos; + + if (!m_pNextPathNode) + FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); + + if (m_pNextPathNode) + m_vecSeekPos = m_pNextPathNode->GetPosition(); + } + SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); + } + } + + break; + } + case OBJECTIVE_GUARD_ATTACK: + { + if (m_pedInObjective) { + SetLookFlag(m_pedInObjective, true); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_lookTimer = m_attackTimer; + TurnBody(); + float distWithTargetSc = distWithTarget.Magnitude(); + if (distWithTargetSc >= 20.0f) { + RestorePreviousObjective(); + } else if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { + if (m_nPedState != PED_SEEK_ENTITY && distWithTargetSc >= 2.0f) { + SetSeek(m_pedInObjective, 1.0f); + } else { + SetAttack(m_pedInObjective); + SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1500.0f)); + } + SetAttackTimer(1000); + } + } else { + RestorePreviousObjective(); + } + break; + } + case OBJECTIVE_FOLLOW_ROUTE: + if (HaveReachedNextPointOnRoute(1.0f)) { + int nextPoint = GetNextPointOnRoute(); + m_nextRoutePointPos = CRouteNode::GetPointPosition(nextPoint); + } else { + SetSeek(m_nextRoutePointPos, 0.8f); + } + break; + case OBJECTIVE_SOLICIT_VEHICLE: + if (m_carInObjective) { + if (m_objectiveTimer <= CTimer::GetTimeInMilliseconds()) { + if (!bInVehicle) { + SetObjective(OBJECTIVE_NONE); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + if (IsPedInControl()) + m_pMyVehicle = nil; + } + } else { + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_SOLICIT) + SetSeekCar(m_carInObjective, 0); + } + } else { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + break; + case OBJECTIVE_HAIL_TAXI: + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TAXI) && CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + Say(SOUND_PED_TAXI_WAIT); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TAXI, 4.0f); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + } + break; + case OBJECTIVE_CATCH_TRAIN: + { + if (m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + } else { + CVehicle* trainToEnter = nil; + float closestCarDist = CHECK_NEARBY_THINGS_MAX_DIST; + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + + CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + for (int i = 0; i < lastVehicle; i++) { + CVehicle* nearVeh = (CVehicle*)vehicles[i]; + if (nearVeh->IsTrain()) { + CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); + float vehDist = vehDistVec.Magnitude(); + if (vehDist < closestCarDist && m_pedInObjective->m_pMyVehicle != nearVeh) + { + trainToEnter = nearVeh; + closestCarDist = vehDist; + } + } + } + if (trainToEnter) { + m_carInObjective = trainToEnter; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + } + } + break; + } + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective) { + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_BUY_ICECREAM) + SetSeekCar(m_carInObjective, 0); + } else { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + break; + case OBJECTIVE_STEAL_ANY_CAR: + { + if (bInVehicle) { + bScriptObjectiveCompleted = true; + RestorePreviousObjective(); + } else if (m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + CVehicle *carToSteal = nil; + float closestCarDist = ENTER_CAR_MAX_DIST; + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + + // NB: This should've been ENTER_CAR_MAX_DIST actually, and is fixed in VC. + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + for(int i = 0; i < lastVehicle; i++) { + CVehicle *nearVeh = (CVehicle*)vehicles[i]; + if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { + if (nearVeh->m_vecMoveSpeed.Magnitude() <= 0.1f) { + if (nearVeh->CanPedOpenLocks(this)) { + CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); + float vehDist = vehDistVec.Magnitude(); + if (vehDist < closestCarDist) { + carToSteal = nearVeh; + closestCarDist = vehDist; + } + } + } + } + } + if (carToSteal) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carToSteal); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else { + RestorePreviousObjective(); + RestorePreviousState(); + } + } + break; + } + case OBJECTIVE_MUG_CHAR: + { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer() || m_pedInObjective->bInVehicle || m_pedInObjective->m_fHealth <= 0.0f) { + ClearObjective(); + return; + } + if (m_pedInObjective->m_nMoveState > PEDMOVE_WALK) { + ClearObjective(); + return; + } + if (m_pedInObjective->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_pedInObjective->m_pedInObjective == this) { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pedInObjective); + SetMoveState(PEDMOVE_SPRINT); + return; + } + if (m_pedInObjective->m_nPedState == PED_FLEE_ENTITY && m_fleeFrom == this + || m_pedInObjective->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE && m_pedInObjective->m_pedInObjective == this) { + ClearObjective(); + SetFindPathAndFlee(m_pedInObjective, 15000, true); + return; + } + float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); + if (distWithTargetScSqr <= sq(10.0f)) { + if (distWithTargetScSqr <= sq(1.4f)) { + CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, + GetPosition().x, GetPosition().y); + + if (reloadAssoc || !m_pedInObjective->IsPedShootable()) { + if (reloadAssoc && + (!reloadAssoc->IsRunning() || reloadAssoc->currentTime / reloadAssoc->hierarchy->totalLength > 0.8f)) { + CAnimBlendAssociation *punchAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); + punchAssoc->flags |= ASSOC_DELETEFADEDOUT; + punchAssoc->flags |= ASSOC_FADEOUTWHENDONE; + CVector2D offset(distWithTarget.x, distWithTarget.y); + int dir = m_pedInObjective->GetLocalDirection(offset); + m_pedInObjective->StartFightDefend(dir, HITLEVEL_HIGH, 5); + m_pedInObjective->ReactToAttack(this); + m_pedInObjective->Say(SOUND_PED_ROBBED); + Say(SOUND_PED_MUGGING); + bRichFromMugging = true; + + // VC FIX: ClearObjective() clears m_pedInObjective in VC (also same with VC_PED_PORTS), so get it before call + CPed *victim = m_pedInObjective; + ClearObjective(); + if (victim->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + || victim->m_pedInObjective != this) { + SetFindPathAndFlee(victim, 15000, true); + m_nLastPedState = PED_WANDER_PATH; + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, victim); + SetMoveState(PEDMOVE_SPRINT); + m_nLastPedState = PED_WANDER_PATH; + } + } + } else { + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + if (weaponType != WEAPONTYPE_UNARMED && weaponType != WEAPONTYPE_BASEBALLBAT) + SetCurrentWeapon(WEAPONTYPE_UNARMED); + + CAnimBlendAssociation *newReloadAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_AK_RELOAD, 8.0f); + newReloadAssoc->flags |= ASSOC_DELETEFADEDOUT; + newReloadAssoc->flags |= ASSOC_FADEOUTWHENDONE; + } + } else { + SetSeek(m_pedInObjective, 1.0f); + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK); + + if (walkAssoc) + walkAssoc->speed = 1.3f; + } + } else { + ClearObjective(); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + } else { +#ifdef VC_PED_PORTS + m_objective = OBJECTIVE_NONE; +#endif + ClearObjective(); + } + break; + } + case OBJECTIVE_FLEE_CAR: + if (!bInVehicle && m_nPedState != PED_FLEE_ENTITY && m_pMyVehicle) { + RestorePreviousObjective(); + SetFlee(m_pMyVehicle, 6000); + break; + } + // fall through + case OBJECTIVE_LEAVE_CAR: + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + if (InVehicle() +#ifdef VC_PED_PORTS + && (FindPlayerPed() != this || !CPad::GetPad(0)->GetAccelerate() + || bBusJacked) +#endif + ) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN + && (m_nPedType != PEDTYPE_COP +#ifdef VC_PED_PORTS + || m_pMyVehicle->IsBoat() +#endif + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.005f))) { + if (m_pMyVehicle->IsTrain()) + SetExitTrain(m_pMyVehicle); +#ifdef VC_PED_PORTS + else if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); +#endif + else + SetExitCar(m_pMyVehicle, 0); + } + } else { + RestorePreviousObjective(); + } + } + break; +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: + { + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + if (InVehicle()) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { + if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); + else if (m_pMyVehicle->bIsBus) + SetExitCar(m_pMyVehicle, 0); + else { + eCarNodes doorNode = CAR_DOOR_LF; + if (m_pMyVehicle->pDriver != this) { + if (m_pMyVehicle->pPassengers[0] == this) { + doorNode = CAR_DOOR_RF; + } else if (m_pMyVehicle->pPassengers[1] == this) { + doorNode = CAR_DOOR_LR; + } else if (m_pMyVehicle->pPassengers[2] == this) { + doorNode = CAR_DOOR_RR; + } + } + SetBeingDraggedFromCar(m_pMyVehicle, doorNode, false); + } + } + } + } + break; + } +#endif + } + if (bObjectiveCompleted + || m_objectiveTimer > 0 && CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + RestorePreviousObjective(); + if (m_objectiveTimer > CTimer::GetTimeInMilliseconds() || !m_objectiveTimer) + m_objectiveTimer = CTimer::GetTimeInMilliseconds() - 1; + + if (CharCreatedBy != RANDOM_CHAR || bInVehicle) { + if (IsPedInControl()) + RestorePreviousState(); + } else { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + ClearAimFlag(); + ClearLookFlag(); + } + } +} + +void +CPed::SetFollowRoute(int16 currentPoint, int16 routeType) +{ + m_routeLastPoint = currentPoint; + m_routeStartPoint = CRouteNode::GetRouteStart(currentPoint); + m_routePointsPassed = 0; + m_routeType = routeType; + m_routePointsBeingPassed = 1; + m_objective = OBJECTIVE_FOLLOW_ROUTE; + m_nextRoutePointPos = CRouteNode::GetPointPosition(GetNextPointOnRoute()); +} + +int +CPed::GetNextPointOnRoute(void) +{ + int16 nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + + // Route is complete + if (nextPoint < 0 || nextPoint > NUMPEDROUTES || m_routeLastPoint != CRouteNode::GetRouteThisPointIsOn(nextPoint)) { + + switch (m_routeType) { + case PEDROUTE_STOP_WHEN_DONE: + nextPoint = -1; + break; + case PEDROUTE_GO_BACKWARD_WHEN_DONE: + m_routePointsBeingPassed = -m_routePointsBeingPassed; + nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + break; + case PEDROUTE_GO_TO_START_WHEN_DONE: + m_routePointsPassed = -1; + nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + break; + default: + break; + } + } + return nextPoint; +} + +bool +CPed::HaveReachedNextPointOnRoute(float distToCountReached) +{ + if ((m_nextRoutePointPos - GetPosition()).Magnitude2D() >= distToCountReached) + return false; + + m_routePointsPassed += m_routePointsBeingPassed; + return true; +} + +bool +CPed::CanSeeEntity(CEntity *entity, float threshold) +{ + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + entity->GetPosition().x, + entity->GetPosition().y, + GetPosition().x, + GetPosition().y); + + if (neededAngle < 0.0f) + neededAngle += TWOPI; + else if (neededAngle > TWOPI) + neededAngle -= TWOPI; + + float ourAngle = m_fRotationCur; + if (ourAngle < 0.0f) + ourAngle += TWOPI; + else if (ourAngle > TWOPI) + ourAngle -= TWOPI; + + float neededTurn = Abs(neededAngle - ourAngle); + + return neededTurn < threshold || TWOPI - threshold < neededTurn; +} + +// Only used while deciding which gun ped should switch to, if no ammo left. +bool +CPed::SelectGunIfArmed(void) +{ + for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { + if (GetWeapon(i).m_nAmmoTotal > 0) { + eWeaponType weaponType = GetWeapon(i).m_eWeaponType; + if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { + SetCurrentWeapon(i); + return true; + } + } + } + SetCurrentWeapon(WEAPONTYPE_UNARMED); + return false; +} + +void +CPed::ReactToPointGun(CEntity *entWithGun) +{ + CPed *pedWithGun = (CPed*)entWithGun; + int waitTime; + + if (IsPlayer() || !IsPedInControl() || CharCreatedBy == MISSION_CHAR) + return; + + if (m_leader == pedWithGun) + return; + + if (m_nWaitState == WAITSTATE_PLAYANIM_HANDSUP || m_nWaitState == WAITSTATE_PLAYANIM_HANDSCOWER || + (GetPosition() - pedWithGun->GetPosition()).MagnitudeSqr2D() > 225.0f) + return; + + if (m_leader) { + if (FindPlayerPed() == m_leader) + return; + + ClearLeader(); + } + if (m_pedStats->m_flags & STAT_GUN_PANIC + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_AIM_GUN) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSCOWER, &waitTime); + Say(SOUND_PED_HANDS_COWER); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + + } else if (m_nPedType != pedWithGun->m_nPedType) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(pedWithGun); + } + + if (m_nPedType == PEDTYPE_COP) { + if (pedWithGun->IsPlayer()) { + ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); + if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + return; + } + } + } + + if (m_nPedType != PEDTYPE_COP + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && (m_nPedState != PED_FLEE_ENTITY || pedWithGun->IsPlayer() && m_fleeFrom != pedWithGun) + && m_nPedState != PED_AIM_GUN && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSUP, &waitTime); + Say(SOUND_PED_HANDS_UP); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + if (m_nPedState == PED_FLEE_ENTITY) { + m_fleeFrom = pedWithGun; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + } + + if (FindPlayerPed() == pedWithGun && bRichFromMugging) { + int money = CGeneral::GetRandomNumberInRange(100, 300); + int pickupCount = money / 40 + 1; + int moneyPerPickup = money / pickupCount; + + for (int i = 0; i < pickupCount; i++) { + float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().x; + float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().y; + bool found = false; + float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; + if (found) { + CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); + } + } + bRichFromMugging = false; + } + } + } +} + +void +CPed::ReactToAttack(CEntity *attacker) +{ + if (IsPlayer() && attacker->IsPed()) { + InformMyGangOfAttack(attacker); + SetLookFlag(attacker, true); + SetLookTimer(700); + return; + } + +#ifdef VC_PED_PORTS + if (m_nPedState == PED_DRIVING && InVehicle() + && (m_pMyVehicle->pDriver == this || m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING && m_pMyVehicle->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE)) { + + if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE + && (m_pMyVehicle->GetStatus() == STATUS_SIMPLE || m_pMyVehicle->GetStatus() == STATUS_PHYSICS) + && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) { + + CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; + m_pMyVehicle->SetStatus(STATUS_PHYSICS); + } + } else +#endif + if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) { + CPed *ourLeader = m_leader; + if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader) + && attacker->IsPed()) { + + CPed *attackerPed = (CPed*)attacker; + if (bNotAllowedToDuck) { + if (!attackerPed->GetWeapon()->IsTypeMelee()) { + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds(); + return; + } + } else if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + return; + } + + if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) { + if (m_pedStats != attackerPed->m_pedStats) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(attackerPed); + } + if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker); + SetMoveState(PEDMOVE_RUN); + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker); + SetObjectiveTimer(20000); + } + } + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed); + SetMoveState(PEDMOVE_RUN); + if (attackerPed->GetWeapon()->IsTypeMelee()) + Say(SOUND_PED_FLEE_RUN); + } + } + } +} + +void +CPed::PedAnimAlignCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + + return; + } + if (ped->m_fHealth == 0.0f) { + ped->QuitEnteringCar(); + return; + } + bool itsVan = !!veh->bIsVan; + bool itsBus = !!veh->bIsBus; +#ifdef FIX_BUGS + bool itsLow = !!veh->bLowVehicle; +#endif + eDoors enterDoor; + AnimationId enterAnim; + + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + itsVan = false; + enterDoor = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + enterDoor = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + itsVan = false; + enterDoor = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + enterDoor = DOOR_REAR_LEFT; + break; + default: + break; + } + + if (veh->IsDoorMissing(enterDoor) || veh->IsDoorFullyOpen(enterDoor)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (ped->m_nPedState == PED_CARJACK) { + ped->PedAnimDoorOpenCB(nil, ped); + return; + } + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + enterAnim = ANIM_VAN_GETIN; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_R; +#ifdef FIX_BUGS + } else if (itsLow) { + enterAnim = ANIM_CAR_GETIN_LOW_RHS; +#endif + } else { + enterAnim = ANIM_CAR_GETIN_RHS; + } + } else if (itsVan) { + enterAnim = ANIM_VAN_GETIN_L; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_L; +#ifdef FIX_BUGS + } else if (itsLow) { + enterAnim = ANIM_CAR_GETIN_LOW_LHS; +#endif + } else { + enterAnim = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, enterAnim); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + + } else if (veh->CanPedOpenLocks(ped)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_R); + } else { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_RHS); + } + } else if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN_L); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_L); + } else { + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && veh->pDriver) { + + if (!veh->bLowVehicle + && veh->pDriver->CharCreatedBy != MISSION_CHAR + && veh->pDriver->m_nPedState == PED_DRIVING) { + + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_QJACK); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, true); + + if (veh->pDriver->IsGangMember()) + veh->pDriver->RegisterThreatWithGangPeds(ped); + return; + } + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_LHS); + } + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + + } else { + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_LHS); + + ped->bCancelEnteringCar = true; + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + } +} + +void +CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + + return; + } + + eDoors door; + CPed *pedInSeat = nil; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; pedInSeat = veh->pPassengers[0]; break; + case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; pedInSeat = veh->pPassengers[2]; break; + case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; pedInSeat = veh->pDriver; break; + case CAR_DOOR_LR: door = DOOR_REAR_LEFT; pedInSeat = veh->pPassengers[1]; break; + default: assert(0); + } + + if (ped->m_fHealth == 0.0f || CPad::GetPad(0)->ArePlayerControlsDisabled() && pedInSeat && pedInSeat->IsPlayer()) { + ped->QuitEnteringCar(); + return; + } + + bool isVan = veh->bIsVan; + bool isBus = veh->bIsBus; + bool isLow = veh->bLowVehicle; + bool vehUpsideDown = veh->IsUpsideDown(); + if (ped->bCancelEnteringCar) { + if (ped->IsPlayer()) { + if (veh->pDriver) { + if (veh->pDriver->m_nPedType == PEDTYPE_COP) { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + } + } +#ifdef CANCELLABLE_CAR_ENTER + if (!veh->IsDoorMissing(door) && veh->CanPedOpenLocks(ped) && veh->IsCar()) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } +#endif + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + ped->bCancelEnteringCar = false; + return; + } + if (!veh->IsDoorMissing(door) && veh->IsCar()) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } + + if (veh->m_vecMoveSpeed.Magnitude() > 0.2f) { + ped->QuitEnteringCar(); + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) + ped->SetFall(1000, ANIM_KO_SPIN_R, false); + else + ped->SetFall(1000, ANIM_KO_SPIN_L, false); + + return; + } + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_OPEN_LHS, 1.0f); + + if (ped->m_vehEnterType == CAR_DOOR_LF || ped->m_vehEnterType == CAR_DOOR_RF) + isVan = false; + + if (ped->m_nPedState != PED_CARJACK || isBus) { + AnimationId animToPlay; + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + + if (isVan) { + animToPlay = ANIM_VAN_GETIN; + } else if (isBus) { + animToPlay = ANIM_COACH_IN_R; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_RHS; + } else { + animToPlay = ANIM_CAR_GETIN_RHS; + } + } else if (isVan) { + animToPlay = ANIM_VAN_GETIN_L; + } else if (isBus) { + animToPlay = ANIM_COACH_IN_L; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_LHS; + } else { + animToPlay = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } else { + CPed *pedToDragOut = nil; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: pedToDragOut = veh->pPassengers[0]; break; + case CAR_DOOR_RR: pedToDragOut = veh->pPassengers[2]; break; + case CAR_DOOR_LF: pedToDragOut = veh->pDriver; break; + case CAR_DOOR_LR: pedToDragOut = veh->pPassengers[1]; break; + default: assert(0); + } + + if (vehUpsideDown) { + ped->QuitEnteringCar(); + if (ped->m_nPedType == PEDTYPE_COP) + ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); + } + + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (pedToDragOut && !pedToDragOut->bDontDragMeOutCar) { + if (pedToDragOut->m_nPedState != PED_DRIVING) { + ped->QuitEnteringCar(); + pedToDragOut = nil; + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_RHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); + } + } else if (ped->m_nPedType == PEDTYPE_COP) { + ped->QuitEnteringCar(); + if (ped->m_pedInObjective && ped->m_pedInObjective->m_nPedState == PED_DRIVING) { + veh->SetStatus(STATUS_PLAYER_DISABLED); + ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); + } else if (!veh->IsDoorMissing(DOOR_FRONT_RIGHT)) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING); + } + } else { + // BUG: Probably we will sit on top of the passenger if his m_ped_flagF4 is true. + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } + } else { + if (pedToDragOut) { + if (pedToDragOut->m_nPedState != PED_DRIVING || pedToDragOut->bDontDragMeOutCar) { + + // BUG: Player freezes in that condition due to its objective isn't restored. It's an unfinished feature, used in VC. + ped->QuitEnteringCar(); + pedToDragOut = nil; + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); + } + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } + } + + if (pedToDragOut) { + pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, false); + if (pedToDragOut->IsGangMember()) + pedToDragOut->RegisterThreatWithGangPeds(ped); + } + } + + if (veh->pDriver && ped) { + veh->pDriver->SetLookFlag(ped, true); + veh->pDriver->SetLookTimer(1000); + } + return; +} + +void +CPed::PedAnimPullPedOutCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (ped->EnteringCar()) { + if (!ped->IsNotInWreckedVehicle()) + return; + +#ifdef CANCELLABLE_CAR_ENTER + if (ped->bCancelEnteringCar) { + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + ped->bCancelEnteringCar = false; + return; + } +#endif + + bool isLow = !!veh->bLowVehicle; + + int padNo; + if (ped->IsPlayer()) { + + // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads + switch (ped->m_nPedType) { + case PEDTYPE_PLAYER1: + padNo = 0; + break; + case PEDTYPE_PLAYER2: + padNo = 1; + break; + case PEDTYPE_PLAYER3: + padNo = 2; + break; + case PEDTYPE_PLAYER4: + padNo = 3; + break; + } + CPad *pad = CPad::GetPad(padNo); + + if (!pad->ArePlayerControlsDisabled()) { + + if (pad->GetTarget() + || pad->NewState.LeftStickX + || pad->NewState.LeftStickY + || pad->NewState.DPadUp + || pad->NewState.DPadDown + || pad->NewState.DPadLeft + || pad->NewState.DPadRight) { + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + return; + } + } + } + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + AnimationId animToPlay; + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (isLow) + animToPlay = ANIM_CAR_GETIN_LOW_RHS; + else + animToPlay = ANIM_CAR_GETIN_RHS; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_LHS; + } else { + animToPlay = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } else { + ped->QuitEnteringCar(); + } + } else { + ped->QuitEnteringCar(); + } +} + +void +CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*) arg; + + CVehicle *veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if(ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + return; + } + + if (ped->IsPlayer() && ped->bGonnaKillTheCarJacker && ((CPlayerPed*)ped)->m_pArrestingCop) { + PedSetInCarCB(nil, ped); + ped->m_nLastPedState = ped->m_nPedState; + ped->m_nPedState = PED_ARRESTED; + ped->bGonnaKillTheCarJacker = false; + if (veh) { + veh->m_nNumGettingIn = 0; + veh->m_nGettingInFlags = 0; + veh->bIsHandbrakeOn = true; + veh->SetStatus(STATUS_PLAYER_DISABLED); + } + return; + } + if (ped->IsPlayer() && ped->m_vehEnterType == CAR_DOOR_LF + && (Pads[0].GetAccelerate() >= 255.0f || Pads[0].GetBrake() >= 255.0f) + && veh->IsCar()) { + if (((CAutomobile*)veh)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != DOOR_STATUS_MISSING) + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); + + PedSetInCarCB(nil, ped); + return; + } + bool isVan = !!veh->bIsVan; + bool isBus = !!veh->bIsBus; + bool isLow = !!veh->bLowVehicle; + eDoors enterDoor; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + isVan = false; + enterDoor = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + enterDoor = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + isVan = false; + enterDoor = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + enterDoor = DOOR_REAR_LEFT; + break; + default: + break; + } + if (!veh->IsDoorMissing(enterDoor)) { + if (veh->IsCar()) + ((CAutomobile*)veh)->Damage.SetDoorStatus(enterDoor, DOOR_STATUS_SWINGING); + } + CPed *driver = veh->pDriver; + if (driver && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { + if (veh->bIsBus) { + driver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + if (driver->IsPlayer()) { + veh->bIsHandbrakeOn = true; + veh->SetStatus(STATUS_PLAYER_DISABLED); + } + driver->bBusJacked = true; + veh->bIsBeingCarJacked = false; + PedSetInCarCB(nil, ped); + if (ped->m_nPedType == PEDTYPE_COP + || ped->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT + || ped->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + } + ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 400; + return; + } + if (driver != ped && ped->m_vehEnterType != CAR_DOOR_LF) { + if (!driver->IsPlayer()) { + driver->bUsePedNodeSeek = true; + driver->m_pLastPathNode = nil; + if (driver->m_pedStats->m_temper <= driver->m_pedStats->m_fear + || driver->CharCreatedBy == MISSION_CHAR + || veh->VehicleCreatedBy == MISSION_VEHICLE) { + driver->bFleeAfterExitingCar = true; + } else { + driver->bGonnaKillTheCarJacker = true; + veh->pDriver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped); + + if (veh->pDriver->m_nPedType == PEDTYPE_COP && ped->IsPlayer()) { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + } + } + if ((ped->m_nPedType != PEDTYPE_EMERGENCY || veh->pDriver->m_nPedType != PEDTYPE_EMERGENCY) + && (ped->m_nPedType != PEDTYPE_COP || veh->pDriver->m_nPedType != PEDTYPE_COP)) { + veh->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + veh->pDriver->Say(SOUND_PED_CAR_JACKED); +#ifdef VC_PED_PORTS + veh->pDriver->SetRadioStation(); +#endif + } else { + ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; + } + } + } + if (veh->IsDoorMissing(enterDoor) || isBus) { + PedAnimDoorCloseCB(nil, ped); + } else { + AnimationId animToPlay; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (isVan) { + animToPlay = ANIM_VAN_CLOSE; + } else if (isLow) { + animToPlay = ANIM_CAR_CLOSEDOOR_LOW_RHS; + } else { + animToPlay = ANIM_CAR_CLOSEDOOR_RHS; + } + } else if (isVan) { + animToPlay = ANIM_VAN_CLOSE_L; + } else if (isLow) { + animToPlay = ANIM_CAR_CLOSEDOOR_LOW_LHS; + } else { + animToPlay = ANIM_CAR_CLOSEDOOR_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorCloseCB, ped); + } +} + +void +CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CAutomobile *veh = (CAutomobile*)(ped->m_pMyVehicle); + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + if (ped->EnteringCar()) { + bool isLow = !!veh->bLowVehicle; + + if (!veh->bIsBus) + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); + + eDoors door; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; + case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; + case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; + case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break; + default: assert(0); + } + + if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING) + veh->Damage.SetDoorStatus(door, DOOR_STATUS_OK); + + if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { + PedSetInCarCB(nil, ped); + } else if (ped->m_vehEnterType == CAR_DOOR_RF + && (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF || + (veh->pDriver != nil && + (veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR +#ifdef VC_PED_PORTS + && veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE +#endif + || !veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil))))) { + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + || ped->m_nPedState == PED_CARJACK +#endif + ) + veh->bIsBeingCarJacked = false; + + ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; + PedSetInCarCB(nil, ped); + + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + if (!ped->IsPlayer()) + ped->bFleeAfterExitingCar = true; + + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + + } else { + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSHUFFLE_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SHUFFLE_RHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, ped); + } + } else { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + } +} + +void +CPed::SetFormation(eFormation type) +{ + // FIX: Formations in GetFormationPosition were in range 1-8, whereas in here it's 0-7. + // To not change the behaviour, range in here tweaked by 1 with the use of enum. + + switch (m_pedFormation) { + case FORMATION_REAR: + case FORMATION_REAR_LEFT: + case FORMATION_REAR_RIGHT: + case FORMATION_FRONT_LEFT: + case FORMATION_FRONT_RIGHT: + case FORMATION_LEFT: + case FORMATION_RIGHT: + case FORMATION_FRONT: + break; + default: + Error("Unknown formation type, PedAI.cpp"); + break; + } + m_pedFormation = type; +} + +CVector +CPed::GetFormationPosition(void) +{ + if (m_pedInObjective->m_nPedState == PED_DEAD) { + if (!m_pedInObjective->m_pedInObjective) { + m_pedInObjective = nil; + return GetPosition(); + } + m_pedInObjective = m_pedInObjective->m_pedInObjective; + } + + CVector formationOffset; + switch (m_pedFormation) { + case FORMATION_REAR: + formationOffset = CVector(0.0f, -1.5f, 0.0f); + break; + case FORMATION_REAR_LEFT: + formationOffset = CVector(-1.5f, -1.5f, 0.0f); + break; + case FORMATION_REAR_RIGHT: + formationOffset = CVector(1.5f, -1.5f, 0.0f); + break; + case FORMATION_FRONT_LEFT: + formationOffset = CVector(-1.5f, 1.5f, 0.0f); + break; + case FORMATION_FRONT_RIGHT: + formationOffset = CVector(1.5f, 1.5f, 0.0f); + break; + case FORMATION_LEFT: + formationOffset = CVector(-1.5f, 0.0f, 0.0f); + break; + case FORMATION_RIGHT: + formationOffset = CVector(1.5f, 0.0f, 0.0f); + break; + case FORMATION_FRONT: + formationOffset = CVector(0.0f, 1.5f, 0.0f); + break; + default: + formationOffset = CVector(0.0f, 0.0f, 0.0f); + break; + } + return formationOffset + m_pedInObjective->GetPosition(); +} + +void +CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!veh) { + PedSetOutCarCB(nil, ped); + return; + } +#ifdef VC_PED_PORTS + CVector posForZ = ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posForZ); + if (ped->GetPosition().z - 0.5f > posForZ.z) { + PedSetOutCarCB(nil, ped); + return; + } +#endif + veh->m_nStaticFrames = 0; + veh->m_vecMoveSpeed += CVector(0.001f, 0.001f, 0.001f); + veh->m_vecTurnSpeed += CVector(0.001f, 0.001f, 0.001f); + if (!veh->bIsBus) + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); + + /* + // Duplicate and only in PC for some reason + if (!veh) { + PedSetOutCarCB(nil, ped); + return; + } + */ + eDoors door; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + door = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + door = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + door = DOOR_REAR_LEFT; + break; + default: + break; + } + bool closeDoor = !veh->IsDoorMissing(door); + + int padNo; + if (ped->IsPlayer()) { + + // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads + switch (ped->m_nPedType) { + case PEDTYPE_PLAYER1: + padNo = 0; + break; + case PEDTYPE_PLAYER2: + padNo = 1; + break; + case PEDTYPE_PLAYER3: + padNo = 2; + break; + case PEDTYPE_PLAYER4: + padNo = 3; + break; + } + CPad* pad = CPad::GetPad(padNo); + bool engineIsIntact = veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225; + if (!pad->ArePlayerControlsDisabled() && veh->m_nDoorLock != CARLOCK_FORCE_SHUT_DOORS + && (pad->GetTarget() + || pad->NewState.LeftStickX + || pad->NewState.LeftStickY + || pad->NewState.DPadUp + || pad->NewState.DPadDown + || pad->NewState.DPadLeft + || pad->NewState.DPadRight) + || veh->bIsBus + || veh->m_pCarFire + || engineIsIntact) { + closeDoor = false; + } + } + +#ifdef VC_PED_PORTS + if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) + closeDoor = false; +#endif + + if (!closeDoor) { + if (!veh->IsDoorMissing(door) && !veh->bIsBus) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } + PedSetOutCarCB(nil, ped); + return; + } + + if (ped->bFleeAfterExitingCar || ped->bGonnaKillTheCarJacker) { + // POTENTIAL BUG? Why DOOR_FRONT_LEFT instead of door variable? or vice versa? + if (!veh->IsDoorMissing(door)) + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); + } else { + switch (door) { + case DOOR_FRONT_LEFT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); + break; + case DOOR_FRONT_RIGHT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); + break; + case DOOR_REAR_LEFT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); + break; + case DOOR_REAR_RIGHT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); + break; + default: + break; + } + } + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, ped); + return; +} + +void +CPed::LineUpPedWithCar(PedLineUpPhase phase) +{ + bool vehIsUpsideDown = false; + int vehAnim; + float seatPosMult = 0.0f; + float currentZ; + float adjustedTimeStep; + + if (CReplay::IsPlayingBack()) + return; + + if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO)) { + SetPedPositionInCar(); + return; + } + bChangedSeat = true; + } + if (phase == LINE_UP_TO_CAR_START) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + CVehicle *veh = m_pMyVehicle; + + // Not quite right, IsUpsideDown func. checks for <= -0.9f. + if (veh->GetUp().z <= -0.8f) + vehIsUpsideDown = true; + + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (vehIsUpsideDown) { + m_fRotationDest = -PI + veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + if (vehIsUpsideDown) { + m_fRotationDest = veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = -0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } else { + // I don't know will this part ever run(maybe boats?), but the game also handles that. I don't know is it intentional. + + if (vehIsUpsideDown) { + m_fRotationDest = veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } + + if (!bInVehicle) + seatPosMult = 1.0f; + +#ifdef VC_PED_PORTS + bool multExtractedFromAnim = false; + bool multExtractedFromAnimBus = false; + float zBlend; +#endif + if (m_pVehicleAnim) { + vehAnim = m_pVehicleAnim->animId; + + switch (vehAnim) { + case ANIM_CAR_JACKED_RHS: + case ANIM_CAR_LJACKED_RHS: + case ANIM_CAR_JACKED_LHS: + case ANIM_CAR_LJACKED_LHS: + case ANIM_VAN_GETIN_L: + case ANIM_VAN_GETIN: +#ifdef VC_PED_PORTS + multExtractedFromAnim = true; + zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.3f, 0.0f) / (1.0f - 0.3f); + // fall through +#endif + case ANIM_CAR_QJACKED: + case ANIM_CAR_GETOUT_LHS: + case ANIM_CAR_GETOUT_LOW_LHS: + case ANIM_CAR_GETOUT_RHS: + case ANIM_CAR_GETOUT_LOW_RHS: +#ifdef VC_PED_PORTS + if (!multExtractedFromAnim) { + multExtractedFromAnim = true; + zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.5f, 0.0f) / (1.0f - 0.5f); + } + // fall through +#endif + case ANIM_CAR_CRAWLOUT_RHS: + case ANIM_CAR_CRAWLOUT_RHS2: + case ANIM_VAN_GETOUT_L: + case ANIM_VAN_GETOUT: + seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_GETIN_RHS: + case ANIM_CAR_GETIN_LHS: +#ifdef VC_PED_PORTS + if (veh && veh->IsCar() && veh->bIsBus) { + multExtractedFromAnimBus = true; + zBlend = Min(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength, 0.5f) / 0.5f; + } + // fall through +#endif + case ANIM_CAR_QJACK: + case ANIM_CAR_GETIN_LOW_LHS: + case ANIM_CAR_GETIN_LOW_RHS: + case ANIM_DRIVE_BOAT: + seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_CLOSEDOOR_LHS: + case ANIM_CAR_CLOSEDOOR_LOW_LHS: + case ANIM_CAR_CLOSEDOOR_RHS: + case ANIM_CAR_CLOSEDOOR_LOW_RHS: + case ANIM_CAR_SHUFFLE_RHS: + case ANIM_CAR_LSHUFFLE_RHS: + seatPosMult = 0.0f; + break; + case ANIM_CAR_CLOSE_LHS: + case ANIM_CAR_CLOSE_RHS: + case ANIM_COACH_OPEN_L: + case ANIM_COACH_OPEN_R: + case ANIM_COACH_IN_L: + case ANIM_COACH_IN_R: + case ANIM_COACH_OUT_L: + seatPosMult = 1.0f; + break; + default: + break; + } + } + + CVector neededPos; + + if (phase == LINE_UP_TO_CAR_2) { + neededPos = GetPosition(); + } else { + neededPos = GetPositionToOpenCarDoor(veh, m_vehEnterType, seatPosMult); + } + + CVector autoZPos = neededPos; + + if (veh->bIsInWater) { + if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) + autoZPos.z += 1.0f; + } else { + CPedPlacement::FindZCoorForPed(&autoZPos); + } + + if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { + neededPos.z = GetPosition().z; + + // Getting out + if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { + float nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); + + // If we're not in ground at next step, apply animation + if (neededPos.z + nextZSpeed >= autoZPos.z) { + m_vecMoveSpeed.z = nextZSpeed; + ApplyMoveSpeed(); + // Removing below line breaks the animation + neededPos.z = GetPosition().z; + } else { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + } + } + + if (autoZPos.z > neededPos.z) { +#ifdef VC_PED_PORTS + if (multExtractedFromAnim) { + neededPos.z += (autoZPos.z - neededPos.z) * zBlend; + } else { +#endif + currentZ = GetPosition().z; + if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { + adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); + } +#ifdef VC_PED_PORTS + } +#endif + } else { + // We may need to raise up the ped + if (phase == LINE_UP_TO_CAR_START) { + currentZ = GetPosition().z; + + if (neededPos.z > currentZ) { +#ifdef VC_PED_PORTS + if (multExtractedFromAnimBus) { + neededPos.z = (neededPos.z - currentZ) * zBlend + currentZ; + } else { +#endif + if (m_pVehicleAnim && + (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS + || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { + adjustedTimeStep = Min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; + } else if (EnteringCar()) { + neededPos.z = Max(currentZ, autoZPos.z); + } +#ifdef VC_PED_PORTS + } +#endif + } + } + } + + bool stillGettingInOut = false; + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) + stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; + + if (!stillGettingInOut) { + m_fRotationCur = m_fRotationDest; + } else { + float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); + float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; + + if (timeUntilStateChange <= 0.0f) { + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; + } + m_vecOffsetSeek.z = 0.0f; + + neededPos -= timeUntilStateChange * m_vecOffsetSeek; + + if (PI + m_fRotationCur < limitedDest) { + limitedDest -= 2 * PI; + } else if (m_fRotationCur - PI > limitedDest) { + limitedDest += 2 * PI; + } + m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); + } + + if (seatPosMult > 0.2f || vehIsUpsideDown) { + SetPosition(neededPos); + SetHeading(m_fRotationCur); + } else { + CMatrix vehDoorMat(veh->GetMatrix()); + vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); + // VC couch anims are inverted, so they're fixing it here. + GetMatrix() = vehDoorMat; + } + +} + +void +CPed::SetCarJack(CVehicle* car) +{ + uint8 doorFlag; + eDoors door; + CPed *pedInSeat = nil; + + if (car->IsBoat()) + return; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + if (car->pPassengers[0]) { + pedInSeat = car->pPassengers[0]; + } else if (m_nPedType == PEDTYPE_COP) { + pedInSeat = car->pDriver; + } + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + pedInSeat = car->pPassengers[2]; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + pedInSeat = car->pDriver; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + pedInSeat = car->pPassengers[1]; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + + if(car->bIsBus) + pedInSeat = car->pDriver; + + if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || + (car->VehicleCreatedBy != MISSION_VEHICLE && car->GetModelIndex() != MI_DODO))) + if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) + if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) + if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) + if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) + SetCarJack_AllClear(car, m_vehEnterType, doorFlag); +} + +void +CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + RemoveWeaponWhenEnteringVehicle(); + if (m_nPedState != PED_SEEK_CAR) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_nPedState = PED_CARJACK; + car->bIsBeingCarJacked = true; + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + + Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); + CVector carEnterPos; + carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + car->m_nGettingInFlags |= doorFlag; + m_vecOffsetSeek = carEnterPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); + bUsesCollision = false; + + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_LHS : ANIM_CAR_ALIGN_LHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_RHS : ANIM_CAR_ALIGN_RHS, 4.0f); + + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); +} + +void +CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) +{ + if (m_nPedState == PED_DRAG_FROM_CAR) + return; + + bUsesCollision = false; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_nLastPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + m_pSeekTarget = veh; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = vehEnterType; + if (m_vehEnterType == CAR_DOOR_LF) { + if (veh->pDriver && veh->pDriver->IsPlayer()) + veh->SetStatus(STATUS_PLAYER_DISABLED); + else + veh->SetStatus(STATUS_ABANDONED); + } + RemoveInCarAnims(); + SetMoveState(PEDMOVE_NONE); + LineUpPedWithCar(LINE_UP_TO_CAR_START); + m_pVehicleAnim = nil; + m_nPedState = PED_DRAG_FROM_CAR; + bChangedSeat = false; + bWillBeQuickJacked = quickJack; + + SetHeading(m_fRotationCur); + + Say(SOUND_PED_CAR_JACKED); + SetRadioStation(); + veh->m_nGettingOutFlags |= GetCarDoorFlag(m_vehEnterType); +} + +void +CPed::BeingDraggedFromCar(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId enterAnim; + bool dontRunAnim = false; + PedLineUpPhase lineUpType; + + if (!m_pVehicleAnim) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO); + } + } + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + if (bWillBeQuickJacked) { + enterAnim = ANIM_CAR_QJACKED; + } else if (m_pMyVehicle->bLowVehicle) { + enterAnim = ANIM_CAR_LJACKED_LHS; + } else { + enterAnim = ANIM_CAR_JACKED_LHS; + } + } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (m_pMyVehicle->bLowVehicle) + enterAnim = ANIM_CAR_LJACKED_RHS; + else + enterAnim = ANIM_CAR_JACKED_RHS; + } else + dontRunAnim = true; + + + if (!dontRunAnim) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, enterAnim); + + m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this); + lineUpType = LINE_UP_TO_CAR_START; + } else if (m_pVehicleAnim->currentTime <= 1.4f) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + lineUpType = LINE_UP_TO_CAR_START; + } else { + lineUpType = LINE_UP_TO_CAR_2; + } + + LineUpPedWithCar(lineUpType); +#ifdef VC_PED_PORTS + if (m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + if (m_pMyVehicle) { + m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); + } + } +#endif +} + +void +CPed::SetEnterCar(CVehicle *car, uint32 unused) +{ + if (CCranes::IsThisCarBeingCarriedByAnyCrane(car)) { + RestorePreviousState(); + RestorePreviousObjective(); + } else { + uint8 doorFlag; + eDoors door; + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + if (!IsPedInControl() || m_fHealth <= 0.0f + || doorFlag & car->m_nGettingInFlags || doorFlag & car->m_nGettingOutFlags + || car->bIsBeingCarJacked || m_pVehicleAnim + || doorFlag && !car->IsDoorReady(door) && !car->IsDoorFullyOpen(door)) + SetMoveState(PEDMOVE_STILL); + else + SetEnterCar_AllClear(car, m_vehEnterType, doorFlag); + } +} + +void +CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + float zDiff = 0.0f; + RemoveWeaponWhenEnteringVehicle(); + car->m_nGettingInFlags |= doorFlag; + bVehEnterDoorIsBlocked = false; + if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_nPedState = PED_ENTER_CAR; + if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { + car->bIsBeingCarJacked = true; + } + + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + bUsesCollision = false; + CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + // Because buses have stairs + if (!m_pMyVehicle->bIsBus) + zDiff = Max(0.0f, doorOpenPos.z - GetPosition().z); + + m_vecOffsetSeek = doorOpenPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + if (car->IsBoat()) { +#ifdef VC_PED_PORTS + // VC checks for handling flag, but we can't do that + if(car->GetModelIndex() == MI_SPEEDER) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); + + PedSetInCarCB(nil, this); + bVehExitWillBeInstant = true; +#else + +#ifndef FIX_BUGS + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); +#else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); +#endif + + m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#endif + if (IsPlayer()) + CWaterLevel::AllocateBoatWakeArray(); + } else { + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); + car->AutoPilot.m_nCruiseSpeed = 0; + } +} + +void +CPed::EnterCar(void) +{ + if (IsNotInWreckedVehicle() && m_fHealth > 0.0f) { + CVehicle *veh = (CVehicle*)m_pSeekTarget; + + // Not used. + // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType); + + if (veh->CanPedOpenLocks(this)) { + if (m_vehEnterType && m_pVehicleAnim) { + veh->ProcessOpenDoor(m_vehEnterType, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); + } + } + bIsInTheAir = false; + LineUpPedWithCar(LINE_UP_TO_CAR_START); + } else { + QuitEnteringCar(); + SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } +} + +void +CPed::QuitEnteringCar(void) +{ + CVehicle *veh = m_pMyVehicle; + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; + + RestartNonPartialAnims(); + + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE)) + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + + if (veh) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK) + veh->bIsBeingCarJacked = false; + + if (veh->m_nNumGettingIn != 0) + veh->m_nNumGettingIn--; + +#ifdef VC_PED_PORTS + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) + RestorePreviousObjective(); +#endif + + veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType); + } + + bUsesCollision = true; + + ReplaceWeaponWhenExitingVehicle(); + + if (DyingOrDead()) { + if (m_pVehicleAnim) { + m_pVehicleAnim->blendDelta = -4.0f; + m_pVehicleAnim->flags |= ASSOC_DELETEFADEDOUT; + m_pVehicleAnim->flags &= ~ASSOC_RUNNING; + } + } else + SetIdle(); + + m_pVehicleAnim = nil; + + if (veh) { +#ifdef VC_PED_PORTS + if (veh->AutoPilot.m_nCruiseSpeed == 0 && veh->VehicleCreatedBy == RANDOM_VEHICLE) +#else + if (veh->AutoPilot.m_nCruiseSpeed == 0) +#endif + veh->AutoPilot.m_nCruiseSpeed = 17; + } +} + +void +AddYardieDoorSmoke(CVehicle *veh, uint32 doorNode) +{ + eDoors door; + switch (doorNode) { + case CAR_DOOR_RF: + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_LF: + door = DOOR_FRONT_LEFT; + break; + default: + break; + } + + if (!veh->IsDoorMissing(door) && veh->IsComponentPresent(doorNode)) { + CVector pos; +#ifdef FIX_BUGS + veh->GetComponentWorldPosition(doorNode, pos); +#else + veh->GetComponentWorldPosition(CAR_DOOR_LF, pos); +#endif + CParticle::AddYardieDoorSmoke(pos, veh->GetMatrix()); + } +} + +// Seperate function in VC, more logical. Not sure is it inlined in III. +void +CPed::SetExitBoat(CVehicle *boat) +{ +#ifndef VC_PED_PORTS + m_nPedState = PED_IDLE; + CVector firstPos = GetPosition(); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + if (boat->GetModelIndex() == MI_SPEEDER && boat->IsUpsideDown()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); + m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); + m_vehEnterType = CAR_DOOR_RF; + m_nPedState = PED_EXIT_CAR; + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + } + SetPosition(firstPos); + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; + bTryingToReachDryLand = true; +#else + m_nPedState = PED_IDLE; + CVector newPos = GetPosition(); + RemoveInCarAnims(); + CColModel* boatCol = boat->GetColModel(); + if (boat->IsUpsideDown()) { + newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; + newPos = boat->GetMatrix() * newPos; + newPos.z += 1.0f; + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + } else { +/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { + if (boat->m_modelIndex == MI_SKIMMER) + newPos.z += 2.0f +*/ + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + CColPoint foundCol; + CEntity *foundEnt = nil; + if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) + newPos.z = FEET_OFFSET + foundCol.point.z; +/* // VC specific + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + SetMoveState(PEDMOVE_STILL); + bTryingToReachDryLand = true; + float upMult = 1.04f + boatCol->boundingBox.min.z; + float rightMult = 0.6f * boatCol->boundingBox.max.x; + newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); + GetPosition() = newPos; + if (m_pMyVehicle) { + PositionPedOutOfCollision(); + } else { + m_pMyVehicle = boat; + PositionPedOutOfCollision(); + m_pMyVehicle = nil; + } + return; + } +*/ } + SetPosition(newPos); + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; +#endif + // Not there in VC. + CWaterLevel::FreeBoatWakeArray(); +} + +// wantedDoorNode = 0 means that func. will determine it +void +CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) +{ + uint32 optedDoorNode = wantedDoorNode; + bool teleportNeeded = false; + bool isLow = !!veh->bLowVehicle; + if (!veh->CanPedExitCar()) { + if (veh->pDriver && !veh->pDriver->IsPlayer()) { + veh->AutoPilot.m_nCruiseSpeed = 0; + veh->AutoPilot.m_nCarMission = MISSION_NONE; + } + return; + } + + if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) + return; + + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + if (wantedDoorNode == 0) { + optedDoorNode = CAR_DOOR_LF; + if (!veh->bIsBus) { + if (veh->pDriver == this) { + optedDoorNode = CAR_DOOR_LF; + } else if (veh->pPassengers[0] == this) { + optedDoorNode = CAR_DOOR_RF; + } else if (veh->pPassengers[1] == this) { + optedDoorNode = CAR_DOOR_LR; + } else if (veh->pPassengers[2] == this) { + optedDoorNode = CAR_DOOR_RR; + } else { + for (int i = 3; i < veh->m_nNumMaxPassengers; ++i) { + if (veh->pPassengers[i] == this) { + if (i & 1) + optedDoorNode = CAR_DOOR_RR; + else + optedDoorNode = CAR_DOOR_LR; + + break; + } + } + } + } + } + bool someoneExitsFromOurExitDoor = false; + bool someoneEntersFromOurExitDoor = false; + switch (optedDoorNode) { + case CAR_DOOR_RF: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RF) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_RR: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RR) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_LF: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LF) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_LR: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LR) + someoneExitsFromOurExitDoor = true; + break; + default: + break; + } + if (someoneEntersFromOurExitDoor && m_objective == OBJECTIVE_LEAVE_CAR) { + RestorePreviousObjective(); + return; + } + if (!someoneExitsFromOurExitDoor || m_nPedType == PEDTYPE_COP && veh->bIsBus) { + // Again, unused... + // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); + bool thereIsRoom = veh->IsRoomForPedToLeaveCar(optedDoorNode, nil); + if (veh->IsOnItsSide()) { + teleportNeeded = true; + } else if (!thereIsRoom) { + bool trySideSeat = false; + CPed *pedOnSideSeat = nil; + switch (optedDoorNode) { + case CAR_DOOR_RF: + if (veh->pDriver || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) { + pedOnSideSeat = veh->pDriver; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_LF; + + break; + case CAR_DOOR_RR: + if (veh->pPassengers[1] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { + pedOnSideSeat = veh->pPassengers[1]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_LR; + + break; + case CAR_DOOR_LF: + if (veh->pPassengers[0] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { + pedOnSideSeat = veh->pPassengers[0]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_RF; + + break; + case CAR_DOOR_LR: + if (veh->pPassengers[2] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { + pedOnSideSeat = (CPed*)veh->pPassengers[2]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_RR; + + break; + default: + break; + } + if (trySideSeat) { + if (!pedOnSideSeat || !IsPlayer() && CharCreatedBy != MISSION_CHAR) + return; + + switch (optedDoorNode) { + case CAR_DOOR_RF: + optedDoorNode = CAR_DOOR_LF; + break; + case CAR_DOOR_RR: + optedDoorNode = CAR_DOOR_LR; + break; + case CAR_DOOR_LF: + optedDoorNode = CAR_DOOR_RF; + break; + case CAR_DOOR_LR: + optedDoorNode = CAR_DOOR_RR; + break; + default: + break; + } + } + // ... + // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); + if (!veh->IsRoomForPedToLeaveCar(optedDoorNode, nil)) { + if (!IsPlayer() && CharCreatedBy != MISSION_CHAR) + return; + + teleportNeeded = true; + } + } + if (m_nPedState == PED_FLEE_POS) { + m_nLastPedState = PED_FLEE_POS; + m_nPrevMoveState = PEDMOVE_RUN; + SetMoveState(PEDMOVE_SPRINT); + } else { + m_nLastPedState = PED_IDLE; + m_nPrevMoveState = PEDMOVE_STILL; + SetMoveState(PEDMOVE_STILL); + } + + ReplaceWeaponWhenExitingVehicle(); + bUsesCollision = false; + m_pSeekTarget = veh; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_vehEnterType = optedDoorNode; + m_nPedState = PED_EXIT_CAR; + if (m_pVehicleAnim && m_pVehicleAnim->flags & ASSOC_PARTIAL) + m_pVehicleAnim->blendDelta = -1000.0f; + SetMoveState(PEDMOVE_NONE); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + RemoveInCarAnims(); + veh->AutoPilot.m_nCruiseSpeed = 0; + if (teleportNeeded) { + PedSetOutCarCB(nil, this); + + // This is same code with CPedPlacement::FindZCoorForPed, except we start from z + 1.5 and also check vehicles. + float zForPed; + float startZ = GetPosition().z - 100.0f; + float foundColZ = -100.0f; + float foundColZ2 = -100.0f; + CColPoint foundCol; + CEntity* foundEnt; + + CVector vec = GetPosition(); + vec.z += 1.5f; + + if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) + foundColZ = foundCol.point.z; + + // Adjust coords and do a second test + vec.x += 0.1f; + vec.y += 0.1f; + + if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) + foundColZ2 = foundCol.point.z; + + zForPed = Max(foundColZ, foundColZ2); + + if (zForPed > -99.0f) + GetMatrix().GetPosition().z = FEET_OFFSET + zForPed; + } else { + if (veh->GetUp().z > -0.8f) { + bool addDoorSmoke = false; + if (veh->GetModelIndex() == MI_YARDIE) + addDoorSmoke = true; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + if (veh->bIsBus) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); + } else { + if (isLow) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); + else + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); + + if (addDoorSmoke) + AddYardieDoorSmoke(veh, CAR_DOOR_RF); + } + break; + case CAR_DOOR_RR: + if (veh->bIsVan) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT); + } else if (isLow) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); + } else { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); + } + break; + case CAR_DOOR_LF: + if (veh->bIsBus) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); + } else { + if (isLow) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); + else + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); + + if (addDoorSmoke) + AddYardieDoorSmoke(veh, CAR_DOOR_LF); + } + break; + case CAR_DOOR_LR: + if (veh->bIsVan) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT_L); + } else if (isLow) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); + } else { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); + } + break; + default: + break; + } + if (!bBusJacked) { + switch (m_vehEnterType) { + case CAR_DOOR_RF: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RF; + break; + case CAR_DOOR_RR: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RR; + break; + case CAR_DOOR_LF: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF; + break; + case CAR_DOOR_LR: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LR; + break; + default: + break; + } + } + m_pVehicleAnim->SetFinishCallback(PedAnimStepOutCarCB, this); + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS2); + } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS); + } + m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); + } + } + bChangedSeat = false; + if (veh->bIsBus) + bRenderPedInCar = true; + + SetRadioStation(); + if (veh->pDriver == this) { + if (IsPlayer()) + veh->SetStatus(STATUS_PLAYER_DISABLED); + else + veh->SetStatus(STATUS_ABANDONED); + } + } +} + +void +CPed::ExitCar(void) +{ + if (!m_pVehicleAnim) + return; + + AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId; + float animTime = m_pVehicleAnim->currentTime; + + m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime); + + if (m_pSeekTarget) { + // Car is upside down + if (m_pMyVehicle->GetUp().z > -0.8f) { + if (exitAnim == ANIM_CAR_CLOSE_RHS || exitAnim == ANIM_CAR_CLOSE_LHS || animTime > 0.3f) + LineUpPedWithCar(LINE_UP_TO_CAR_END); + else + LineUpPedWithCar((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); + } else { + LineUpPedWithCar(LINE_UP_TO_CAR_END); + } + } + + // If there is someone in front of the door, make him fall while we exit. + if (m_nPedState == PED_EXIT_CAR) { + CPed *foundPed = nil; + for (int i = 0; i < m_numNearPeds; i++) { + if ((m_nearPeds[i]->GetPosition() - GetPosition()).MagnitudeSqr2D() < 0.04f) { + foundPed = m_nearPeds[i]; + break; + } + } + if (foundPed && animTime > 0.4f && foundPed->IsPedInControl()) + foundPed->SetFall(1000, ANIM_KO_SKID_FRONT, 1); + } +} + +// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. +CVector +CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component) +{ + CVector localPos; + CVector vehDoorPos; + + localPos = GetLocalPositionToOpenCarDoor(veh, component, 1.0f); + vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); + +/* + // Not used. + CVector localVehDoorOffset; + + if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) { + localVehDoorOffset = vecPedVanRearDoorAnimOffset; + } else { + if (veh->bIsLow) { + localVehDoorOffset = vecPedCarDoorLoAnimOffset; + } else { + localVehDoorOffset = vecPedCarDoorAnimOffset; + } + } + + vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); +*/ + return vehDoorPos; +} + +void +CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) +{ + CVector *enterOffset = nil; + if (m_vehEnterType == CAR_DOOR_LF && veh->pDriver + || m_vehEnterType == CAR_DOOR_RF && veh->pPassengers[0] + || m_vehEnterType == CAR_DOOR_LR && veh->pPassengers[1] + || m_vehEnterType == CAR_DOOR_RR && veh->pPassengers[2]) + { + enterOffset = &vecPedQuickDraggedOutCarAnimOffset; + } + + CVector lfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LF); + CVector rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + + // Left front door is closer + if ((lfPos - GetPosition()).MagnitudeSqr2D() < (rfPos - GetPosition()).MagnitudeSqr2D()) { + + if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; + } + } else { + + if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { + + CPed *rfPassenger = veh->pPassengers[0]; + if (rfPassenger && (rfPassenger->m_leader == this || rfPassenger->bDontDragMeOutCar || + veh->VehicleCreatedBy == MISSION_VEHICLE && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) + || (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; + } + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } + } +} + +bool +CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen) +{ + CVector rfPos, lrPos, rrPos; + bool canEnter = false; + + CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); + + switch (veh->GetModelIndex()) { + case MI_BUS: + m_vehEnterType = CAR_DOOR_RF; + posToOpen = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + return true; + case MI_RHINO: + default: + break; + } + + CVector2D rfPosDist(999.0f, 999.0f); + CVector2D lrPosDist(999.0f, 999.0f); + CVector2D rrPosDist(999.0f, 999.0f); + + if (!veh->pPassengers[0] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) { + + rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + canEnter = true; + rfPosDist = rfPos - GetPosition(); + } + if (vehModel->m_numDoors == 4) { + if (!veh->pPassengers[1] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) { + lrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LR); + canEnter = true; + lrPosDist = lrPos - GetPosition(); + } + if (!veh->pPassengers[2] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) { + rrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RR); + canEnter = true; + rrPosDist = rrPos - GetPosition(); + } + + // When the door we should enter is blocked by some object. + if (!canEnter) + veh->ShufflePassengersToMakeSpace(); + } + + CVector2D nextToCompare = rfPosDist; + posToOpen = rfPos; + m_vehEnterType = CAR_DOOR_RF; + if (lrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { + m_vehEnterType = CAR_DOOR_LR; + posToOpen = lrPos; + nextToCompare = lrPosDist; + } + + if (rrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { + m_vehEnterType = CAR_DOOR_RR; + posToOpen = rrPos; + } + return canEnter; +} + +void +CPed::GoToNearestDoor(CVehicle *veh) +{ + CVector posToOpen; + GetNearestDoor(veh, posToOpen); + SetSeek(posToOpen, 0.5f); + SetMoveState(PEDMOVE_RUN); +} + +void +CPed::SetAnimOffsetForEnterOrExitVehicle(void) +{ + // FIX: If there were no translations on enter anims, there were overflows all over this function. + + CAnimBlendHierarchy *enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_JACKED_LHS)->hierarchy; + CAnimBlendSequence *seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedDraggedOutCarAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LHS)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedCarDoorAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedCarDoorLoAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_QJACKED)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedQuickDraggedOutCarAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_VAN_GETIN_L)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedVanRearDoorAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_TRAIN_GETOUT)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedTrainDoorAnimOffset = lastFrame->translation; + } + } +} + +void +CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + CVector finalPos; + CVector draggedOutOffset; + + CMatrix pedMat(ped->GetMatrix()); + ped->bUsesCollision = true; + ped->RestartNonPartialAnims(); + draggedOutOffset = vecPedQuickDraggedOutCarAnimOffset; + if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + draggedOutOffset.x = -draggedOutOffset.x; + + finalPos = Multiply3x3(pedMat, draggedOutOffset) + ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&finalPos); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(finalPos); + + if (veh) { + ped->m_fRotationDest = veh->GetForward().Heading() - HALFPI; + ped->m_fRotationCur = ped->m_fRotationDest; + ped->CalculateNewOrientation(); + + if (!veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedQuickDraggedOutCarAnimOffset)) + ped->PositionPedOutOfCollision(); + } + + if (!ped->CanSetPedState()) + return; + + ped->SetIdle(); + if (veh) { + if (ped->bFleeAfterExitingCar) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 14000); + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + + } else if (ped->bGonnaKillTheCarJacker) { + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective && CGeneral::GetRandomNumber() & 1) { + if (ped->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped->m_pedInObjective); + + } else { + CPed *driver = veh->pDriver; + if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { + ped->SetFlee(veh->GetPosition(), 14000); + } else { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + ped->Say(SOUND_PED_FLEE_RUN); + } + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && veh->pDriver && veh->pDriver->IsPlayer() + && !CTheScripts::IsPlayerOnAMission()) { + +#ifndef VC_PED_PORTS + if (CGeneral::GetRandomNumber() < MYRAND_MAX / 2) { + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); + } else +#endif + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + +#ifdef VC_PED_PORTS + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && !veh->pDriver && FindPlayerPed()->m_carInObjective == veh + && !CTheScripts::IsPlayerOnAMission()) { + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); +#endif + } else { + ped->SetFindPathAndFlee(veh->GetPosition(), 10000); + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->Say(SOUND_PED_FLEE_RUN); + } + } + } + if (ped->m_nLastPedState == PED_IDLE) + ped->m_nLastPedState = PED_WANDER_PATH; +} + +void +CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed *ped = (CPed*)arg; + + ped->bUsesCollision = true; + ped->RestartNonPartialAnims(); + bool itsRearDoor = false; + + if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + itsRearDoor = true; + + CMatrix pedMat(ped->GetMatrix()); + CVector posAfterBeingDragged = Multiply3x3(pedMat, (itsRearDoor ? -vecPedDraggedOutCarAnimOffset : vecPedDraggedOutCarAnimOffset)); + posAfterBeingDragged += ped->GetPosition(); +#ifndef VC_PED_PORTS + posAfterBeingDragged.z += 1.0f; +#endif + CPedPlacement::FindZCoorForPed(&posAfterBeingDragged); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posAfterBeingDragged); + + if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedDraggedOutCarAnimOffset)) { + ped->PositionPedOutOfCollision(); + } + + if (!ped->CanSetPedState()) + return; + + if (!ped->m_pMyVehicle) { + ped->SetIdle(); + ped->SetGetUp(); + return; + } + + CPed *driver = ped->m_pMyVehicle->pDriver; + + if (ped->IsPlayer()) { + ped->SetIdle(); + + } else if (ped->bFleeAfterExitingCar) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + + } else if (ped->bGonnaKillTheCarJacker) { + // Kill objective is already set at this point. + + ped->bGonnaKillTheCarJacker = false; + if (!ped->m_pedInObjective || !(CGeneral::GetRandomNumber() & 1)) { + if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { + ped->m_nPedState = PED_NONE; + ped->m_nLastPedState = PED_NONE; + ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); + } else { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + } + } + + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR + && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && driver + && driver->IsPlayer() && !CTheScripts::IsPlayerOnAMission()) { + +#ifndef VC_PED_PORTS + if (CGeneral::GetRandomNumber() & 1) + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); + else +#endif + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + + } else { +#ifdef VC_PED_PORTS + if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR + && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && !driver + && FindPlayerPed()->m_carInObjective == ped->m_pMyVehicle && !CTheScripts::IsPlayerOnAMission()) + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + else +#endif + { + ped->m_nPedState = PED_NONE; + ped->m_nLastPedState = PED_NONE; + ped->SetFindPathAndFlee(ped->m_pMyVehicle->GetPosition(), 10000); + } + } + ped->SetGetUp(); +} + +uint8 +CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos) +{ + GetNearestTrainPedPosition(train, doorPos); +/* + // Not used. + CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex); + CMatrix trainMat = CMatrix(train->GetMatrix()); + + doorPos = trainModel->m_positions[m_vehEnterType]; + doorPos.x -= 1.5f; + doorPos = Multiply3x3(trainMat, doorPos); + doorPos += train->GetPosition(); +*/ + return 1; +} + +uint8 +CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos) +{ + CVector enterStepOffset; + CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(train->GetModelIndex()); + CMatrix trainMat = CMatrix(train->GetMatrix()); + CVector leftEntryPos, rightEntryPos, midEntryPos; + float distLeftEntry, distRightEntry, distMidEntry; + + // enterStepOffset = vecPedCarDoorAnimOffset; + enterStepOffset = CVector(1.5f, 0.0f, 0.0f); + + if (train->pPassengers[TRAIN_POS_LEFT_ENTRY]) { + distLeftEntry = 999.0f; + } else { + leftEntryPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterStepOffset; + leftEntryPos = Multiply3x3(trainMat, leftEntryPos); + leftEntryPos += train->GetPosition(); + distLeftEntry = (leftEntryPos - GetPosition()).Magnitude(); + } + + if (train->pPassengers[TRAIN_POS_MID_ENTRY]) { + distMidEntry = 999.0f; + } else { + midEntryPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterStepOffset; + midEntryPos = Multiply3x3(trainMat, midEntryPos); + midEntryPos += train->GetPosition(); + distMidEntry = (midEntryPos - GetPosition()).Magnitude(); + } + + if (train->pPassengers[TRAIN_POS_RIGHT_ENTRY]) { + distRightEntry = 999.0f; + } else { + rightEntryPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterStepOffset; + rightEntryPos = Multiply3x3(trainMat, rightEntryPos); + rightEntryPos += train->GetPosition(); + distRightEntry = (rightEntryPos - GetPosition()).Magnitude(); + } + + if (distMidEntry < distLeftEntry) { + if (distMidEntry < distRightEntry) { + enterPos = midEntryPos; + m_vehEnterType = TRAIN_POS_MID_ENTRY; + } else { + enterPos = rightEntryPos; + m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + } + } else if (distRightEntry < distLeftEntry) { + enterPos = rightEntryPos; + m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + } else { + enterPos = leftEntryPos; + m_vehEnterType = TRAIN_POS_LEFT_ENTRY; + } + + return 1; +} + +void +CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed *ped = (CPed*)arg; + CTrain *veh = (CTrain*)ped->m_pMyVehicle; + + if (!veh) + return; + + ped->bInVehicle = true; + ped->m_nPedState = PED_DRIVING; + ped->RestorePreviousObjective(); + ped->SetMoveState(PEDMOVE_STILL); + veh->AddPassenger(ped); +} + +void +CPed::SetEnterTrain(CVehicle *train, uint32 unused) +{ + if (m_nPedState == PED_ENTER_TRAIN || !((CTrain*)train)->Doors[0].IsFullyOpen()) + return; + + /* + // Not used + CVector enterPos; + GetNearestTrainPedPosition(train, enterPos); + */ + m_fRotationCur = train->GetForward().Heading() - HALFPI; + m_pMyVehicle = train; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + + m_nPedState = PED_ENTER_TRAIN; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETIN, 4.0f); + m_pVehicleAnim->SetFinishCallback(PedSetInTrainCB, this); + bUsesCollision = false; + LineUpPedWithTrain(); + if (IsPlayer()) { + if (((CPlayerPed*)this)->m_bAdrenalineActive) + ((CPlayerPed*)this)->ClearAdrenaline(); + } +} + +void +CPed::EnterTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::SetPedPositionInTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::LineUpPedWithTrain(void) +{ + CVector lineUpPos; + CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(m_pMyVehicle->GetModelIndex()); + CVector enterOffset(1.5f, 0.0f, -0.2f); + + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; + m_fRotationDest = m_fRotationCur; + + if (!bInVehicle) { + GetNearestTrainDoor(m_pMyVehicle, lineUpPos); + lineUpPos.z += 0.2f; + } else { + if (m_pMyVehicle->pPassengers[TRAIN_POS_LEFT_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterOffset; + + } else if (m_pMyVehicle->pPassengers[TRAIN_POS_MID_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterOffset; + + } else if (m_pMyVehicle->pPassengers[TRAIN_POS_RIGHT_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterOffset; + } + lineUpPos = Multiply3x3(m_pMyVehicle->GetMatrix(), lineUpPos); + lineUpPos += m_pMyVehicle->GetPosition(); + } + + if (m_pVehicleAnim) { + float percentageLeft = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; + lineUpPos += (GetPosition() - lineUpPos) * percentageLeft; + } + + SetPosition(lineUpPos); + SetHeading(m_fRotationCur); +} + +void +CPed::SetExitTrain(CVehicle* train) +{ + if (m_nPedState == PED_EXIT_TRAIN || train->GetStatus() != STATUS_TRAIN_NOT_MOVING || !((CTrain*)train)->Doors[0].IsFullyOpen()) + return; + + /* + // Not used + CVector exitPos; + GetNearestTrainPedPosition(train, exitPos); + */ + m_nPedState = PED_EXIT_TRAIN; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETOUT, 4.0f); + m_pVehicleAnim->SetFinishCallback(PedSetOutTrainCB, this); + bUsesCollision = false; + LineUpPedWithTrain(); +} + +void +CPed::ExitTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; + + ped->bUsesCollision = true; + ped->m_pVehicleAnim = nil; + ped->bInVehicle = false; + ped->m_nPedState = PED_IDLE; + ped->RestorePreviousObjective(); + ped->SetMoveState(PEDMOVE_STILL); + + CMatrix pedMat(ped->GetMatrix()); + ped->m_fRotationCur = HALFPI + veh->GetForward().Heading(); + ped->m_fRotationDest = ped->m_fRotationCur; + CVector posAfterExit = Multiply3x3(pedMat, vecPedTrainDoorAnimOffset); + posAfterExit += ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posAfterExit); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posAfterExit); + ped->SetHeading(ped->m_fRotationCur); + veh->RemovePassenger(ped); +} + +void +CPed::RegisterThreatWithGangPeds(CEntity *attacker) +{ + CPed *attackerPed = nil; + if (attacker) { + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed && (attackerPed->IsPlayer() || attackerPed->IsGangMember())) { + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->IsPointerValid()) { + if (nearPed != this && nearPed->m_nPedType == m_nPedType) + nearPed->m_fearFlags |= CPedType::GetFlag(attackerPed->m_nPedType); + } + } + } + } + } + + if (attackerPed && attackerPed->IsPlayer() && (attackerPed->m_nPedState == PED_CARJACK || attackerPed->bInVehicle)) { + if (!attackerPed->m_pMyVehicle || attackerPed->m_pMyVehicle->GetModelIndex() != MI_TOYZ) { + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), ENTER_CAR_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + if (lastVehicle > 8) + lastVehicle = 8; + + for (int j = 0; j < lastVehicle; ++j) { + CVehicle *nearVeh = (CVehicle*) vehicles[j]; + + if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { + CPed *nearVehDriver = nearVeh->pDriver; + + if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { + + if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { + nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; + nearVeh->SetStatus(STATUS_PHYSICS); + nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; + nearVeh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + } + } + } + } + } +} + +// Some helper function which doesn't exist in og game. +inline void +SelectClosestNodeForSeek(CPed *ped, CPathNode *node, CVector2D closeDist, CVector2D farDist, CPathNode *closeNode, CPathNode *closeNode2, int runCount = 3) +{ + for (int i = 0; i < node->numLinks; i++) { + + CPathNode *testNode = &ThePaths.m_pathNodes[ThePaths.ConnectedNode(i + node->firstLink)]; + + if (testNode && testNode != closeNode && testNode != closeNode2) { + CVector2D posDiff(ped->m_vecSeekPos - testNode->GetPosition()); + float dist = posDiff.MagnitudeSqr(); + + if (farDist.MagnitudeSqr() > dist) { + + if (closeDist.MagnitudeSqr() <= dist) { + ped->m_pNextPathNode = closeNode; + closeDist = posDiff; + } else { + ped->m_pNextPathNode = (closeNode2 ? closeNode2 : testNode); + farDist = posDiff; + } + } + + if (--runCount > 0) + SelectClosestNodeForSeek(ped, testNode, closeDist, farDist, closeNode, (closeNode2 ? closeNode2 : testNode), runCount); + } + } +} + +bool +CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords) +{ + if (m_pNextPathNode || !bUsePedNodeSeek) + return false; + + CVector ourPos = GetPosition(); + + int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f); + + CVector seekObjPos = m_vecSeekPos; + seekObjPos.z += 1.0f; + + if (CWorld::GetIsLineOfSightClear(ourPos, seekObjPos, true, false, false, true, false, false, false)) + return false; + + m_pNextPathNode = nil; + + CVector2D seekPosDist (m_vecSeekPos - ourPos); + + CPathNode *closestNode = &ThePaths.m_pathNodes[closestNodeId]; + CVector2D closeDist(m_vecSeekPos - closestNode->GetPosition()); + + SelectClosestNodeForSeek(this, closestNode, closeDist, seekPosDist, closestNode, nil); + + // Above function decided that going to the next node is more logical than seeking the object. + if (m_pNextPathNode) { + + CVector pathToNextNode = m_pNextPathNode->GetPosition() - ourPos; + if (pathToNextNode.MagnitudeSqr2D() < seekPosDist.MagnitudeSqr()) { + *bestCoords = m_pNextPathNode->GetPosition(); + return true; + } + m_pNextPathNode = nil; + } + + return false; +} + +bool +CPed::DuckAndCover(void) +{ + if (!m_pedInObjective || CTimer::GetTimeInMilliseconds() <= m_duckAndCoverTimer) + return false; + + if (bKindaStayInSamePlace){ + + if (CTimer::GetTimeInMilliseconds() <= m_leaveCarTimer) { + if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + } + if (!bIsAimingGun) + SetAimFlag(m_pedInObjective); + + } else { + bCrouchWhenShooting = false; + bKindaStayInSamePlace = false; + bIsDucking = false; + bDuckAndCover = false; + m_headingRate = 10.0f; + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(20000,30000); + if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) + ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover--; + } + return false; + } + + bool justDucked = false; + CVehicle *foundVeh = nil; + float maxDist = 225.0f; + bIsDucking = false; + bCrouchWhenShooting = false; + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle *veh = (CVehicle*) vehicles[i]; + if (veh->m_vecMoveSpeed.Magnitude() <= 0.02f + && !veh->bIsBus + && !veh->bIsVan + && !veh->bIsBig + && veh->m_numPedsUseItAsCover < 3) { + float dist = (GetPosition() - veh->GetPosition()).MagnitudeSqr(); + if (dist < maxDist) { + maxDist = dist; + foundVeh = veh; + } + } + } + if (foundVeh) { + // Unused. + // CVector lfWheelPos, rfWheelPos; + // foundVeh->GetComponentWorldPosition(CAR_WHEEL_RF, rfWheelPos); + // foundVeh->GetComponentWorldPosition(CAR_WHEEL_LF, lfWheelPos); + CVector rightSide, leftSide; + + // 3 persons can use the car as cover. Found the correct position for us. + if (foundVeh->m_numPedsUseItAsCover == 2) { + rightSide = CVector(1.5f, -0.5f, 0.0f); + leftSide = CVector(-1.5f, -0.5f, 0.0f); + } else if (foundVeh->m_numPedsUseItAsCover == 1) { + rightSide = CVector(1.5f, 0.5f, 0.0f); + leftSide = CVector(-1.5f, 0.5f, 0.0f); + } else if (foundVeh->m_numPedsUseItAsCover == 0) { + rightSide = CVector(1.5f, 0.0f, 0.0f); + leftSide = CVector(-1.5f, 0.0f, 0.0f); + } + + CMatrix vehMatrix(foundVeh->GetMatrix()); + CVector duckAtRightSide = Multiply3x3(vehMatrix, rightSide) + foundVeh->GetPosition(); + + CVector duckAtLeftSide = Multiply3x3(vehMatrix, leftSide) + foundVeh->GetPosition(); + + CVector distWithPedRightSide = m_pedInObjective->GetPosition() - duckAtRightSide; + CVector distWithPedLeftSide = m_pedInObjective->GetPosition() - duckAtLeftSide; + + CVector duckPos; + if (distWithPedRightSide.MagnitudeSqr() <= distWithPedLeftSide.MagnitudeSqr()) + duckPos = duckAtLeftSide; + else + duckPos = duckAtRightSide; + + if (CWorld::TestSphereAgainstWorld(duckPos, 0.5f, nil, true, true, true, false, false, false) + && CWorld::GetIsLineOfSightClear(GetPosition(), duckPos, 1, 0, 0, 1, 0, 0, 0)) { + SetSeek(duckPos, 1.0f); + m_headingRate = 15.0f; + bIsRunning = true; + bDuckAndCover = true; + justDucked = true; + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 500; + if (foundVeh->bIsLawEnforcer) + m_carInObjective = foundVeh; + + // BUG? Shouldn't we register the reference? + m_pSeekTarget = foundVeh; + ClearPointGunAt(); + } else { + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 15000); + bDuckAndCover = false; + } + } else { + bDuckAndCover = false; + } + } + + if (!justDucked && !bDuckAndCover) + return false; + + if (!Seek()) + return true; + + bKindaStayInSamePlace = true; + bDuckAndCover = false; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) + ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover++; + + SetIdle(); + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + } + + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(3000, 6000); + return false; +} + +CVector +CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset) +{ + CVector doorPos; + CMatrix vehMat(veh->GetMatrix()); + + doorPos = Multiply3x3(vehMat, GetLocalPositionToOpenCarDoor(veh, component, offset)); + + return veh->GetPosition() + doorPos; +} + +CVector +CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult) +{ + CVehicleModelInfo *vehModel; + CVector vehDoorPos; + CVector vehDoorOffset; + float seatOffset; + + vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); + if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) { + seatOffset = 0.0f; + vehDoorOffset = vecPedVanRearDoorAnimOffset; + } else { + seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult; + if (veh->bLowVehicle) { + vehDoorOffset = vecPedCarDoorLoAnimOffset; + } else { + vehDoorOffset = vecPedCarDoorAnimOffset; + } + } + + switch (component) { + case CAR_DOOR_RF: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case CAR_DOOR_RR: + vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case CAR_DOOR_LF: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + case CAR_DOOR_LR: + vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + default: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); + } + return vehDoorPos - vehDoorOffset; +} + +void +CPed::SetDuck(uint32 time) +{ + if (bIsDucking || CTimer::GetTimeInMilliseconds() <= m_duckTimer) + return; + + if (bCrouchWhenShooting && (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN)) { + CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); + if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_LOW, 4.0f); + bIsDucking = true; + m_duckTimer = CTimer::GetTimeInMilliseconds() + time; + } + } else { + CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); + bIsDucking = true; + m_duckTimer = CTimer::GetTimeInMilliseconds() + time; + } + } +} + +void +CPed::Duck(void) +{ + if (CTimer::GetTimeInMilliseconds() > m_duckTimer) + ClearDuck(); +} + +void +CPed::ClearDuck(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); + + if (!animAssoc) { + bIsDucking = false; + return; + } + } + + if (!bCrouchWhenShooting) + return; + + if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN) + return; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); + } +} + +void +CPed::InformMyGangOfAttack(CEntity *attacker) +{ + CPed *attackerPed; + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) + return; + + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed->m_nPedType == PEDTYPE_COP) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed && nearPed != this) { + CPed *leader = nearPed->m_leader; + if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) + { + nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); + nearPed->SetObjectiveTimer(30000); + } + } + } +} + +void +CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CAutomobile* veh = (CAutomobile*)(ped->m_pMyVehicle); + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (veh->bLowVehicle) { + veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR_LOW, 1.0f); + } else { + veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, 1.0f); + } + + veh->m_nGettingOutFlags &= ~CAR_DOOR_FLAG_LF; + + if (veh->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) + veh->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_OK); +} + +void +CPed::SetSeekBoatPosition(CVehicle *boat) +{ + if (m_nPedState == PED_SEEK_IN_BOAT || boat->pDriver +#if defined VC_PED_PORTS || defined FIX_BUGS + || !IsPedInControl() +#endif + ) + return; + + SetStoredState(); + m_carInObjective = boat; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + m_pMyVehicle = boat; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_distanceToCountSeekDone = 0.5f; + m_nPedState = PED_SEEK_IN_BOAT; +} + +void +CPed::SeekBoatPosition(void) +{ + if (m_carInObjective && !m_carInObjective->pDriver) { + CVehicleModelInfo *boatModel = m_carInObjective->GetModelInfo(); + + CVector enterOffset; + enterOffset = boatModel->GetFrontSeatPosn(); + enterOffset.x = 0.0f; + CMatrix boatMat(m_carInObjective->GetMatrix()); + SetMoveState(PEDMOVE_WALK); + m_vecSeekPos = boatMat * enterOffset; + if (Seek()) { + // We arrived to the boat + m_vehEnterType = 0; + SetEnterCar(m_carInObjective, 0); + } + } else + RestorePreviousState(); +} + +bool +CPed::IsRoomToBeCarJacked(void) +{ + if (!m_pMyVehicle) + return false; + + CVector offset; + if (m_pMyVehicle->bLowVehicle || m_nPedType == PEDTYPE_COP) { + offset = vecPedDraggedOutCarAnimOffset; + } else { + offset = vecPedQuickDraggedOutCarAnimOffset; + } + + offset.z = 0.0f; + if (m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, &offset)) { + return true; + } + + return false; +} + +void +CPed::RemoveInCarAnims(void) +{ + if (!IsPlayer()) + return; + + CAnimBlendAssociation *animAssoc; + + if (m_pMyVehicle && m_pMyVehicle->bLowVehicle) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + } + +#ifdef VC_PED_PORTS + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +#endif + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +} + +bool +CPed::PositionPedOutOfCollision(void) +{ + CVehicle *veh; + CVector posNearVeh; + CVector posSomewhereClose; + bool putNearVeh = false; + bool putSomewhereClose = false; + int smallestDistNearVeh = 999; + int smallestDistSomewhereClose = 999; + + if (!m_pMyVehicle) + return false; + + CVector vehPos = m_pMyVehicle->GetPosition(); + CVector potentialPos; + potentialPos.y = GetPosition().y - 3.5f; + potentialPos.z = GetPosition().z; + + for (int yTry = 0; yTry < 15; yTry++) { + potentialPos.x = GetPosition().x - 3.5f; + + for (int xTry = 0; xTry < 15; xTry++) { + CPedPlacement::FindZCoorForPed(&potentialPos); + CVector distVec = potentialPos - vehPos; + float dist = distVec.Magnitude(); + + // Makes close distances bigger for some reason. + float mult = (0.6f + dist) / dist; + CVector adjustedPotentialPos = distVec * mult + vehPos; + if (CWorld::GetIsLineOfSightClear(vehPos, adjustedPotentialPos, true, false, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, true, false, false, true, false, false)) { + + float potentialChangeSqr = (potentialPos - GetPosition()).MagnitudeSqr(); + veh = (CVehicle*)CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, false, true, false, false, false, false); + if (veh) { + if (potentialChangeSqr < smallestDistNearVeh) { + posNearVeh = potentialPos; + putNearVeh = true; + smallestDistNearVeh = potentialChangeSqr; + } + } else if (potentialChangeSqr < smallestDistSomewhereClose) { + smallestDistSomewhereClose = potentialChangeSqr; + posSomewhereClose = potentialPos; + putSomewhereClose = true; + } + } + potentialPos.x += 0.5f; + } + potentialPos.y += 0.5f; + } + + if (!putSomewhereClose && !putNearVeh) + return false; + + // We refrain from using posNearVeh, probably because of it may be top of the vehicle. + if (putSomewhereClose) { + SetPosition(posSomewhereClose); + } else { + CVector vehSize = veh->GetModelInfo()->GetColModel()->boundingBox.max; + posNearVeh.z += vehSize.z; + SetPosition(posNearVeh); + } + return true; +} + +bool +CPed::WarpPedToNearLeaderOffScreen(void) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = m_leader->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = Min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +bool +CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = warpTo->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = Min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} \ No newline at end of file diff --git a/src/peds/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 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/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/Font.cpp b/src/render/Font.cpp index f7f5fafc..65ab42ff 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) @@ -224,6 +227,12 @@ 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; +int CFont::ButtonsSlot = -1; +#endif // BUTTON_ICONS + void CFont::Initialise(void) { @@ -286,6 +295,34 @@ CFont::Initialise(void) SetAlphaFade(255.0f); SetDropShadowPosition(0); CTxdStore::PopCurrentTxd(); + +#ifdef BUTTON_ICONS + 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"); +#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 @@ -334,6 +371,13 @@ CFont::ReloadFonts(uint8 set) void CFont::Shutdown(void) { +#ifdef BUTTON_ICONS + 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(); Sprite[2].Delete(); @@ -359,8 +403,34 @@ 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) { @@ -642,7 +712,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); @@ -722,8 +799,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; @@ -833,6 +917,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 @@ -860,6 +953,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) { @@ -964,6 +1091,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++; } @@ -978,12 +1129,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; @@ -1037,9 +1216,11 @@ CFont::GetNextSpace(wchar *s) if(*s == '~'){ s++; while(*s != '~') s++; +#ifndef FIX_BUGS s++; if(*s == ' ') break; +#endif } } return s; @@ -1047,7 +1228,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) { @@ -1067,13 +1248,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* @@ -1094,6 +1299,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..7b67e310 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,11 +102,24 @@ public: static CSprite2d Sprite[MAX_FONTS]; static CFontDetails Details; +#ifdef BUTTON_ICONS + static int32 ButtonsSlot; + 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); 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 e42242b6..d54f1c05 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -534,7 +534,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); @@ -1029,7 +1029,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(); @@ -1342,9 +1342,9 @@ void CHud::Draw() 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_SCALE_FROM_RIGHT(50.0f) - SCREEN_SCALE_X(8.0f) - radarBulge; + CFont::SetCentreSize(rectWidth); const int16 shadow = 1; @@ -1856,8 +1856,7 @@ void CHud::DrawAfterFade() CFont::SetPropOn(); #ifdef FIX_BUGS - //CFont::SetRightJustifyWrap(SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 500.0f)); - CFont::SetRightJustifyWrap(SCREEN_SCALE_X(-500.0f)); + CFont::SetRightJustifyWrap(SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 500.0f)); #else CFont::SetRightJustifyWrap(-500.0f); #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/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/render/Renderer.cpp b/src/render/Renderer.cpp index 4ad1d3b9..a0f66819 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) { @@ -111,7 +137,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 +207,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; @@ -190,6 +216,7 @@ CRenderer::RenderOneNonRoad(CEntity *e) e->Render(); if(e->IsVehicle()){ + BACKFACE_CULLING_OFF; e->bImBeingRendered = true; CVisibilityPlugins::RenderAlphaAtomics(); e->bImBeingRendered = false; @@ -347,6 +374,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 +390,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 @@ -570,7 +597,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 +627,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; } @@ -611,7 +638,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 +688,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 +824,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 @@ -848,6 +920,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) { @@ -1014,8 +1117,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 +1151,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 +1174,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 +1227,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 +1252,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 +1389,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/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/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/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); diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp new file mode 100644 index 00000000..469262d3 --- /dev/null +++ b/src/rw/MemoryHeap.cpp @@ -0,0 +1,497 @@ +#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); } } + +#define MEMORYHEAP_ASSERT(cond) assert(cond) +#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) assert(cond) + +// 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_GAME; + 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_GAME; + 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[block->m_memId] -= block->m_size + sizeof(HeapBlockDesc); + m_blocksUsed[block->m_memId]--; + 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(); + // TODO: 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); + block->m_memId = MEMID_FREE; + 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) +{ + 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; +} + +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-1 + '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; +} + +#endif diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h new file mode 100644 index 00000000..23163c1c --- /dev/null +++ b/src/rw/MemoryHeap.h @@ -0,0 +1,225 @@ +#pragma once + +// some windows shit +#ifdef MoveMemory +#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 +}; + +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; + } +}; + +#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 +{ + 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; + } +}; + +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); + int32 GetLargestFreeBlock(void) { return m_freeList.m_last.m_prev->m_size; } + + 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 *b = m_freeList.m_first.FindSmallestFreeBlock(block->m_size); + block->InsertHeapFreeBlock(b->m_prev); + } +}; + +extern CMemoryHeap gMainHeap; diff --git a/src/rw/MemoryMgr.cpp b/src/rw/MemoryMgr.cpp new file mode 100644 index 00000000..e2f6f144 --- /dev/null +++ b/src/rw/MemoryMgr.cpp @@ -0,0 +1,130 @@ +#include "common.h" +#include "MemoryHeap.h" +#include "MemoryMgr.h" + + +uint8 *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((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; + 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((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; + 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((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; +#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/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index 6a7010e2..e0133985 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -7,8 +7,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 @@ -19,7 +21,7 @@ bool gPS2alphaTest = false; #endif bool gBackfaceCulling = true; -#ifndef FINAL +#if !defined(FINAL) || defined(DEBUGMENU) static bool charsetOpen; void OpenCharsetSafe() { @@ -62,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) { @@ -642,9 +605,81 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) return (nil); } -#ifdef USE_TEXTURE_POOL -WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); } -WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); } +#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) diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index 130eb636..1a5f64b1 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(); @@ -53,8 +50,8 @@ RwCamera *CameraCreate(RwInt32 width, RwBool zBuffer); -void _TexturePoolsInitialise(); -void _TexturePoolsShutdown(); + +RpAtomic *ConvertPlatformAtomic(RpAtomic *atomic, void *data); #if defined(FIX_BUGS) && defined (GTA_PC) void SetAlphaTest(RwUInt32 alpharef); diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp index 5dde20dd..d0addcca 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; @@ -150,11 +151,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 +271,7 @@ WriteVideoCardCapsFile(void) CFileMgr::CloseFile(file); } } +#endif void ConvertingTexturesScreen(uint32 num, uint32 count, const char *text) @@ -282,6 +353,22 @@ CreateTxdImageForVideoCard() return false; } +#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 + 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++) { ConvertingTexturesScreen(i, TXDSTORESIZE, "CVT_MSG"); @@ -309,6 +396,9 @@ CreateTxdImageForVideoCard() delete []buf; delete pDir; CStreaming::RemoveTxd(i); +#ifdef RW_GL3 + rw::gl3::needToReadBackTextures = false; +#endif return false; } @@ -332,9 +422,19 @@ 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; +#ifdef RW_GL3 + rw::gl3::needToReadBackTextures = false; +#endif + if (!pDir->WriteDirFile("models\\txd.dir")) { DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR"); delete pDir; 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 diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 8878a26a..b27d96c8 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -10,8 +10,7 @@ #include "VisibilityPlugins.h" #include "World.h" #include "custompipes.h" - -#define FADE_DISTANCE 20.0f +#include "MemoryHeap.h" CLinkList CVisibilityPlugins::m_alphaList; CLinkList CVisibilityPlugins::m_alphaEntityList; @@ -32,6 +31,119 @@ float CVisibilityPlugins::ms_pedLod0Dist; float CVisibilityPlugins::ms_pedLod1Dist; float CVisibilityPlugins::ms_pedFadeDist; +#ifdef GTA_PS2 // maybe something else? +// if wanted, delete the original geometry data after rendering +// and only keep the instanced data +bool +rpDefaultGeometryInstance(RpGeometry *geo, void *atomic, int del) +{ +#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* +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) { @@ -134,7 +246,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 @@ -203,7 +315,7 @@ CVisibilityPlugins::RenderWheelAtomicCB(RpAtomic *atomic) if(lodatm){ if(RpAtomicGetGeometry(lodatm) != RpAtomicGetGeometry(atomic)) RpAtomicSetGeometry(atomic, RpAtomicGetGeometry(lodatm), rpATOMICSAMEBOUNDINGSPHERE); - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -220,7 +332,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; } @@ -234,7 +346,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; @@ -252,7 +364,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; @@ -260,7 +372,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); @@ -268,7 +380,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); } @@ -295,7 +407,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; } @@ -320,10 +432,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; @@ -346,7 +458,7 @@ CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle(RpAtomic *atomic) if(dot > 0.0f) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -369,7 +481,7 @@ CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle(RpAtomic *atomic) return atomic; if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -383,7 +495,7 @@ CVisibilityPlugins::RenderVehicleHiDetailCB_Boat(RpAtomic *atomic) clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic)); distsq = GetDistanceSquaredFromCamera(clumpframe); if(distsq < ms_bigVehicleLod1Dist) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -405,7 +517,7 @@ CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle(RpAtomic *atomic) if(dot > 0.0f) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -429,7 +541,7 @@ CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle(RpAtomic *atomic) return atomic; if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -446,7 +558,7 @@ CVisibilityPlugins::RenderVehicleReallyLowDetailCB(RpAtomic *atomic) if(dist >= ms_vehicleLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -463,7 +575,7 @@ CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle(RpAtomic *atomic) clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic)); distsq = GetDistanceSquaredFromCamera(clumpframe); if(distsq >= ms_bigVehicleLod1Dist) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -484,7 +596,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; } @@ -509,10 +621,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; @@ -523,7 +635,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; } @@ -539,7 +651,7 @@ CVisibilityPlugins::RenderPedLowDetailCB(RpAtomic *atomic) if(dist >= ms_pedLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -558,7 +670,7 @@ CVisibilityPlugins::RenderPedHiDetailCB(RpAtomic *atomic) if(dist < ms_pedLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -577,7 +689,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); } @@ -707,6 +819,11 @@ CVisibilityPlugins::PluginAttach(void) ms_clumpPluginOffset = RpClumpRegisterPlugin(sizeof(ClumpExt), ID_VISIBILITYCLUMP, ClumpConstructor, ClumpDestructor, ClumpCopyConstructor); + +#if GTA_VERSION <= GTA3_PS2_160 + Initialise(); +#endif + return ms_atomicPluginOffset != -1 && ms_clumpPluginOffset != -1; } @@ -777,12 +894,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/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" diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 4d41a900..7354c90a 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 "MemoryMgr.h" #define MAX_SUBSYSTEMS (16) @@ -244,8 +245,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 @@ -275,7 +278,11 @@ psMouseSetPos(RwV2d *pos) RwMemoryFunctions* psGetMemoryFunctions(void) { +#ifdef USE_CUSTOM_ALLOCATOR + return &memFuncs; +#else return nil; +#endif } /* @@ -382,7 +389,7 @@ psInitialize(void) InitialiseLanguage(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -436,7 +443,7 @@ psInitialize(void) #ifndef PS2_MENU -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -826,7 +833,10 @@ psSelectDevice() PSGLOBAL(fullScreen) = !FrontEndMenuManager.m_nPrefsWindowed; #endif - + +#ifdef MULTISAMPLING + RwD3D8EngineSetMultiSamplingLevels(1 << FrontEndMenuManager.m_nPrefsMSAALevel); +#endif return TRUE; } @@ -893,7 +903,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); @@ -1414,8 +1424,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) { - FrontEndMenuManager.m_nMouseTempPosX = xpos; - FrontEndMenuManager.m_nMouseTempPosY = ypos; + 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 @@ -1438,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 @@ -1454,6 +1471,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/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/skel/win/win.cpp b/src/skel/win/win.cpp index 9effaa31..c16ea2a1 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 "MemoryMgr.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 } /* @@ -646,7 +651,7 @@ psInitialize(void) C_PcSave::SetSaveDirectory(_psGetUserFilesFolder()); InitialiseLanguage(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -698,7 +703,7 @@ psInitialize(void) #ifndef PS2_MENU -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -2006,12 +2011,18 @@ 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 + +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); #endif /* diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 95a68769..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; @@ -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/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/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); 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..7008818b 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; @@ -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 diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp index b8a957cf..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; @@ -68,7 +69,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; @@ -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())){ 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..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 @@ -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); 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) { 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/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] diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index c0da2239..bba7091c 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -1,113 +1,117 @@ -[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_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! [HELP2_A] -Pulsa el ~h~botón /~w~ cuando corras para ~h~esprintar. +Pulsa el ~h~botón /~w~ mientras corres para ~h~esprintar~w~. [HELP3] Sólo puedes esprintar durante cortos períodos antes de cansarte. [HELP4_A] -Pulsa el ~h~ botón ~k~~VEHICLE_ACCELERATE~~w~ para ~h~acelerar. +Pulsa el~h~ botón ~k~~VEHICLE_ACCELERATE~~w~ para ~h~acelerar~w~. [HELP4_D] -Mueve el~h~ joystick analógico de la derecha ~w~ hacia arriba para ~h~acelerar. +Mueve el~h~ joystick analógico derecho~w~ hacia arriba para ~h~acelerar~w~. [HELP5_A] Pulsa el~h~ botón ~k~~VEHICLE_BRAKE~~w~ para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo está detenido. [HELP5_D] -Mueve del ~h~joystick analógico de la derecha~w~ hacia atrás para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo se ha detenido. +Mueve el ~h~joystick analógico derecho~w~ hacia atrás para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo se ha detenido. [HELP6_A] -Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP6_C] -Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP6_D] -Pulsa el ~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~ para utilizar el ~h~ freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP7_A] -Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el rifle de francotirador. +Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el fusil de francotirador. [HELP7_D] -Pulsa y mantén el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar ~w~ con el rifle de francotirador. +Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el fusil de francotirador. [HELP8_A] -Pulsa el~h~ botón ~k~~PED_SNIPER_ZOOM_IN~ ~w~para ~h~ampliar el zoom ~w~con el rifle y el~h~ botón ~k~~PED_SNIPER_ZOOM_OUT~ ~w~para ~h~reducir el zoom ~w~de nuevo. +Pulsa el~h~ botón ~k~~PED_SNIPER_ZOOM_IN~ ~w~para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. [HELP9_A] -Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el rifle de francotirador. +Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el fusil de francotirador. [HELP10] -Esta insignia indica que estás buscado por la policía. +Esta insignia indica que la policía va a por ti. [HELP11] -Cuantas más insignias tengas mayor será tu grado de peligrosidad asignado en la búsqueda y captura. +Cuantas más insignias tengas, más peligroso te considerarán. [HELP13] -Algunas veces puedes necesitar utilizar caminos no mostrados en el radar. +Algunas veces tendrás que usar caminos no mostrados en el radar. [TIMER] Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. [MISTY1] -~r~¡Misty es carne de depósito de cadáveres! +~r~¡Misty está para el arrastre! [OUT_VEH] -~g~¡Fuera del vehículo! +~g~¡Sal del vehículo! [GARAGE] -Conduce el coche dentro del garaje, luego sal caminando. +Mete el vehículo dentro del garaje y luego sal caminando. [WANTED1] -~g~¡Despista a los polis y pierde tu grado de búsqueda y captura! +~g~¡Despista a la poli! [NODOORS] -~g~¡No son sardinas! Consigue un coche con suficientes asientos. +~g~¡No son sardinas! Consigue un vehículo con suficientes asientos. [TRASH] -~g~¡Has dejado tu vehículo bien jodido! ¡Haz que lo reparen! +~g~¡Has dejado tu vehículo hecho unos zorros! ¡Haz que lo reparen! [WRECKED] ~r~¡El vehículo está destrozado! @@ -116,7 +120,7 @@ Conduce el coche dentro del garaje, luego sal caminando. ~g~Toca el claxon. [HORN4] -Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. [NOMONEY] ~g~¡Necesitas más pasta! @@ -128,16 +132,16 @@ Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon ~r~¡Te siguen la pista! [REWARD] -RECOMPENSA $~1~ +RECOMPENSA: $~1~ [GAMEOVR] -JUEGO ACABADO +FIN DE LA PARTIDA [Z] -Eje-Z valor: ~1~ +Valor del eje Z: ~1~ [M_FAIL] -¡FRACASO EN LA MISIÓN! +¡MISIÓN FRACASADA! [M_PASS] ¡MISIÓN SUPERADA! $~1~ @@ -146,16 +150,16 @@ Eje-Z valor: ~1~ ¡TRABAJO ESPORÁDICO SUPERADO! [O_FAIL] -¡FRACASO EN TRABAJO ESPORÁDICO! +¡TRABAJO ESPORÁDICO FRACASADO! [DEAD] ¡LIQUIDADO! [BUSTED] -¡REVENTADO! +¡TRINCADO! [S_PROMP] -Cuando no estés en una misión puedes ~h~guardar tu partida aquí~w~, esto hará avanzar el tiempo seis horas. +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~ @@ -173,55 +177,55 @@ Coches activados. Coches desactivados. [TEXTXYZ] -Escribiendo coordenadas para archivar... +Escribiendo coordenadas al archivo... [CHEATON] -Modo trucos ACTIVADO +Trucos ACTIVADOS [CHEATOF] -Modo trucos DESACTIVADO +Trucos DESACTIVADOS [UZI_IN] -¡La Uzi está ahora en el depósito de Municiones! +¡La Uzi ya está disponible en la tienda Ammu-Nation! [IMPORT1] -Ve afuera y espera a tu vehículo. +Sal y espera a tu vehículo. [PAGEB1] -Pistola entregada en escondite +Pistola ya disponible en tu guarida. [PAGEB2] -Uzi entregada en escondite +Uzi ya disponible en tu guarida. [PAGEB3] -Armadura personal entregada en escondite +Chaleco antibalas ya disponible en tu guarida. [PAGEB4] -Escopeta entregada en escondite +Escopeta ya disponible en tu guarida. [PAGEB5] -granadas entregadas en escondite +Granadas ya disponibles en tu guarida. [PAGEB6] -molotovs entregados en escondite +Molotovs ya disponibles en tu guarida. [PAGEB7] -AK47 entregada en escondite +AK47 ya disponible en tu guarida. [PAGEB8] -Rifle de francotirador entregado en escondite +Fusil de francotirador ya disponible en tu guarida. [PAGEB9] -M16 entregado en escondite +M16 ya disponible en tu guarida. [PAGEB10] -Lanzacohetes entregado en escondite +Lanzacohetes ya disponible en tu guarida. [PAGEB11] -Lanzallamas entregado en escondite +Lanzallamas ya disponible en tu guarida. [WANT_A] -Sólo serás arrestado si tienes un ~h~grado de búsqueda y captura. +Sólo serás arrestado si estás en ~h~búsqueda y captura~w~. [WANT_B] Tu ~h~grado de peligrosidad asignado a tu búsqueda y captura~w~ está representado por la hilera de estrellas en la parte superior derecha de la pantalla. @@ -236,31 +240,31 @@ 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_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: @@ -269,7 +273,7 @@ DAÑO: MUERTES: [FARES] -TARIFAS: +CARRERAS: [BULL] LINGOTES: @@ -284,22 +288,22 @@ ESTADO DEL COCHE: RECOGIDOS: [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 @@ -332,7 +336,7 @@ MISIONES DE RAY MISIONES DE LOVE [YARDIE] -MISIONES DE YARDIE +MISIONES DE JAMAICANOS [HOOD] MISIONES DE HOOD @@ -344,10 +348,10 @@ Liberty City Portland [PORT_W] -Punta Callahan +Callahan Point [PORT_S] -Embarcadero Atlantic +Muelle Atlantic [PORT_E] Puerto de Portland @@ -356,7 +360,7 @@ Puerto de Portland Trenton [S_VIEW] -Mirador de Portland +Portland View [CHINA] Chinatown @@ -368,28 +372,28 @@ Playa de Portland Saint Mark's [REDLIGH] -Distrito Red Light +Barrio rojo [TOWERS] -Altos de Hepburn +Cerros de Hepburn [HARWOOD] Harwood [ROADBR1] -Puerto de Callahan +Puente Callahan [ROADBR2] -Puerto de Callahan +Puente Callahan [TUNNELP] Túnel Porter [BOMB1] -Garaje de 8-Ball +Taller de 8-Ball [COM_ZON] -Isla Staunton +Staunton Island [STADIUM] Aspatria @@ -401,43 +405,43 @@ Rockford Campus de Liberty [CONSTRU] -Fuerte Staunton +Fort Staunton [PARK] -Belleville Park +Parque Belleville [COM_EAS] Newport [SHOPING] -Punta de Bedford +Bedford Point [YAKUSA] Torrington [SUB_ZON] -Costa de Vale +Shoreside Vale [AIRPORT] -Aeropuerto internacional +Aeropuerto Int. Francis [PROJECT] -Jardines de Wichita +Wichita Gardens [SUB_IND] -Cala de la Cúspide +Pike Creek [SWANKS] -Bosque de Cedros +Cedar Grove [BIG_DAM] Presa Cochrane [SUB_ZO2] -Costa de Vale +Shoreside Vale [SUB_ZO3] -Costa de Vale +Shoreside Vale [CAR_1] Ambulancia @@ -446,16 +450,16 @@ Ambulancia Camión de bomberos [CAR_3] -Policía +Coche patrulla [CAR_4] -Oficial +Enforcer [CAR_5] -Cuartel +Barracks [CAR_6] -Rinoceronte +Rhino [CAR_7] Coche del FBI @@ -473,7 +477,7 @@ Coach Flatbed [CAR_12] -Rápido +Linerunner [CAR_13] Trashmaster @@ -482,7 +486,7 @@ Trashmaster Patriot [CAR_15] -Sr. Whoopee +Mr. Whoopee [CAR_16] Mule @@ -506,7 +510,7 @@ Blista Dodo [CAR_23] -Bus +Autobús [CAR_24] Sentinel @@ -518,7 +522,7 @@ Cheetah Banshee [CAR_27] -Aguijón +Stinger [CAR_28] Infernus @@ -539,13 +543,13 @@ Perennial Landstalker [CAR_34] -Manana +Mañana [CAR_35] Idaho [CAR_36] -Semental +Stallion [CAR_37] Taxi @@ -557,160 +561,160 @@ Cabbie Buggy [LUIGIS] -Casa de Luigi +Club de Luigi [GOAWAY] ~g~¡Ya estás en una misión! [LUIGGO] -~g~Luigi está entrevistando a algunas chicas nuevas -¡Vuelve más tarde! +~g~Luigi está entrevistando a unas chicas nuevas... ¡Vuelve más tarde! [JOEYGO] -~g~Joey's está en la ciudad con Misty. ¡Pásate más tarde! +~g~Joey ha salido con Misty. ¡Pásate más tarde! [TONIGO] -~g~Toni ha llevado a su mamá a la ópera -¡Llama en otro momento! +~g~Toni ha llevado a su mamá a la ópera... ¡Llama en otro momento! [KEMUGO] -~g~Maria y Kemuri están muy ocupadas en este momento - ¡Pásate más tarde! +~g~María y Kemuri están muy liadas... ¡Pásate más tarde! [KENJGO] -~g~Kenji ha ido a encuentro con los Yakuza -¡Llama en otro momento! +~g~Kenji está reunido con la yakuza, ¡llama en otro momento! [RAYGO] -~g~Ray tiene otros servicios por los que rondar -¡Inténtalo de nuevo más tarde! +~g~Ray tiene otros baños por los que rondar, ¡ven en otro momento! [LOVEGO] -~g~Donald Love tiene otros asuntos que atender -¡Pide una cita más tarde! +~g~Donald Love tiene otros asuntos que atender. ¡Pide una cita más tarde! [KENSGO] -~g~¡Kenji está ocupado! -¡Llama más tarde! +~g~¡Kenji está ocupado! ¡Llama más tarde! [ASUSGO] ~g~¡Asuka no está disponible en este momento! [HOODGO] -~g~Los Capos no están disponibles en este momento! +~g~¡Los Hoods no pueden atenderte en este momento! [WRONGT1] -~g~Vuelve entre las 05:00 y las 21:00 para un trabajo +~g~Vuelve entre las 05:00 y las 21:00 para buscar trabajo. [WRONGT2] -~g~Vuelve entre las 06:00 y las 14:00 para un trabajo +~g~Vuelve entre las 06:00 y las 14:00 para buscar trabajo. [WRONGT3] -~g~Vuelve entre las 15:00 y las 00:00 para un trabajo +~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. [GUN_1A] -Utiliza el ~h~botón ~k~~PED_CYCLE_WEAPON_RIGHT~ ~w~y el ~h~botón ~k~~PED_CYCLE_WEAPON_LEFT~ ~w~para pasar por tus armas. +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~, ¡pulsa el ~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... +¡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~, ¡pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... +¡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~ ¡pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... [GUN_3A] -Mientras 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. +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. [GUN_3B] -Mientras 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. +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 que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. +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 que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. +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 el apuntar y disparar en estos objetivos de papel. Cuando hayas terminado retoma la misión. +Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. [TAXI1] -~g~ Busca la tarifa. +~g~Busca un cliente. [FARE1] -~g~Destino ~w~'Club Sex Kitten Miau' ~g~en Redlight. +~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. [FARE2] -~g~Destino ~w~'Supa Save' ~g~en el Mirador de Portland. +~g~Ve a ~w~Supa Save ~g~en Portland View. [FARE3] -~g~Destino ~w~la 'sala de la vieja escuela' ~g~en Chinatown. +~g~Ve a ~w~la sala Clásica ~g~en Chinatown. [FARE4] -~g~Destino ~w~el 'Café Greasy Joe' ~g~en Punta Callahan. +~g~Ve a la ~w~cafetería Greasy Joe ~g~en Callahan Point. [FARE5] -~g~Destino ~w~'depósito de Municiones' ~g~en Redlight. +~g~Ve a la ~w~tienda de armas Ammu-Nation ~g~en el barrio rojo. [FARE6] -~g~Destino ~w~'Autos de crédito fácil' ~g~en Saint Mark. +~g~Ve a ~w~Easy Credit Autos ~g~en Saint Mark's. [FARE7] -~g~Destino ~w~'Bar de topless de Woody' ~g~en Redlight. +~g~Ve al ~w~bar de topless de Woody ~g~en el barrio rojo. [FARE8] -~g~Destino ~w~'Restaurante Marcos' ~g~en Saint Mark. +~g~Ve al ~w~restaurante Marcos ~g~en Saint Mark's. [FARE9] -~g~Destino ~w~'garaje de importación y exportación' ~g~en Portland Harbor. +~g~Ve al ~w~taller de importación y exportación ~g~en el puerto de Portland. [FARE10] -~g~Destino ~w~'Punk Noodles' ~g~en Chinatown. +~g~Ve a ~w~Punk Noodles ~g~en Chinatown. [FARE12] -~g~Destino ~w~'Estadio de Fútbol' ~g~en Aspatria. +~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. [FARE13] -~g~Destino ~w~'La iglesia' ~g~en Punta de Bedford +~g~Ve a la ~w~iglesia ~g~de Bedford Point. [FARE14] -~g~Destino ~w~'El Casino' ~g~en Torrington +~g~Ve al ~w~casino ~g~de Torrington. [FARE15] -~g~Destino ~w~'Universidad Liberty' ~g~en el Campus de Liberty +~g~Ve a la ~w~universidad ~g~en el Campus de Liberty. [FARE16] -~g~Destino ~w~'Centro comercial' ~g~en la zona de Belleville Park +~g~Ve al ~w~centro comercial ~g~en la zona del parque Belleville. [FARE17] -~g~Destino ~w~'Muso' ~g~en Newport +~g~Ve al ~w~museo ~g~de Newport. [FARE18] -~g~Destino ~w~'Edificio de AmCo' ~g~en Torrington +~g~Ve al ~w~edificio de AmCo ~g~en Torrington. [FARE19] -~g~Destino ~w~'Bolt Burgers' ~g~en Punta de Bedford +~g~Ve a ~w~Bolt Burgers ~g~en Bedford Point. [FARE20] -~g~Destino ~w~'El parque' ~g~en Belleville +~g~Ve al ~w~parque ~g~de Belleville. [FARE21] -~g~Destino ~w~'Aeropuerto internacional de Francis' +~g~Ve al ~w~Aeropuerto Internacional Francis. [FARE22] -~g~Destino ~w~'el dique de Cochrane' +~g~Ve a la ~w~presa Cochrane~g~. [FARE24] -~g~Destino ~w~'El hospital' ~g~en la Cúspide de la Cala +~g~Ve al ~w~hospital ~g~de Pike Creek. [FARE25] -~g~Destino ~w~'El parque' ~g~en la Costa de Vale +~g~Ve al ~w~parque ~g~de Shoreside Vale. [FARE26] -~g~Destino ~w~'Torres del Noroeste' ~g~en los Jardines de Wichita +~g~Ve a las ~w~Torres del Noroeste ~g~de Wichita Gardens. [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! +¡MÁS GRANDES! ¡MÁS RÁPIDO! ¡MÁS DUROS! Los nuevos taxis Borgnine abren su negocio en Harwood. ¡Llame hoy al 555-BORGNINE! [TSCORE2] $~1~ [IN_ROW] -~1~ ¡Prima EN UNA FILA! $~1~ +¡~1~ CONSECUTIVOS! $~1~ [TTUTOR] Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. @@ -719,82 +723,84 @@ Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misi Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. [ATUTOR2] -~g~Conduce CON CUIDADO a los pacientes hasta el hospital. Cada golpe reduce sus posibilidades de supervivencia. +~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. [A_TIME] +~1~ segundos [A_FULL] -~r~¡¡Ambulancia completa!! +~r~¡Ambulancia llena! [A_RANGE] -~g~La radio de la ambulancia está fuera de alcance, ¡acércate hasta un hospital! +~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! [FTUTOR] Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. [FTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del coche de bomberos. +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. [F_PASS1] ¡Fuego apagado! [F_RANGE] -~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate hasta una estación de bomberos! +~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! [C_BREIF] -~g~Sospechoso visto por última vez en la zona ~a~. +~g~Sospechoso visto por última vez en: ~a~. [C_RANGE] -~g~La radio de la policía está fuera de alcance, ¡acércate a una comisaría! +~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! [DODO_FT] -¡Huiste por ~1~ segundos! +¡Volaste durante ~1~ segundos! [EBAL_A] -Conozco un lugar al borde del distrito Red Light donde podemos escondernos, +Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, [EBAL_A1] -pero mis manos están hechas un desastre de modo que será mejor que conduzcas tú, hermano. +pero mis manos están destrozadas, así que conduce tú, hermano. [EBAL_1] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. [EBAL_1B] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. [EBAL_2] ~g~¡Vuelve al coche! [EBAL_3] -Este es el ~h~radar~w~. Utilízalo para surcar la ciudad, ¡sigue el ~h~pitido~w~ en el ~h~radar~w~ para encontrar el escondite! +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! [EBAL_D] -Conozco un tipo, tiene contactos, su nombre es Luigi. +Conozco a un tipo con contactos, se llama Luigi. [EBAL_D1] -Él y yo nos conocemos de antes de modo que probablemente podríamos conseguirte algún trabajo. Venga, vamos hacia allí. +Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. [EBAL_E] Venga, vamos a pasarnos por allí y te presentaré. +{ UNUSED } + [EBAL_I] -El jefe saldrá para veros dentro de poco... +El jefe os recibirá enseguida... [EBAL_J] -8-Ball tiene un asunto arriba. +8-Ball que ocuparse de una cosa arriba. [EBAL_K] -Quizás puedes hacerme un favor +Quizá puedas hacerme un favor. [EBAL_L] -Una de mis chicas necesita que la lleven de modo que consigue un coche y recoge a Misty en la clínica. Luego tráela de vuelta aquí. +Una de mis chicas necesita que la lleven, así que consigue un coche, recoge a Misty en la clínica y luego tráela aquí. [EBAL_N] -¡Así que mantén tus manos sobre el volante +¡Así que no quites las manos del volante! [EBAL_4] -~r~¡8-Ball está muerto! +~r~¡8-Ball ha muerto! [EBAL_5] ~g~¡Consigue un vehículo! @@ -806,7 +812,7 @@ Una de mis chicas necesita que la lleven de modo que consigue un coche y recoge 'LAS CHICAS DE LUIGI' [LM2] -'NO PEGUES A MI ZORRA' +'NO DROGUES A MI ZORRA' [LM3] 'LLEVA A MISTY POR MÍ' @@ -815,10 +821,10 @@ Una de mis chicas necesita que la lleven de modo que consigue un coche y recoge 'EL BAILE DE LA POLICÍA' [LM1_2] -~g~Lleva a Misty al Club de Luigi. +~g~Lleva a Misty al club de Luigi. [LM1_3] -~g~Toca el claxon para conseguir que la chica entre en el coche. +~g~Toca el claxon para que la chica entre en el coche. [LM1_6] ~g~¡Vuelve al coche! @@ -827,238 +833,238 @@ Una de mis chicas necesita que la lleven de modo que consigue un coche y recoge Detén el vehículo junto a Misty y déjala subir. [LM1_8] -Puedes ir y ver a Luigi en busca de más trabajo o ver que se cuece en Liberty City. +Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. [LM2_A] -Hay un nuevo tipo importante en la ciudad que responde al nombre de AZOTE. +Hay una nueva droga en la ciudad llamada SPANK. [LM2_E] -Algún tipo listo ha estado mostrando esta basura a mis chicas abajo en el puerto de Portland. +Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portland. [LM2_B] -¡Ve y muéstrale un bate de béisbol en su cara! +¡Ve y dale con un bate de béisbol en su cara! [LM2_G] ¡Quiero una compensación por este insulto! [LM2_1] -~g~Coge su coche y haz que lo vuelvan a rociar. +~g~Coge su coche y haz que cambien su pintura. [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! +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! [LM2_2C] -¡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~! +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! [LM2_2D] -¡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~! +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! [LM2_3] -~g~¡Esconde el coche en el garaje de Luigi! +~g~¡Mete el coche en el garaje de Luigi! [LM2_4] -~g~¡Vuelve a rociar el coche! +~g~¡Vuelve a pintar el coche! [LM3_A] -Hey, tengo que hablar contigo... De acuerdo Mick, hablaré contigo más tarde. +Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. [LM3_B] -¿Cómo te vá, chico? +¿Cómo te va, chico? [LM3_C] -El hijo del Don, Joey Leone, quiere un poco de acción de su chica de siempre, Misty. +El hijo del Don, Joey Leone, quiere fiesta con su chica de siempre, Misty. [LM3_D] -Ve a recogerla en los Altos de Hepburn... +Recógela en los cerros de Hepburn, [LM3_E] -pero cuidado, ésa es la turba del Diablo. +pero cuidado, ese es territorio de los Diablos. [LM3_F] -Luego llévala hasta el garaje de él en Trenton y hazlo rápido, +Luego llévala rapidito hasta su taller en Trenton, [LM3_H] -¡así que mantén la vista sobre la carretera y lejos de Misty! +¡así que estate pendiente del camino y no de Misty! [LM3_1D] -Pulsa el ~h~ botón L3 ~w~ para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. +Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. [LM3_2] -~g~Lleva a Misty a Joey's. +~g~Lleva a Misty al local de Joey. [LM3_4] -~g~¡Ve a recoger a Misty! +~g~¡Recoge a Misty! [LM3_5] -Ahora trabajas de forma regular para Luigi, ¿no? Ya era hora de que tuviese un conductor en el que pudiésemos confiar! +Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! [LM3_7] -Estaré contigo en un minuto, bujía. +Estaré contigo en un minuto, bujía mía. [LM3_10] -~g~¡Coge un vehículo! +~g~¡Consigue un vehículo! [LM4_B] -Ve y ocúpate de las cosas por mí. +Ve y resuélvelo de mi parte. [LM4_C] -Si necesitas una pieza ve a la puerta trasera del depósito de Municiones en el lado contrario al metro. +Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. [LM5_A] -El baile de la policía se está celebrando en la sala de la vieja escuela cerca del puente +El baile de la policía se está celebrando en la sala Clásica, cerca del puente, [LM5_B] -y parece que están buscando un poco de acción a la 'antigua usanza'. +y parece que tienen ganas de una fiesta más ''clásica''. [LM5_C] -Ahora tengo chicas por toda la ciudad, pateando las calles. +Tengo chicas haciendo la calles. [LM5_D] -Llévalas al baile, harán bulto. +Llévalas al baile, sacarán una buena tajada. [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. +~g~¡Tienes a las chicas tan embutidas que les van a salir moratones! ~g~Primero deja a las que llevas y luego ve a por más. [LM5_2] -~r~¡Una de las chicas de Luigi es un saco de grasa! +~r~¡Te has cargado a una de las chicas de Luigi! [LM5_3] ~g~¡Necesitas un coche! [LM5_4] -~g~Recoge a las chicas que trabajan en St. Marks. +~g~Recoge a las chicas que trabajan en Saint Mark's. [LM5_5] -~g~Lleva a las chicas al Baile de la Policía! +~g~¡Lleva a las chicas al baile de la policía! [LM5_8] -~g~Chicas trabajando en el Baile: ~1~ +~g~Chicas trabajando en el baile: ~1~ [JM2] -'DESPEDIDA A LEE CHONG 'EL GORDO'' +'DESPEDIDA A LEE CHONG ''EL GORDO''' [JM4] -'EL CHOFER DE CIPRIANI' +'EL CHÓFER DE CIPRIANI' [JM5] -'LA MOFETA MUERTA EN EL MALETERO' +'FIAMBRE EN EL MALETERO' [JM1_1] -~g~Lleva el coche de Forelli hasta el garaje de 8-Ball al Norte de aquí, detrás de 'Autos de crédito fácil'. +~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. [JM1_2] -~g~Vuelve a aparcar el coche en el restaurante de Marco. +~g~Vuelve a aparcar el coche frente al restaurante de Marco. [JM1_3] ~g~¡Activa la bomba del coche y luego sal de ahí! [JM1_4] -~g~¡Estás destrozando el vehículo! ¡Repáralo! +~g~¡Te estás cargando el coche! ¡Repáralo! [JM1_5] -~g~¡La bomba del coche no está colocada! +~g~¡La bomba del coche no está activada! [JM1_6] -~g~Vuelve a colocar el coche en la posición correcta. +~g~Vuelve a aparcar el coche en el sitio correcto. [JM1_8A] -~y~¡Hey, es mi gran hombre! +~y~¡Ey, pero si es mi colega! [JM1_8B] -~y~La tienda de bombas está automatizada. Simplemente entra conduciendo, detén tu coche y la tienda hará el resto. +~y~El taller de bombas está automatizado. Solo tienes que meter el coche, pararlo y el taller hará el resto. [JM1_8C] -~y~Ten, tu primer coche puede salirte gratis, pero después de eso te costará dinero. +~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. [JM2_A] -Lee Chong 'el Gordo' está dando palizas para una nueva banda de Colombia... o Colorado... o algo así.... +Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. [JM2_B] -La verdad es que no estoy seguro. De todas formas, quién necesita detalles. +No me acuerdo. El caso es que no importa. [JM2_D] -Esa rata a vendido su último refrito. +Ese cabrito ha vendido su último fideo. [JM2_E] -¡Quiero que le liquides! +¡Lo quiero muerto! [JM2_G] -Equípate con una nueve, sabes dónde está, ¿verdad? +Búscate un nueve, queda claro, ¿no? [JM2_H] -Bueno, recuerda, vigila tu espalda en China Town, es territorio de las Tríadas. +Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. [JM3_A] -De acuerdo vamos a por la furgoneta de la paga. +Vamos a asaltar un furgón blindado. [JM3_B] -Sale de China Town todos los días. +Sale de Chinatown todos los días. [JM3_C] -Las balas ni siquiera abollarán el blindaje de la armadura de la furgoneta, de modo que coge un coche y échala de la carretera. +Las balas ni siquiera abollarán el furgón, así que coge un coche y échalo de la carretera. [JM3_D] -Ahora golpéala fuerte y los imbéciles de los guardias de seguridad se achicarán. +Si lo zurras bien, los imbéciles de los guardias se achantarán. [JM3_E] -Luego llévala al almacén en los muelles y mis chicos se encargarán desde ahí. +Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí. [JM3_F] -Bueno, no estarán haciendo sus rondas todo el día, de modo que no pierdas el tiempo. +El furgón no estará fuera todo el día, así que no pierdas el tiempo. [JM3_1] -~g~Lleva la furgoneta al almacén. +~g~Lleva el furgón al almacén. [JM3_2] ~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. [JM4_B] -¡Oh! ¡Aquí está el tipo del que te hablaba! +¡Ah, aquí está el tío que te decía! [JM4_C] -De acuerdo, escucha. Este tío no es italiano y no es un mecánico, pero puede arreglar las cosas. +Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. [JM4_D] -Este es el Capo, Toni Cipriani. +Este es el capo de papá, Toni Cipriani. [JM4_E] -Sí, soy Toni Cipriani +Sí, soy Toni Cipriani. [JM4_F] -Bien, llévale al restaurante de Mamá en St Marks. +Llévale al restaurante de Mamma en Saint Mark's, ¿va? [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? +Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? [JM4_2] -¡Espera aquí! Mantén el motor en marcha. Esto no es una visita social. +¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. [JM4_3] ¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! [JM4_4] -Las Tríadas creen que pueden meterse conmigo, las Tríadas, ¡CONMIGO! +Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! [JM4_6] -¡Hey vigila el coche! Dije que nada de numeritos. +¡Mi coche! Dije que con cuidado. [JM4_7] -~g~Lleva a Toni al restaurante de su mamá. +~g~Lleva a Toni al restaurante de Mamma. [JM4_8] -~r~¡Toni ha sido liquidado! +~r~¡Han liquidado a Toni! [JM5_A] -¡Cojonudo! Estupendo. +Guapo, muy guapo... [JM5_B] -De acuerdo, ¡justo el tipo con el que necesito hablar! +¡Justo te estaba buscando! [JM5_D] -Uno de los Forellis pensó que era un tipo listo, de modo que se llevó lo que estaba buscando. +Uno de los Forelli se las daba de mafioso y se llevó su merecido. [JM5_E] -Lleva el cuerpo a la trituradora en Harwood, ¿de acuerdo? +Lleva el cuerpo a la trituradora en Harwood, ¿vale? [JM5_1] ~g~¡Llévalo a la trituradora! @@ -1067,16 +1073,16 @@ Lleva el cuerpo a la trituradora en Harwood, ¿de acuerdo? ~g~¡Son los hermanos Forelli! [JM6_A] -Debe ser todo un viajecito, ¿eh? +Vaya cochazo, ¿eh? [JM6_B] -De acuerdo, escucha. Lleva un coche hasta la casa franca en St. Marks y recoge a algunos de los míos. +Bueno, escucha. Lleva un coche a la casa franca de Saint Mark's y recoge a unos colegas. [JM6_C] -Están atracando un banco y necesitan un conductor. +Van a atracar un banco y necesitan un conductor. [JM6_D] -Di mi palabra de que eras el hombre, de modo que no fastidies esto. +Di mi palabra de que eras su hombre, así que no la cagues. [JM6_E] Llévales al banco antes de las cinco en punto, ni un minuto después. @@ -1085,13 +1091,13 @@ Llévales al banco antes de las cinco en punto, ni un minuto después. Mantén el motor en marcha, entraremos y saldremos enseguida. [JM6_3] -¡¡¡Sácanos de aquí!! +¡Sácanos de aquí! [JM6_4] -¡¡¡Líbrate de los polis y llévanos a la casa franca!! +¡Líbrate de la poli y llévanos a la casa franca! [JM6_6] -~g~¡Ve y consigue un vehículo menos llamativo! +~g~¡Busca un vehículo menos llamativo! [JM6_7] ~g~¡Necesitas a los 3 para robar el banco! @@ -1100,7 +1106,7 @@ Mantén el motor en marcha, entraremos y saldremos enseguida. 'SACANDO LA COLADA' [TM2] -'EL ENCARGO' +'LA ENTREGA' [TM3] 'SALVATORE HA CONVOCADO UNA REUNIÓN' @@ -1109,217 +1115,214 @@ Mantén el motor en marcha, entraremos y saldremos enseguida. 'TRÍADAS Y TRIBULACIONES' [TM5] -'EL PEZ GLOBO' +'LLUVIA DE PECES' [TONI_P] ¡Tengo un trabajo urgente para ti! -Toni [TM1_A] -~w~Toma asiento, chico, siéntate. +Siéntate, chico, siéntate de una vez. [TM1_B] -~w~Así que la lavandería no pagará protección, ¿eh? +La lavandería no quiere pagar la protección, ¿eh? [TM1_C] -~w~¿Las Tríadas creen que pueden meterse conmigo? +¿Las Tríadas creen que pueden meterse conmigo? [TM1_D] -~w~Vamos a enseñar a esos aspirantes a tipos duros lo que significa ser un tipo duro. +¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! [TM1_E] -~w~Sí, enséñales algo de respeto. Ningún hijo mío recibe de nadie de las Tríadas. +¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! [TM1_F] -~w~Tu padre, Dios acoja su alma, no aguantó ninguna mierda de las Tríadas en Sicilia. +Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. [TM1_G] -~w~Lo siento Ma. Sí Ma. +Lo siento, mamá. Sí, mamá. [TM1_H] -~w~Quiero que destruyas sus furgonetas de lavandería +Quiero que te cargues sus furgonetas de lavandería [TM1_I] -~w~y destroces a cualquiera de las Tríadas que se interponga en tu camino. +y a cualquiera de las Tríadas que se cruce en tu camino. [TM1_J] -~w~8-Ball puede suministrarte lo que necesites. +8-Ball te dará lo que necesites. [TM2_A] -~w~TONI ha salido a machacar a la gente o a intentarlo. +Toni ha salido a partir cabezas, o a intentarlo... [TM2_AA] -Nunca será tan duro como su padre, te dejó una nota en la mesa. +Nunca será tan duro como su padre. Te dejó una nota en la mesa. [TM2_B] -~w~La lavandería ha aceptado pagar. ¡Lo hiciste realmente bien, chico! +La lavandería ya quiere pagar. ¡Buen trabajo, chico! [TM2_C] -~w~Ve a recoger el dinero y tráelo de vuelta aquí. Cuidado con las Tríadas. +Ve a por el dinero y tráelo aquí. Cuidado con las Tríadas. [TM2_D] -~w~Pueden estar metiéndote un petardo por el culo, y no mancharse. +Puede que intenten metértela doblada, pero no te dejes. [TM2_E] -~w~¡Nadie, quiero decir nadie, se mete con TONI CIPRIANI! +¡Nadie, quiero decir nadie, se mete con Toni Cipriani! [TM2_1] -~g~¡¡Devuélvele el dinero a Toni!! +~g~¡Lleva el dinero a Toni! [TM2_2] ~g~¡Los dejaste tiesos a todos! [TM3_MA] -~w~¡No sé dónde está! +¡No sé dónde está! [TM3_MB] -~w~Te juro que ese chico mío a veces no se conoce a sí mismo. +Te juro que mi hijo a veces no sabe lo que hace. [TM3_MC] -~w~Ahora bien, su padre era diferente. Siempre en la cumbre, al cargo de todo, valiente... +Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... [TM3_A] -~w~Don Salvatore ha convocado una reunión. +Don Salvatore ha convocado una reunión. [TM3_B] -~w~Necesito que recojas la limusina y a su chico, Joey, del garaje. +Necesito que vayas a por la limusina y su hijo, Joey, a su taller. [TM3_C] -~w~Luego recoge a Luigi en su club, vuelve aquí y recógeme a mí, +Luego recoge a Luigi en su club, ven a buscarme, [TM3_D] -~w~luego todos iremos juntos a la casa del jefe. +y nos iremos todos juntos a la casa del jefe. [TM3_E] -~w~Esos Tríadas, no saben cuándo parar. +Los de las Tríadas no saben cuándo parar... [TM3_F] -~w~Quieren una guerra. Tendrán una guerra. +Si quieren guerra, la tendrán. [TM3_G] -~w~Ahora en marcha. +Ponte en marcha. [TM3_1] -~g~Coge el Stretch de Joey's. +~g~Ve al taller de Joey a por la limusina. [TM3_2] -~g~Ahora ve a recoger a Luigi. +~g~Recoge a Luigi. [TM3_3] -~g~Ahora ve a recoger a Toni. +~g~Ahora recoge a Toni. [TM3_4] -~g~Lleva a los mafiosos hasta la casa de Salvatore. +~g~Lleva a los mafiosos a la casa de Salvatore. [TM3_5] -~y~¡¡Es una emboscada de las Tríadas!! +~y~¡Es una emboscada de las Tríadas! [TM4_B] -~w~¡Estamos en GUERRA! Las Tríadas tienen una fábrica de pescado como fachada. +¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. [TM4_C] -~w~La mayor parte de sus negocios se pierde en el mercado de pescado de Chinatown. +Casi todos sus negocios pasan por la lonja de Chinatown. [TM4_D] -~w~Esa lavandería todavía nos debe por la protección. +La lavandería todavía no ha pagado la protección. [TM4_E] -~w~Consideran que las Tríadas les están protegiendo ahora, así que digo que les demos su merecido castigo. +Creen que está protegida por las Tríadas, así que creo que se merecen un castigo. [TM4_F] -~w~¡Toma a esos chicos y golpea a los Señores de la Guerra de las Tríadas! +¡Llévate a estos chicos y elimina a los líderes de las Tríadas! [TM4_G] -~w~Demonios, si tienes la oportunidad, revienta también a algunos de sus soldados. +Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. [TM4_GAT] -~g~Necesitas un 'Camión para pescado Tríada' para entrar. - -[TM5_A] -TEXT NO LONGER REQUIRED +~g~Necesitas un camión de pescado de las Tríadas para entrar. [TM5_B] -~w~Ya he tenido bastante de esta mierda. +Vale, ya me he hartado de esta mierda. [TM5_C] -~w~¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! +¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! [TM5_D] 8-Ball ha instalado una bomba en un camión de la basura. [TM5_E] -~w~Tiene un temporizador, así que si la lías no quedarán evidencias. Vete y toma ese camión de basura. +Tiene un temporizador, así que si la lías no quedará nada de ti. Ve a por el camión. [TM5_F] -~w~¡Cuidado, 8-Ball dice que es muy sensible y que cualquier movimiento puede hacerlo estallar! +¡Cuidado, 8-Ball dice que es muy sensible y que cualquier golpe puede hacerlo estallar! [TM5_G] -~w~Su fábrica de pescado abrirá sus puertas a un camión de basura, así que puedes conducirlo allí directamente. +Su piscifactoría abrirá sus puertas a uno de sus camiones, así que podrás entrar sin más. [TM5_H] -~w~Aparca entre las latas de gas y ¡sal pitando de ese infierno! +¡Aparca entre los tanques de gas y lárgate de ahí! [TM5_I] -~w~Quiero que llueva trozos de caballa. +Quiero que llueva pescado. [TM5_J] -~w~Esto es realmente bíblico, nada de bajo presupuesto. +En plan bíblico, nada de bajo presupuesto. [FM2] -CORTANDO LA HIERBA +'CORTANDO LA HIERBA' [FM4] -ÚLTIMOS DESEOS +'ÚLTIMA VOLUNTAD' [FM1_A] -~w~Yo y los chicos queremos hablar de negocios +Mis chicos y yo queremos hablar de negocios, [FM1_B] -~w~Así que esta tarde vas a vigilar a mi chica. +así que esta tarde vas a cuidar de mi chica. [FM1_C] -~w~¡OYE, MARÍA! ¡MUEVE ESE CULO! +¡OYE, MARÍA! ¡MUEVE ESE CULO! [FM1_D] -~w~El grandísimo estúpido hace esto todo el tiempo. +La muy idiota siempre hace lo mismo. [FM1_E] -~w~Y aquí está ella ¡La primera y única Reina de Saba! +Y aquí está, ¡la primera y única reina de Saba! [FM1_F] -~w~¿Qué hacíais ahí arriba? +¿Qué hacías arriba? [FM1_G] -~w~Fuera lo que fuera, seguro que me cuesta dinero. +Fuera lo que fuera, seguro que me cuesta dinero. [FM1_H] -~w~Bueno, no pensarás que me voy a quedar a conversar ¿no? +Bueno, no pensarás que estoy aquí para conversar, ¿o sí? [FM1_I] -~w~Métete en ese coche y cierra la bocaza. +Métete en el coche y cierra el pico. [FM1_J] -~w~Llévate la limusina, pero devuélvela de una pieza ¿me has oído? +Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? [FM1_K] -~w~Y vigílala, puede causarte problemas. +Y cuidado con ella, es una lianta. [FM1_L] -~w~¡Sí, sí, sí! Estoy segura de que tu nuevo perrito faldero tiene todo previsto. +¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. [FM1_M] -~w~¿Pues no es fuerte y grande? +¿No es fuerte y grande? [FM1_N] -~w~¡Eh, Fido, vayamos a visitar a Chico y hacer una fiestecita! +¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! [FM1_P] ~g~Ese de ahí es Chico, párate cerca. [FM1_S] -~w~Ahí vas, señora. +Aquí tienes, señorita. [FM1_TT] -~w~¡ES UNA REDADA POLICIAL! +¡UNA REDADA! [FM1_1] ~g~¡Vuelve al Stretch! @@ -1328,214 +1331,214 @@ CORTANDO LA HIERBA ~g~¡Entra en el Stretch! [FM1_3] -~r~Si abandonas a María y Salvatore te zurrará, vuelve y recógela. +~r~Si abandonas a María, Salvatore hará que te maten. Vuelve y recógela. [FM1_4] -~g~¡Te has deshecho de la mujer del Don! ¡Vuelve al almacén y espera a María! +~g~¡Has dejado a la chica del Don tirada! ¡Vuelve al almacén y espera a María! [FM1_5] ~g~¡Lleva a María sana y salva con Salvatore! [FM1_6] -~g~¡Chico no estará allí para siempre, lleva a María al muelle! +~g~¡Chico no estará esperando todo el día, lleva a María al muelle! [FM1_7] -~r~¡María está muerta! A Salvatore no le va a gustar nada... +~r~¡María está muerta! A Salvatore le va a sentar muy mal... [FM1_8] -~r~¡Te cargaste al proveedor de Maria! +~r~¡Te cargaste al camello de María! [FM2_J] -Déjanos solos un minuto. +Déjanos a solas un momento. [FM2_A] -El Cartel colombiano está haciendo SPANK en algún lugar de Liberty. +El cártel colombiano fabrica SPANK en Liberty, [FM2_K] -pero no sabemos dónde y parece como si supieran todo lo que hacemos antes de que lo hagamos. +pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. [FM2_L] Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. [FM2_M] -Ha estado malgastando más dinero del que gana. +Ha estado gastando más dinero del que gana. [FM2_N] -Normalmente toma un taxi de vuelta a casa tras el trabajo. Así que síguele. +Suele ir del trabajo a casa en taxi, así que síguelo. [FM2_O] -Y si nos está traicionando... mátalo. +Y si nos está vendiendo... mátalo. [FM2_F] Aquí viene nuestro amiguito. El señor Bocazas en persona. [FM2_G] -¿Te han seguido? Sabes que lo que pasa aquí es nuestro pequeño secreto. +¿Te han seguido? Ya sabes que esto es nuestro secretito. [FM2_H] -No... no. No me han seguido. ¿Tienes mi mercancía? +No, no, no me han seguido. ¿Tienes lo mío? [FM2_I] -Aquí está tu SPANK, soplón, ahora habla. +Toma tu SPANK, soplón, ahora habla. [FM2_P] -OK, así que los de Leone libran una guerra en dos frentes. +Vale, los Leone libran una guerra en dos frentes. [FM2_Q] -Tienen una guerra territorial con las Tríadas y no hay signos de que ninguno se vaya a rendir. +Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. [FM2_R] -Mientras tanto Joey Leone se ha hecho mala sangre con los Forellis. +Mientras tanto, Joey Leone ha cabreado a los Forelli. [FM2_S] -Cada día que pasa pierden hombres e influencia en la ciudad. +Cada día pierden más hombres e influencia. [FM2_T] -Salvatore es cada vez más peligroso y paranoico. Sospecha de todos y de todo. +Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. [FM2_U] -Con lealtades como la tuya, por qué tendría que preocuparse. +Con lo leales que son algunos, ¿de qué tendría que preocuparse? [FM2_1] ~g~¡Ahí está Curly Bob! [FM2_2] -~g~¡Curly ha salido del club, síguele! +~g~¡Curly ha salido del club, síguelo! [FM2_5] -~g~Llévale al Puerto Portland. +~g~Llévale al puerto de Portland. [FM2_6] -~r~¡Curly no entrará en un taxi accidentado! +~r~¡Curly no se meterá en un taxi cascado! [FM2_7] -~r~¡Curly se ha esfumado! ¡Ya no hay encuentro! +~r~¡Curly se ha asustado! ¡Han cancelado la reunión! [FM2_8] -~g~¡Golpea a Curly Bob! +~g~¡Elimina a Curly Bob! [FM2_9] -~r~¡Curly Bob está muerto! +~r~¡Curly Bob la ha espichado! [FM2_10] -~r~¡Curly se largó! +~r~¡Curly se ha largado! [FM2_11] -~g~Aparca frente al club de Luigi, Curly Bob saldrá pronto. +~g~Aparca enfrente del club de Luigi; Curly Bob saldrá pronto. [FM2_12] -~r~¡Os ha dado esquinazo! +~r~¡Te ha dado esquinazo! [FM3_A] -~w~Tenemos que terminar con esos bastardos colombianos, +Tenemos que despachar a esos puñeteros colombianos, [FM3_B] -~w~pero mientras estamos en guerra con las Tríadas no somos lo bastante fuertes. +pero mientras estemos en guerra con las Tríadas, no tendremos la fuerza necesaria. [FM3_C] -~w~El Cartel tiene fondos ilimitados procedentes de esa mierda de SPANK. +El cártel tiene fondos ilimitados gracias a esa mierda del SPANK. [FM3_D] -~w~si les atacamos abiertamente, fregarán el suelo con nosotros. +Si les atacamos abiertamente, nos harán picadillo. [FM3_E] -~w~Deben estar haciendo SPANK en ese barco grande al que os llevó Curly. +Estarán fabricando el SPANK en ese barco grande al que te llevó Curly. [FM3_F] -~w~Así que tenemos que usar las cabezas, o mejor, una cabeza. La tuya. +Así que tenemos que actuar con cuidado, o mejor dicho, tú tienes que hacerlo. [FM3_G] -~w~Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal hacia mí, Salvatore Leone. +Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal para mí, Salvatore Leone. [FM3_H] -~w~Si haces esto por mí, serás todo un hombre, cualquier cosa que quieras. +Si haces esto por mí, serás como de la familia. Todo lo que quieras. [FM3_I] -~w~Ve a ver a 8-Ball, necesitas su experiencia para volar ese barco. +Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. [FM3_8A] -~w~¡Eh, hombre! Salvatore ha llamado, +¡Hombre, colega! Salvatore me avisó, [FM3_8B] -~w~pero un trabajo como este necesita muchos fuegos artificiales. +pero este trabajo va a necesitar muchos fuegos artificiales. [FM3_8D] -~w~pero sabes que conmigo consigues mucho a cambio de tu pasta. +pero ya sabes que conmigo valdrá la pena. [FM3_8E] -~w~De acuerdo, ¡vamos a hacerlo! +Venga, ¡vamos allá! [FM3_8F] -~w~Puedo hacer detonar este pequeño, pero aún no puedo usar una pieza con estas manos. +Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. [FM3_8G] -~w~¡Toma, este rifle te ayudará a reventar algunas cabezas! +¡Toma, este fusil te ayudará a volar unas cuántas cabezas! [FM3_4] ~g~¡Para el coche y deja que 8-Ball salga! [FM3_7] -~r~¡¡8-Ball se ha helado! +~r~¡8-Ball ha pasado a mejor vida! [FM3_8] ~r~¡Los guardias han sido alertados! [FM4_A] -~w~Es mi limpiador favorito. +¡Mi socio favorito! [FM4_B] -~w~Estoy orgulloso de ti, hijo, sacudiste la mierda de esas pelotas grasientas. +Estoy orgulloso de ti, hijo, pusiste finos a esos sudacas. [FM4_C] -~w~Tengo un trabajito más para ti antes de que podamos celebrarlo. +Tengo un trabajito más para ti antes de que podamos celebrarlo. [FM4_D] -~w~Hay un coche a la vuelta del edificio del club de Luigi. +Hay un coche a la vuelta del edificio del club de Luigi. [FM4_E] -~w~El interior está pringado de sesos. +El interior está pringado de sesos. [FM4_F] -~w~Tuvimos que ayudar a un tipo a que se decidiera, y fue un poco -er- sucio. +Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. [FM4_H] -~w~Llévalo a la trituradora antes de que los polis lo encuentren. +Llévalo a la trituradora antes de que lo encuentre la pasma. [AM3] -'SANGRA PAPARAZZI' +'PURGA DE PAPARAZZIS' [AM4] -'DÍA DE PAGA PARA RAY' +'LA PAGA DE RAY' [AM5] -'TANNER DOS CARAS' +'TANNER EL TRAIDOR' [AM1_A] Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, [AM1_B] -de negocios o de lo que sea. Pongamos las cartas sobre la mesa. +sea de negocios u otra. Pongamos las cartas sobre la mesa. [AM1_C] -Yo soy Yakuza y sé que trabajas para la familia de Salvatore Leone. +Soy yakuza y sé que trabajaste para la familia de Salvatore Leone. [AM1_D] Puedo darte trabajo en nuestra organización, [AM1_E] -Pero primero debes demostrarme que has cortado todos tus lazos con la Mafia. +pero primero debes demostrarme que has cortado todos tus lazos con la mafia. [AM1_G] -Asegúrate de que no llega vivo a su club. +Asegúrate de que no salga con vida. [AM1_H] -Mientras tanto María y yo nos pondremos al día por los viejos tiempos. +Mientras tanto María y yo nos pondremos al día. [AM1_I] -Oh.. Asuka, tienes masajista. +Uy, Asuka, tienes un masajeador... [AM1_J] -Eso no es un masajista. +Eso no es un masajeador. [AM1_1] ~g~¡Salvatore está saliendo del club de Luigi! @@ -1547,43 +1550,43 @@ Eso no es un masajista. ~r~¡Has perdido a Salvatore! [AM1_4] -~r~Buen intento, ¡has asustado al objetivo! ¿Y te llamas a ti mismo pistolero? +~r~Muy bonito, ¡has asustado al objetivo! ¿Y te consideras un asesino? [AM1_5] -~g~Ve al Distrito de la Luz Roja y espera a que Salvatore salga del club. +~g~Ve al barrio rojo y espera a que Salvatore salga del club. [AM1_7] -~r~Salvatore está en casa, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar Chacal! +~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! [AM1_8] -~g~Salvatore saldrá del club del Luigi aproximadamente a las ~1~:~1~ +~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. [AM2_4] -~g~¡Te han visto venir como a un elefante al galope! +~g~¡Has irrumpido como un elefante en una cacharrería! [AM3_A] -Un periodista ha estado metiendo sus narices por aquí. +Un periodista ha estado husmeando por aquí. [AM3_B] -María y yo nos hemos tomado unas pequeñas vacaciones juntos hasta que puedas librarte de ese mirón pervertido. +María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. [AM4_A] -¡Es mi guapo manitas! +¡Si es guapo manitas! [AM4_B] -María está muy ocupada en este momento, pero le diré que has llamado. +María está un poquito liada, pero le diré que has venido. [AM4_C] -¿Quién es? ¿Asuka? Ya sé que he sido una niña traviesa, ¡pero es que necesitaba mear! ¿Vale? +¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? [AM4_D] -Es el momento de que te encuentres con nuestro hombre dentro del DPL. +Es hora de que conozcas a nuestro espía en la policía. [AM4_E] Aquí está su pago por el último trabajito que hizo para nosotros. [AM4_F] -El es comprensiblemente cauteloso. +Él es comprensiblemente cauteloso. [AM4_G] Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. @@ -1592,205 +1595,205 @@ Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. María y yo hemos ido de compras. [AM5_B] -¡Nuestra fuente en la policía nos ha informado de que uno de nuestros conductores es un extrañamente animado poli camuflado! +¡Nuestro contacto en la policía nos ha informado que uno de nuestros conductores es un poli infiltrado que se mueve de forma extraña! [AM5_C] -El es un inútil fuera de su coche así que lo hemos marcado con un seguidor. +Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizador. [AM5_D] -¡Hazle sangrar! +¡Haz que sufra! [AM5_1] -¡Tanner está sobre ti! +¡Tanner te ha pillado! [AS1] 'CEBO' [AS2] -'MARCHANDO UN EXPRESO' +'CAFÉ PARA LLEVAR' [AS4] 'RESCATE' [AS1_A] -~w~Parece que Miguel piensa que le maltrato +Parece que Miguel piensa que le maltrato. [AS1_B] -~w~Pero él ha revelado cuánto teme Catalina tu búsqueda de revancha. +Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. [AS2_A] -~w~Infravaloramos los planes de Catalina para el SPANK +Subestimamos los planes que tiene Catalina para el SPANK. [AS2_B] -~w~Va mucho más allá de los Yardies vendiéndolo en las esquinas. +Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. [AS2_D] -~w~Han vendido SPANK en puestos callejeros. +Vende SPANK en puestos callejeros. [AS2_1] -¡¡Todos los puestos de expreso en Portland destruidos!! +~g~¡Todos los puestos de café en Portland han sido destruidos! [AS2_2] -~g~¡¡Todos los puestos de expreso en Staunton Island destruidos!! +~g~¡Todos los puestos de café en Staunton Island han sido destruidos! [AS2_3] -~g~¡¡Todos los puestos de expreso en Shoreside Vale destruidos!! +~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! [AS2_4] -~r~¡¡El Cartel ha avisado a sus camellos!! +~r~¡El cártel ha avisado a sus camellos! [AS2_5] -~g~¡Todavía hay puestos de expreso en Shoreside Vale y en Staunto Island! +~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! [AS2_6] -~g~¡Todavía hay puestos de expreso en Shoreside Vale! +~g~¡Todavía hay puestos de café en Shoreside Vale! [AS2_7] -~g~¡Todavía hay puestos de expreso en Staunton Island! +~g~¡Todavía hay puestos de café en Staunton Island! [AS2_8] -~g~¡Todavía hay puestos de expreso en Portland! +~g~¡Todavía hay puestos de café en Portland! [AS2_9] -~g~¡Todavía hay puestos de expreso en Portland y en Shoreside Vale! +~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! [AS2_10] -~g~¡Todavía hay puestos de expreso en Portland y en Staunton Island! +~g~¡Todavía hay puestos de café en Portland y en Staunton Island! [AS2_12] -~g~¡Cruza los distritos de Liberty para buscar puestos de ~b~Marchando un Expreso! +~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! [AS3_A] -~W~¿Lo apretamos un poco más o esperamos a que se vuelva negro y caiga? +¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? [AS3_B] -~w~Dale un pinchazo rápido... +Dale un toque rápido... [AS3_D] -~w~¡Mi manitas! +¡Mi manitas! [AS3_E] -~w~Me aburría, así que vine a hacer compañía a Asuka. +Me aburría, así que vine a hacerle compañía a Asuka. [AS3_1] -~g~Busca un ~r~bote~g~ y ve al ~b~boya del aeropuerto! +~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! [AS3_3] -~g~Espera a que el ~y~avión~g~ comience a acercarse! +~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! [AS3_5] -~g~¡Recupera la carga! +~g~¡Recupera el cargamento! [AS3_4] -~g~¡¡Usa un lanzador de cohetes para derribar ~y~el avión~g~!! +~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! [AS3_2] -~b~¡Ve al boya del aeropuerto! ~y~¡¡El avión se está acercando!! +~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! [AS3_6] ~g~~1~ DE 8 [KM1] -'KANBU REVIENTA' +'LA FUGA DEL KANBU' [KM3] -'TRATO SIGILOSO' +'UN MAL TRATO' [KM4] 'SHIMA' [KM5] -'HEROÍNA' +'CONTRINCANTES TRAFICANTES' [KM1_A] -Mi hermana habla muy bien de ti, +Mi hermana te tiene en gran estima, [KM1_E] -aunque todavía debo convencerme de que un gaijin puede ofrecerme algo más que contratiempos. +pero yo debo convencerme de que un gaijin puede ofrecerme algo más que desilusiones. [KM1_B] Tal vez puedas ayudar con una situación que me tiene en desventaja. [KM1_F] -Desde luego que el fracaso lleva consigo su propia desgracia. +Por supuesto, el fracaso conllevará una desgracia. [KM1_C] -Un Yakuza Kanbu está bajo custodia esperando ser trasladado y juzgado. +Un kanbu, o jefe de la yakuza, está bajo custodia a la espera de juicio. [KM1_G] -Es un valioso miembro de la familia. +Es un miembro importante de la familia. [KM1_H] Libéralo y llévatelo al dojo de Bedford Point. [KM1_D] -Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda el dojo tendrá el honor de proporcionarte dos hombres que permanecerán a tu lado. +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. [KM1_1] -~g~¡Roba un coche de la pasma! +~g~¡Roba un coche de la policía! [KM1_2] -~g~¡Carga el coche con una bomba! +~g~¡Instala una bomba en el coche! [KM1_3] -~g~Ahora llévalo al dojo Yakuza. +~g~Ahora llévalo al dojo de la yakuza. [KM1_5] -~g~Vale, ahora ve a la comisaría. +~g~Ahora ve a la comisaría. [KM1_6] ~g~¡Pon una bomba en el coche! [KM1_7] -~g~¡Sólo vehículos de policía autorizados! +~g~¡Sólo pueden entrar vehículos de policía autorizados! [KM1_9] -~r~No usaste un coche bomba para destruir la pared. +~r~No destruiste la pared con un coche bomba. [KM1_10] -~r~El Yakuza Kanbu está muerto - ¡y tu honor también! +~r~El kanbu está muerto, ¡y tu honor también! [KM1_11] -~r~¡Trajiste la desgracia a ti mismo! +~r~¡La policía te ha seguido! [KM2_A] -Es imposible sobreestimar la importancia del protocolo en esta sección de trabajo. +Es imposible sobreestimar la importancia del protocolo en este trabajo. [KM2_B] -Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca tuve la oportunidad de devolver su amabilidad. +Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corresponder su amabilidad. [KM2_C] -Su punto débil son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. +Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. [KM2_F] -Mi honor lo demanda. +Mi honor lo exige. [KM2_2] ~g~Coche entregado. [KM3_A] -Cuando los problemas acechan, el tonto les da la espalda, mientras el hombre sabio los enfrenta. +Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. [KM3_B] -El Cartel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. +El cártel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. [KM3_C] Ahora están negociando con los jamaicanos para humillarnos aún más. [KM3_D] -Están cerrando un trato en toda la ciudad. +Están cerrando un trato en la ciudad. [KM3_F] -Llévate a uno de mis hombres, roba un coche Yardie y ve a presentar tus respetos a los colombianos. +Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus respetos a los colombianos. [KM3_E] -Nuestro honor demanda que no dejes a nadie vivo. +¡Nuestro honor exige que no dejes a nadie vivo! [KM3_2] -~g~Ve y recoge a tu contacto. +~g~Recoge a tu contacto. [KM3_3] -~g~¡La reunión está teniendo lugar en el estacionamiento del hospital de Rockford! +~g~¡La reunión está teniendo lugar en el aparcamiento del hospital de Rockford! [KM3_4] ~r~¡Han escapado! @@ -1799,43 +1802,45 @@ Nuestro honor demanda que no dejes a nadie vivo. ~g~¡Mátalos, mátalos a todos! [KM3_8] -~g~¡Necesitas un coche Yardie para hacer el trabajo! +~g~¡Necesitas un coche de los jamaicanos para este trabajo! [KM3_9] -~r~Uno de los colombianos está muerto, se acabó el trato. +~r~Uno de los colombianos ha muerto, se ha cancelado el trato. [KM3_10] ~r~¡El contacto está muerto! [KM4_A] -Para ser verdaderamente fuerte es importante que nunca demuestres debilidad. +Para ser verdaderamente fuerte, es importante no mostrar debilidad. [KM4_C] -Ve y recolecta el dinero inmediatamente, para que podamos ingresarlo en las cuentas del casino. +Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. [KM4_1] ¡No puedo pagarte y no lo haría aunque pudiera! [KM4_9] -¡Una banda de jóvenes acaban de arrasar el local! ¡Se han llevado todo! +¡Una banda de chavales acaba de arrasar el local! ¡Se han llevado todo! [KM4_2] -No servís para nada. +¡Sois inútiles! [KM4_10] -De todas maneras, ¡qué clase de Yakuza eres TÚ? +Además, ¿qué clase de yakuza eres tú? + +{ Unused string? } [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. +No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. [KM4_4] -~g~¡Castiga a la banda responsable y recupera el dinero de la protección! +~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! [KM4_7] ~r~¡El tendero la acaba de palmar! [KM4_5] -Donald Love desea que te dejes caer en su jardín de té para que podáis hablar. +Donald Love desea que te pases por su jardín de té para tener una charla. [KM4_6] ¡Aquí está todo el dinero! @@ -1844,319 +1849,319 @@ Donald Love desea que te dejes caer en su jardín de té para que podáis hablar ~g~¡Maletín recolectado! [KM5_A] -¡TÚ! ¡Qué adecuado que elijas este momento para enseñar tu cara culo! +¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! [KM5_B] -Parece que tus intentos para disuadir a los jamaicanos +¡Parece que tus intentos para disuadir a los jamaicanos [KM5_B1] -que se conviertan en chicos malos en el Cartel, ¡son totalmente inadecuados! +de convertirse en aliados del cártel han sido totalmente inútiles! [KM5_C] -¡Los camellos Yardie se alinean en las calles de Liberty vendiendo paquetes de SPANK como si fueran perritos calientes! +¡Los traficantes jamaicanos están llenando las calles de Liberty, vendiendo SPANK como si fueran perritos calientes! [KM5_D] -Estos cerdos del Cartel se están riendo de nosotros, ¡en mi cara! +Estos cerdos del cártel se están riendo de nosotros, ¡de mí! [KM5_E] -¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene una base segura! +¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene un buen motivo! [KM5_F] -¡¡¡Entierra estos sacos de basura y lava tu vergüenza en ríos de la sangre de nuestros enemigos!!! +¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! [KM5_3] -~r~Fallaste al matar al menos a ~1~ yardies. +~r~No has matado a ~1~ jamaicanos. [KM5_4] -~g~Felicitaciones, mataste a ~1~ yardies. +~g~Enhorabuena, has matado a ~1~ jamaicanos. [KM5_5] -~g~Enhorabuena, mataste ~1~ yardies. ~1~$ EXTRA +~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES [RM1] 'SILENCIA AL SOPLÓN' [RM3] -'POCA EVIDENCIA' +'FALTA DE PRUEBAS' [RM4] 'DE PESCA' [RM5] -'PASTA DE YESO' +'DESESCAYOLADOR' [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. +Se encuentra bajo protección armada en una propiedad de WitSec en el centro de Newport, en algún piso que hay detrás del aparcamiento. [RM1_E] -Incendia ese lugar, eso les hará salir y podrás cazarlos, asegúrate de que no hable con nadie. +Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. [RM1_1] -~g~Comprueba la casa de protección de testigos. +~g~Ve a la casa de protección de testigos. [RM1_2] -~g~¡Saca a McAffrey! +~g~¡Cárgate a McAffrey! [RM2_A1] -¡Eh tú, el chaval de ahí! +¡Chico, estoy aquí! [RM2_A] -Un viejo colega del ejército lleva un asunto en Rockford. +Un viejo colega del ejército tiene un negocio en Rockford. [RM2_D] -Va a necesitar algún respaldo y a cambio te dará cualquier herramienta que compres a precios de ganga. +Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. [RM2_E] -Ray se adelantó al llamar....pero pensé que serías algo más. +Ray me avisó... Pero pensé que vendría más gente. [RM2_F] -Bien, tres armas son mejor que una, así que hazte con lo que necesites. +Bueno, tres brazos son mejor que uno, así que sírvete. [RM2_G] -~g~¡Ve a echar un vistazo a Phil! +~g~¡Ve a ver a Phil! [RM2_H] -~r~¡¡Han matado a Phil!! +~r~¡Han matado a Phil! [RM2_L] -¡Hey! ¡Si hubiera estado de tu bando en Nicaragua quizás todavía conservaría mi brazo! +¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! [RM2_N] -No te preocupes por el dinero. Ahora lárgate de aquí, yo entretendré a los polis. +Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. [RM3_D] -Están llevando la prueba por toda la ciudad. +Están transportando las pruebas por la ciudad. [RM3_E] -Vas a tener que deshacerte del coche y recoger hasta la última prueba que quede por ahí. +Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. [RM3_F] -Cuando lo tengas todo, déjalo en el coche y préndele fuego. +En cuanto tengas todas, déjalas en tu coche y préndele fuego. [RM3_G] -Lo vamos a llevar mucho mejor sin este chico. +Cuando acabes, nos irá mucho mejor, chico. [RM3_1] -~g~Deja la prueba en un coche y después préndele fuego. +~g~Deja las pruebas en un coche y después préndele fuego. [RM3_4] -~g~¡El Fiscal ha retirado la prueba! +~g~¡Al fiscal se le ha caído una prueba! [RM3_6] -~r~¡Las fotos habrán acabado con toda posibilidad de Libertad! +~r~¡Las fotos circularán por toda la ciudad! [RM3_7] ~g~¡Ahora préndele fuego al coche! [RM4_A] -Creo que mi socio es una rata. +Creo que mi socio es un soplón. [RM4_C] -Casi todas las noches sale a pescar con su barca cerca del faro que hay en Portland Rock. +Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. [RM4_D] -¡Roba una barca de la policía y asegúrate de que se vengan abajo sus planes de darte una puñalada trapera! +¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! [RM4_1] -~g~Vete y roba una barca de la policía. +~g~Ve y roba una lancha de la policía. [RM4_2] -~g~¡Vete al faro y 'liquida' al socio de Ray! +~g~¡Ve al faro y ''hunde'' al socio de Ray! [RM5_A] ¡Inútil de mierda! [RM5_A1] -¡Eres un absoluto imbécil! Tengo el culo a tiro y ni siquiera eres capaz de matar a una maldita mosca. +¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. [RM5_B] -¡Te he pagado una pasta para que mates al testigo y aún sigue vivo! +¡Te pagué una pasta para matar al testigo y aún sigue vivo! [RM5_B1] -¡Y hoy va a declarar ante los Federales! +¡Y hoy va a declarar ante los federales! [RM5_C] -Le van a llevar de un momento a otro del Hospital General Carson a Rockford. +Está a punto de ser trasladado del hospital general Carson, en Rockford. [RM5_D] -Si se chiva, yo canto.... +Si él canta, yo canto... [RM5_E] -¡así que vete y haz el trabajo por el que se te pagó! +¡así que termina el trabajo por el que te pagué! [RM5_1] -~g~¡¡Detén la ambulancia!! +~g~Intercepta la ambulancia. [RM5_2] -~g~¡¡Te han chafado!! +~g~¡Te han descubierto! [RM5_3] -~g~¡Ha sido una trampa! +~g~¡Era un señuelo! [RM5_4] -~g~¡¡Las balas no van a atravesar ese chaleco antibalas!! +~g~¡Las balas no penetran en esa escayola de cuerpo entero! [RM5_5] -~g~¡¡Ese chaleco antibalas es a prueba de fuego!! +~g~¡Esa escayola de cuerpo entero es ignífugo! [RM5_7] -~r~¡¡Han llevado al testigo!! +~r~¡El testigo está a salvo! [RM5_8] -~g~¡¡El testigo se ha ahogado!! +~g~¡El testigo se ha ahogado! [LOVE2] -'¡EXTERMINA A WAKA-GASHIRA!' +'¡EXTERMINA AL WAKA-GASHIRA!' [LOVE3] 'UNA GOTA EN EL OCÉANO' [LOVE1_A] -Antes que nada, déjame que te agradezca que te hayas ocupado de ese asunto personal. +Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. [LOVE1_F] -La gente tiende a malinterpretar las cosas últimamente. +Últimamente la gente tiende a malinterpretar las cosas. [LOVE1_D] -Están intentando sacarme más de lo pactado, pero no soy precisamente partidario de revisar los tratos. +Pretenden exigirme más de lo pactado, pero no me gusta renegociar. [LOVE1_E] -Un trato es un trato, así que no van a ver ni un duro mío. +Un trato es un trato, así que no van a ver ni un dólar mío. [LOVE1_G] -Ve a rescatar a mi amigo, haz lo que haga falta. +Rescata a mi amigo cueste lo que cueste. [LOVE1_2] -~g~Rescata al Anciano Caballero Oriental. +~g~Rescata al anciano oriental. [LOVE1_3] -~g~Lleva de vuelta al edificio de Donal Love al Anciano Caballero Oriental. +~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. [LOVE1_4] -~g~El Anciano Caballero Oriental debe estar en uno de los aparcamientos.... +~g~El anciano oriental debe estar detrás de alguna de estas puertas... [LOVE1_6] -~r~¡Las tripas del Anciano Caballero Oriental están esparcidas por las calles! +~r~¡Las tripas del anciano oriental están desparramadas por las calles! [LOVE1_7] -~g~Sólo se abrirá la puerta para un coche de la Banda Colombiana. +~g~La puerta sólo se abrirá ante un coche de los colombianos. [LOVE2_A] -No hay nada como una de esas guerras de bandas pasadas de moda para hacer que bajen los precios de la vivienda, +No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, [LOVE2_B] -excepto desencadenar una plaga......pero eso sería llegar demasiado lejos en este caso. +excepto una plaga... pero eso sería excesivo en este caso. [LOVE2_C] -He observado que Yakuza y los Colombianos no son precisamente buenos amigos. +He observado que la yakuza y los colombianos no son precisamente buenos amigos. [LOVE2_D] -Vamos a aprovechar las posibilidades de negocio que se presentan. +Vamos a aprovechar esta oportunidad de negocio. [LOVE2_E] -Quiero que mates a Kanji Kase, el WAKA-cuchillera de Yakuza. +Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. [LOVE2_F] -Kenji está asistiendo a una reunión en lo alto del aparcamiento de los almacenes de Newport. +Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. [LOVE2_G] -¡Hazte con un coche de la banda del Cartel y elimínalo! +¡Hazte con un coche de la banda del cártel y elimínalo! [LOVE2_H] -El Yakuza debe culpar al Cartel por esta declaración de guerra. +La yakuza debe culpar al cártel de esta declaración de guerra. [LOVE2_1] ~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! [LOVE2_2] -~g~¡Ahora ve a los ~p~almacenes de Newport~g~ y cárgate a Kenji! +~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! [LOVE2_3] -~r~¡Si lo haces sin un coche del Cartel te identificarán! +~r~¡Si no llevas un coche del cártel, te descubrirán! [LOVE2_4] -~r~¡¡El Yakuza te ha identificado!! +~r~¡La yakuza te ha reconocido! [LOVE2_6] -~r~¡¡Has matado a todos los testigos!! +~r~¡Has matado a todos los testigos! [LOVE3_A] -En estos días de hipocresía moral ciertos artículos pueden resultar difíciles de importar. +En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. [LOVE3_C] -Echará varios paquetes en el agua. +Echará varios paquetes al agua. [LOVE3_D] -Asegúrate de que los recoges antes que nadie más lo haga. +Asegúrate de los consigues antes que nadie. [LOVE3_1] -~g~¡Consigue una ~r~barca~g~ y sigue al ~y~avión~g~! +~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! [LOVE4] -'GRAN LADRÓN AÉREO' +'ROBO DE ALTOS VUELOS' [LOVE5] 'SERVICIO DE ESCOLTA' [LOVE4_A] -Gracias por hacerte con esos paquetes, pero no eran más que una trampa. +Gracias por conseguir esos paquetes, pero sólo eran un señuelo. [LOVE4_B] -Lo siento, pero a veces así son los negocios. +Lo siento, pero a veces los negocios son así. [LOVE4_C] -Mi objetivo real se ocultaba por completo en el avión. +Mi verdadero objetivo se ocultaba en la avioneta. [LOVE4_F] -Tengo sobornados a los oficiales. +He sobornado a los funcionarios. [LOVE4_1] -~r~¡Está aquí el Cartel Colombiano!! +~r~¡El cártel colombiano está aquí! [LOVE4_2] -~g~¡Ha desaparecido el paquete! Sigue la pista a los colombianos y recupéralo. +~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. [LOVE4_3] -~g~¿Construcción Panlántica ...? +~g~¿''Panlantic Construction''...? [LOVE4_5] -~g~El paquete debería estar en el avión.... +~g~El paquete debería estar en la avioneta... [LOVE4_6] -~g~¡Sube en el ascensor a lo alto de la torre! +~g~¡Usa el ascensor! [LOVE5_B] -Mi amigo Oriental va a necesitar una escolta mientras trata de comprobar si mi última adquisición es auténtica o no. +Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. [LOVE5_1] -~g~¡Vamos! +~g~¡En marcha! [LOVE5_2] ~g~¡Vas a necesitar un coche! [LOVE5_3] -~g~¡Sigue hasta que puedas encontrar la salida del túnel! +~g~¡Comprueba la salida del túnel! [LOVE5_4] ~r~¡Protege el camión! [RM6] -'HOMBRE SEÑALADO' +'HOMBRE MUERTO' [RM6_A] ¿No te han seguido? Bien. [RM6_B] -Así de fácil, ¡no tengo dónde meterme y me estoy empezando a hundir aquí mismo! +Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! [RM6_D] -Soy un hombre señalado, así que tengo que largarme de aquí. +Soy hombre muerto, así que tengo que largarme. [RM6_E] -¡Consigue que no pierda mi vuelo en el aeropuerto y haré que haya merecido la pena tu trabajo! +¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! [RM6_666] -Cuida de mi Patriot a prueba de balas. Nos vemos en Miami, Ray +Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray [CAT1] 'RESCATE' @@ -2165,55 +2170,33 @@ Cuida de mi Patriot a prueba de balas. Nos vemos en Miami, Ray 'EL INTERCAMBIO' [CAT1_A] -Tengo a la preciosa María. No creo que quieras que su cara parezca como si se hubiera enfadado con el carnicero. +Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, + +{ UNUSED DUPLICATE } [CAT2_F] -Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado 50 $! +Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado cincuenta dólares! + +{ UNUSED DUPLICATE } [CAT2_G] -Tenía tanto miedo, pero entonces me dije a mí misma, ahora eres una gran chica. +Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. + +{ UNUSED DUPLICATE } [CAT2_H] Oh, nos lo vamos a pasar a lo grande, porque, ¿sabes?, mi hermana dijo que quería venirse a vivir con sus dos hijos, +{ UNUSED DUPLICATE } + [CAT2_I] -porque su marido a vuelto a enredar por ahí y..... - -[CAT1_C] -XXXX - -[CAT1_D] -XXXX - -[CAT1_E] -XXXX +porque su marido a vuelto a enredar por ahí y... [CAT1_F] ¡Ve a donde está Catalina antes de que se acabe el tiempo! -[CAT1_G] -XXXX - -[CAT1_H] -XXXX - -[CAT1_I] -XXXX - -[CAT1_J] -XXXX - -[CAT1_K] -XXXX - -[CAT1_L] -XXXX - -[AS4_1] -XXXX - [CAT_MON] -~g~Todavía no tienes suficiente dinero. Necesitas 500.000 $. +~g~Todavía te falta dinero. Necesitas 500.000 dólares. [BITCH_D] ~g~¡María está muerta! @@ -2225,82 +2208,82 @@ FORZAR EL CLIMA CLIMA NORMAL [8001] -¡¡Has fallado miserablemente!! +¡Has fallado miserablemente! [1000] -ESTÁS MUERTO +HAS MUERTO [1001] -ESTÁS MUERTO +HAS MUERTO [1002] -ESTÁS MUERTO +HAS MUERTO [1003] -ESTÁS MUERTO +HAS MUERTO [1004] -ESTÁS MUERTO +HAS MUERTO [1005] -AVERIADO +TRINCADO [1006] -AVERIADO +TRINCADO [1007] -AVERIADO +TRINCADO [1008] -AVERIADO +TRINCADO [1009] -AVERIADO +TRINCADO [GA_4] -Las bombas de coche valen 1000 $ cada una +Una bomba de coche vale 1.000 dólares. [GA_5] -Tu coche ya tiene instalada una bomba. +Tu coche ya tiene una bomba instalada. [GA_6] -Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL POR PATAS! +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! [GA_7] -Arma con el ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba estallará cuando se arranque el motor. +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. [GA_8] Utiliza el detonador para activar la bomba. [GA_9] -Ha conseguido ~1~de los 10 coches especiales +Ha conseguido ~1~ de los 10 coches especiales. [GA_10] -Buen ejemplar. Aquí tienes tus ~1~$ +Buen trabajo. Aquí tienes tus ~1~ dólares. [GA_11] -Las ruedas ya están listas. ¡No sirve para nada! +Ya tenemos este modelo. ¡No nos sirve para nada! [GA_12] Bomba armada [GA_13] -Entregado como un profesional. Completa la lista y conseguirás una bonificación. +Eres todo un profesional. Completa la lista y conseguirás una recompensa. [GA_14] -Todos los coches. ¡ESTUPENDO! Aquí hay algo para ti. +Ya están todos los coches. ¡Estupendo! Toma un detallito. [GA_15] Espero que te guste el nuevo color. [GA_16] -Repintarlo es adicional. +Esta mano de pintura es gratuita. [GA_19] No nos interesa ese modelo. [GA_20] -Tenemos de esos más de los que podamos ocuparnos. Lo siento, tío, no hay negocio. +Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. [CR_1] La grúa no puede levantar este vehículo. @@ -2309,28 +2292,28 @@ La grúa no puede levantar este vehículo. No tienes suficiente dinero. [CO_ALL] -Los tienes todos. Aquí hay algo para ti... +Te has hecho con todos. Toma un detallito... [PAUSED] -JUEGO EN PAUSA GAME PAUSED +PARTIDA EN PAUSA [HEALTH1] -¡Lárgate de aquí! Estás completamente sano. +¡Largo! Estás completamente sano. [HEALTH2] -La salud cuesta dinero. +La sanidad cuesta dinero. [HEALTH3] Te pondré como nuevo. [HEALTH4] -Eso te va a costar 250 $. +Te va a costar 250 $. [FEB_STA] Estadísticas [FEB_BRI] -Informes +Resumen [FEB_CON] Controles @@ -2348,7 +2331,7 @@ Idioma ESTADÍSTICAS [FEP_BRI] -INFORMES +RESUMEN [FEP_CON] CONTROLES @@ -2372,7 +2355,7 @@ Cuánta destrucción has producido ¿Has perdido el hilo? [FEF_CO1] -¿Necesitas más control, pirado? +¿Necesitas más control? [FEF_CO2] Elige la mejor configuración del mando para tu estilo de juego @@ -2384,7 +2367,7 @@ Elige la mejor configuración del mando para tu estilo de juego Guarda y carga tus partidas [FEF_AU1] -¡Pon el volumen a tope! +¡Dale candela al volumen! [FEF_AU2] Elige una emisora de radio y un efecto de sonido @@ -2396,26 +2379,27 @@ Elige una emisora de radio y un efecto de sonido Personaliza el juego para tu televisión [FEF_LA1] -¿Qué dices de los willis? +¿Qué dices de los Willis? [FEF_LA2] -Elige la forma de hablar que prefieras +Elige tu idioma preferido [FEB_PMB] -Informes de la Misión Previa: +Resumen de la última misión: [FEC_NA] -No Disponible +No disponible [FEC_CWL] -Cambiar al Arma izquierda +Siguiente arma [FEC_CWR] -Cambiar al Arma izquierda +Arma anterior [FEC_LOF] Mirar hacia delante +{ !!!!!!!!!!!!!!!!!! ACHTUNG! THIS STRING IS USED FOR BOTH THE MAP'S CURRENT TARGET AS WELL AS FOR THE ACTION OF TARGETING WITH A GUN! THIS WILL SCREW AROUND TRANSLATIONS !!!!!!!!!!!!!!! } [FEC_TAR] Objetivo @@ -2423,19 +2407,19 @@ Objetivo Movimiento [FEC_CAM] -Modos de Cámara +Cambiar cámara [FEC_PAU] Pausa [FEC_ENV] -Entrar al vehículo +Entrar en vehículo [FEC_JUM] Saltar [FEC_ATT] -Ataque o Arma de Fuego +Atacar o disparar [FEC_RUN] Correr @@ -2450,31 +2434,31 @@ Mirar a la izquierda Mirar [FEC_LB2] -detrás +atrás [FEC_LB] -Mirar detrás +Mirar atrás [FEC_LR] Mirar a la derecha [FEC_HOR] -Bocina +Claxon [FEC_VES] -Control del vehículo +Controlar vehículo [FEC_RSC] -Cambiar de emisora de Radio +Cambiar emisora de radio [FEC_BRA] -Freno o Marcha Atrás +Freno o marcha atrás [FEC_HAB] Freno de mano [FEC_CAW] -Arma del coche +Arma del vehículo [FEC_ACC] Acelerar @@ -2498,13 +2482,13 @@ Ajuste3 Ajuste4 [FEC_CDP] -Pantalla del mando: +Controles a mostrar: [FEC_ONF] -A Pie +A pie [FEC_INC] -En Coche +En vehículos [FEC_VIB] Vibración: @@ -2525,7 +2509,7 @@ Ninguna HEAD RADIO [FEA_FM1] -DOUBLE CLEFF FM +DOUBLE CLEF FM [FEA_FM2] K-JAH RADIO @@ -2546,10 +2530,10 @@ MSX FM FLASHBACK 95.6 [FEA_FM8] -CHATTERBOX 109 +CHATTERBOX FM [FED_DBG] -Menú de Depuración +Menú de depuración [FED_RID] Recargar IDE @@ -2567,127 +2551,127 @@ CCullZones::RecalculateCullZoneData CTheScripts::DbgFlag [FED_DLS] -Activada la Luz de Depuración Blanca Grande +Cambiar luz blanca grande de depuración [FED_SPR] -Mostrar Grupos de Carretera Ped +Mostrar grupos de peatones en carretera [FED_SCR] -Mostrar Grupos de Carretera de Coches +Mostrar grupos de vehículos en carretera [FED_SCZ] -Mostrar Zonas 'A escoger' +Mostrar zonas de máscara selectiva [FED_DSR] -Compilar las Solicitudes de Streaming +Solicitudes de depuración de streaming [FED_SCP] gbShowCollisionPolys [FEM_MCM] -Memory Card Menu +Menú de Memory Card [FEM_RMC] -Registrar MemCard Uno +Registrar MemCard uno [FEM_TFM] -Probar Formato de MemCard Uno +Probar MemCard uno formateada [FEM_TUM] -Probar Memcard Uno SinFormato +Probar Memcard uno sin formato [FEM_CRD] -Crear Dir Raiz +Crear directorio raíz [FEM_CLI] -Crear y Cargar Iconos +Crear y cargar iconos [FEM_FFF] -Llenar Primer Archivo con Necedades +Llenar primer archivo con basura [FEM_SOG] -Guardar Sólo El Juego +Guardar sólo partida [FEM_CES] -Comprobar Cada 0kBpara Guardar +Comprobar cada guardado de 0kB4 [FEM_STG] -Guardar El Juego +Guardar partida [FEM_STS] -Guardar El Juego bajo el nombre GTA3 +Guardar partida bajo el nombre GTA3 [FEM_CPD] -Crear copia protegida del directorio Revista +Crear copia protegida del directorio mag [FEM_MC2] -Memory Card Menu 2 +Menú de Memory Card 2 [FEM_TS] -Probar Guardar: +Prueba de guardado: [FEM_TL] -Probar Guardar: +Prueba de carga: [FEM_TD] -Probar Borrar: +Prueba de borrado: [PL_STAT] -Estadísticas del jugador +Estadísticas de jugador [PE_WAST] -Personas que has dilapilado +Personas asesinadas [PE_WSOT] -Personas dilapiladas por otros +Personas asesinadas por otros [CAR_EXP] -Coches explotados +Coches reventados [TM_BUST] -Tiempos no conseguidos +Veces arrestado [M_WASTE] -Hombres civiles dilapilados +Hombres civiles asesinados [F_WASTE] -Mujeres civiles dilapiladas +Mujeres civiles asesinadas [PIG_WST] -Polis dilapilados +Polis asesinados [GNG_WST] -Miembros de bandas dilapilados +Maleantes asesinados [MED_WST] -Personal médico dilapilado +Médicos asesinados [FIRE_WS] -Bomberos empleados +Bomberos asesinados [DED_CRI] -Criminales dilapilado +Criminales asesinados [DED_DED] -Vagos dilapilados +Vagabundos asesinados [DED_HOK] -Prostitutas dilapiladas +Prostitutas asesinadas [HEL_DST] Helicópteros destruidos [PER_COM] -Porcentaje cumplido +Porcentaje completado [KGS_EXP] Kgs de explosivos empleados [ACCURA] -Puntería +Precisión de tiro [ELBURRO] -Mejor tiempo de Turismo en segundos +Mejor tiempo de ''Turismo'' en segundos [CAR_CRU] Coches destrozados @@ -2705,91 +2689,91 @@ Días de juego transcurridos mm de lluvia caídos [MXCARD] -Máx. dist. Salto INSANO (pies) +Dist. máx. de salto acrobático (pies) [MXCARJ] -Máx. altitud Salto INSANO (pies) +Altitud máx. de salto acrobático (pies) [MXCARDM] -Máx. dist. Salto INSANO (metros) +Dist. máx. de salto acrobático (metros) [MXCARJM] -Máx. altura Salto INSANO (metros) +Altitud máx. de salto acrobático (metros) [MXFLIP] -Máx. vueltas Salto INSANO +Vueltas durante salto acrobático [MXJUMP] -Máx. rotación Salto INSANO +Rotación máx. de salto acrobático [BSTSTU] -Mejor maniobra INSANA hasta ahora: +Mejor acrobacia hasta ahora: [INSTUN] -Maniobra Insana +Acrobacia [PRINST] -Maniobra insana perfecta +Acrobacia perfecta [DBINST] -Maniobra insana doble +Acrobacia doble [DBPINS] -Maniobra insana doble perfecta +Acrobacia doble perfecta [TRINST] -Maniobra insana triple +Acrobacia triple [PRTRST] -Maniobra insana triple perfecta +Acrobacia triple perfecta [QUINST] -Maniobra insana cuádruple +Acrobacia cuádruple [PQUINS] -Maniobra insana cuádruple perfecta +Acrobacia cuádruple perfecta [NOSTUC] -Ninguna maniobra insana completada +No se han hecho acrobacias [NOUNIF] -Saltos Únicos completados +Saltos únicos completados [NOUNGM] -Total de Saltos Únicos +Saltos únicos [NMISON] Misiones intentadas [NMMISP] -Misiones conseguidas +Misiones superadas [PASDRO] -Pasajeros tirados en marcha +Pasajeros transportados [MONTAX] Dinero conseguido en taxi [DAYPLC] -Gasto diario en policias +Gasto diario de la policía [CRIMRA] -Porcentaje criminal: +Rango de criminal: [GMSTOR] -Almacén de Juego +Almacenar partida [PREBRF] -Informes Previos +Resúmenes anteriores [CNTLS] Controles [MUSMEN] -Música / Efectos Especiales +Música/Efectos [GAMSET] -Ajustes del Juego +Ajustes del juego [LANGUA] Idioma @@ -2798,13 +2782,13 @@ Idioma Pantalla [DEBUGM] -Menú de Depuración +Menú de depuración [QUITOP] -Salir de las Opciones +Salir de las opciones [CONTRL] -Configuración de Control +Configuración de controles [SET1EN] Ajuste 1. Activado @@ -2837,49 +2821,49 @@ Volver SONIDO [MUSVOL] -Volumen de la Música +Volumen de la música [SFXVOL] -Volumen de los Efectos Especiales +Volumen de los efectos [SCROPT] OPCIONES DE PANTALLA [CTRSCR] -Centrar Pantalla +Centrar pantalla [SCRFOR] -Formato de Pantalla +Formato de imagen [GMSVLQ] -JUEGO GUARDAR-CARGAR-SALIR +GUARDAR-CARGAR-SALIR [GMREST] -Reiniciar Juego +Reiniciar partida [GMLOAD] -Cargar Juego +CARGAR PARTIDA [NOGMSV] Sólo puedes guardar desde tu escondite. [DLFILE] -Borrar Archivos de Grand Theft Auto III +Borrar archivos de Grand Theft Auto III [CHFILE] ELEGIR ARCHIVO A CARGAR [CHCDLD] -Elegir Tarjeta desde la que Cargar +ELEGIR MEMORY CARD A USAR [CDUNFR] -Tarjeta sin formato. +Memory Card sin formato. [CHFIDL] -ELIGE UN ARCHIVO A BORRAR +ELEGIR ARCHIVO A BORRAR [SVCONF] -CONFIRMACIÓN DE GURDAR +CONFIRMACIÓN [SVFNAM] El nombre de tu archivo guardado es @@ -2888,7 +2872,7 @@ El nombre de tu archivo guardado es Error. Fallo al guardar. [LANGSL] -SELECCIÓN DEL IDIOMA +SELECCIÓN DE IDIOMA [ENGLIS] Inglés @@ -2912,106 +2896,106 @@ ReLoadIde ReLoadIpl [PARSHP] -Analizar Pila +Analizar pila [DBGFON] -Activado CTheScripts::DbgFlag +CTheScripts::DbgFlag activado [DBFOFF] -Desactivado CTheScripts::DbgFlag +CTheScripts::DbgFlag desactivado [BGWHON] -Activada Luz Blanca Grande de Depuración +Luz blanca grande de depuración activada [BGWOFF] -Desactivada Luz Blanca Grande de Depuración +Luz blanca grande de depuración desactivada [DSTRON] -Activadas Solicitudes de Depuración de Streaming +Solicitudes de depuración de streaming activadas [DSTROFF] -Desactivadas Solicitudes de Depuración de Streaming +Solicitudes de depuración de streaming desactivadas [PDRGON] -Activado ShowPedRoadGroups +ShowPedRoadGroups activado [PRGOFF] -Desactivado ShowPedRoadGroups +ShowPedRoadGroups desactivado [CRRGON] -Activado ShowCarRoadGroups +ShowCarRoadGroups activado [CRGOFF] -Desactivado ShowCarRoadGroups +ShowCarRoadGroups desactivado [CLZOON] -Activado Mostrar Zonas a escoger +Zonas de máscara selectiva mostradas [CLZOOF] -Desactivado Mostrar Zonas a escoger +Zonas de máscara selectiva ocultadas [SHPLON] -gbShowCollisionPolys Sí +gbShowCollisionPolys activado [SHPLOF] -gbShowCollisionPolys No +gbShowCollisionPolys desactivado [CULREC] CCullZones::RecalculateCullZoneData() [FORMM1] -FormatMemCard 1 (materialprueba) +FormatMemCard 1 (prueba) [UNFRM1] -UnFormatMemCard 1 (materialprueba) +UnFormatMemCard 1 (prueba) [GORLEV] -Nivel Gore +Nivel de violencia [SICASS] -Joder de mala manera +Puta locura [SICSIC] -Cabrón fastidioso +Puto manicomio [SCASSL] -Seleccionado Joder de mala manera +Seleccionado Puta locura [SCSCSL] -Seleccionado Cabrón fastidioso +Seleccionado Puto manicomio [PRVMEN] -Informes de Misiones Previas +Resúmenes de misiones anteriores [DOSVGM] -¿Deseas guardar el juego? +¿Deseas guardar la partida? [FORMEN] -Menú de Formato +Menú de formato [MEMTST] Pantalla MemoryCardTest [REGCAR] -Registrar MemoryCard Uno +Registrar MemoryCard uno [TEFONE] -Probar Formato de MemCard Uno +Probar MemCard uno con formato [TEUFON] -Probar MemCard Uno sin formato +Probar MemCard uno sin formato [CRROOT] CreateRootDir [CRLDIC] -Crear y Cargar Iconos +Crear y cargar iconos [FLFSGF] -Llenar Primer Archivo Con Necedades +Llenar el primer archivo con basura [PUSAVE] -Guardar Sólo el juego +Guardar sólo la partida [CHEVOK] CheckEveryOkB4Save @@ -3020,19 +3004,19 @@ CheckEveryOkB4Save SaveTheGame [CNTSAV] -No se puede guardar el juego. En una misión. +No se puede guardar la partida en una misión. [CNCSAV] -No se puede guardar el juego. Estás en un coche +No se puede guardar la partida dentro de un vehículo. [CRMGSV] -Crear directorio de revista con protección de copia +Crear directorio de cargador con protección de copia [MGSVNC] -No Creado MagazineDirectory +MagazineDirectory no creado [MGSVCN] -Creado MagazineDirectory +MagazineDirectory creado [YES] Sí @@ -3044,7 +3028,7 @@ No x [LAST] -Último Mensaje +Último mensaje [FEDS_XB] Seleccionar @@ -3056,124 +3040,124 @@ Botón START - CONTINUAR de [FEC_TUC] -Control de Torreón +Controlar torreta [FEC_SM3] -Activador de Misión Espacial (botón R3) +Activar misión secundaria (botón R3) [FEC_RS3] -Cambiar de emisora de Radio (botón L3) +Cambiar emisora de radio (botón L3) [FEC_HO3] -Bocina (botón L3) +Claxon (botón L3) [DIAB1] 'TURISMO' [DIAB2] -'YO GRITO, TU GRITAS' +'IRA HELADA' [DIAB3] -'JUICIO POR FUEGO' +'A LA HOGUERA' [DIAB4] 'GRANDE Y VENOSO' [DIAB1_A] -El burro quiere ofrecerte una oportunidad. Ve al teléfono público de Hepburn Heights si quieres más información. +El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. [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. +Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. [DIAB1_1] -~g~3...2...1... ¡VAMOS VAMOS VAMOS! +~g~3... 2... 1... ¡ADELANTE! [DIAB1_4] -~g~Hazte con un coche rápido y ve a la cuadrícula de inicio. +~g~Hazte con un coche rápido y ve a la parrilla de salida. [DIAB1_3] -~r~No podrías ganar ni una rifa, ¡FRACASADO! +~r~No sabes ganar ni una rifa, ¡FRACASADO! [DIAB1_2] -~g~Felicidades, ganaste con un tiempo increíble de ~1~ segundo. +~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. [FIRST] -~g~ Primero (or ~g~1o) +~g~1.° [SECOND] -~g~ Segundo (or ~g~2o) +~g~2.° [THIRD] -~g~ Tercero (or ~g~3o) +~g~3.° [FOURTH] -~g~ Cuarto (or ~g~4o) +~g~4.° [DIAB2_1] -~g~ Recoge el maletín en Harwood. +~g~Recoge el maletín en Harwood. [DIAB2_2] -~g~ Encuentra una furgoneta de helados. +~g~Encuentra un camión de helados. [DIAB2_3] -~g~ Aparca la furgoneta de helados en Atlantic Quays. +~g~Aparca el camión de helados en el muelle Atlantic. [DIAB2_4] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. [DIAB2_6] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. [DIAB2_7] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. [DIAB2_5] -~g~ Sal de la furgoneta y luego usa el mando a distancia para detonar la furgoneta del helado. +~g~Sal del camión y luego usa el mando a distancia para detonarlo. [YD1] -'PELEA BLING-BLING' +'CORRE A POR LA PASTA' [YD2] 'JINETE CON UZI' [YD3] -'REUNIÓN DE COCHES DE GANGSTERS' +'COLECCIONANDO COCHES DE BANDAS' [YD4] -'LLEGÓ EL REINADO' +'POR LOS AIRES' [YD_P] -El Rey Courtney quiere hablarte. ¡¡Ve al teléfono público de Aspatria!! +El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! [YD1_A] -~w~Este es el Rey Courtney +Habla el rey Courtney. [YD1_A1] -~w~Mi banda Yardie necesita un conductor y tú tienes reputación de ser hábil al volante. +Mi banda jamaicana necesita un conductor y tú tienes reputación de ser bueno. [YD1_B] -~w~Ve al basurero que hay detrás del estadio y en un coche espera a los otros candidatos. +Ve en un coche al basurero que hay detrás del estadio y a los otros candidatos. [YD1_C] -~w~Tengo hombres vigilando los puestos de control en todo Staunton. +Tengo hombres vigilando puntos de control por toda Staunton. [YD1_D] -~w~El primer conductor que llegue a un puesto de control se lleva un billete de los grandes, luego hay que ir a la siguiente parada. +El primer conductor que llegue a un punto de control se lleva mil pavos, y así de punto a punto. [YD1_D1] -~w~Si ganas más puestos de control que cualquier otro conductor, podría tener algo de trabajo para ti. +Si ganas más puntos de control que los demás, podría tener trabajo para ti. [YD1_E] -~g~Preparado para una carrera! +~g~¡Prepárate! [YD1_F] -~g~Te saltaste el comienzo -¡Me gusta tu estilo!! +~g~Te has saltado la salida. ¡Me gusta tu estilo! [YD1_G] -~r~Esto es una CARRERA DE COCHES. ¡Necesitas un COCHE, idiota! +~r~Esto es una carrera DE COCHES. ¡Necesitas un COCHE, idiota! [YD1GO] -~g~VAMOS!! +~g~¡VAMOS! [YD1_1] ~r~1 @@ -3185,82 +3169,82 @@ El Rey Courtney quiere hablarte. ¡¡Ve al teléfono público de Aspatria!! ~r~3 [YD1_BON] -¡¡1.000$!! +¡1.000$! [Y1_1ST] -~G~¡Llegaste el primero con ~1~ exitosos puestos de control! +~G~¡Has quedado primero con ~1~ puntos de control! [Y1_2ND] -~y~Segundo con ~1~ exitosos puestos de control. ~y~Cerca, pero ¡no eres el mejor! +~y~Eres el segundo con ~1~ puntos de control. ~y~¡Casi, pero no! [Y1_3RD] -~r~Tercero con ~1~ exitosos puestos de control. ~r~¡Creí que dijiste que eras bueno! +~r~Eres el tercero con ~1~ puntos de control. ~r~¿No decías que eras bueno? [Y1_LAST] -~r~¡Fuiste el último! ~r~¡Malgastaste mi tiempo, IDIOTA! +~r~¡Has quedado el último! ~r~¡Me has hecho perder el tiempo, IDIOTA! [Y1_J1ST] -~y~Empatado el primero con ~1~ exitosos puestos de control. ~y~Bien, pero ¡debes ser el mejor si quieres conducir para la Reina Lizzy! +~y~Has empatado el primero con ~1~ puntos de control. ~y~Bien, ¡pero debes ser el mejor si quieres conducir para la Reina Lizzy! [Y1_J2ND] -~r~Empatado el segundo con ~1~ exitosos puestos de control. ¡Conduces como un mono loco! +~r~Has empatado el segundo con ~1~ puntos de control. ¡Conduces como un mono loco! [Y1JLAST] -~r~¡Empatado el último! Hablas como un conductor, pero conduces como un hablador! +~r~¡Has empatado el último! ¡Hablas como un conductor, pero conduces como un hablador! [Y1_TEST] -COCHE AL AGUA!! +¡COCHE AL AGUA! [YD2_A] -~w~Necesito ver si eres capaz de hacer mi trabajo sucio. +Necesito ver si eres capaz de hacer mi trabajo sucio, [YD2_A1] -~w~A ver si se puede confiar en ti. +si se puede confiar en ti. [YD2_B] -~w~Dos de mis chicos estarán allí en cualquier momento para llevarte de paseo, +Dos de mis chicos llegarán allí enseguida para llevarte de paseo, [YD2_B1] -~w~a ver si eres quien dices que eres. +a ver si eres quien dices que eres. [YD2_C] -~w~Nos vamos a dar un pequeño paseo a Hepburn Heights, acabaremos con los asquerosos Diablos que han estado metiéndose con la Reina Lizzy. +Vamos a dar un paseíto por los cerros de Hepburn para cargarnos a los asquerosos Diablos que han estado metiéndose con la reina Lizzy. [YD2_CC] -~w~Toma, necesitaras una 'pieza' +Toma, necesitarás una pipa. [YD2_D] -~w~Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te entren dudas. +Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. [YD2_E] -~w~¡Vamos a conducir! +¡Conduce! [YD2_F] -~r~Ha obtenido la libertad bajo fianza con nuestra pasta, ¡dispara a su culo amarillo!!! +~r~Se quiere escapar, ¡cárgatelo! [YD2_G1] -~w~Hepburn Heights... Vamos a matar algunos asquerosos Diablos... +Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... [YD2_G2] -~w~Pero recuerda, ~r~¡No salgas de este coche!! +Pero recuerda, ~r~¡no salgas de este coche! [YD2_H] -~w~VALE, Llévanos de vuelta a territorio Yardie! VAMOS VAMOS VAMOS!!! +¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! [YD2_L] -~w~¡Lo hiciste bien, Reaperman! +¡Eres la Muerte personificada! [YD2_M] -~r~¡Ha destrozado mi coche! ¡Liquidale! +~r~¡Ha destrozado mi coche! ¡Liquídale! [YD2_N] -~w~¡Vuelve a poner tu culo en este coche! +¡Vuelve al coche! [YD3_A] -Quiero que empujes algunos coches de gangsters +Quiero que robes coches de otras bandas [YD3_A1] -para que podamos dar el golpe en territorio enemigo. +para que podamos atacar sus territorios. [YD3_B] Necesito un Mafia Sentinel, @@ -3269,121 +3253,118 @@ Necesito un Mafia Sentinel, un Yakuza Stinger y un [YD3_B2] -Diablo Stallion para poder dar a cualquier gangster de Liberty. +Diablo Stallion para que podamos ir a por cualquier banda de Liberty. [YD3_C] -Déjales en el garaje de Newport y recuerda, +Déjalos en el garaje de Newport y recuerda, [YD3_C1] -¡¡aniquilados no nos son de utilidad !! +¡dañados no nos sirven de nada! [YD3_D] -Nivel de texto sobrante +UNUSED [YD3_E] -~r~¡Ya le has dado a un coche de gangsters, diablo! +~r~¡Ya has entregado un coche de los Diablos! [YD3_F] -~r~¡Ya le has dado a un coche de gangsters Mafia! +~r~¡Ya has entregado un coche de la mafia! [YD3_G] -~r~¡Ya le has dado a un coche de gangsters Yakuza! +~r~¡Ya has entregado un coche de la yakuza! [YD3_H] -~g~¡Coche de gangsters Diablo empujado! +~g~¡Coche de los Diablos entregado! [YD3_I] -~g~¡Coche de gangsters Mafia empujado! +~g~¡Coche de la mafia entregado! [YD3_J] -~g~¡Coche de gangsters Yakuza empujado! +~g~¡Coche de la yakuza entregado! [YD3_K] -~r~¡El coche está casi destrozado!¡Haz que lo reparen! +~r~¡El coche está casi destrozado! ¡Haz que lo reparen! [YD3_L] -~g~¡Llevalo al ~p~ garaje! +~g~¡Llévalo al ~p~garaje~g~! [YD3_M] -~r~¡Lo volcaste! ¡Consigue otro! +~r~¡Has volcado el vehículo! ¡Consigue otro! [YD4_A] ¡Escucha! [YD4_A1] -Pásate por Bedford Point. +Mueve el culo a Bedford Point. [YD4_A2] -¡Hay un cargamento en un viejo coche y lo necesito pronto! +¡Hay un cargamento en una tartana que necesito pronto! [YD4_B] -CARTA: He oído que has sido un chico aplicado. Bien, yo he sido una chica aplicada. +CARTA: Dicen que estuviste entretenido. Igual que yo. [YD4_C] -Creo que es hora de que seas testigo del poder real del ¡'SPANK'! Besos y abrazos, Catalina, xxx +¡Es hora de que seas testigo del verdadero poder del 'SPANK'! Con mucho amor, Catalina. [YD4_D] -POSDATA: ¡¡MUERE PEEG DOG, MUERE!! +P.D. ¡MUERE, BASURA, MUERE! [YD4_1] -¡¡Te hemos pellado necio!! +~g~¡Son psicópatas adictos al SPANK! [YD4_2] -¡¡Destruye las furgonetas de SPANK +~g~¡Destruye las furgonetas de SPANK! [HM_1] -'DINERO UZI' +'PASADA AMETRALLADA' [HM_2] -'TOYMINATOR' +'BOMBINATOR' [HM_3] 'PREPARADO PARA ESTALLAR' [HM_5] -'REDOBLE' +'ENFRENTAMIENTO' [HOOD1_A] Ve al teléfono público de Wichita Gardens y hablaremos de negocios. [HM1_A] -¡Tío, Soy D-Ice de los Red Jacks! +¡Ey! ¡Soy D-Ice, de los Red Jacks! [HM1_C] -Esos jovenes macarras, salen a la calle y no tienen nada más que pistolas y SPANK en sus cabezas. +Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. [HM1_3] -~g~Los 'Nines' tienen su territorio en Wichita Gardens. +~g~Los Nines tienen su territorio en Wichita Gardens. [HM2_3] -Si golpeas las ruedas de un vehículo el RC buggy ¡se detonará! +¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! [HM2_4] -Si se sale fuera de cobertura el RC buggy ¡se detonará! +¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! [HM2_5] -~r~¡Fuera de cobertura! +~r~¡Te has ido de cobertura! [HM3_1] -~g~Ve al garaje pero pon atención porque si el coche se daña demasiado ¡explotará! +~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! [HM3_2] -~g~Lleva el coche de vuelta, tiene que estar en perfectas condiciones ¡sin daños! +~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! [HM3_3] -~g~¡Haz que reparen el coche! +~g~¡Haz que reparen el vehículo! [HM4_D] ~g~¡Hazte con un vehículo! -[HM4_E] -NO MAS TEXTO REQUERIDO - [HM4_1] -~g~Dirígete al lugar donde el cargamento ha sido esparcido, necesitas conseguir 30 lingotes de oro. +~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. [HM4_2] -~g~Recuerda, cuando el vehículo es demasiado pesado y lento ve al garaje y deja el cargamento. +~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. [HM5_3] ~r~¡Te han dicho que uses sólo un bate de béisbol! @@ -3404,13 +3385,13 @@ NO MAS TEXTO REQUERIDO 'SU AMANTE' [MEAT1_A] -Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléfono público de Trento si crees que puedes ayudar. +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. [MEA1_B3] -~g~Ve y reúnete con el Director del Banco. +~g~Reúnete con el director del banco. [MEA1_B6] -~g~Lleva el coche a la trituradora para eliminar las evidencias, sal del coche y la grúa lo recogerá. +~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. [MEA1_1] ~r~¡El director del banco está muerto! @@ -3422,16 +3403,16 @@ Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléf ~g~¡Sal del coche! [MEA1_4] -~r~Has dejado atrás al director del banco! +~r~¡Has abandonado al director del banco! [MEA2_B3] -~g~Ve a encontrarte con los ladrones. +~g~Reúnete con los ladrones. [MEA2_B4] -~g~Llévalos a la fábrica de comestibles Bitch'n'Dog +~g~Llévalos a la fábrica de comestibles Bitch'n' Dog. [MEA2_B6] -~g~Haz que repinten el coche para eliminar cualquier evidencia. +~g~Haz que repinten el coche para borrar las pruebas. [MEA2_1] ~r~¡Te dijeron que trituraras el vehículo! @@ -3443,16 +3424,16 @@ Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléf ~r~¡Has dejado atrás a un ladrón! [MEA3_B3] -~g~Ve y recoge a la Sra. Chonks +~g~Recoge a la Sra. Chonks. [MEA3_B6] -~g~Llévate el coche y tíralo al mar, así eliminaremos cualquier evidencia. +~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. [MEA3_1] ~r~¡La mujer está muerta! [MEA3_2] -~r~¡Se suponía que ibas a tirar el vehículo al agua! +~r~¡Se suponía que debías tirar el coche al agua! [MEA3_3] ~r~¡Has dejado atrás a su mujer! @@ -3461,49 +3442,49 @@ Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléf ~g~Recoge al amante de su mujer. [MEA4_B6] -Es demasiado tarde para eso, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé del negocio... +Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... [MEA4_1] ~r~¡Carlos está muerto! [MEA4_3] -~r~¡Has dejado atrás a Carlos el prestamista! +~r~¡Has abandonado a Carlos, el usurero! [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~. +Pulsa y mantén pulsado el ~h~botón ~k~~VEHICLE_LOOKLEFT~~w~ o el ~h~botón ~k~~VEHICLE_LOOKRIGHT~~w~ para mirar~h~ a la izquierda~w~ o ~h~a la derecha ~w~mientras te encuentres en un vehículo. Pulsa ambos para mirar~h~ atrás~w~. [LOVE6_1] ~g~¡Ahora llévate a los policías lejos del almacén! [LOVE6_2] -~r~¡No conseguiste llevar lejos a la policía! +~r~¡No has distraído a la policía! [RM4_3] -¡El socio de Ray ha escapado! +~r~¡El socio de Ray ha escapado! [RM6_C] -La CIA parece tener intereses creados con el SPANK +La CIA parece estar interesada en el SPANK [RM6_C1] -y a ellos no les gusta que nos metamos con el Cartel. +y no les gusta que nos metamos con el cártel. [C_PASS] ¡AMENAZA ELIMINADA! [CTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. [CTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. [COPCART] -~g~Tienes ~1~ segundos para retornar a un vehículo de la policía antes de que termine la misión. +~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. [C_FAIL] -¡Misión Vigilante terminada! +¡Misión de justiciero terminada! [C_CANC] -~r~¡Misión Vigilante cancelada! +~r~¡Misión de justiciero cancelada! [C_ESCP] ~r~¡El sospechoso ha escapado! @@ -3512,13 +3493,13 @@ Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilan ~r~¡Tu trabajo como defensor de la ley ha terminado! [C_VIGIL] -¡¡BONO VIGILANTE!! +¡PREMIO POR JUSTICIERO! [A_FAIL2] -~r~¡Tu falta de urgencia ha sido fatal para el paciente! +~r~¡Tu falta de rapidez ha sido fatal para el paciente! [A_FAIL3] -~r~¡¡El paciente está muerto!! +~r~¡El paciente está muerto! [A_PASS] ¡Rescatado! @@ -3530,76 +3511,76 @@ Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilan ¡Nunca te cansarás! [RM2_M] -Si necesitas un poco de pólvora pasa por aquí y coge lo que necesites de las taquillas. +Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. [HEAL_A] -Tu ~h~salud ~w~ está marcada en naraja en la parte superior derecha de la pantalla. +Tu ~h~salud ~w~está indicada en naranja en la parte superior derecha de la pantalla. [YD1_CNT] ¡~1~ de 15! [FM1_9] -~g~Esa de allí es la fiesta, deja a María enfrente. +~g~La fiesta es allí. Deja a María enfrente. [FM1_Y] -~w~Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo, y que me has tratado muy bien. Con respeto y todo eso. +Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo y que me has tratado muy bien, con respeto. [FM1_AA] -~w~Oh, será mejor que me vaya. Espero que nos veamos pronto. +Bueno, será mejor que me vaya. Espero que nos veamos pronto. [NOCONTE] -Por favor vuelve a conectar el mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) al puerto de mando 1 para continuar. +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 soportado. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). +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 soportado. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). +El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). [WRONGCD] -Disco incorrecto. Por favor inserta el disco correcto. +Disco incorrecto. Introduce el disco correcto. [NOCD] -La bandeja del disco está vacía. Por favor inserta un disco. +La bandeja del disco está vacía. Introduce un disco. [OPENCD] -La bandeja del disco está abierta. Por favor ciera la bandeja de disco. +La bandeja del disco está abierta. Cierra la bandeja de disco. [CDERROR] Error al leer el DVD de Grand Theft Auto III [RESTART] -Empezando una juego nuevo +Empezando una nueva partida [GA_3] -¡No hay más freebies. 1000$ para repintar! +¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! [GA_1] -¡Uauhh! ¡No toco nada TAN caliente! +¡Hala! ¡Demasiado peligroso para mi gusto! [GA_1A] -Regresa cuando no estés tan ocupado... +Vuelve cuando no estés tan ocupado... [S_PROM2] -El garaje de al lado puede alojar un vehículo cuando tú guardas tu partida. +Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. [STOCK] mercancía agotada [FM1_O] -~w~Creo que está en la estación de ferrocarril del muelle de Chinatown. +Creo que está en la estación de ferrocarril del muelle de Chinatown. [EBAL_B] -Este es el lugar, justo aquí, dejemos la calle y ¡encontremos un cambio de ropas! +Es aquí, ¡entremos y cambiémonos de ropa! [EBAL_G] -Este es el club de Luigi. Vamos por la parte de atrás y usemos la puerta de servicio. +Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. [AM4_3] ¡Tú debes de ser el nuevo chico de los recados de Asuka! [AM4_4] -¿Tienes el dinero? ¿Está todo aquí? +¿Tienes el dinero? ¿Está todo? [AM4_5] Ya sé lo que estás pensando, otro policía corrupto. @@ -3608,124 +3589,124 @@ Ya sé lo que estás pensando, otro policía corrupto. Bueno, éste es un mundo corrupto. [AM4_7] -Sólo porque perdí un par de socios, esos mamones de asuntos internos han empezado a meter las narices. +Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. [AM4_8] -Cuento con que pueden pillarme. +¡Y seguro que les llega mi olor! [AM4_9] -Bien, esta ciudad es una gran alcantarilla. +¡Pues esta ciudad es una gran alcantarilla! [AM4_10] -Pero voy a necesitar un poco de ayuda fuera del sindicato. +Pero voy a necesitar un ayudita ajena al cuerpo. [AM4_11] -Y si estás interesado ya sabes dónde encontrarme. +Si estás interesado, ya sabes dónde encontrarme. [CAM_A] -Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar ~h~cámara ~w~ modos cuando vayas a pié o estés en un vehículo. +Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar la ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. [CAM_B] -Pulsa el ~h~botón de dirección hacia arriba ~w~ y ~h~ abajo ~w~ para cambiar los modos de ~h~cámara ~w~cuando vayas a pié o estés en un vehículo. +Pulsa el ~h~botón de dirección hacia arriba ~w~y ~h~abajo ~w~para cambiar los modos de ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. [KM2_1] ~g~Repara el coche, tiene que estar en perfecto estado. [LM3_6] -Joey... +¡Joey...! [LM3_6A] -¿Voy a jugar contigo otra vez? +¿Voy a jugar con tu paquetín otra vez? [LM3_9A] -debe de haber algo de trabajo para ti. +que tendré trabajo para ti. [LM3_9B] ¿De acuerdo? [AWAY2] -~r~Se escaparon. +~r~Se ha escapado. [AWAY] ~r~¡Se ha pirado de aquí! [JM6_1] -Ve al banco de la avenida principal. +Llévanos al banco de la avenida principal. [GA_6B] -Aparca, selecciónalo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y ¡ADELANTE! +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! [GA_7B] -Armar con ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba explotará cuando el motor sea arrancado. +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. [BAT1] ~g~¡Coge el bate! [EBAL_O] -Si no estropeas esto, puede que haya más trabajo para ti. Ahora ¡vete de aquí! +Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! [HELP9_B] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~ el rifle del francotirador. +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 rifle del francotirador. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. [JM6_8] ~r~¡Has perdido a todos los ladrones! [COLT_IN] -¡La pistola está ahora en el almacén de Munición! +¡La pistola ya está disponible en la tienda Ammu-Nation! [TAXI2] ~r~¡Se te acabó el tiempo! [TAXI3] -~r~¡Tu pasajero se marchó aterrorizado! +~r~¡Tu cliente ha salido por patas! [TAXI7] ~r~Tu coche está destrozado, haz que lo reparen. [TAXI4] -¡Tarifa completa! +¡Carrera terminada! [TAXI5] -¡¡DE VELOCIDAD!! +¡VIAJE RÁPIDO! [TAXI6] Misión de taxi terminada [FRANGO] -~g~¡Salvatore quiere que ayudes a Toni a tratar con los Triad primero! +~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! [PAGEB12] -Policía Bribe entregado en el escondite +Soborno policial ya disponible en tu guarida. [PAGEB13] -Salud entregada en el escondite +Salud ya disponible en tu guarida. [PAGEB14] -Adrenalina entregada en el escondite +Adrenalina ya disponible en tu guarida. [KM1_4] ~g~¡Necesitas un coche de policía para hacer el trabajo! [CAT1_B] -trae 500.000 a la Villa en Cedar Grove. +lleva 500.000 dólares a la mansión de Cedar Grove. [JM2_C] -Tiene un puesto de fideos en China Town. +Tiene un puesto de fideos en Chinatown. [RM6_1] -Aquí está la llave de la cerradura. +Esta llave es de un almacén. [RM6_2] -Encontrarás algo de dinero en metálico y 'suministros' que he almacenado en caso de que las cosas se pongan feas. +Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas se ponían feas. [RM6_3] -Nos vemos pronto. +Hasta la vista. [FE_INIP] -Iniciando y cargando el Menú de Pausa... Por favor espera. +Iniciando y cargando el menú de pausa... Espera, por favor. [FESZ_CA] Cancelar @@ -3734,31 +3715,31 @@ Cancelar Abandonar [FESZ_L1] -¡Partida guardada con éxito! +¡La partida se ha guardado! [FESZ_L2] -Tu nombre guardado es: +El nombre guardado es: [FESZ_OK] ACEPTAR [FES_NGA] -Partida nueva +Nueva partida [FES_CAN] Cancelar [FESZ_QL] -Todo progreso en tu partida actual no guardado será perdido. ¿Proceder con la carga? +Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? [FESZ_QD] ¿Quieres borrar esta partida guardada? [FESZ_QO] -¿Quieres sobreescribir este partida guardado? +¿Quieres sobreescribir esta partida guardada? [FESZ_QR] -¿Estás seguro de que quieres empezar una nueva partida? Todo progreso desde la última partida guardada será perdido. ¿Proceder? +¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. [FESZ_QS] ¿QUIERES GUARDAR? @@ -3767,70 +3748,70 @@ Todo progreso en tu partida actual no guardado será perdido. ¿Proceder con la Puerto 1. Archivo protegido. [T4X4_1] -'LUGAR DE JUEGOS DEL PATRIOTA' +'PATIO DE RECREO' [T4X4_2] 'UN PASEO POR EL PARQUE' [T4X4_3] -'AGARRADO!' +'¡AGARRADO!' [MM_1] -'DISTURBIO DE DIFERENTES NIVELES' +'CAOS EN EL APARCAMIENTO' [T4X4_1A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~ 15~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. [T4X4_1B] ¡~1~ de 15! [T4X4_1C] -~y~PASA A 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~. +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~20 SEGUNDOS~g~ adicionales. [T4X4_2A] -¡¡~g~Tienes ~y~2 minutos ~g~ para conseguir ~y~12~g~ puestos de control!! ~g~Puedes conseguirlos en ~y~ CUALQUIER ORDEN. +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. [T4X4_2B] ¡~1~ de 12! [T4X4_2C] -~y~PASA A TRAVÉS ~g~ del primer puesto de control para que comience el cronómetro. ~g~Cada puesto de control te premiará con ~y~10 SEGUNDOS~g~ +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~10 SEGUNDOS~g~ adicionales. [T4X4_3A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~20~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN. +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. [T4X4_3B] -~Y~PASA A 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~. +~Y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~15 SEGUNDOS~g~ adicionales. [T4X4_3C] ¡~1~ de 20! [T4X4_F] -¡~r~Saliste bajo fianza! ¿Demasiado duro para ti? +~r~¡Te has escapado! ¿Demasiado difícil para ti? [MM_1_A] -¡~g~Tienes ~y~2 minutos ~g~ para conseguir ~y~20 puestos de control ~g~ en el multiniveles! ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN. +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~20 puntos de control~g~ en el aparcamiento! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. [MM_1_B] ¡~1~ de 20! [MM_1_C] -~g~Eso son 20 segundos, más ~y~5 SEGUNDOS ~g~ por cada puesto de control. ~g~El cornómetro comenzará ~y~ INMEDIATAMENTE. +~g~Tendrás 20 segundos, más ~y~5 SEGUNDOS~g~ por cada punto de control. ~g~El cronómetro comenzará ~y~INMEDIATAMENTE. [FM2_14] -~r~¡Estuviste muy cerca y asustaste a Curly! +~r~¡Te acercaste demasiado y asustaste a Curly! [FM2_15] -~g~No te acerques demasiado o Curly ¡sospechará algo! +~g~No te acerques mucho, ¡o Curly sospechará! [UPSIDE] -~r~¡Giraste las ruedas! +~r~¡Has volcado! [FM2_16] -ASUSTOMETRO: +ASUSTÓMETRO: [LM3_11] -~g~Misty no irá en el autobús,¡hazte con otro vehículo! +~g~Misty no irá en un autobús, ¡hazte con otro vehículo! [LANDSTK] Landstalker @@ -3854,7 +3835,7 @@ Sentinel Patriot [FIRETRK] -Coche de bomberos +Camión de bomberos [TRASHM] Trashmaster @@ -3863,7 +3844,7 @@ Trashmaster Stretch [MANANA] -Manana +Mañana [INFERNS] Infernus @@ -3884,7 +3865,7 @@ Cheetah Ambulancia [FBICAR] -F.B.I. +Coche del FBI [MOONBM] Moonbeam @@ -3902,13 +3883,13 @@ Kuruma Bobcat [WHOOPEE] -Mr Whoopee +Mr. Whoopee [BFINJC] -Inyección BF +BF Injection [POLICAR] -Policía +Coche patrulla [ENFORCR] Enforcer @@ -3923,13 +3904,13 @@ Banshee Predator [BUS] -Bus +Autobús [RHINO] Rhino [BARRCKS] -Barracas OL +Barracks OL [TRAIN] Tren @@ -3953,40 +3934,40 @@ Stallion Rumpo [RCBANDT] -Bandido RC +Bandit RC [BELLYUP] -Triad +Furgoneta de las Tríadas [MRWONGS] Mr Wongs [MAFIACR] -Mafia +Sentinel de la mafia [YARDICR] -Yardie +Lobo jamaicano [YAKUZCR] -Yakuza +Stinger de la yakuza [DIABLCR] -Diablo +Stallion de los Diablos [COLOMCR] -Cartel +Cruiser del cártel [HOODSCR] -Hoods +Rumpo XL de los hood [AEROPL] Avioneta [SPEEDER] -Veloz +Speeder [REEFER] -Chaquetón +Reefer [PANLANT] Panlantic @@ -4004,136 +3985,127 @@ Borgnine TOYZ [FEST_DF] -Distancia recorrida a pié (millas) +Distancia recorrida a pie (millas) [FEST_DC] Distancia recorrida en coche (millas) [FESTDFM] -Distancia recorrida a pié (m) +Distancia recorrida a pie (metros) [FESTDCM] -Distancia recorrida en coche (m) +Distancia recorrida en coche (metros) [FEST_R1] -Área de juego Patriota en segundos +''Patio de recreo'' en segundos [FEST_R2] -Un paseo por el Parque en segundos +''Un paseo por el parque'' en segundos [FEST_R3] -¡Agarrado! en segundos +''¡Agarrado!'' en segundos [FEST_RM] -Disturbio en el multiniveles en segundos +''Caos en el aparcamiento'' en segundos [FEST_LS] -Gente salvada en una ambulancia +Gente salvada con una ambulancia [FEST_CC] -Criminales matados en Misión Vigilante +Criminales asesinados en misiones de justiciero [FEST_FE] -Total de fuegos extinguidos +Incendios extinguidos [FEST_LF] Vuelo más largo en Dodo [FEST_BD] -Mejor idoneo para desconectar la bomba +Mejor tiempo al desactivar la bomba [FEST_RP] -Rampas pasadas +Masacres superadas [FEST_MP] -Misiones pasada +Misiones superadas [FEST_BB] -Pelea bling-bling: +Carrera forrada: [FEST_H0] -Máximos puestos de control +Máximo de puntos de control [FEST_GC] -Total de Coches de gangsters: +Coches de bandas destruidos: [FEST_H1] -Destrucción Diablo +Destrucción de los Diablos [FEST_H2] -Masacre de Mafia +La masacre de la mafia [FEST_H3] -Calamidad en el Casino +Calamidad en el casino [FEST_H4] -Destructor Rumpo - -[USJI1] -TEXTO NO MAS REQUERIDO - -[USJI2] -TEXTO NO MAS REQUERIDO - -[USJI3] -TEXTO NO MAS REQUERIDO +Exterminio de Rumpos [USJ] -¡BONO DE ACROBACIA UNICA! +¡PREMIO POR ACROBACIA ÚNICA! [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$ +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 [HM1_1] -~g~Congela 20 Purpura Nines en 2 minutos 30 segundos. +~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. [KM1_8A] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apartarte del camino. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. [KM1_8D] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apártarte del camino. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. [KM1_12] -~g~¡Llévalo al dojo pero deshazte primero de los policías! +~g~¡Llévalo al dojo, pero deshazte primero de la policía! [RATNG1] Carterista [RATNG2] -Querido +Abusón [RATNG3] -Ladrón - -[RATNG4] Chorizo +[RATNG4] +Granuja + [RATNG5] -Goon +Secuaz [RATNG6] -Hombre sobre ruedas +Conductor [RATNG7] -Músculos de alquiler +Guardaespaldas [RATNG8] -Reparador +Negociador [RATNG9] -Asociado +Socio [RATNG10] -Limpiador +Sicario [RATNG11] Asesino [RATNG12] -Hombre diestro +Mano derecha [RATNG13] -Ejecutor +Verdugo [RATNG14] Capo @@ -4142,37 +4114,37 @@ Capo Jefe [1010] -~r~Tu vehículo está volcado +~r~Tu vehículo ha volcado [1011] -~r~Tu vehículo está volcado +~r~Tu vehículo ha volcado [1012] -~r~Tu vehículo está volcado +~r~Tu vehículo ha volcado [1013] -~r~Tu vehículo está volcado +~r~Tu vehículo ha volcado [1014] -~r~Tu vehículo está volcado +~r~Tu vehículo ha volcado [JM4_10] -VALE, Chaval. Llévame a la lavandería de Chinatown primero, tengo un negocio del que ocuparme. +Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. [JM4_11] -Esas mujeres que lavan no están recibiendo su dinero de protección. +Las lavanderas no están pagando por su protección. [JM4_12] -Y vigila el coche, Joey acaba de arreglar ese montón de basura +Y ojo con el coche, Joey acaba de arreglar esta chatarra. [JM4_13] -Entonces no me vengas con cuentos, ¿VALE? +Así que con cuidado, ¿vale? [KM4_11] -~g~¡Llévate el dinero de vuelta al casino! +~g~¡Lleva el dinero de vuelta al casino! [FEF_BR2] -Encuéntralo de nuevo leyendo cualquier informe de misión conseguido hasta la fecha. +Encuéntralo de nuevo leyendo los resúmenes de las misiones jugadas hasta la fecha. [TRAIN_1] Estación Kurowski @@ -4190,340 +4162,340 @@ Estación Portland Estación Rockford [SUBWAY3] -Estación Staunton South +Estación Staunton sur [SUBWAY4] Terminal Shoreside [MEA4_2] -~r~¡Marty Chonks está muerta! +~r~¡Marty Chonks ha muerto! [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. +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. [JM4_A] -Sí, lo sé Toni, la he puesto a tono. Ella está a punto, ¿sabes lo que de digo? +Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? [JM4_5] -Pasa más tarde y les daremos algo para que lave, ¡sus propias ropas manchadas de sangre! +Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! [AMMU_A] -Luigi dijo que tú necesitabas una pieza... +Luigi dijo que necesitabas una pipa... [AMMU_B] -Joey me dijo que te armáramos... +Joey me pidió que te armáramos... [AMMU_C] -Así que ve por la parte de atrás de la tienda. Te dejé un nueve en el patio. +Ve a la parte de atrás. Te dejé un nueve en el patio. [AMMU_D] -Te conseguí todas las defensas necesarias para la casa. +Tengo todo lo necesario para defender tu casa. [AMMU_E] ¿También quieres una licencia? [AMMU_F] -No necesito ver ningún documento, pareces de fiar. +No necesito tu documentación, pareces de fiar. [DETON] -DETONACION: +DETONACIÓN: [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. +Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. [DRIVE_B] -Ten 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. +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. [RECORD] -~g~¡¡NUEVO RECORD!! +~g~¡NUEVO RÉCORD! [NRECORD] -~r~¡NO HAY NUEVO RECORD! +~r~¡NO HAY UN NUEVO RÉCORD! [RCHELP] -Pulsa botón ~k~~PED_FIREWEAPON~, o conduce el coche de RC hasta las ruedas de un coche para detonarlo. +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. [RCHELPA] -Pulsa el botón ~k~~PED_FIREWEAPON~, o conduce el coche RC hasta unas ruedas de coche para detonarlo. +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. [RC_1] -¡Tienes 2 minutos para volar cuantos coches de gangsters Diablo sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! [RC_2] -¡Tienes 2 minutos para bolar cuantos coches de gangsters Mafia sean posibles! +¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! [RC_3] -Tienes 2 minutos para bolar cuantos coches de gangsters Yakuza sean posibles! +¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! [RC_4] -¡Tienes 2 minutos para volar cuantos coches de gangsters Yardie sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! [RC_5] -Tienes 2 minutos para volar cuantos coches de gangsters Hood sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! [RC_6] -Tienes 2 minutos para volar cuantos coches de gangsters Cartel sean posibles! +¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! [RAMPAGE] -¡¡ATAQUE!! +¡MASACRE! [RAMP_P] -¡ATAQUE COMPLETADO! +¡MASACRE COMPLETADA! [RAMP_F] -ATAQUE FALLIDO +MASACRE FALLIDA [PAGE_00] . [PAGE_01] -¡Mata ~1~ Diablo en 120 segundos! +¡Mata a ~1~ Diablos en 120 segundos! [PAGE_02] -¡Destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos en 120 segundos! [PAGE_03] -¡Mata ~1~ Mafia en 120 segundos! +¡Mata a ~1~ mafiosos en 120 segundos! [PAGE_04] -¡Mata ~1~ Tríadas en 120 segundos! +¡Mata a ~1~ Tríadas en 120 segundos! [PAGE_05] -¡Mata ~1~ Tríada en 120 segundos! +¡Mata a ~1~ Tríadas en 120 segundos! [PAGE_06] -¡Destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos en 120 segundos! [PAGE_07] -¡Revienta ~1~ cabezas Yardie en 120 segundos! +¡Revienta ~1~ cabezas jamaicanas en 120 segundos! [PAGE_08] -¡Quema ~1~ Yakuza en 120 segundos! +¡Quema a ~1~ yakuzas en 120 segundos! [PAGE_09] -¡Destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos en 120 segundos! [PAGE_10] -¡Destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos en 120 segundos! [PAGE_11] -¡Aniquila ~1~ Yardie en 120 segundos! +¡Aniquila a ~1~ jamaicanos en 120 segundos! [PAGE_12] -¡Quema ~1~ Yakuza en 120 segundos! +¡Quema a ~1~ yakuzas en 120 segundos! [PAGE_13] -¡Vuela ~1~ Yardie en 120 segundos! +¡Vuela a ~1~ jamaicanos en 120 segundos! [PAGE_14] -¡Fríe ~1~ Colombianos en 120 segundos! +¡Fríe a ~1~ colombianos en 120 segundos! [PAGE_15] -¡Machaca ~1~ Hood en 120 segundos! +¡Machaca a ~1~ Hoods en 120 segundos! [PAGE_16] -¡Destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos en 120 segundos! [PAGE_17] -¡Machaca ~1~ Colombianos con un coche en 120 segundos! +¡Arrolla a ~1~ colombianos con un coche en 120 segundos! [PAGE_18] -¡Conduce por ahí en coche y destruye ~1~ vehículo en 120 segundos! +¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! [PAGE_19] -¡Corta ~1~ cabezas colombiana en 120 segundos! +¡Revienta ~1~ cabezas colombianas en 120 segundos! [PAGE_20] -¡Córtale la cabeza a ~1~ Hoods en 120 segundos! +¡Decapita a ~1~ Hoods en 120 segundos! [JM1_A] -Ey, estoy aburrida, ¿cuándo vas a tomarme? +Jo, me aburro, ¿cuándo me la vas a meter? [JM1_B] -En un momento, cariño, tengo un pequeño negocio del que ocuparme. +Dame un momento, cariño, que tengo un asuntillo que tratar. [JM1_C] -Tengo un pequeño trabajo para ti, colega. +Tengo un trabajito para ti, colega. [JM1_D] Los hermanos Forelli me deben dinero desde hace mucho tiempo [JM1_E] -y ellos necesitan que alguien les enseñe un poco de respeto. +y hay que enseñarles respeto. [JM1_F] -Labios Forelli está poniéndose como un cerdo en el St Marks Bistro +Labios Forelli está atiborrándose en el restaurante de Saint Mark's, [JM1_G] -así que roba su coche y llévalo a la tienda de bombas 8-Ball en Harwood. +así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. [JM1_H] -Conoces 8-Ball, ¿verdad? +Conoces a 8-Ball, ¿verdad? [JM1_I] -Una vez que esté cargado con una bomba, ve a aparcar el coche donde lo encontraste. +En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. [JM1_J] -Luego siéntate y contempla todo el espectáculo. +Luego salte y disfruta del espectáculo. [JM1_K] Pero cuidado, no va a estar comiendo toda la vida. [CAT2_A1] -¡Vamos, perra estúpida! +¡Vamos, perra! [CAT2_A] -La verdadera cuestión es, lo que quieres es ¿rescatar a María o llevarme a mí de vuelta? +La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? [CAT2_B] -Bueno, tengo noticias para ti, +Tengo una noticia para ti: [CAT2_B2] -dispararte será un placer pero salir contigo fue sólo un asunto de negocios. +matarte será un placer, pero salir contigo sólo fue un negocio. [CAT2_C] -¡Eres muy peccino, amigo! +¡Eres muy pequeñito, amigo! [CAT2_D] -Echame el dinero +Dame el dinero. [CAT2_E] -Has sido un chico aplicado! +¡Has estado muy ocupado! [CAT2_E2] -Pero no has aprendido, yo no soy de fiar +Pero no has aprendido que yo no soy de fiar. [CAT2_E3] -Mata al idiota +¡Mata al idiota! [CAT2_J] -Atrapa esta cosa en el aire! +¡Despega de una vez! [HM5_1] -Tío, Ice dijo que vendría. Hay reglas. Bates sólo. No armas, no coches. +Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. [HM5_5] -Esta es una batalla por el respeto, ¿vale? +Es una batalla por respeto, ¿vale? [HELP14] -Para conseguir armas pasa sobre ellas. Estas no pueden conseguirse cuando se está dentro de un vehículo. +Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. [CRUSH] -Aparca en el área señalada y sal de tu vehículo. El vehículo será entonces triturado. +Aparca en la zona señalada y sal de tu vehículo para que sea triturado. [DIAB2_B] -Una banda de infames me ha amenazado con quitarme mi afiliación si no les pago una parte. +Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. [DIAB2_C] Amenazaron al hombre equivocado, amigo. [DIAB2_D] -Ellos tienen debilidad por el helado. +Su debilidad son los helados. [DIAB2_E] -Consigue la bomba que he ocultado en Harwood, +Hazte con la bomba que dejé en Harwood, [DIAB2_F] -secuestra la furgoneta habitual de los helados en sus rondas. +secuestra la camioneta del heladero mientras hace su ronda [DIAB2_G] -y seduce a esos idiotas para que caigan en su ruina con el jeengle-jeengle +y engaña a esos idiotas con esa musiquita. [DIAB2_H] -Se ocultan en un almacén de Atlantic Quay +Se esconden en un almacén del muelle Atlantic. [DIAB3_A] -Algunas Tríadas insolentes robaron mi bonito coche anoche, +¡Unas Tríadas insolentes robaron mi lindo carro anoche, [DIAB3_B] -destrózalo y deja que se queme. +lo destrozaron y lo quemaron! [DIAB3_C] -Algunos de mi más preciosos artículos sobre burros estaban en el maletero - +En el baúl había algunas de mis más preciadas posesiones sobre burros... [DIAB3_D] -objetos de colección que son irremplazables, amigo. +Objetos de coleccionista irremplazables, amigo. [DIAB3_E] -He escondido un arma punzante en el borde de Chinatown. +Escondí un arma en el borde de Chinatown. [DIAB3_F] -Tómalo y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira bien fundada de El Burro. +Tómala y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira pijuda de El Burro. [DIAB3_1] -MATA 25 TRIADS +MATA A 25 TRÍADAS [DIAB4_A] -¡Un ladrón oportunista ha robado mi furgoneta donde llevaba mis últimas publicaciones periodísticas! +¡Un ladrón oportunista robó una camioneta con mi última publicación! [DIAB4_B] -Pero ese idiota colgado de SPANK ha dejado las puertas de atrás abiertas +Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, [DIAB4_C] -y ahora toda mi bellamente editada, +¡y ahora mi literatura para adultos [DIAB4_D] -literatura para adultos con tan buen gusto fotografiada está siendo esparcida por todo Liberty! +tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! [DIAB4_E] -Coge la furgoneta y sigue el sendero de Donkey Does Dallas volúmenes 1,2 y 3 +Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, [DIAB4_F] -conseguido según vas. +tomándolos por el camino. [DIAB4_G] -Cuando hayas seguido el sendero de ese ladronzuelo con cabeza de SPANK, acaba con él! +¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! [DIAB4_H] -Luego reparte mi material de Revistas XXX en el Red Light District (Distrito de la luz roja) +Luego reparte mis revistas XXX por el barrio rojo. [DIAB4_1] -~g~Lleva la furgoneta a la parte de atrás de Revistas XXX +~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. [HM1_E] -Quiero mostrarle a esos perros macarras cómo funciona un verdadero tiroteo desde un vehículo +Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. [HM1_H] -¡Llévate a esos nueve fuera de aquí!! +¡Haz que esos Nines se larguen! [HM2_A] -Esos Nines me están presionando. +Los Nines me están presionando. [HM2_B] -Esos perros tienen coches blindados y están traficando con SPANK... +Tienen coches blindados y ahora están traficando SPANK [HM2_C] -y colocándoselo a los hermanos sin pudor. +a los hermanos sin ningún pudor. [HM2_D] -Hay un coche aparcado arriba de la calle. +Hay un coche aparcado en la calle. [HM2_E] -Hay algo de material allí dentro para poner a esos mariquitas en su sitio... +Dentro verás algo que te servirá para poner a esos gallinas en su sitio [HM3_A] -Algún effa ha cableado mis ruedas para bolarlas. +Algún cazurro me ha puesto una bomba en el coche. [HM3_B] -Si pierdo esas ruedas, mi reputación en la calle estará muerta. +Si lo pierdo, mi reputación en la calle se irá a la porra. [HM3_C] -Coge mi coche y llévalo al garaje de St Marks, ¿vale tío? +Coge mi coche y llévalo al taller de Saint Mark's, ¿valiendo? [HM3_D] -Déjales difundir eso, déjales que se ocupen de esa bomba. +Que se encarguen ellos de desarmar la bomba. [HM3_E] -Los relojes están avanzando y el cableado está liado. +El tiempo avanza y ese trasto es un peligro. [HM3_F] -Otro fallo más y esa cosa podría volar. +Un golpe más de la cuenta y podría saltar por los aires. [HM3_G] -¡Ahora muévelo! +¡Tira! [HM4_A] -Tío, un vuelo de la Reserva federal se acaba de estrellar en el Francis International. +Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. [HM4_B] Hay platino por toda la pista. @@ -4532,151 +4504,151 @@ Hay platino por toda la pista. Consigue un coche y agarra todo lo que puedas. [HM4_F] -Puedes dejar el marrón en uno de mis garajes. +Puedes dejar la mercancía en uno de mis garajes. [HM4_G] -Este platino es muy pesado y va a hacer que tus ruedas se muevan más despacio. +El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, [HM4_H] -Así que haz repartos regulares en el garaje. +así que ve dejándolo de vez en cuando en el garaje. [HM5_A] -Esos Nines se han quedado con pocos costrosos... +Ya solo quedan unos pocos Nines, [HM5_B] -pero todavía quieren seguir. +pero todavía quieren guerra. [HM5_C] -Aceptaron un cuerpo a cuerpo. . +Han aceptado un mano a mano. [HM5_D] -Uno de sus gangsters contra dos de los nuestros, o mejor... +Un puñado de los suyos contra dos de los nuestros, [HM5_E] -dos de vosotros +o más bien, tú y uno más. [HM5_F] -Yo os apoyaré pero... +Os ayudaría, pero... [HM5_G] -La vista de mi libertad bajo fianza no es hasta dentro de tres meses, +No quiero jugarme mi libertad condicional, [HM5_H] -¿sabes lo que te digo? +¿me captas? [HM5_I] -Ve y reúnete con mi hermano pequeño, +Reúnete con mi hermano pequeño, [HM5_J] -Te enseñará dónde están peleando por una causa justa. +él te enseñará dónde será la pelea. [MEA1_B] -El nombre es Chonks, Marty Chonks. +Me llamo Chonks, Marty Chonks. [MEA1_C] -Soy el dueño de la fábrica de comestibles Bitchin' Dog que está a la vuelta de la esquina. +Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. [MEA1_D] -Tengo problemas económicos, pero ¡ey!, y quién no, ¿verdad? +Tengo problemas económicos, pero, ¿y quién no? [MEA1_E] -Voy a reunirme con el director de mi banco más tarde. +He quedado con el director de mi banco. [MEA1_F] -Es un tramposo bastardo que sigue engordando los pagos del préstamo para llevarse una buena porción. +Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. [MEA1_G] -Coge mi coche, ve a buscarle y traelé de vuelta. +Coge mi coche, búscale y tráelo de vuelta. [MEA1_H] -¡¡Tengo una pequeña sorpresa para ese parasito chupasangres!! +¡Tengo una sorpresita para ese parásito chupasangre! [MEA2_A] -Contraté algunos ladrones para que entraran en mi apartamento... +Contraté a unos ladrones para que entraran en mi piso [MEA2_C] -Los bastardos ladrones amenazan con contárselo a la compañía de seguros, +Ahora los muy cabritos me amenazan con delatarme [MEA2_D] -si no les doy una parte +si no les doy una parte. [MEA2_E] -¿Puedes creerlo? +¿Te lo puedes creer? [MEA2_F] -He dejado un coche dentro de las puertas de la fábrica. +He dejado un coche dentro de la fábrica. [MEA2_G] -Úsalo para ir a recogerles en su territorio en el Red Light District. +Ve a recogerles con él en su territorio, en el barrio rojo. [MEA2_H] -Luego traelos de vuelta a la fábrica de manera que pueda hacerles ver el punto de vista de Marty. +Luego tráelos a la fábrica para que conozcan la opinión de Marty. [MEA3_A] -El negocio se va a hundir a no ser que me haga con una buena cantidad de dinero muy pronto. +El negocio se irá a pique si no consigo un pastizal muy pronto. [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. +Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. [MEA3_C] -He dejado un coche en el lugar habitual +He dejado un coche donde siempre. [MEA3_D] -Ve a recoger a mi esposa en Classic Nails y traela de vuelta a la fábrica. +Ve a por a mi esposa a Classic Nails y tráela a la fábrica. [MEA4_A] -Diablos,¡tengo problemas! +Mierda, ¡la he liado! [MEA4_B] -Resulta que mi esposa estaba viéndose con un tipo a quien le debo dinero. +Resulta que mi esposa salía con uno al que debo dinero. [MEA4_C] -¡Parece muy enfadado y está tratando de recuperar su dinero! +¡Se ha cabreado y ahora quiere vengarse! [MEA4_E] -cree que voy a devolverle el dinero... +y piensa que voy a devolverle el dinero. [MEA4_F] -pero yo creo que... +Pero creo... [MEA4_G] -¡los perros de Liberty van a disfrutar de un nuevo sabor este mes! +¡que los perros de Liberty van a disfrutar de un sabor nuevo este mes! [WELCOME] BIENVENIDO A [HM1_2] -~g~Hazte con un vehículo, y recuerda que sólo cuentan los asesinatos con Uzi desde el coche. +~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el 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. +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~. [LRQC_1] -Asuka y yo vamos a tener que hablar, uh, +Asuka y yo tenemos que hablar... [LRQC_2] -¿Por qué no das un paseo por ahí? +¿Por qué no te das una vuelta? [LRQC_3] -Necesitas un lugar para esconderte +Necesitarás un escondite. [LRQC_4] -Hay un almacén en la orilla de Belleville que puede tener lo que necesitas. +Hay un almacén en la orilla de Belleville que podría servirte. [LRQC_5] -Regresa a mi apartamento cuando estés listo, +Regresa a mi apartamento cuando estés listo [LRQC_6] -y podemos tener una pequeña charla. +y podremos tener una charla. [JM6_5] -~g~Necesitas un vehículo para escapar, ¡idiota! +~g~Necesitas un vehículo de fuga, ¡idiota! [JM2_F] -Si necesitas una pieza ve por detrás de AmmuNation, enfrente del metro. +Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. [LOVE4_7] -~g~Hay una zona de construcción en Staunton Island, puede que llevaran el paquete allí. +~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. [LOVE4_8] ~g~Necesitarás un coche para abrir el garaje. @@ -4685,55 +4657,55 @@ Si necesitas una pieza ve por detrás de AmmuNation, enfrente del metro. GANANCIAS: ~1~ $ [AM1_9] -~r~¡Salvatore ha escapado de vuelta al club de Luigi! +~r~¡Salvatore ha vuelto a meterse en el club de Luigi! [AM1_6] -~g~Si te dejas ver por el club de Luigi, ¡la Mafia te encontrará! +~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! [TM2_3] ~g~¡Es una trampa! ¡Liquidadlos a todos! [FM4_1] -Esta es María. ¡El coche es una trampa! Encuéntrame en el lado sur de Callahan Bridge. +Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. [JM1_7] ~g~¡Cierra la puerta del coche! ¡Se dará cuenta! [KM5_1] -~g~¡¡TRAFICANTE DESMENUZADO!! +~g~¡TRAFICANTE LIQUIDADO! [KM5_6] -~g~Debes matar al menos 8 traficantes Yardie. +~g~Debes matar a al menos 8 traficantes jamaicanos. [KM5_7] -~g~¡Mátalos rápido! Una vez que venden el SPANK se retiran de las calles. +~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. [RM3_8] -~r~¡¡El coche es un señuelo!! +~r~¡El coche es un señuelo! [LM3_8] Hola, soy Joey. [LM3_9] -Luigi dijo que tú eras de fiar, así que vuelve más tarde, +Luigi dijo que eras de fiar, así que vuelve más tarde, [KM3_5] -~g~Toca el claxon para poder hacer el trato. +~g~Toca el claxon para empezar con el trato. [LOVE7] -DESAPARICION DEL AMOR +'LA DESAPARICIÓN DE LOVE' [LOVE2_5] -~g~¡Kenji es carne de parachoques! ¡Sal de Newport y deshazte del coche! +~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! [AS2_11] -~g~ ~1~ DE 9! +~g~¡~1~ DE 9! [GARAGE1] -~g~Sal del vehículo y camina afuera. +~g~Sal del vehículo y aléjate caminando. [KM3_11] -~g~El Cartel ha sido atacado y el maletín no ha sido recuperado. +~g~El cártel ha sido atacado y el maletín no ha sido recuperado. [KM3_12] ~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. @@ -4742,529 +4714,528 @@ DESAPARICION DEL AMOR ~g~Lleva el maletín de vuelta al casino. [RM5_6] -~g~¡Ha salido en libertad bajo fianza! ¡¡Destruye su chaleco salvavidas con un vehículo o una explosión!! +~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! [PBOAT_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. [PBOAT_2] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. [DIAB1_B] -Este es El Burro de los Diablos. +Al habla El Burro, de los Diablos. [DIAB1_D] -Ahora estás en Liberty, pero ya te estás ganando una reputación en las calles. +Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. [DIAB1_E] -Hay una carrera en la calle que empieza en la vieja escuela cerca de Callahan Bridge. +Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. [DIAB1_F] -Consíguete unas ruedas y el primero que pase por todos los checkpoints gana el premio. +Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. [HM2_1] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~ para detonar. +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. [HM2_1A] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para detonar. +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. [HM2_2] -~r~¡Fallaste en la destrucción de los coches blindados! +~r~¡No has destruido todos los furgones blindados! [HM2_6] -~g~¡Coche blindado destrozado! +~g~¡Te has cargado un furgón blindado! [RM3_A] -Conozco un hombre muy importante en la ciudad, un tipo suave, +Conozco a un pez gordo de la ciudad, un tipo muy cándido, [RM3_H] -con gustos exóticos y el suficiente dinero para pagárselos. +con, digamos... gustos exóticos y el dinero para pagárselos. [RM3_B] -Está involucrado en un asunto legal y la acusación tiene fotos de él muy comprometedoras +Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras [RM3_C] en una fiesta en la morgue o algo así. [LOVE6_A] -Una lección en negocios, amigo mío. +Una lección sobre negocios, amigo mío: [LOVE6_E] -Si tienes una mercancía única, el mundo y su mujer tratarán de quitártela de tus garras. +Si tienes una mercancía única, todo el mundo tratará de arrebatártela, [LOVE6_C] -Equipos SWAT han acordonado el área alrededor de mi asociado y el paquete. +Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. [LOVE6_D] -Ve hacia allí, recoge la furgoneta y actúa como un señuelo. +Ve allí, recoge la furgoneta y haz de señuelo. [LOVE6_F] -Mantenles ocupados y él podrá escaparse bien. +Mantenles ocupados y él podrá escaparse. [AM3_C] -¡Está probablemente afuera en la bahía mientras lees esto! ¡Roba un barco de policía, y hunde su carrera! +Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! [FESZ_UC] CANCELAR [FEDS_SM] -L1,R1-CAMBIAR MENU Mientras se busque un menú en particular: +L1, R1 - CAMBIAR MENÚ [FEDS_AS] -;=-CAMBIAR SELECCION +;= - CAMBIAR SELECCIÓN [FEDSAS2] -<>-CAMBIAR SELECCION +<> - CAMBIAR SELECCIÓN [FEDS_SS] -L1,R1-CAMBIAR SELECCION +L1,R1 - CAMBIAR SELECCIÓN [FEDSSC1] -;-MOVIMIENTO MAS RAPIDO +; - ACELERAR [FEDSSC2] -=-DETENER MOVIMIENTO += - RALENTIZAR [MEA2_3] -~g~Traer el coche de vuelta a la fábrica. +~g~Lleva el coche de vuelta a la fábrica. [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. +~g~Ve al almacén a por el cargamento de Ray. [RM6_5] -~g~La CIA tiene el puente bajo vigilancia, encuentra otra ruta para pasar +~g~La CIA vigila el puente, busca otro camino. [HM2_F] -y destroza todo su material blindado. +y cargarte sus blindados. [HM_4] -'LINGOTES DE ORO' - -[MEA2_B5] -TEXTO NO MAS REQUERIDO - -[MEA1_B5] -TEXTO NO MAS REQUERIDO - -[MEA3_B5] -TEXTO NO MAS REQUERIDO +'FIEBRE DEL PLATINO' [MEA4_B7] -pero si pasas por mi oficina... +Pero si pasas por mi oficina... [MEA3_B4] -¿ Marty quiere verme? Bueno, pues que sea rápido porque tengo que ir a la peluquería. +¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. [KM3_7] -¡Es una trampa Yakuza, tío! +¡Es una trampa de la yakuza, tío! [FES_LOF] Fallo al cargar. [P1INSA] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. ~1~K de espacio disponible para guardar. ~1~K necesario. +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. [P1INSN] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. No hay espacio disponible para guardar. Por favor borra algunos archivos. +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 no tiene espacio suficiente. Por favor, borra algunos archivos. [FES_SLO] -GUARDAR ARCHIVO +ARCHIVO [FES_ISC] -ESTA CORRUPTO +ESTÁ DAÑADO [FESZ_TI] -GUARDAR Z1 +ARCHIVO Z1 [FESZ_SA] -Guardar Partida +Guardar partida [P1NOIN] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1 +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. +Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. [MC_LDFL] -¡Error al cargar! +¡Fallo al cargar! [MC_NWRE] -Ahora, reinicio de partida +Reiniciando partida. [LOVE6_3] -~g~Tienes ~1~ segundo para volver al Securicar antes de que falles en la misión. +~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. [LOVE6_4] -~r~¡Te deshiciste del Securicar señuelo! +~r~¡Has abandonado el Securicar señuelo! [HELP1] -Detente en el centro del marcador azul. +Detente en el centro de la señal azul. [HELP12] -Vaya hasta el centro del marcador azul para dar comienzo una misión. +Entra en la señal azul para comenzar una misión. [HJSTAT] -Distancia: ~1~. ~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. [HJSTATW] -Distancia: ~1~.~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ Y, ¡qué buen aterrizaje! +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! [DIAB1_5] -TIEMPO DE CARRERA +TIEMPO DE CARRERA: [LOVE3_4] -~r~¡Has destruído el avión!! +~r~¡Has destruido el avión! [F_FAIL1] -¡Misión de coche de bomberos terminada! +¡Misión del camión de bomberos terminada! [F_CANC] -~r~ ¡Misión de coche de bomberos cancelada! +~r~¡Misión del camión de bomberos cancelada! [F_EXTIN] -FUEGOS: +INCENDIOS: [A_COMP1] -¡Misión de paramédicos completada! +¡Misiones de sanitario completadas! [A_CANC] -~r~¡Misión de paramédicos cancelada! +~r~¡Misión de sanitario cancelada! [A_COMP3] -¡Misión de paramédicos completada! ¡Nunca te cansarás cuando estés corriendo! +¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! [ATUTOR] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. [ATUTOR3] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. [ALEVEL] -Nivel de misión de paramédico ~1~ +Nivel de misión de sanitario: ~1~ [A_FAIL1] -Misión de paramédico terminada. +Misión de sanitario terminada. [FEST_HA] -Nivel más alto de misión de paramédico +Nivel más alto de misión de sanitario [A_SAVES] GENTE SALVADA: ~1~ [C_KILLS] -CRIMINALES MATADOS: ~1~ +CRIMINALES ABATIDOS: ~1~ [HM1_B] -Tengo un problema, están tratando de camelarme. +Tengo un problema, me la están liando. [AM2_A] La muerte de Salvatore es una placentera noticia, [AM2_A2] -eres un asesino eficaz - Eso me gusta en un hombre. +eres un asesino eficaz. Eso me gusta en un hombre. [AM2_B] Este es mi hermano Kenji. [AM2_C] -Asuka tiene un pequeño trabajo para ti, pero cuando hayas terminado, pásate por mi casino y podremos hablar. +Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. [AM2_D] -Justo como Kenji, siempre tratando de jugar con mis juguetes. +Típico de Kenji, siempre está detrás de mis juguetes. + +{ The voiced dialogue doesn't match the English subtitle for the next string } [AM2_E] -Mi fuente en la policía me dice que la Mafia está acechando nuestros intereses en la ciudad +Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia + +{ The voiced dialogue doesn't match the English subtitle for the next string } [AM2_E2] -con el propósito de localizarte. +en varios puntos de la ciudad. + +{ The voiced dialogue doesn't match the English subtitle for the next string } [AM2_F] -No podemos continuar con nuestras operaciones hasta que entablen negociaciones. +No tenemos tiempo para contactar con nadie y evitar que nos incriminen. + +{ The voiced dialogue doesn't match the English subtitle for the next string } [AM2_G] -Liquida a esos estúpidos espías y acaba con esta vendetta de una vez por todas. +Liquida a esos polis espías, pero cuidado: tendrán apoyo. [F_START] -~g~Informe de vehículo en llamas en el ~a~área. Ve y extingue el fuego. +~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. [AM4_1A] -Ve al teléfono de West Belleville Park. +Ve a la cabina al oeste del Parque Belleville. [AM4_1B] -Ve al teléfono de Liberty Campus. +Ve a la cabina del Campus de Liberty. [AM4_1C] -Ve al teléfono de South Belleville Park. +Ve a la cabina al sur del Parque Belleville. [AM4_1D] -Encuéntrame en el bloque del baño en el parque. +Ven a verme a los baños públicos del parque. [HJSTATF] -Distancia:~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_ +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. [HJSTAWF] -Distancia: ~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_. Y, ¡qué buen aterrizaje! +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! [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. +Pero ojo, también habrá Jacks que se creerán que vas a por ellos. [HM1_D] -'Nueves' es su etiqueta y púrpura es su bandera y cada día ellos sacuden sus colores... +Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar [HM1_G] -otro día más que los 'Jacks' parecen blanditos. +es otro día más que los Jacks parecemos blandos. [MEA2_B] -y roba lo que encuentres para que así pueda reclamarle al seguro como haces tú. +y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. [TM3_H] -~w~Te lo montaste bien allí, chaval, muy bien. +Buen trabajo, chaval, muy bueno. [TM3_I] -~w~Vamos, te presentaré al Don. +Vente, te presentaré al Don. [TM3_J] -~w~¡Eeeyyyy! ¡Luigi! +¡Hola! ¡Luigi! [TM3_K] -~w~Oh, mis chicas han estado echándote de menos mucho tiempo, Salvatore, has estado fuera mucho tiempo. +Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. [TM3_L] -~w~Diles que una vez que nos hayamos ocupado de este desgraciado incidente, +Diles que en cuanto resolvamos este desafortunado incidente [TM3_M] -~w~iremos todos al club para celebrar, ¿vale? +iremos todos al club para celebrarlo, ¿vale? [TM3_N] -~w~Ese es mi chico +¡Mi niño! [TM3_N2] -~w~¿Cómo lo llevas, papá? +¿Cómo lo llevas, papá? [TM3_O] -~w~¿Has encontrado ya una buena mujer? +¿Has encontrado ya una buena mujer? [TM3_P] -~w~Ey, tu madre, que en paz descanse, se retorcería en la tumba +Tu madre, que en paz descanse, se retorcería en la tumba [TM3_Q] -~w~si te viera sin una mujer. +si te viera sin una mujer. [TM3_R] -~w~Lo sé, papá, me estoy ocupando de eso. +Lo sé, papá, estoy en ello. [TM3_S] -~w~¡TONI! ¿Cómo está tu madre? +¡Toni! ¿Cómo está tu madre? [TM3_T] -~w~Ella es una gran mujer, ¿sabes? Fuerte. Firenze. +Es una gran mujer, ¿sabes? Fuerte, ''firenze''. [TM3_U] -~w~Ella está bien... estupenda. +Está bien, estupendamente. [TM3_V] -~w~Fantástico, fantástico. Ahora escuchadme, chavales, entrad dentro mientras yo hablo aquí con nuestro nuevo amigo. +Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. [TM3_W] -~w~No veo más que cosas buenas para ti, hijo mío... +Tienes un gran futuro por delante, hijo mío... [RM1_A] -Esa bola de mierda, McAffrey, aceptó más sobornos que nadie. +¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, [RM1_B] -Cree que va a conseguir una rebaja honorable de sus cargos si ofrece evidencias del estado +se piensa que le darán la pensión completa si se convierte en un testigo de cargo! [RM1_C] -¡El ha cantado! +¡Y ha cantado! [RM4_B] Tenemos que cerrarle la boca para siempre. [RM4_E] -Quiero que se vaya a dormir con los peces en lugar de comérselos. +¡Quiero que se vaya a dormir con los peces, en vez de comérselos! [LOVE3_B] -En su aproximación al aeropuerto esta noche, una avioneta ligera sobrevolará la bahía. +Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. [LOVE4_D] -Desgraciadamente las autoridades aduaneras registraron el avión y lo estaban desguazando +Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar [LOVE4_H] -hasta que yo intervine a pesar del gran coste personal. +hasta que yo intervine a través de mi fortuna. [LOVE4_E] -Cruza el puente a Shoreside Vale, y ve al aeropuerto Francis International. +Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. [GTAB_A] -Ey, saquemos esto de aquí. Dios sabe qué será. +Oye, saquemos esto de aquí. Dios sabrá lo que será, [GTAB_B] -pero él parece quererlo a toda costa así que debe de tener algún valor. +pero él lo quiere a toda costa, así que tendrá algún valor. [GTAB_C] -¡Quién diablos! +¡¿Qué diablos?! [GTAB_D] ¡TÚ! [GTAB_E] -¡Ey, tranquilo, amigo! ¡De nada! De nada! +¡Tranquilo, amigo! ¡No es nada! ¡No es nada! [GTAB_F] -¡Te dejé metiendo tu corazón en el charco! +¡Te dejé desangrándote entre la basura! [GTAB_G] No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. [GTAB_H] -¡No seas mariquita! +¡No seas cagón! [GTAB_I] -¡No tenemos elección, nene! +¡No tenemos elección, nena! [GTAB_J] -¡Siempre hay una elección, bastardo! +¡Siempre la hay, imbécil! [GTAB_K] -¡Siento mucho lo de ese perro enloquecido, son todos iguales... ¿¿por favor?? +¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? [GTAB_L] -Así que la buscona se fué. +Así que la zorra se fue. [GTAB_M] Pero me has hecho un favor, [GTAB_N] -no eres el único que tiene una cuenta pendiente con el Cartel, +no eres el único que tiene una cuenta pendiente con el cártel... [GTAB_O] -¡ese gusano mató a mi hermano! +¡Este gusano mató a mi hermano! [GTAB_P] -¡Nunca maté a ningún Yakuza! +¡Nunca maté a ningún yakuza! [GTAB_Q] -¡MENTIROSO! Todos vimos al asesino del Cartel. +¡Mientes! Todos vimos al asesino del cártel. [GTAB_R] ¡Vamos a cazaros y a mataros a todos, perros colombianos! [GTAB_S] -Estaré trabajando con nuestro querido amigo para extraerle información y un poco de placer. +Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. [GTAB_T] -Tú, ven más tarde, estoy seguro que voy a necesitar tus servicios. +Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. [GTAB_U] -Por favor, amigo, no me dejes con ella, ¡esa chica está loca! ¿Amigo?. Ey, ¡AMIIIGO!... ¡Aiiieeeaaaargghh! +¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! [LOVE5_A] -Estás demostrando ser una inversión segura, algo muy raro en estos días que corren. +Estás demostrando ser una inversión segura, algo muy raro en estos días. [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. +~g~El cártel espera a una banda jamaicana, ¡así que roba uno de sus coches! Dirígete al norte; encontrarás uno en Newport. [LOVE1_1] -~g~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) +~g~Roba un coche de la banda colombiana para que puedas entrar en su escondite. Dirígete hacia el norte; podrás encontrar uno en Fort Staunton. [FM1_Q1] -~w~¿Estás buscando un poco de diversión?. ¿Un poco de... hmmm? ¿Algo de zurra? +¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? [FM1_R] -~w~Hola, chico. Hah, lo de siempre. +Hola, Chico. No, solo lo de siempre. [FM1_T] -~w~Gracias Chico, nos vemos pronto. +Gracias, Chico, nos vemos. [FM1_W] -~w~De acuerdo Fido, espera aquí y quédate pendiente del coche mientras yo voy a menear mi culo, ¿vale? +Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? [FM1_X] -~w~VALE Fido, salgamos de aquí. ¡Uauhhh! +¡Vale, tú, salgamos de aquí! ¡Uaaah! [FM1_Q] -~w~¡Ey María! ¡Es mi chica favorita! +¡Ay, mira, es mi chica favorita! [FM1_S1] -~w~Ey, a lo mejor deberías echar un vistazo en la fiesta del almacén en el lado este de Atlantic Quays. +Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. [FM1_U] -~w~Gracias y disfruta. Es buen material +Gracias y disfruta. Es buen material. [FM1_V] -~w~Vamos Fido, ¡vamos a echar un vistazo a esa fiesta! +¡Venga, tú, vamos a ver esa fiesta! [FM1_SS] -~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: Asistir redada de narcóticos en Atlantic Quays. +~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. [LOVE6_B] -incluso aunque no sean conscientes de su verdadera valía. +aun sin conocer su verdadera valía. [TM3_A1] -~r~¡El amigo de Joey! +~r~¡Joey está frito! [TM3_A2] ~r~¡Joey y Luigi han sido incinerados! [TM3_A3] -~r~¡Joey, Luigi y Toni están quemados! +~r~¡Joey, Luigi y Toni están calcinados! [FM4_2] -Escucha, Salvatore cree que estamos engañándole, +Mira, Salvatore cree que se la estamos jugando, [FM4_3] -así que te ofreció al Cartel para poder hacer un trato. +así que te vendió al cártel para llegar a un trato. [FM4_4] -No podía permitir que hiciera eso, o sea, lo peor es que, +No podía permitírselo, o sea, lo peor es... [FM4_4B] -es mi culpa... porque le dije que éramos un asunto a tratar. +que yo tengo la culpa, porque le dije que somos pareja. [FM4_5] -No me preguntes por qué. No lo sé. +¡No me preguntes por qué, no lo sé! [FM4_6] -Mira, eres un hombre marcado en terreno Mafia y yo tengo que salir de aquí también. +Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. [FM4_6B] -¡He visto demasiados asesinatos. Demasiada sangre! +¡He visto demasiados asesinatos, demasiada sangre! [FM4_7] -Es una amiga mía, ¿vale?, una vieja amiga... es Asuka, alguien en quien podemos confiar. +Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. [FM4_8] -Vamos, ya vale de discursos. +Vamos, dejémonos de discursos. [FM4_9] -Será mejor que salgamos de aquí antes de que haya más italianos histéricos pretendiendo hacer reuniones poco amistosas. +Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. [CRED001] ROCKSTAR STUDIOS [CRED002] -PRODUCER +PRODUCTOR [CRED003] LESLIE BENZIES [CRED004] -ART DIRECTOR +DIRECTOR DE ARTE [CRED005] AARON GARBUT [CRED006] -TECHNICAL DIRECTION +DIRECCIÓN TÉCNICA [CRED007] OBBE VERMEIJ @@ -5273,7 +5244,7 @@ OBBE VERMEIJ ADAM FOWLER [CRED009] -DESIGN +DISEÑO [CRED010] CRAIG FILSHIE @@ -5288,7 +5259,7 @@ CHRIS ROTHWELL JAMES WORRALL [CRED014] -WRITTEN BY +GUIÓN [CRED015] JAMES WORRALL @@ -5300,13 +5271,13 @@ PAUL KUROWSKI DAN HOUSER [CRED018] -CHARACTERS +PERSONAJES [CRED019] IAN MCQUE [CRED020] -ANIMATION & DIRECTION +ANIMACIÓN Y DIRECCIÓN [CRED021] ALEX HORTON @@ -5321,7 +5292,7 @@ AUTO DESIGN PAUL KUROWSKI [CRED025] -ARTISTS +ARTISTAS [CRED026] KEIRAN BAILLIE @@ -5342,7 +5313,7 @@ ANDREW SOOSAY ALISDAIR WOOD [CRED032] -CODERS +PROGRAMADORES [CRED033] ALAN CAMPBELL @@ -5360,7 +5331,7 @@ ALEXANDER ROGER GRAEME WILLIAMSON [CRED038] -SCORE +MÚSICA [CRED039] CRAIG CONNER @@ -5369,25 +5340,25 @@ CRAIG CONNER STUART ROSS [CRED041] -SOUND DESIGN & MASTERING +DISEÑO DE SONIDO Y MASTERIZADO [CRED042] ALLAN WALKER [CRED043] -AUDIO PROGRAMMING +PROGRAMACIÓN DE AUDIO [CRED044] RAYMOND USHER [CRED045] -TEST MANAGER +DIRECTOR DE PRUEBAS [CRED046] CRAIG ARBUTHNOTT [CRED047] -LEAD TESTERS +JEFES DE PRUEBAS [CRED048] ANDY DUTHIE @@ -5399,7 +5370,7 @@ JOHN HAIME NEIL CORBETT [CRD050A] -TESTERS +PROBADORES [CRED051] GRAEME JENNINGS @@ -5420,7 +5391,7 @@ MARK FLETT MICHAEL SUTHERLAND [CRED057] -TECHNICAL SUPPORT +SOPORTE TÉCNICO [CRED058] LORRAINE ROY @@ -5432,43 +5403,43 @@ CHRISTINE CHALMERS ROCKSTAR [CRED061] -EXECUTIVE PRODUCER +PRODUCTOR EJECUTIVO [CRED062] SAM HOUSER [CRED063] -PRODUCER +PRODUCTOR [CRED064] DAN HOUSER [CRED065] -DIRECTOR OF DEVELOPMENT +DIRECTOR DE DESARROLLO [CRED066] JAMIE KING [CRED067] -TECHNICAL PRODUCER +PRODUCTOR TÉCNICO [CRED068] GARY J. FOREMAN [CRED069] -ASSOCIATE PRODUCER +PRODUCTOR ASOCIADO [CRED070] JEREMY POPE [CRED071] -MUSIC SUPERVISOR +SUPERVISOR MUSICAL [CRED072] TERRY DONOVAN [CRED073] -ROCKSTAR PRODUCTION TEAM +EQUIPO DE PRODUCCIÓN DE ROCKSTAR [CRED074] TERRY DONOVAN @@ -5504,37 +5475,37 @@ PAUL YEATES STANTON SARJEANT [CRED085] -VP OF MARKETING +VICEPRESIDENTE DE MÁRKETING [CRED086] TERRY DONOVAN [CRED087] -TECHNICAL COORDINATOR +COORDINADOR TÉCNICO [CRED088] BRANDON ROSE [CRED089] -QA MANAGER +DIRECTOR DE C.C. [CRED090] JEFF ROSA [CRED091] -LEAD ANALYST +JEFE DE ANÁLISIS [CRED092] ADAM DAVIDSON [CRED093] -GAME ANALYST +ANALISTA DEL JUEGO [CRED094] RICHARD HUIE [CRED095] -TEST TEAM +EQUIPO DE PRUEBAS [CRED096] LANCE WILLIAMS @@ -5549,7 +5520,7 @@ BRIAN PLANER OSWALD GREENE [CRED100] -LIBERTY TREE EDITORIAL +EDITORIAL DEL LIBERTY TREE [CRED101] JAMES WORRALL @@ -5570,106 +5541,106 @@ JENEFER GROSS LAURA PATERSON [CRED107] -CUT-SCENES +CINEMÁTICAS [CRED108] -SCRIPT BY DAN HOUSER AND JAMES WORRALL +GUIÓN DE DAN HOUSER Y JAMES WORRALL [CRED109] -AUDIO DIRECTED BY DAN HOUSER +AUDIO DIRIGIDO POR DAN HOUSER [CRED110] -AUDIO PRODUCED BY RENAUD SEBBANE +AUDIO PRODUCIDO POR RENAUD SEBBANE [CRED111] -CAST +REPARTO [CRED112] -FRANK VINCENT AS SALVATORE LEONE +FRANK VINCENT COMO SALVATORE LEONE [CRED113] -JOE PANTOLIANO AS LUIGI GOTERELLI +JOE PANTOLIANO COMO LUIGI GOTERELLI [CRED114] -MICHAEL MADSEN AS TONI CIPRIANI +MICHAEL MADSEN COMO TONI CIPRIANI [CRED115] -MICHAEL RAPAPORT AS JOEY LEONE +MICHAEL RAPAPORT COMO JOEY LEONE [CRED116] -DEBBI MAZAR AS MARIA +DEBBI MAZAR COMO MARÍA [CRED117] -KYLE MACLACHAN AS DONALD LOVE +KYLE MACLACHAN COMO DONALD LOVE [CRED118] -ROBERT LOGGIA AS RAY MACHOWSKI +ROBERT LOGGIA COMO RAY MACHOWSKI [CRED119] -GURU AS 8-BALL +GURU COMO 8-BALL [CRED120] -SONDRA JAMES AS MOMMA +SONDRA JAMES COMO MAMMA [CRED121] -LIANA PAI AS ASUKA +LIANA PAI COMO ASUKA [CRED122] -LES MAU AS KENJI +LES MAU COMO KENJI [CRED123] -CYNTHIA FARRELL AS CATALINA +CYNTHIA FARRELL COMO CATALINA [CRED124] -AL ESPINOSA AS MIGUEL +AL ESPINOSA COMO MIGUEL [CRED125] -CHRIS PHILLIPS AS EL BURRO +CHRIS PHILLIPS COMO EL BURRO [CRED126] -HUNTER PLATIN AS CHICO +HUNTER PLATIN COMO CHICO [CRED127] -WALTER MUDU AS D-ICE +WALTER MUDU COMO D-ICE [CRED128] -CURTIS MCCLARIN AS CURTLY +CURTIS MCCLARIN COMO CURTLY [CRED129] -BILL FIORE AS DARKEL +BILL FIORE COMO DARKEL [CRED130] -CHRIS PHILLIPS AS MARTY CHONKS +CHRIS PHILLIPS COMO MARTY CHONKS [CRED131] -HUNTER PLATIN AS CURLY BOB +HUNTER PLATIN COMO CURLY BOB [CRED132] -WALTER MUDU AS KING COURTNEY +WALTER MUDU COMO KING COURTNEY [CRED133] -HUNTER PLATIN AS ONE-ARMED PHIL +HUNTER PLATIN COMO ONE-ARMED PHIL [CRED134] -KIM GURNEY AS MISTY +KIM GURNEY COMO MISTY [CRED135] -MOTION CAPTURE +CAPTURA DE MOVIMIENTOS [CRED136] -ANIMATED BY +ANIMACIÓN [CRD136A] ALEX HORTON [CRED137] -DIRECTED BY +DIRECCIÓN [CRD137A] NAVID KHONSARI [CRED138] -PRODUCED BY +PRODUCCIÓN [CRD138A] JAMIE KING @@ -5678,10 +5649,10 @@ JAMIE KING RENAUD SEBBANE [CRED139] -RECORDED AT MODERN UPRISING STUDIOS, BROOKLYN +GRABADA EN MODERN UPRISING STUDIOS, BROOKLYN [CRED140] -ACTORS +ACTORES [CRD140A] RENAUD SEBBANE @@ -5696,22 +5667,22 @@ STEPHEN DANIELS ROBERT STIO [CRD140E] -JENNY GROSS. +JENNY GROSS [CRED141] -PEDESTRIAN DIALOGUE +DIÁLOGO DE PEATONES [CRED142] -WRITTEN BY DAN HOUSER, NAVID KHONSARI & JAMES WORRALL +ESCRITO POR DAN HOUSER, NAVID KHONSARI Y JAMES WORRALL [CRED143] -DIRECTED BY CRAIG CONNER, DAN HOUSER AND LAZLOW +DIRIGIDO POR CRAIG CONNER, DAN HOUSER Y LAZLOW [CRED144] -PRODUCED BY RENAUD SEBBANE +PRODUCIDO POR RENAUD SEBBANE [CRED145] -CAST +REPARTO [CRED146] HUNTER PLATIN @@ -5927,10 +5898,10 @@ FALKO BURKERT SARA SEWELL [CRED217] -RADIO STATIONS AND MUSIC +EMISORAS DE RADIO Y MÚSICA [CRED218] -PRODUCERS FOR ROCKSTAR UK +PRODUCTORES DE ROCKSTAR REINO UNIDO [CRD218A] CRAIG CONNER @@ -5939,19 +5910,19 @@ CRAIG CONNER STUART ROSS [CRED219] -SOUNDTRACK CO-ORDINATOR +COORDINADOR DE BANDA SONORA [CRED220] TERRY DONOVAN [CRED221] -PRODUCER FOR ROCKSTAR GAMES +PRODUCTOR DE ROCKSTAR GAMES [CRED222] DAN HOUSER [CRED223] -EDITED BY +EDICIÓN [CRED224] CRAIG CONNER @@ -5963,7 +5934,7 @@ ALLAN WALKER LAZLOW [CRED227] -DJ BANTER AND IMAGING WRITTEN BY +GUIÓN DE LOCUTORES Y ANUNCIOS [CRED228] DAN HOUSER @@ -5972,7 +5943,7 @@ DAN HOUSER LAZLOW [CRED230] -SPECIAL THANKS TO +AGRADECIMIENTOS ESPECIALES [CRED231] ADAM TEDMAN @@ -6005,7 +5976,7 @@ EMILY ANDERSON RICHIE HENDERSON [CRED241] -CHRSTIAN CANTAMESSA +CHRISTIAN CANTAMESSA [CRED242] JERONIMO BARRERA @@ -6047,7 +6018,7 @@ MALCOLM SMITH ANDREW SEMPLE [CRED256] -ARTIST +ARTISTAS [CRED257] STUART PETRI @@ -6089,229 +6060,229 @@ STEVE K. GREG LAU [CINCAM] -Cámara Cinemática +Vista cinematográfica [KM1_13] -Lleva el vehículo al garaje! +¡Mete el vehículo en el garaje! [KM3_14] -~r~¡Has sido ubicado, se rompió el trato!! +~r~¡Te han descubierto, han cancelado el trato! [EBAL_H] -Espera aquí tío, mientras voy y hablo con Luigi. +Espera, tío, que voy a hablar con Luigi. [EBAL_M] -¡Recuerda que nadie se mete con mis chicas! +¡Recuerda: nadie se mete con mis chicas! [LM2_F] -Entonces coge su coche y repíntalo. +Luego coge su coche y repíntalo. [LM2_D] -aquí, aquí, cógelo. +toma, toma, para ti. [LM1_9] Hola, soy Misty. [LM4_A] -Algún Diablo mal nacido ha estado vendiendo a sus putitas en mi patio de atrás. +Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. [FM2_B] -¡Nos hicimos con una rata! +¡Tenemos a un chivato! [FM2_C] -No está ni 'chuleando' ni 'traficando' así que debe de estar hablando. +No está ni chuleando ni traficando, así que estará cantando. [FM3_CC] -~w~Regresa, hermano, cuando tengas el dinero. +Regresa cuando tengas el dinero. [FEDS_AM] -<>- CAMBIAR MENU +<> - CAMBIAR MENÚ [LOVE5_5] -~r~¡Fallaste protegiendo el camión! +~r~¡No has protegido al camión! [RM6_6] -~r~¡Ray está muerto! +~r~¡Ray ha muerto! [RM6_7] ~r~¡Ray ha perdido su avión! [RM6_8] -~g~Has dejado atrás a Ray, vuelve a por él. +~g~Has abandonado a Ray, vuelve a por él. [FM1_10] -~g~Has dejado atrás a María, vuelve y recógela. +~g~Has abandonado a María, vuelve y recógela. [LOVE4_9] -~r~¡El avión ha sido destrozado! +~r~¡El avión ha sido destruido! [LOV4_10] -~r~¡La única pista del lugar donde está el paquete ha sido destruída! +~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! [KM2_D] -No hace falta decir que debemos darle los coches como un regalo, para pagar la deduda que tenemos con él. +No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. [KM4_B] -El negocio es lo suficientemente afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. +El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. [KM2_E] -Debes obtener los coches de la lista y llevarlos a un garaje detrás del aparcamiento de Newport. +Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. [FM3_8I] -~w~Consigue una posición ventajosa, entonces entraré cuando dispares el primer tiro. +Encuentra una posición elevada. Entraré cuando dispares el primer tiro. [LOVE1_B] La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, [LOVE1_H] -pero los grupos de hombres se hacen ambiciosos. +pero los grupos de hombres se vuelven codiciosos. [LOVE1_C] -Un valioso recurso, un viejo caballero oriental que conozco, +Un activo valioso, un anciano oriental que conozco, [LOVE1_I] -ha sido tomado prisionero por unos sudamericanos en Aspatria. +está siendo retenido por unos sudamericanos en Aspatria. [MEA4_D] -He aceptado verle... +He aceptado verle, [MEA4_B4] -Marty te envió, ¿ahh?. VALE, voy a enseñar a ese asqueroso el significado de la palabra negocio. +¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. [MEA4_B5] -¡Carl, hola! y eehh... necesito más tiempo para conseguir tu dinero. +¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. [MEA1_B4] -Ah, el Sr. Chonks te envió, ¿verdad?. Vamos a hacerle una visita al amiguete. +Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. [HM5_6] -Vamos a romperle el cuello a algún que otro mamón. +Vamos a partir cabezas... [LOVE1_5] -~g~Deja de perder el tiempo, hazte con un coche de la mafia Colombiana y rescata al socio de Love. +~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. [AS1_D] -~w~Actúa como cebo y consigue que los escuadrones de la muerte te sigan hasta Pike Creek. +Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, [AS1_E] -~w~donde algunos de mis hombres estarán esperándoles. +donde estarán esperando algunos de mis hombres. [AS2_C] -~w~el Cartel tiene una compañía de tapadera, el Kappa Coffe House. +El cártel tiene una tapadera, el Kappa Coffee House. [AS2_E] -~w~No tenemos otra opción que poner esos puntos de venta de droga fuera de servicio. +No tenemos otra opción más que sabotear esos puntos de venta. [AS2_F] -~w~¡¡Redúcelos a astillas!! +¡Redúcelos a cenizas! [AS2_A1] -~w~Ciertamente Miguel tiene algo de esa famosa resistencia latina. +¡Está claro que Miguel tiene esa famosa resistencia latina! [AS2_A2] -~w~Estoy muy agotado. +Estoy agotada. [SIREN_3] -Para conectar las sirenas de este vehículo pulsa el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. [SIREN_4] -Para conectar las sirenas de este vehículo golpea el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. [AS3_C] -~w~¡Eeeeeeyoooo! ¿Qué ES esa cosa amarilla pegajosa? +¡Buaj! ¿Qué es esa cosa amarilla pegajosa? [AS3_C1] -~w~Oh, hola nena. +¡Hola, guapo! [AS3_F] -~w~Tiene los atributos de una chica muy natural, esta nena. +Esta chica tiene un talento nato para la tortura. [AS3_F1] -~w~Se las ha arreglado para quitarle esta pequeña joya a nuestro invitado. +Se las ha arreglado para extraerle esta joyita a nuestro invitado. [AS3_G] -~w~Hay un avión que está llegando al Francis International en 2 horas. +Hay una avioneta que llegará al Aeropuerto Francis en dos horas. [AS3_G1] -~w~Está lleno de veneno de Catalina. +Está lleno del veneno de Catalina. [AS3_H] -~w~Puedes evitar la seguridad del aeropuerto sacando un bote hasta las boyas luminosas. +Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, [AS3_H1] -y disparando al avión en su aterrizaje. +así podrás disparar a la avioneta al aterrizar. [AS3_I] -~w~¡Recoge el cargamento de los escombros! +¡Recoge el cargamento de entre los escombros y tráelo! [AS3_J] -~w~Oh, ten cuidado ahora, ¿VALE nena? +Ten cuidado, guapo, ¿vale? [AS3_K] -~w~Ahora prueba el aceite picante... +Ahora prueba con el aceite picante... [RM2_F1] -¡Esos colombianos estarán aquí en cualquier momento! +¡Los colombianos llegarán en cualquier momento! [RM2_K] -Maldición, ¡¡están aquí!! ¡¡ECHA EL PESTILLO Y CARGA!! +Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! [LOVE2_7] -~g~ ¡Ahora tira el coche! +~g~¡Ahora deshazte del coche! [LOVE2_8] -~g~¡Ahora sal de Newport! +~g~¡Sal de Newport! [AM1_F] -Salvatore Leone saldrá de Luigis a eso de las (~1~: ~1~). +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) [LOVE5_C] -Quiero que le sigas, y asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. +Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. [FESZ_SR] -¡Error al guardar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +¡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? +¿Deseas formatear la Memory Card (PS2) en la ranura de MEMORY CARD 1? [FELZ_FO] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. [FES_NOC] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. [FES_LOE] -¡Error al cargar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +¡Fallo al cargar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. [FES_DEE] -¡Error al borrar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +¡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. +Memory Card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. [ERFOUN] -¡Error al formatear la memory card (PS2)! +¡Error al formatear la Memory Card (PS2)! [ERMCNP] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +No hay Memory Card (PS2) en la ranura de MEMORY CARD 1. [SVMEM1] -Guardar en la memory card (PS2) de la ranura de MEMORY CARD 1. +Guardando en la Memory Card (PS2) de la ranura de MEMORY CARD 1. [FORSLO] -Formatear memory card (PS2) de la ranura de MEMORY CARD 1. +Formateando Memory Card (PS2) de la ranura de MEMORY CARD 1. [SLONFM] -¡Error al formatear la memory card (PS2)! +¡Error al formatear la Memory Card (PS2)! [SLONDR] -No hay espacio suficiente en la memory card (PS2). Inserta una memory card (PS2) con, al menos, 500KB de espacio libre en la ranura de MEMORY CARD 1. +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. +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. +Formateando la Memory Card (PS2) de la ranura de MEMORY CARD 1. No extraigas la Memory Card (PS2), ni reinicies o apagues la consola. [FES_ISF] NO PRESENTE @@ -6320,88 +6291,88 @@ NO PRESENTE PRESENTE [SLONNO] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +No hay una Memory Card (PS2) en la ranura de MEMORY CARD 1. [SLONNF] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. +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)? +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la Memory Card (PS2)? [FESZ_FF] -Error al formatear! Por favor comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +¡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? (SI o NO) +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? (SI o NO) +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. +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. +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. +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. +Borrando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. [LM2_C] -Luigi dijo que, que te diera esto y así... +Luigi dijo que... que te diera esto... [LM3_G] -Joey no es a quien estabas esperando, ¿recuerdas?, tienes el pie en la puerta... +que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... [LM5_E] -Consigue tanto dinero como puedas antes de que los policías se lo metan en el bolsillo. +Saca todo el dinero que puedas a los polis antes de que se lo beban. [JM5_C] -De acuerdo, hay un coche cargado con un fiambre en el café cercano a Callahan Point. +Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. [RM2_B] -Tuvimos acción en Nicaragua, en aquellos tiempos cuando el país sabía lo que estaba haciendo +Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. [RM2_C] -Algunos cerdos del Cartel le asustaron ayer, y dijeron que volverían hoy para quitarle parte de su almacén. +En fin, ayer unos cerdos del cártel lo zurraron y le dijeron que volverían hoy para quitarle parte de su stock. [RM2_D1] -Iría yo mismo pero la vieja ciática está molestándome otra vez -achís, achís-, esto, ehhh... buena suerte. +Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. [CATINF1] -~g~¡Captura a Catalina! +~g~¡Liquida a Catalina! [CATINF2] ~g~Sigue al helicóptero para encontrar a Catalina. [BOATIN1] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. [BOATIN2] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. [BOATIN3] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. [BOATIN4] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. [JM6] -'LA HUÍDA' +'LA HUIDA' [FM1] 'CARABINA' [JM1] -'EL ULTIMO ALMUERZO DE 'MIKE 'LABIOS' +'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' [FM21] -'BOMBARDEA ESA BASE: ACTO I' +'BASE FUERA: ACTO I' [FM3] -'BOMBARDEA ESA BASE: ACTO II' +'BASE FUERA: ACTO II' [AM1] 'SAYONARA, SALVATORE' @@ -6410,22 +6381,22 @@ Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote 'BAJO VIGILANCIA' [KM2] -'GRAND THEFT AUTO' +'ROBO DE VEHÍCULOS' [AS3] -'S.A.M.' +'TIERRA-AIRE' [RM2] -'SUMINISTRO DE ARMAS' +'ESCASEZ DE MANOS' [LOVE6] -'SEÑUELO' ' +'SEÑUELO' [LOVE1] 'EL LIBERADOR' [RC1] -'DESTRUCCIÓN DEL DIABLO' +'DESTRUCCIÓN DE LOS DIABLOS' [RC2] 'LA MASACRE DE LA MAFIA' @@ -6434,25 +6405,25 @@ Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote 'CALAMIDAD EN EL CASINO' [RC4] -'ATAQUE RUMPO' +'EXTERMINIO DE RUMPOS' [RM2_E1] -¡No puedo creer que esos bastardos de la barriga amarilla me dejaran sin la cobertura necesaria otra vez! +¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! [GREN_1] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. [GREN_2] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. [GREN_3] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. [LOVE4_G] -Mi propiedad estará esperándote en el angar de aduanas del avión. +Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. [KABOOM] -¡BOOM! +¡BUUUM! [SPLAT] ¡PLOF! @@ -6461,100 +6432,100 @@ Mi propiedad estará esperándote en el angar de aduanas del avión. ¡APLASTADO! [SOAKED] -¡EMPAPADO! +¡AGUADO! [HEAD] -HEAD RADIO +Head Radio [DBL_CLF] -DOUBLE CLEF FM +Double Clef FM [FLASHB] -FLASHBACK FM +Flashback FM [RISE] -RISE FM +Rise FM [LIPS] -LIPS 106 +Lips 106 [CHAT] -CHATTERBOX FM +Chatterbox FM [K_JAH] -K-JAH Radio +K-Jah Radio [GAM_FM] -GAME FM +Game Radio FM [MSX_FM] MSX FM [TUBE1] -Cuando el metro abra, podrás coger un tren hasta Staunton Island +Cuando el metro abra, podrás coger un tren hasta Staunton Island. [TUBE2] -Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al aeropuerto Francis International. +Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. [TUBE_2] -Para abordar un tren del metro, pulsa el ~h~ botón 'entrar al vehículo' ~w~. +Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. [LEGAL] -~g~¡Eliminar la amenaza criminal! +~g~¡Elimina la amenaza criminal! [GA_2] -Nuevo motor y trabajo de pintura. ¡Los policías no te reconocerán! +He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! [LM1_8A] -Para ganar un poco de dinero extra, por qué no 'tomar prestado' un taxi... +Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... [TAXIH1] -Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. +Para cerca de un peatón señalado para recogerlo y luego condúcelo a su destino antes de que se acabe el tiempo. [LM5_7] -~g~¡Menos de cuatro chicas trabajando el ~p~ Fuzz Ball ~g~ y Luigi no será feliz! +~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! [KM2_3] -~g~Recuerda los ~r~ coches ~g~ tienen que estar en perfecto estado para ser aceptados en el ~p~ garaje ~g~. +~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. [KM5_2] -~g~Un Yardie anda por las calles. +~g~Uno de los jamaicanos se ha ido. [BETRA_A] -Perdón, cariño. +Lo siento, cariño. [BETRA_B] -Soy una chica ambiciosa ¿y tú?, +Soy una chica ambiciosa, ¿y tú? [BETRA_C] -eres tiempo perdido. +Un Don Nadie. [JAILB_Q] -Vamos! +¡Vamos! [JAILB_R] -Señor picha-boba! +¡Señor pendejo! [JAILB_S] -No hay problema en matarte. +No nos importará matarte. [JAILB_T] -Vas a sentirlo. +Os vais a arrepentir. [JAILB_U] -De acuerdo, de acuerdo. Piérdete. +Bien, bien, piérdete. [HELP15] -Cuando vayas a pié pulsa el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para ~h~ mirar atrás ~w~. +Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. [FEC_LB3] -Mira detrás +Mirar atrás [FEC_R3] (botón R3) [FES_AFO] -Esta memory card (PS2) ya está formateada. +Esta Memory Card (PS2) ya está formateada. [FEA_UP] ; @@ -6569,16 +6540,16 @@ Esta memory card (PS2) ya está formateada. > [FEDSAS3] -- CAMBIAR SELECCION +- CAMBIAR SELECCIÓN [FEDSAS4] -;=<> - CAMBIAR SELECCION +;=<> - CAMBIAR SELECCIÓN [SPRAY_4] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. [SPRAY_1] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. [LITTLE] LITTLE T @@ -6587,55 +6558,55 @@ LITTLE T NICK LOVE [AM1_10] -~g~Salvatore estará abandonando Luigi's aproximadamente a las 0~1~:~1~. +~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. [JAILB_V] -la ciudad de Liberty hoy está conmocionada. +Hoy, Liberty City se ha visto conmocionada. [JAILB_A] -Así la policía y los servicios de urgencias se encargan de las secuelas ... +La policía y los servicios de emergencia lidian con las consecuencias [JAILB_B] de un ataque devastador a un convoy policial ocurrido esta mañana. [JAILB_C] -Ningún detalle se ha hecho público sobre los prisioneros que estaban siendo trasladados en el convoy, +No se ha informado de quiénes eran los prisioneros trasladados en el convoy [JAILB_D] -Y ningún grupo ha admitido su responsabilidad. +y ningún grupo ha reconocido la autoría. [JAILB_E] -El convoy abandonó las oficinas de la policía a primera hora de esta mañana... +El convoy abandonó las oficinas de la policía esta mañana [JAILB_F] -con el objeto de hacer una transferencia de rutina a la penitenciaría de Liberty. +para hacer una transferencia de reos a la penitenciaría de Liberty. [JAILB_G] -El ataque se produjo en el puente de Callahan, +El ataque se produjo en el puente Callahan, [JAILB_H] -dejando pocos testigos y el puente notablemente dañado. +dejando pocos testigos y al puente seriamente dañado. [JAILB_I] -Se cree que algunos de los convictos han perecido en la explosión... +Se cree que algunos de los convictos han perecido en la explosión [JAILB_J] -que siguió al ataque inicial. +posterior al ataque inicial. [JAILB_W] -Pasadas las horas parece evidente que el ataque propinado a la policía se llevó a cabo por profesionales, +Pasadas las horas se hizo evidente que el ataque era obra de profesionales, [JAILB_K] -Cuando la identificación de los delincuentes ausentes se había complicado más aún... +ya que la identificación de los prófugos se complicó [JAILB_L] -por un ataque de piratas informático a las bases de datos de los cuarteles de la policía. +cuando piratas informáticos atacaron las bases de datos de la policía. [JAILB_O] -Con el proyecto del túnel Porter fuera del plazo previsto, +Con el retraso del proyecto del túnel Porter, [JAILB_P] -el desastre deja a Portland aislada del resto de la ciudad. +este desastre deja a Portland aislada del resto de la ciudad. [JAILB_M] * @@ -6644,7 +6615,7 @@ el desastre deja a Portland aislada del resto de la ciudad. * [JAILB_X] -En una declaración realizada hoy previamente, +UNUSED [FEDS_SE] Botón / - ELEGIR @@ -6653,34 +6624,34 @@ Botón / - ELEGIR Botón / - ELEGIR Botón " - VOLVER [TM4_A] -~w~Oh, eres tú. TONI no está aquí. +Ah, eres tú. Toni no está. [TM4_A2] -~w~Pero ha dejado para ti una de sus encantadoras cartas de amor. +Pero te ha dejado una de sus cartitas de amor. [DIAB2_A] -¡Puse en marcha mi negocio de entretenimiento exótico de la nada, excepto lo que cabía en mis pantalones de cuero! +¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! [LM5_9] CHICAS: [PERPIC] -Paquetes Ocultos encontrados +Paquetes ocultos encontrados [CO_ONE] -Paquete Oculto ~1~ de ~1~ +Paquete oculto ~1~ de ~1~ [LOVE3_3] -~g~El avión ha tirado ~1~de los 6 paquetes. +~g~La avioneta ha tirado ~1~ de los 6 paquetes. [FARE11] -~g~Destino ~w~'Lugar en obras' ~g~ en Fort Staunton. +~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. [GA_21] -No puedes almacenar más coches en este aparcamiento. +No puedes guardar más coches en este garaje. [CHEAT1] -Trampas activadas +Trucos activados [CHEAT2] Arma trucada @@ -6692,7 +6663,7 @@ Salud trucada Armadura trucada [CHEAT5] -Nivel de Se Busca trucado +Busca y captura trucado [CHEAT6] Dinero trucado @@ -6701,37 +6672,37 @@ Dinero trucado Clima trucado [AS1_H] -~r~¡¡No has conseguido guiar al Escuadrón de la Muerte a la trampa del Yakuza!! +~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! [FEDS_BA] -Botón "- VOLVER +Botón " - VOLVER [RAMP_A] -¡COMPLETADAS TODAS LAS RAMPAS! +¡TODAS LAS MASACRES COMPLETADAS! [USJ_ALL] -¡COMPLETADAS TODAS LOS MANIOBRAS ÚNICAS! +¡TODAS LAS ACROBACIAS COMPLETADAS! [FARE23] -~g~Destino ~w~'garaje importación exportación' ~g~en el distrito de Cochrane Dam +~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. [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. +Puedes coger el tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. [L_TRN_2] -Puedes 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. +Puedes coger el tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. [S_TRN_1] -Puedes 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. +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. [S_TRN_2] -Puedes 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. +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. [AS1_C] -~w~Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty y cuyo único objetivo es el de darte caza. +Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. [AS1_G] -~r~¡¡Todos los Yakuza están muertos!! +~r~¡Todos los yakuza están muertos! [JAN] Ene @@ -6776,172 +6747,174 @@ Dic COCHES RESTANTES: [BONUS] -~g~EXTRA ~1~$ +~g~~1~$ ADICIONALES [HORN1] -Pulsa el ~h~botón L3 ~w~ para tocar el ~h~claxon. +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. [HORN2] -Pulsa el ~h~botón L1 ~w~ para tocar el ~h~claxon. +Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. [HORN3] -Pulsa el ~h~botón R1 ~w~ para tocar el ~h~claxon. +Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. [LM3_1A] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. [LM3_1B] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. [LM3_1C] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. [RADIO_A] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. [RADIO_B] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. [RADIO_C] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +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 moverte por las ~h~emisoras de radio. +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. [FEC_EXV] -Entrar y salir del vehículo +Entrar/salir de vehículo [TAXI_M] 'TAXISTA' [COP_M] -'VIGILANTE' +'JUSTICIERO' [FIRE_M] 'BOMBERO' [AMBUL_M] -'PARAMÉDICO' +'SANITARIO' [HJ_IS] -PRIMA POR ESCENA LOCA: ~1~$ +PREMIO POR ACROBACIA: ~1~$ [HJ_PIS] -PRIMA POR ESCENA LOCA PERFECTA ~1~$ +PREMIO POR ACROBACIA PERFECTA: ~1~$ [HJ_DIS] -PRIMA POR DOBLE ESCENA LOCA ~1~$ +PREMIO POR ACROBACIA DOBLE: ~1~$ [HJ_PDIS] -PRIMA POR DOBLE ESCENA LOCA PERFECTA ~1~$ +PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ [HJ_TIS] -PRIMA POR TRIPLE ESCENA LOCA ~1~$ +PREMIO POR ACROBACIA TRIPLE: ~1~$ [HJ_PTIS] -PRIMA POR TRIPLE ESCENA LOCA PERFECTA ~1~$ +PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ [HJ_QIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA ~1~$ +PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ [HJ_PQIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA PERFECTA ~1~$ +PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ [AM1_K] -Salvatore Leone estará saliendo de Luigi's en unas tres horas. (0~1~:~1~) +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) [IMPEXPP] -El garaje Importación Exportación, Puerto de Portland. Tenemos órdenes para varios vehículos. Revisa nuestro tablón de notas para ver necesidades. +Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. [VANHSTP] -¿Algunos coches de seguridad cascados? Llévalos a nuestro garaje en el Puerto de Portland. +¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. [EMVHPUP] -Se han pagado grandes porcentajes por coches nuevos/usados. Llévalos a la grúa que hay al noroeste del Puerto de Portland. +Se compran vehículos de emergencia nuevos y usados a buen precio. Llévalos a la grúa que hay al noroeste del puerto de Portland. [STANDS] -ESCALERAS ROTAS: +PUESTOS DESTROZADOS: [STASH] -¡~g~Guarda el SPANK en la parte trasera de la ~p~zona en construcción! +~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! [MCSTNS] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SI o NO) +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SÍ o NO) [LOVE3_5] -~g~El avión está ahora a tu alcance. +~g~La avioneta está ahora a tu alcance. [LOVE3_6] -¡~r~La Poli encontró antes los paquetes! +~r~¡La bofia ha llegado a los paquetes antes que tú! [SIREN_1] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. [SIREN_2] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. [FM3_8C] -~w~Necesitaré 100.000 $ para cubrir gastos. +Necesitaré 100.000 $ para cubrir gastos, [MCLOAD] -Cargando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. [FES_GME] -Error al leer la memory card (PS2) de la ranura de MEMORY CARD 1. Por favor compruébalo e inténtalo de nuevo. +Fallo al leer la Memory Card (PS2) de la ranura de MEMORY CARD 1. Compruébala e inténtalo de nuevo. [FESZ_QF] -¿Estás seguro que quieres formatear la memory card (PS2) de la ranura de MEMORY CARD 1? +¿Seguro que quieres formatear la Memory Card (PS2) de la ranura de MEMORY CARD 1? [FESZ_LS] -Cargado con éxito. +Carga completada. [RM3_5] ~g~Tienes ~1~ de 6 paquetes de pruebas. [LOVE3_2] -¡~g~Tienes todos los paquetes! Llévalos de vuelat a Donald Love. +~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. [LOVE4_4] -¡~g~Lleva el paquete de vuelta a Donald Love! +~g~¡Lleva el paquete a Donald Love! [FEB_SAV] Cargar [FEP_SAV] -CARGAR JUEGO +CARGAR PARTIDA [AS2_12A] -Después de destrozar el primer puesto, ¡tendrás 8 mintutos antes que el Cartel envíe a sus matones! +~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! [AS3_1A] -¡~g~Ahora vete al ~b~boya del aeropuerto! +~g~¡Ahora ve a la ~b~boya señalada~g~! [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. +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. + +{ Possibly unused } [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! +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! [END_A] -Los Residentes de Cedar Groove se adaptan a las consecuencias +Los residentes de Cedar Groove todavía están asumiendo [END_B] -emocionales tras el estallido de la guerra +las consecuencias emocionales provocadas [END_C] -que se produjo ayer en la zona. +por la guerra que estalló ayer en la zona. [END_D] -Un residente local, Clive Denver describió a la policía +Un residente local, Clive Denver, dijo a la policía [END_E] -a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. +que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. [END_F] -Oh, sabes, vamos a pasar un buen rato, porqué lo sabes. +¿Sabes? Vamos a pasar un buen rato, porque, como sabes... [END_G] -Te quiero, Yo, yo, yo realmente te quiero, porque eres un hombre tan fuerte +¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, [END_H] y eso es todo lo que necesito. @@ -6950,61 +6923,61 @@ y eso es todo lo que necesito. Bueno, ¿qué estaba diciendo? [END_J] -Oh, sabes, lo he olvidado. Pero sabes lo que quiero decir, ¿verdad? +Lo he olvidado. Pero me entiendes, ¿verdad? [END_K] -El sonido de las explosiones sacudieros las casas más próximas, la gente se esconde. +Las explosiones sacudieron las casas más próximas y a sus residentes. [END_L] -Varios ciudadanos resultaron heridos a causa del tiroteo entre +Varios ciudadanos resultaron heridos a causa del tiroteo [END_M] -las fuerzas terrestres y un helicóptero que rodeaba a la presa. +entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. [END_N] -Sí, aquí en los jardínes tenemos una vista excelente. +Sí, en estos jardínes tuvimos una vista excelente. [END_O] -Cuando finalmente el helicóptero consiguió escapar, +Cuando el helicóptero estalló, [END_P] -mejor que los fuegos artificiales del 4 de Julio. +fue mejor que los fuegos artificiales del 4 de julio. [END_Q] -Con un número de víctimas superior a veinte, +El número de víctimas asciende a las veinte [END_R] -la policía continúa buscando cuerpos. +mientras la policía sigue encontrando cuerpos. [END_S] -No han habido desmentidos oficiales acerca de los rumores +No se han negado oficialmente los rumores [END_T] -de que los muertos eran miembros de Cartel Colombiano, +de que las víctimas eran miembros del cártel colombiano, [END_U] -y se sigue sin pistas que aclaren las causas de la masacre. +y aún no hay pistas que aclaren las causas de la masacre. [END_V] -Me he roto una uña y me pelo hecho un asco, ¿puedes creértelo? +Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? [PAPER1] -UN DISPARO CRIMINAL REALIZADO POR SU NOVIA Y CÓMPLICE. EL TRIBUNAL CON UN VERDICTO ANÓNIMO, ENCUENTRA CULPABLE AL LADRÓN ARMADO. +CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. [PAPER2] ¡DIEZ AÑOS POR AMOR! [END_W] -Me ha costado cincuenta dólares... +Me costó cincuenta dólares... [FEB_CPC] -Configuración del control +Configuración de controles [FEC_PED] Controles a pie [FEC_VEH] -Controles en vehículo +Controles en vehículos [FEC_FPR] Controles en primera persona @@ -7013,10 +6986,10 @@ Controles en primera persona Controles comunes [FEC_PWL] -IR a la izquierda +Ir a la izquierda [FEC_PWR] -IR a la derecha +Ir a la derecha [FEC_PWF] Andar hacia delante @@ -7025,43 +6998,43 @@ Andar hacia delante Andar hacia la cámara [FEC_PLB] -Mirar hacia atrás. +Mirar hacia atrás [FEC_PFR] Disparar arma [FEC_CLE] -Cambiar Arma a la Izq. +Arma de la izquierda [FEC_CRI] -Cambiar Arma a la Dcha. +Arma de la derecha [FEC_LKT] -Bloquear objetivo +Fijar objetivo [FEC_PJP] -Salto Peatón +Saltar a pie [FEC_PSP] -Sprint Peatón +Esprintar a pie [FEC_PSH] -Disparar Peatón +Disparar a pie [FEC_TLF] -Siguiente objetivo a la izq. +Objetivo a la izq. [FEC_TRG] -Siguiente objetivo a la dcha. +Objetivo a la dcha. [FEC_CCM] -Centrar cámara detrás del jugador. +Centrar cámara tras jugador [FEC_SZI] -Acercar rifle francotirador +Acercar zoom de fusil [FEC_SZO] -Alejar rifle francotirador +Alejar zoom de fusil [FEC_LKL] Mirar izq. en primera persona @@ -7097,13 +7070,13 @@ Acelerar vehículo Frenar vehículo [FEC_TSM] -Intercambiar SubMisiones Sí/No +Misiones secundarias [FEC_CRD] -Cambiar emisoras de radio +Cambiar emisora de radio [FEC_ENT] -Entrar/Salir del vehículo +Entrar /salir de vehículo [FEC_WPN] Disparar arma @@ -7112,20 +7085,19 @@ Disparar arma Pausa [FEC_FPO] -Cambiar armas primera persona. +Armas en primera persona [FEC_SMS] -Cambiar puntero del ratón. +Mostrar puntero del ratón [FEC_CMS] -Cambiar modo cámara en todas situaciones. +Cambiar cámara en todas las situaciones [FEC_TSS] Capturar pantalla [FEN_STA] -INICIAR JUEGO - +INICIAR PARTIDA [FEN_NET] Red @@ -7133,10 +7105,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 +7117,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 +7138,7 @@ Dominación Nombre: [FEN_GNA] -Nombre del juego: +Nombre de partida: [FEM_MAP] Elegir mapa @@ -7181,7 +7153,7 @@ Color del jugador Liberty City [FEM_MA1] -RedLight +Barrio rojo [FEM_MA2] Chinatown @@ -7190,28 +7162,28 @@ 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. +Sólo se permiten teclas del teclado. [FEC_DBG] -Menú de depuración +MENÚ DE DEPURACIÓN [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 @@ -7226,28 +7198,28 @@ BCR 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. @@ -7256,46 +7228,46 @@ Usar Mirar a izq. con Mirar a la dcha. 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 +7285,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 +7333,7 @@ ELEGIR MAPA TIPO DE JUEGO [FET_CTL] -AJUSTE DEL MANDO +AJUSTES DEL MANDO [FET_OPT] OPCIONES @@ -7373,40 +7345,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 +7396,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 +7429,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 +7447,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 @@ -7499,31 +7471,31 @@ Tipo de mando: APLICAR [FES_CSA] -Seleccionar aspecto de la lista inferior: +Selecciona una apariencia: [FES_SKN] -NOMBRE DEL ASPECTO +NOMBRE DE APARIENCIA [FES_DAT] FECHA [FES_NON] -NO HAY SKINS DISPONIBLES +NO HAY APARIENCIAS DISPONIBLES [FEA_FM9] REPRODUCTOR MP3 [FESZ_QZ] -¿Estás seguro que deseas guardar esta partida? +¿Seguro que deseas guardar esta partida? [FES_CGA] -Huecos del juego disponibles: +Espacios de partida disponibles: [FES_SCG] -¿Guardar el juego actual? +¿Guardar la partida actual? [FES_LCG] -¿Cargar el juego y seguir jugando? +¿Cargar partida y seguir jugando? [FEC_FIR] Disparar @@ -7538,7 +7510,7 @@ Arma anterior Avanzar [FEC_BAC] -Hacia atrás +Retroceder [FEC_LEF] Izquierda @@ -7553,13 +7525,13 @@ Acercar zoom Alejar zoom [FEC_EEX] -Entrar+salir +Entrar /salir [FEC_RAD] Radio [FEC_SUB] -Rendición +Misión secundaria [FEC_CMR] Cambiar cámara @@ -7568,22 +7540,22 @@ Cambiar cámara Saltar [FEC_SPN] -Esprint +Esprintar [FEC_HND] Freno de mano [FEC_TUL] -Torreta a la izqd. +Torreta a izq. [FEC_TUR] -Torreta a la dcha. +Torreta a dcha. [FEC_LOL] -Mirar a la izq. +Mirar a izq. [FEC_LOR] -Mirar a la dcha. +Mirar a dcha. [FEC_NTR] Siguiente objetivo @@ -7607,7 +7579,7 @@ A PIE EN VEHÍCULO [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 @@ -7616,7 +7588,7 @@ ACCIÓN - [FEC_SPC] -BES +ESPACIO [FEC_MXO] MXB1 @@ -7625,7 +7597,7 @@ MXB1 MXB2 [FEC_UNB] -SIN ESTABLECER +SIN ASIGNAR [FET_CME] MÉTODO DE CONTROL @@ -7643,28 +7615,28 @@ 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 +Torreta a izq. [FEC_TFR] -Torre derecha +Torreta a dcha. [FEC_TFU] -Torre /Dodo arriba +Torreta /Dodo arriba [FEC_TFD] -Torre /Dodo abajo +Torreta /Dodo abajo [FEC_MWF] -RUEDA ARR +RUEDA ARR. [FEC_MWB] -RUEDA AB +RUEDA AB. [FEC_ORR] o @@ -7673,13 +7645,13 @@ o SIN USO [FEC_LUD] -Mirar Ar +Mirar arriba [FEC_LDU] -Mirar Ab +Mirar abajo [FEC_CMP] -COMOBO: MIRAR I+D +COMBO: MIRAR I+D [FEC_NTT] No hay texto para esta tecla @@ -7688,10 +7660,10 @@ No hay texto para esta tecla F~1~ [FEC_IRT] -INS +INSERT [FEC_DLL] -SUP +SUPR [FEC_HME] INICIO @@ -7700,10 +7672,10 @@ INICIO FIN [FEC_PGU] -REPAG +RE PÁG [FEC_PGD] -AVPAG +AV PÁG [FEC_UPA] ARRIBA @@ -7712,7 +7684,7 @@ ARRIBA ABAJO [FEC_LFA] -IZQDA +IZDA [FEC_RFA] DCHA @@ -7745,10 +7717,10 @@ INTRO BLOQ DESPL [FEC_PSB] -PAUSA INTER +PAUSA/INTER [FEC_BSP] -RETROCEDER +RETROCESO [FEC_TAB] TAB @@ -7763,25 +7735,25 @@ 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Ú @@ -7790,25 +7762,25 @@ APMENÚ 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 +Grand Theft Auto III necesita al menos 12 MB de memoria de vídeo [DIAB3_G] ¡Arriba! [FEM_RES] -REANUDAR JUEGO +REANUDAR PARTIDA [FES_SNG] -INICIAR NUEVO JUEGO +INICIAR NUEVA PARTIDA [FEM_SP] -Jugador individual +UN JUGADOR [FEM_MP] MULTIJUGADOR @@ -7820,40 +7792,40 @@ 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 @@ -7862,7 +7834,7 @@ PANTALLA PANORÁMICA ATRÁS [FEA_MUS] -VOLUMEN DE LA MÚSICA +VOLUMEN DE MÚSICA [FEA_SFX] VOLUMEN DE EFECTOS @@ -7889,7 +7861,7 @@ ESPAÑOL HARDWARE DE SONIDO [FEA_SPK] -AJUSTE DE ALTAVOCES +CONFIGURACIÓN DE ALTAVOCES [FEA_2SP] 2 ALTAVOCES @@ -7898,19 +7870,24 @@ 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 [GMSAVE] -GUARDAR JUEGO +GUARDAR PARTIDA [FES_DGA] -BORRAR JUEGO +BORRAR PARTIDA + +{ STRING MISSING FROM THE OFFICIAL SPANISH TRANSLATION. } + +[FEM_NON] +NADA [FEC_IVV] INVERTIR VERTICALIDAD RATÓN @@ -7919,25 +7896,25 @@ 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 [WIN_RSZ] -Error al seleccionar nueva pantalla de resolución +Error al seleccionar la nueva resolución de pantalla [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 @@ -7946,13 +7923,13 @@ CONDUCCIÓN CONTROLADA POR EL RATÓN 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 +7938,34 @@ 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 +Apariencia predeterminada del jugador.bmp [JM3] -'VAN HEIST' +'EL ROBO DE LA FURGONETA' [EBAL] -'DÁME LIBERTAD' +'DAME LIBERTAD' [LM4] -'EXPLOSIVA ACCIÓN MACARRA' +'UN CHULO Y SU ESCOPETA' [REPLAY] -VOLVER A JUGAR +REPETICIÓN [FEC_SFT] MAYÚS [CRED254] -JEFE DE ESTUDIO +JEFE DEL ESTUDIO [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,29 +7980,150 @@ 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 NOT AVAILABLE - ORIGINAL SETTING RESTORED +HARDWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG +{ 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 diff --git a/vendor/librw b/vendor/librw index e68ef137..2066cf66 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit e68ef1374d20071887348e9031f5fa38a2e4f7ed +Subproject commit 2066cf6634383e056cd5dda105e87f8da04b1ed8 diff --git a/vendor/opus b/vendor/opus index 034c1b61..6bae366f 160000 --- a/vendor/opus +++ b/vendor/opus @@ -1 +1 @@ -Subproject commit 034c1b61a250457649d788bbf983b3f0fb63f02e +Subproject commit 6bae366f9fef25191fc812c430e8abd40a13a233 diff --git a/vendor/opusfile b/vendor/opusfile index f94a1764..6452e838 160000 --- a/vendor/opusfile +++ b/vendor/opusfile @@ -1 +1 @@ -Subproject commit f94a1764b0dcdd84ee8c13c040de9f4c1a67e4df +Subproject commit 6452e838e68e8f4fc0b3599523c760ac6276ce89