diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 5af12d3a..00000000 --- a/.clang-format +++ /dev/null @@ -1,37 +0,0 @@ ---- -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false - BeforeLambdaBody: false - BeforeWhile: false -BreakBeforeBraces: Attach -ColumnLimit: 0 -IndentWidth: 4 -IndentCaseLabels: true -IncludeBlocks: Regroup -IncludeCategories: - - Regex: '<[[:alnum:].]+\.h>' - Priority: 1 - - Regex: '<[[:alnum:].]+>' - Priority: 2 - - Regex: '.*/.*' - Priority: 3 - - Regex: '.*' - Priority: 4 -DerivePointerAlignment: false -PointerAlignment: Left -... diff --git a/.clang-tidy b/.clang-tidy deleted file mode 100644 index ea50801d..00000000 --- a/.clang-tidy +++ /dev/null @@ -1,17 +0,0 @@ -Checks: '-*,readability-*,performance-*,modernize-*,-modernize-use-trailing-return-type,bugprone-*' -WarningsAsErrors: true -HeaderFilterRegex: '' -FormatStyle: none -CheckOptions: - - key: readability-identifier-naming.ClassCase - value: CamelCase - - key: readability-identifier-naming.ClassMethodCase - value: CamelCase - - key: readability-identifier-naming.ClassMemberPrefix - value: m_ - - key: readability-identifier-naming.ClassMemberCase - value: CamelCase - - key: readability-identifier-naming.ClassConstantCase - value: UPPER_CASE - - key: readability-identifier-naming.FunctionCase - value: CamelCase \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ebdfa7ac --- /dev/null +++ b/.editorconfig @@ -0,0 +1,76 @@ +# top-most EditorConfig file +root=true + +# Unix-style newlines with a newline ending every file +[*] +indent_style=tab +tab_width=4 +charset=utf-8 +trim_trailing_whitespace=true +end_of_line=lf +insert_final_newline=true + +[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli}] + +vc_generate_documentation_comments=doxygen_slash_star + +cpp_indent_braces=false +cpp_alignment_tab_fill_style=use_spaces +cpp_indent_multi_line_relative_to=innermost_parenthesis +cpp_indent_within_parentheses=indent +cpp_indent_preserve_within_parentheses=false +cpp_indent_case_labels=false +cpp_indent_case_contents=true +cpp_indent_case_contents_when_block=false +cpp_indent_lambda_braces_when_parameter=true +cpp_indent_goto_labels=one_left +cpp_indent_preprocessor=leftmost_column +cpp_indent_access_specifiers=false +cpp_indent_namespace_contents=true +cpp_indent_preserve_comments=false +cpp_new_line_before_open_brace_namespace=same_line +cpp_new_line_before_open_brace_type=same_line +cpp_new_line_before_open_brace_function=same_line +cpp_new_line_before_open_brace_block=same_line +cpp_new_line_before_open_brace_lambda=same_line +cpp_new_line_scope_braces_on_separate_lines=false +cpp_new_line_close_brace_same_line_empty_type=false +cpp_new_line_close_brace_same_line_empty_function=false +cpp_new_line_before_catch=false +cpp_new_line_before_else=false +cpp_new_line_before_while_in_do_while=false +cpp_space_before_function_open_parenthesis=remove +cpp_space_within_parameter_list_parentheses=false +cpp_space_between_empty_parameter_list_parentheses=false +cpp_space_after_keywords_in_control_flow_statements=true +cpp_space_within_control_flow_statement_parentheses=false +cpp_space_before_lambda_open_parenthesis=false +cpp_space_within_cast_parentheses=false +cpp_space_after_cast_close_parenthesis=false +cpp_space_within_expression_parentheses=false +cpp_space_before_block_open_brace=true +cpp_space_between_empty_braces=false +cpp_space_before_initializer_list_open_brace=false +cpp_space_within_initializer_list_braces=true +cpp_space_preserve_in_initializer_list=true +cpp_space_before_open_square_bracket=false +cpp_space_within_square_brackets=false +cpp_space_before_empty_square_brackets=false +cpp_space_between_empty_square_brackets=false +cpp_space_group_square_brackets=true +cpp_space_within_lambda_brackets=false +cpp_space_between_empty_lambda_brackets=false +cpp_space_before_comma=false +cpp_space_after_comma=true +cpp_space_remove_around_member_operators=true +cpp_space_before_inheritance_colon=true +cpp_space_before_constructor_colon=true +cpp_space_remove_before_semicolon=true +cpp_space_after_semicolon=false +cpp_space_remove_around_unary_operator=true +cpp_space_around_binary_operator=insert +cpp_space_around_assignment_operator=insert +cpp_space_pointer_reference_alignment=left +cpp_space_around_ternary_operator=insert +cpp_wrap_preserve_blocks=one_liners +cpp_indent_comment=fasle diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..14e48fbe --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,11 @@ +# format codebase +19e77a38d837ce781ba0ca6ea8e78b67a6e3b5a5 + +# add semi-colons to macros consistently +9e4ce24fd2851e65df776dd9c57bcb0d45f4453a + +# convert to unix line endings +72477e01e2711e0f61cdb192ee266e5e21b8846f + +# enum cleanup +faf42d2f8cf432df2993b031f079b0b8c6d7dbe7 diff --git a/.gitattributes b/.gitattributes index 8218efdb..6313b56c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.sh eol=lf \ No newline at end of file +* text=auto eol=lf diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0e7785d9..ab3917c1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,20 +10,24 @@ jobs: build-and-test: name: Build & Test (${{ matrix.os }}) runs-on: ${{ matrix.os }} + continue-on-error: true strategy: matrix: - os: [ windows-2022, ubuntu-20.04 ] + os: [ windows-2022, ubuntu-20.04, macos-11 ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - - name: Add msbuild to PATH (windows only) + - name: Add msbuild to PATH (Windows only) if: ${{ matrix.os == 'windows-2022' }} uses: microsoft/setup-msbuild@v1.1 with: vs-version: '[17,18)' msbuild-architecture: x64 + - name: Install libssl (Mac Only) + if: ${{ matrix.os == 'macos-11' }} + run: brew install openssl@3 - name: cmake uses: lukka/run-cmake@v10 with: @@ -31,7 +35,7 @@ jobs: buildPreset: "ci-${{matrix.os}}" testPreset: "ci-${{matrix.os}}" - name: artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ github.ref == 'ref/head/main' }} with: name: build-${{matrix.os}} diff --git a/.gitignore b/.gitignore index 28f8f297..e093ba4b 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,6 @@ thirdparty/zlib-1.2.11/ .env docker/__pycache__ -docker-compose.override.yml \ No newline at end of file +docker-compose.override.yml + +!*Test.bin diff --git a/.gitmodules b/.gitmodules index 6fb56bde..33193447 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,12 +14,6 @@ path = thirdparty/mariadb-connector-cpp url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git ignore = dirty -[submodule "thirdparty/docker-utils"] - path = thirdparty/docker-utils - url = https://github.com/lcdr/utils.git -[submodule "thirdparty/LUnpack"] - path = thirdparty/LUnpack - url = https://github.com/Xiphoseer/LUnpack.git [submodule "thirdparty/AccountManager"] path = thirdparty/AccountManager url = https://github.com/DarkflameUniverse/AccountManager diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cf311d2..41d4219f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.18) project(Darkflame) include(CTest) +set (CMAKE_CXX_STANDARD 17) + # Read variables from file FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables) @@ -10,447 +12,361 @@ string(REPLACE "\n" ";" variables ${variables}) # Set the cmake variables, formatted as "VARIABLE #" in variables foreach(variable ${variables}) - # If the string contains a #, skip it - if(NOT "${variable}" MATCHES "#") - - # Split the variable into name and value - string(REPLACE "=" ";" variable ${variable}) + # If the string contains a #, skip it + if(NOT "${variable}" MATCHES "#") - # Check that the length of the variable is 2 (name and value) - list(LENGTH variable length) - if(${length} EQUAL 2) + # Split the variable into name and value + string(REPLACE "=" ";" variable ${variable}) - list(GET variable 0 variable_name) - list(GET variable 1 variable_value) + # Check that the length of the variable is 2 (name and value) + list(LENGTH variable length) + if(${length} EQUAL 2) - # Set the variable - set(${variable_name} ${variable_value}) + list(GET variable 0 variable_name) + list(GET variable 1 variable_value) - # Add compiler definition - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}") + # Set the variable + set(${variable_name} ${variable_value}) - message(STATUS "Variable: ${variable_name} = ${variable_value}") + # Add compiler definition + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}") + + message(STATUS "Variable: ${variable_name} = ${variable_value}") endif() endif() endforeach() -# On windows it's better to build this from source, as there's no way FindZLIB is gonna find it -if(NOT WIN32) -find_package(ZLIB REQUIRED) -endif() - -# Fetch External (Non-Submodule) Libraries -if(WIN32) -include(FetchContent) - -FetchContent_Declare( - zlib - URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip - URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1 -) - -FetchContent_MakeAvailable(zlib) - -set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR}) -set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}") # Why? -add_library(ZLIB::ZLIB ALIAS zlib) # You're welcome - -endif(WIN32) - -if(UNIX AND NOT APPLE) - include(FetchContent) - if (__include_backtrace__ AND __compile_backtrace__) - FetchContent_Declare( - backtrace - GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git - ) - - FetchContent_MakeAvailable(backtrace) - - if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs) - set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind") - - execute_process( - COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}" - ) - endif() - - link_directories(${backtrace_SOURCE_DIR}/.libs/) - include_directories(${backtrace_SOURCE_DIR}) - endif() -endif() - # Set the version set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}") - # Echo the version message(STATUS "Version: ${PROJECT_VERSION}") -set(CMAKE_CXX_STANDARD 17) +# Disable demo, tests and examples for recastNavigation. Turn these to ON if you want to use them +# This has to be done here to prevent a rare build error due to missing dependencies on the initial generations. +set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "" FORCE) +set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "" FORCE) +set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE) -if(WIN32) - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) -endif(WIN32) +# Compiler flags: +# Disabled deprecated warnings as the MySQL includes have deprecated code in them. +# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent. +# Disabled no-register +# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}") +if(UNIX) + if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC -lstdc++fs") + endif() + if (__dynamic AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") + endif() + if (__ggdb) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") +elseif(MSVC) + # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now + add_compile_options("/wd4267" "/utf-8") +elseif(WIN32) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() # Our output dir set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) -# Create a /res directory -make_directory(${CMAKE_BINARY_DIR}/res) +# TODO make this not have to override the build type directories +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) -# Create a /locale directory -make_directory(${CMAKE_BINARY_DIR}/locale) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +# Create a /resServer directory +make_directory(${CMAKE_BINARY_DIR}/resServer) # Create a /logs directory make_directory(${CMAKE_BINARY_DIR}/logs) -# Copy ini files on first build -if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini - COPYONLY - ) +# Copy resource files on first build +set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") +foreach(resource_file ${RESOURCE_FILES}) + if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file}) + configure_file( + ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file} + COPYONLY + ) + message("Moved ${resource_file} to project binary directory") + endif() +endforeach() + +# Copy navmesh data on first build and extract it +if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/) + configure_file( + ${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip + COPYONLY + ) + + file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip) + file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip) endif() -# Copy files to output -configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY) +# Copy vanity files on first build +set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml") +foreach(file ${VANITY_FILES}) + configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) +endforeach() -# 3rdparty includes -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/) -if(APPLE) - include_directories(/usr/local/include/) -endif(APPLE) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include) -include_directories(${ZLIB_INCLUDE_DIRS}) +# Move our migrations for MasterServer to run +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/) +file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql) +foreach(file ${SQL_FILES}) + get_filename_component(file ${file} NAME) + if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/dlu/${file}) + configure_file( + ${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file} + COPYONLY + ) + endif() +endforeach() -# Bcrypt -if (NOT WIN32) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt) -else () -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include) -endif () +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/cdserver/) +file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/cdserver/*.sql) +foreach(file ${SQL_FILES}) + get_filename_component(file ${file} NAME) + if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}) + configure_file( + ${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file} + COPYONLY + ) + endif() +endforeach() -# Our includes +# Create our list of include directories +set(INCLUDED_DIRECTORIES + "dCommon" + "dCommon/dClient" + "dCommon/dEnums" + "dChatFilter" + "dGame" + "dGame/dBehaviors" + "dGame/dComponents" + "dGame/dGameMessages" + "dGame/dInventory" + "dGame/dMission" + "dGame/dEntity" + "dGame/dPropertyBehaviors" + "dGame/dPropertyBehaviors/ControlBehaviorMessages" + "dGame/dUtilities" + "dPhysics" + "dNavigation" + "dNavigation/dTerrain" + "dZoneManager" + "dDatabase" + "dDatabase/Tables" + "dNet" + "dScripts" + "dScripts/02_server" + "dScripts/ai" + "dScripts/client" + "dScripts/EquipmentScripts" + "dScripts/EquipmentTriggers" + "dScripts/zone" + "dScripts/02_server/DLU" + "dScripts/02_server/Enemy" + "dScripts/02_server/Equipment" + "dScripts/02_server/Map" + "dScripts/02_server/Minigame" + "dScripts/02_server/Objects" + "dScripts/02_server/Pets" + "dScripts/02_server/Enemy/AG" + "dScripts/02_server/Enemy/AM" + "dScripts/02_server/Enemy/FV" + "dScripts/02_server/Enemy/General" + "dScripts/02_server/Enemy/Survival" + "dScripts/02_server/Enemy/VE" + "dScripts/02_server/Enemy/Waves" + "dScripts/02_server/Map/AG" + "dScripts/02_server/Map/AG_Spider_Queen" + "dScripts/02_server/Map/AM" + "dScripts/02_server/Map/FV" + "dScripts/02_server/Map/General" + "dScripts/02_server/Map/GF" + "dScripts/02_server/Map/njhub" + "dScripts/02_server/Map/NS" + "dScripts/02_server/Map/NT" + "dScripts/02_server/Map/PR" + "dScripts/02_server/Map/Property" + "dScripts/02_server/Map/SS" + "dScripts/02_server/Map/VE" + "dScripts/02_server/Map/FV/Racing" + "dScripts/02_server/Map/General/Ninjago" + "dScripts/02_server/Map/njhub/boss_instance" + "dScripts/02_server/Map/NS/Waves" + "dScripts/02_server/Map/Property/AG_Med" + "dScripts/02_server/Map/Property/AG_Small" + "dScripts/02_server/Map/Property/NS_Med" + "dScripts/02_server/Minigame/General" + "dScripts/ai/ACT" + "dScripts/ai/AG" + "dScripts/ai/FV" + "dScripts/ai/GENERAL" + "dScripts/ai/GF" + "dScripts/ai/MINIGAME" + "dScripts/ai/NP" + "dScripts/ai/NS" + "dScripts/ai/PETS" + "dScripts/ai/PROPERTY" + "dScripts/ai/RACING" + "dScripts/ai/SPEC" + "dScripts/ai/WILD" + "dScripts/ai/ACT/FootRace" + "dScripts/ai/MINIGAME/SG_GF" + "dScripts/ai/MINIGAME/SG_GF/SERVER" + "dScripts/ai/NS/NS_PP_01" + "dScripts/ai/NS/WH" + "dScripts/ai/PROPERTY/AG" + "dScripts/ai/RACING/OBJECTS" + "dScripts/client/ai" + "dScripts/client/ai/PR" + "dScripts/zone/AG" + "dScripts/zone/LUPs" + "dScripts/zone/PROPERTY" + "dScripts/zone/PROPERTY/FV" + "dScripts/zone/PROPERTY/GF" + "dScripts/zone/PROPERTY/NS" + + "thirdparty/raknet/Source" + "thirdparty/tinyxml2" + "thirdparty/recastnavigation" + "thirdparty/SQLite" + "thirdparty/cpplinq" + + "tests" + "tests/dCommonTests" + "tests/dGameTests" + "tests/dGameTests/dComponentsTests" + ) + +# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) +if (APPLE) + include_directories("/usr/local/include/") +endif() + +if (WIN32) + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include") +elseif (UNIX) + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt") + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt") +endif() + +# Add binary directory as an include directory include_directories(${PROJECT_BINARY_DIR}) -include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/) -include_directories(${PROJECT_SOURCE_DIR}/dCommon/) -include_directories(${PROJECT_SOURCE_DIR}/dGame/) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dGameMessages) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dInventory) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dMission) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dEntity) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dUtilities) -include_directories(${PROJECT_SOURCE_DIR}/dPhysics/) -include_directories(${PROJECT_SOURCE_DIR}/dZoneManager/) -include_directories(${PROJECT_SOURCE_DIR}/dDatabase/) -include_directories(${PROJECT_SOURCE_DIR}/dDatabase/Tables/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/SQLite/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/) -include_directories(${PROJECT_SOURCE_DIR}/dNet/) -include_directories(${PROJECT_SOURCE_DIR}/dScripts/) -# Lib folders: +# Actually include the directories from our list +foreach (dir ${INCLUDED_DIRECTORIES}) + include_directories(${PROJECT_SOURCE_DIR}/${dir}) +endforeach() + +# Add linking directories: link_directories(${PROJECT_BINARY_DIR}) -# Third-Party libraries +# Load all of our third party directories add_subdirectory(thirdparty) -# Source Code +# Glob together all headers that need to be precompiled file( -GLOB SOURCES -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp -) - -# Source Code for AuthServer -file( -GLOB SOURCES_AUTH -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp -) - -# Source Code for MasterServer -file( -GLOB SOURCES_MASTER -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp -) - -# Source Code for ChatServer -file( -GLOB SOURCES_CHAT -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dChatServer/*.cpp -) - -# Source Code for dCommon -file( -GLOB SOURCES_DCOMMON -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dCommon/*.cpp -) - -# Source Code for dChatFilter -file( -GLOB SOURCES_DCHATFILTER -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dChatFilter/*.cpp -) - -# Source Code for dDatabase -file( -GLOB SOURCES_DDATABASE -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dDatabase/*.cpp -${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.cpp + GLOB HEADERS_DDATABASE + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dDatabase/*.h + ${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h + ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h ) file( - GLOB HEADERS_DDATABASE - LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dDatabase/*.h - ${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h - ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h + GLOB HEADERS_DZONEMANAGER + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dZoneManager/*.h ) file( - GLOB HEADERS_DZONEMANAGER - LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dZoneManager/*.h + GLOB HEADERS_DCOMMON + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dCommon/*.h ) file( - GLOB HEADERS_DCOMMON - LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dCommon/*.h + GLOB HEADERS_DGAME + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dGame/Entity.h + ${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h + ${PROJECT_SOURCE_DIR}/dGame/EntityManager.h + ${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h ) -file( - GLOB HEADERS_DGAME - LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dGame/Entity.h - ${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h - ${PROJECT_SOURCE_DIR}/dGame/EntityManager.h - ${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h -) +# Add our library subdirectories for creation of the library object +add_subdirectory(dCommon) +add_subdirectory(dDatabase) +add_subdirectory(dChatFilter) +add_subdirectory(dNet) +add_subdirectory(dScripts) # Add for dGame to use +add_subdirectory(dGame) +add_subdirectory(dZoneManager) +add_subdirectory(dNavigation) +add_subdirectory(dPhysics) -# Source Code for dNet -file( -GLOB SOURCES_DNET -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dNet/*.cpp -) +# Create a list of common libraries shared between all binaries +set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp") -# Source Code for dGame -file( -GLOB SOURCES_DGAME -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dGame/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dBehaviors/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dComponents/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dGameMessages/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dInventory/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dMission/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dEntity/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dUtilities/*.cpp -${PROJECT_SOURCE_DIR}/dScripts/*.cpp -) +# Add platform specific common libraries +if (UNIX) + set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread") -# Source Code for dZoneManager -file( -GLOB SOURCES_DZM -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp -) + if (NOT APPLE AND __include_backtrace__) + set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace") + endif() +endif() -# Source Code for dPhysics -file( -GLOB SOURCES_DPHYSICS -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dPhysics/*.cpp -) +# Include all of our binary directories +add_subdirectory(dWorldServer) +add_subdirectory(dAuthServer) +add_subdirectory(dChatServer) +add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries -if(MSVC) - # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now - add_compile_options("/wd4267") -endif(MSVC) - -# Our static libraries: -add_library(dCommon ${SOURCES_DCOMMON}) -add_library(dChatFilter ${SOURCES_DCHATFILTER}) -add_library(dDatabase ${SOURCES_DDATABASE}) -add_library(dNet ${SOURCES_DNET}) -add_library(dGame ${SOURCES_DGAME}) -add_library(dZoneManager ${SOURCES_DZM}) -add_library(dPhysics ${SOURCES_DPHYSICS}) -target_link_libraries(dDatabase sqlite3) -target_link_libraries(dNet dCommon) #Needed because otherwise linker errors occur. -target_link_libraries(dCommon ZLIB::ZLIB) -target_link_libraries(dCommon libbcrypt) -target_link_libraries(dDatabase mariadbConnCpp) -target_link_libraries(dNet dDatabase) -target_link_libraries(dGame dDatabase) -target_link_libraries(dChatFilter dDatabase) - -if(WIN32) -target_link_libraries(raknet ws2_32) -endif(WIN32) - -# Our executables: -add_executable(WorldServer ${SOURCES}) -add_executable(AuthServer ${SOURCES_AUTH}) -add_executable(MasterServer ${SOURCES_MASTER}) -add_executable(ChatServer ${SOURCES_CHAT}) - -# Add out precompiled headers +# Add our precompiled headers target_precompile_headers( - dGame PRIVATE - ${HEADERS_DGAME} + dGame PRIVATE + ${HEADERS_DGAME} ) target_precompile_headers( - dZoneManager PRIVATE - ${HEADERS_DZONEMANAGER} + dZoneManager PRIVATE + ${HEADERS_DZONEMANAGER} ) # Need to specify to use the CXX compiler language here or else we get errors including . target_precompile_headers( - dDatabase PRIVATE - "$<$:${HEADERS_DDATABASE}>" + dDatabase PRIVATE + "$<$:${HEADERS_DDATABASE}>" ) target_precompile_headers( - dCommon PRIVATE - ${HEADERS_DCOMMON} + dCommon PRIVATE + ${HEADERS_DCOMMON} ) target_precompile_headers( - tinyxml2 PRIVATE - "$<$:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>" + tinyxml2 PRIVATE + "$<$:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>" ) -# Target libraries to link to: -target_link_libraries(WorldServer dCommon) -target_link_libraries(WorldServer dChatFilter) -target_link_libraries(WorldServer dDatabase) -target_link_libraries(WorldServer dNet) -target_link_libraries(WorldServer dGame) -target_link_libraries(WorldServer dZoneManager) -target_link_libraries(WorldServer dPhysics) -target_link_libraries(WorldServer detour) -target_link_libraries(WorldServer recast) -target_link_libraries(WorldServer raknet) -target_link_libraries(WorldServer mariadbConnCpp) -if(UNIX) -if(NOT APPLE AND __include_backtrace__) -target_link_libraries(WorldServer backtrace) -target_link_libraries(MasterServer backtrace) -target_link_libraries(AuthServer backtrace) -target_link_libraries(ChatServer backtrace) +if (${__enable_testing__} MATCHES "1") + add_subdirectory(tests) endif() - -endif(UNIX) -target_link_libraries(WorldServer tinyxml2) - -# Target libraries for Auth: -target_link_libraries(AuthServer dCommon) -target_link_libraries(AuthServer dDatabase) -target_link_libraries(AuthServer dNet) -target_link_libraries(AuthServer raknet) -target_link_libraries(AuthServer mariadbConnCpp) -if(UNIX) -target_link_libraries(AuthServer pthread) -target_link_libraries(AuthServer dl) -endif(UNIX) - -# Target libraries for Master: -target_link_libraries(MasterServer dCommon) -target_link_libraries(MasterServer dDatabase) -target_link_libraries(MasterServer dNet) -target_link_libraries(MasterServer raknet) -target_link_libraries(MasterServer mariadbConnCpp) -if(UNIX) -target_link_libraries(MasterServer pthread) -target_link_libraries(MasterServer dl) -endif(UNIX) - -# Target libraries for Chat: -target_link_libraries(ChatServer dCommon) -target_link_libraries(ChatServer dChatFilter) -target_link_libraries(ChatServer dDatabase) -target_link_libraries(ChatServer dNet) -target_link_libraries(ChatServer raknet) -target_link_libraries(ChatServer mariadbConnCpp) -if(UNIX) -target_link_libraries(ChatServer pthread) -target_link_libraries(ChatServer dl) -endif(UNIX) - -# Compiler flags: -# Disabled deprecated warnings as the MySQL includes have deprecated code in them. -# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent. -# Disabled no-register -# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. -if(UNIX) - if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC") - endif() - if (__dynamic) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") - endif() - if (__ggdb) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") - endif() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") -endif(UNIX) - -if(WIN32) -add_dependencies(MasterServer WorldServer) -add_dependencies(MasterServer AuthServer) -add_dependencies(MasterServer ChatServer) -endif() - -# Finally, add the tests -add_subdirectory(tests) - diff --git a/CMakePresets.json b/CMakePresets.json index 241220e0..f8170755 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,98 +1,128 @@ { - "version": 3, - "cmakeMinimumRequired": { - "major": 3, - "minor": 14, - "patch": 0 - }, - "configurePresets": [ - { - "name": "default", - "displayName": "Default configure step", - "description": "Use 'build' dir and Unix makefiles", - "binaryDir": "${sourceDir}/build", - "generator": "Unix Makefiles" + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 14, + "patch": 0 }, - { - "name": "ci-ubuntu-20.04", - "displayName": "CI configure step for Ubuntu", - "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default" - }, - { - "name": "ci-windows-2022", - "displayName": "CI configure step for Windows", - "description": "Set architecture to 64-bit (b/c RakNet)", - "inherits": "default", - "generator": "Visual Studio 17 2022", - "architecture": { - "value": "x64" + "configurePresets": [ + { + "name": "default", + "displayName": "Default configure step", + "description": "Use 'build' dir and Unix makefiles", + "binaryDir": "${sourceDir}/build", + "generator": "Unix Makefiles" }, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo" + { + "name": "ci-ubuntu-20.04", + "displayName": "CI configure step for Ubuntu", + "description": "Same as default, Used in GitHub actions workflow", + "inherits": "default" + }, + { + "name": "ci-macos-11", + "displayName": "CI configure step for MacOS", + "description": "Same as default, Used in GitHub actions workflow", + "inherits": "default" + }, + { + "name": "ci-windows-2022", + "displayName": "CI configure step for Windows", + "description": "Set architecture to 64-bit (b/c RakNet)", + "inherits": "default", + "generator": "Visual Studio 17 2022", + "architecture": { + "value": "x64" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "windows-default", + "inherits": "ci-windows-2022", + "displayName": "Windows only Configure Settings", + "description": "Sets build and install directories", + "generator": "Ninja", + "architecture": { + "value": "x64", + "strategy": "external" + } } - }, - { - "name": "windows-default", - "inherits": "ci-windows-2022", - "displayName": "Windows only Configure Settings", - "description": "Sets build and install directories", - "generator": "Ninja", - "architecture": { - "value": "x64", - "strategy": "external" - } - } - ], - "buildPresets": [ - { - "name": "default", - "configurePreset": "default", - "displayName": "Default Build", - "description": "Default Build", - "jobs": 2 - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "Windows CI Build", - "description": "This preset is used by the CI build on windows", - "configuration": "RelWithDebInfo", - "jobs": 2 - }, - { - "name": "ci-ubuntu-20.04", - "configurePreset": "ci-ubuntu-20.04", - "displayName": "Linux CI Build", - "description": "This preset is used by the CI build on linux", - "jobs": 2 - } - ], - "testPresets": [ - { - "name": "ci-ubuntu-20.04", - "configurePreset": "ci-ubuntu-20.04", - "displayName": "CI Tests on Linux", - "description": "Runs all tests on a linux configuration", - "execution": { + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "displayName": "Default Build", + "description": "Default Build", "jobs": 2 }, - "output": { - "outputOnFailure": true - } - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "CI Tests on windows", - "description": "Runs all tests on a windows configuration", - "configuration": "RelWithDebInfo", - "execution": { + { + "name": "ci-windows-2022", + "configurePreset": "ci-windows-2022", + "displayName": "Windows CI Build", + "description": "This preset is used by the CI build on windows", + "configuration": "RelWithDebInfo", "jobs": 2 }, - "output": { - "outputOnFailure": true + { + "name": "ci-ubuntu-20.04", + "configurePreset": "ci-ubuntu-20.04", + "displayName": "Linux CI Build", + "description": "This preset is used by the CI build on linux", + "jobs": 2 + }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "MacOS CI Build", + "description": "This preset is used by the CI build on MacOS", + "jobs": 2 } - } - ] -} + ], + "testPresets": [ + { + "name": "ci-ubuntu-20.04", + "configurePreset": "ci-ubuntu-20.04", + "displayName": "CI Tests on Linux", + "description": "Runs all tests on a linux configuration", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "CI Tests on MacOS", + "description": "Runs all tests on a Mac configuration", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "ci-windows-2022", + "configurePreset": "ci-windows-2022", + "displayName": "CI Tests on windows", + "description": "Runs all tests on a windows configuration", + "configuration": "RelWithDebInfo", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + }, + "filter": { + "exclude": { + "name": "((example)|(minigzip))+" + } + } + } + ] + } diff --git a/CMakeVariables.txt b/CMakeVariables.txt index ed0cfce8..d3c8b36f 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -1,6 +1,6 @@ PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MINOR=0 -PROJECT_VERSION_PATCH=2 +PROJECT_VERSION_PATCH=4 # LICENSE LICENSE=AGPL-3.0 # The network version. @@ -8,13 +8,17 @@ LICENSE=AGPL-3.0 # 171022 - Unmodded client NET_VERSION=171022 # Debugging -# __dynamic=1 # Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. -# __ggdb=1 +__dynamic=1 # Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info. -# __include_backtrace__=1 +# __ggdb=1 # Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs. +# __include_backtrace__=1 +# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries. # __compile_backtrace__=1 -# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries. +# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with. __maria_db_connector_compile_jobs__=1 -# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with. \ No newline at end of file +# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done. +__enable_testing__=1 +# The path to OpenSSL. Change this if your OpenSSL install path is different than the default. +OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64fcbc9f..a44629f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -123,6 +123,15 @@ added, which produced InvalidScript errors. Check out a compiled list of development resources and tools [here](https://lu-dev.net/). + +Please use [.editorconfig](https://editorconfig.org/#pre-installed) with your preferred IDE. + +And run: +```bash +git config blame.ignoreRevsFile .git-blame-ignore-revs +``` +to ignore the gitblame of mass formatting commits + ## Coding Style This project has gone through multiple iterations of coding style. In the code you'll find a number of different coding styles in use. What follows is the preferred style for this project. @@ -154,7 +163,7 @@ if (x) { } ``` -Instead of +Instead of ```cpp if ( x ) { diff --git a/Docker.md b/Docker.md index 7d5f7bc6..b06bd0fe 100644 --- a/Docker.md +++ b/Docker.md @@ -4,7 +4,7 @@ - [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker) - [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop) -- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this. +- LEGO® Universe Client. Check the main [README](./README.md) for details on this. ## Run server inside Docker @@ -25,8 +25,7 @@ **NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded. ``` -git submodule init -git submodule update +git submodule update --init --recursive ``` **NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb diff --git a/Docker_Windows.md b/Docker_Windows.md index 1cc633cc..984bbe57 100644 --- a/Docker_Windows.md +++ b/Docker_Windows.md @@ -25,7 +25,7 @@ 11. Once the command has completed (you can see you path again and can enter commands), close the window. 12. Inside the downloaded folder, copy `.env.example` and name the copy `.env` 13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_. -14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files. +14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`. > If you need the extra performance, place the client files in `\\wsl$\\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems). 15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value. diff --git a/README.md b/README.md index 6b82e1b0..f51b5e2a 100644 --- a/README.md +++ b/README.md @@ -18,196 +18,192 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous. ### Hosting a server -We do not recommend hosting public servers. DLU is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. +We do not recommend hosting public servers. Darkflame Universe is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. ### Supply of resource files -Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed in the resources tab below when checking if a client will work. +Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work. -## Build -Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience. +## Steps to setup server +* [Clone this repository](#clone-the-repository) +* [Install dependencies](#install-dependencies) +* [Database setup](#database-setup) +* [Build the server](#build-the-server) +* [Configuring your server](#configuring-your-server) + * [Required Configuration](#required-configuration) + * [Optional Configuration](#optional-configuration) +* [Verify your setup](#verify-your-setup) +* [Running the server](#running-the-server) +* [User Guide](#user-guide) -### Prerequisites -**Clone the repository** +## Clone the repository +If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win) + +Then run the following command ```bash git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer ``` -**Python** -Some tools utilized to streamline the setup process require Python 3, make sure you have it installed. +## Install dependencies +### Windows packages +Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. +You'll also need to download and install [CMake](https://cmake.org/download/) (version **CMake version 3.18** or later!). -### Choosing the right version for your client -DLU clients identify themselves using a higher version number than the regular live clients out there. -This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. +### MacOS packages +Ensure you have [brew](https://brew.sh) installed. +You will need to install the following packages +```bash +brew install cmake gcc mariadb openssl zlib +``` -If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number. +### Linux packages +Make sure packages like `gcc`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. You will also need a MySQL database solution to use. We recommend using `mariadb-server`. -### Linux builds -Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. +For Ubuntu, you would run the following commands. On other systems, the package install command will differ. -CMake must be version 3.14 or higher! +```bash +sudo apt update && sudo apt upgrade -**Build the repository** +# Install packages +sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake +``` +#### Required CMake version +This project uses **CMake version 3.18** or higher and as such you will need to ensure you have this version installed. +You can check your CMake version by using the following command in a terminal. +```bash +cmake --version +``` + +If you are going to be using an Ubuntu environment to run the server, you may need to get a more recent version of `cmake` than the packages available may provide. + +The general approach to do so would be to obtain a copy of the signing key and then add the CMake repository to your apt. +You can do so with the following commands. + +[Source of the below commands](https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line) + +```bash +# Remove the old version of CMake +sudo apt purge --auto-remove cmake + +# Prepare for installation +sudo apt update && sudo apt install -y software-properties-common lsb-release && sudo apt clean all + +# Obtain a copy of the signing key +wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + +# Add the repository to your sources list. +sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + +# Next you'll want to ensure that Kitware's keyring stays up to date +sudo apt update +sudo apt install kitware-archive-keyring +sudo rm /etc/apt/trusted.gpg.d/kitware.gpg + +# If sudo apt update above returned an error, copy the public key at the end of the error message and run the following command +# if the error message was "The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6AF7F09730B3F0A4" +# then the below command would be "sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4" +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys + +# Finally update and install +sudo apt update +sudo apt install cmake +``` + +## Database setup +First you'll need to start MariaDB. + +For Windows the service is always running by default. + +For MacOS, run the following command +```bash +brew services start mariadb +``` + +For Linux, run the following command +```bash +sudo systemctl start mysql +# If systemctl is not a known command on your distribution, try the following instead +sudo service mysql start +``` + +**You will need to run this command every time you restart your environment** + +If you are using Linux and `systemctl` and want the MariaDB instance to start on startup, run the following command +```bash +sudo systemctl enable --now mysql +``` + +Once MariaDB is started, you'll need to create a user and an empty database for Darkflame Universe to use. + +First, login to the MariaDB instance. + +To do this on Ubuntu/Linux, MacOS, or another Unix like operating system, run the following command in a terminal +```bash +# Logs you into the MariaDB instance as root +sudo mysql +``` + +For Windows, run the following command in the `Command Prompt (MariaDB xx.xx)` terminal +```bash +# Logs you into the mysql instance +mysql -u root -p +# You will then be prompted for the password you set for root during installation of MariaDB +``` + +Now that you are logged in, run the following commands. + +```bash +# Creates a user for this computer which uses a password and grant said user all privileges. +# Change mydarkflameuser to a custom username and password to a custom password. +GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION; +FLUSH PRIVILEGES; + +# Then create a database for Darkflame Universe to use. +CREATE DATABASE darkflame; +``` + +## Build the server You can either run `build.sh` when in the root folder of the repository: ```bash ./build.sh ``` -Or manually run the commands used in `build.sh`: +Or manually run the commands used in [build.sh](build.sh). +If you would like to build the server faster, append `-j` where number is the number of simultaneous compile jobs to run at once. It is recommended that you have this number always be 1 less than your core count to prevent slowdowns. The command would look like this if you would build with 4 jobs at once: ```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build - -# Run CMake to generate make files -cmake .. - -# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8` -make +./build.sh -j4 ``` +### Notes +Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building: +* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory. +* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023. -### MacOS builds -Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`). +## Configuring your server +This server has a few steps that need to be taken to configure the server for your use case. -In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location -```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build +### Required Configuration +Darkflame Universe can run with either a packed or an unpacked client. +Navigate to `build/sharedconfig.ini` and fill in the following fields: +* `mysql_host` (This is the IP address or hostname of your MariaDB server. This is highly likely `localhost`) + * If you setup your MariaDB instance on a port other than 3306, which can be done on a Windows install, you will need to make this value `tcp://localhost:portNum` where portNum is replaced with the port you chose to run MariaDB on. +* `mysql_database` (This is the database you created for the server) +* `mysql_username` (This is the user you created for the server) +* `mysql_password` (This is the password for the user you created for the server) +* `client_location` (This is the location of the client files. This should be the folder path of a packed or unpacked client) + * Ideally the path to the client should not contain any spaces. -# Run CMake to generate build files -cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl - -# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8` -cmake --build . --config Release -``` - -### Windows builds (native) -Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode. - -**Build the repository** -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. - -:: Run CMake with build flag to build -cmake --build . --config Release -``` -**Windows for ARM** has not been tested but should build by doing the following -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. -DMARIADB_BUILD_SOURCE=ON - -:: Run CMake with build flag to build -cmake --build . --config Release -``` - -### Windows builds (WSL) -This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11. - -**Open the Command Prompt application with Administrator permissions and run the following:** -```bash -# Installing Windows Subsystem for Linux -wsl --install -``` - -**Open the Ubuntu application and run the following:** -```bash -# Make sure the install is up to date -apt update && apt upgrade - -# Make sure the gcc, cmake, and build-essentials are installed -sudo apt install gcc -sudo apt install cmake -sudo apt install build-essential -``` - -[**Follow the Linux instructions**](#linux-builds) - -### ARM builds -AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested - -### Updating your build -To update your server to the latest version navigate to your cloned directory -```bash -cd /path/to/DarkflameServer -``` -run the following commands to update to the latest changes -```bash -git pull -git submodule update --init --recursive -``` -now follow the build section for your system - -## Setting up the environment - -### Database -Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. - -Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running. -* Create a database for Darkflame Universe to use -* Run each SQL file in the order at which they appear [here](migrations/dlu/) on the database - -### Resources - -**LEGO® Universe 1.10.64** - -This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe. - -Known good SHA256 checksums of the client: -- `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) -- `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) -- `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) - -Known good *SHA1* checksum of the DLU client: -- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) - -How to generate a SHA256 checksum: -```bash -# Replace with the file path to the client - -# If on Linux or MacOS -shasum -a 256 - -# If on Windows -certutil -hashfile SHA256 -``` - -**Unpacking the client** -* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils) -* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked - -**Setup resource directory** -* In the `build` directory create a `res` directory if it does not already exist. -* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory -* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes` - -**Setup locale** -* In the `build` directory create a `locale` directory if it does not already exist -* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory - -**Client database** -* Use `fdb_to_sqlite.py` in lcdr's utilities on `res/cdclient.fdb` in the unpacked client to convert the client database to `cdclient.sqlite` -* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite` -* Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database - -**Configuration** - -After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary. - -**Verify** +### Optional Configuration +* After the server has been built there should be five `ini` files in the build directory: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. +* `authconfig.ini` contains an option to enable or disable play keys on your server. Do not change the default port for auth. +* `chatconfig.ini` contains a port option. +* `masterconfig.ini` contains options related to permissions you want to run your servers with. +* `sharedconfig.ini` contains several options that are shared across all servers +* `worldconfig.ini` contains several options to turn on QOL improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off. +## Verify your setup Your build directory should now look like this: * AuthServer * ChatServer @@ -216,211 +212,105 @@ Your build directory should now look like this: * authconfig.ini * chatconfig.ini * masterconfig.ini +* sharedconfig.ini * worldconfig.ini -* **locale/** - * locale.xml -* **res/** - * CDServer.sqlite - * chatplus_en_us.txt - * **macros/** - * ... - * **BrickModels/** - * ... - * **maps/** - * **navmeshes/** - * ... - * ... * ... ## Running the server -If everything has been configured correctly you should now be able to run the `MasterServer` binary. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the binary network permissions or run it under sudo. +If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo. +To give `AuthServer` network permissions and not require sudo, run the following command +```bash +sudo setcap 'cap_net_bind_service=+ep' AuthServer +``` +and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0. ### First admin user Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users! -### Account Manager +### Account management tool (Nexus Dashboard) +**If you are just using this server for yourself, you can skip setting up Nexus Dashboard** -Follow the instructions [here](https://github.com/DarkflameUniverse/AccountManager) to setup the DLU account management Python web application. This is the intended way for users to create accounts. +Follow the instructions [here](https://github.com/DarkflameUniverse/NexusDashboard) to setup the DLU Nexus Dashboard web application. This is the intended way for users to create accounts and the intended way for moderators to approve names/pets/properties and do other moderation actions. ### Admin levels +The admin level, or Game Master level (hereafter referred to as gmlevel), is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. gmlevel `8` should be used to give a player a majority of privileges without the safety critical once. -The admin level, or game master level, is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. Admin level `8` should be used to give a player a majority of privileges without the safety critical once. +While a character has a gmlevel of anything but `0`, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of `0`. -While a character has a gmlevel of anything but 0, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of 0. +# User guide +Some changes to the client `boot.cfg` file are needed to play on your server. -## User guide -A few modifications have to be made to the client. - -### Client configuration +## Allowing a user to connect to your server To connect to a server follow these steps: * In the client directory, locate `boot.cfg` * Open it in a text editor and locate where it says `AUTHSERVERIP=0:` * Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers +* Next locate the line `UGCUSE3DSERVICES=7:` +* Ensure the number after the 7 is a `0` * Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system * Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users. -### Survival +## Updating your server +To update your server to the latest version navigate to your cloned directory +```bash +cd path/to/DarkflameServer +``` +Run the following commands to update to the latest changes +```bash +git pull +git submodule update --init --recursive +``` +Now follow the [build](#build-the-server) section for your system and your server is up to date. -The client script for the survival minigame has a bug in it which can cause the minigame to not load. To fix this, follow these instructions: -* Open `res/scripts/ai/minigame/survival/l_zone_survival_client.lua` -* Navigate to line `617` -* Change `PlayerReady(self)` to `onPlayerReady(self)` -* Save the file, overriding readonly mode if required +## In-game commands +* A list of all in-game commands can be found [here](./docs/Commands.md). -If you still experience the bug, try deleting/renaming `res/pack/scripts.pk`. +## Verifying your client files -### Brick-By-Brick building +### LEGO® Universe 1.10.64 +To verify that you are indeed using a LEGO® Universe 1.10.64 client, make sure you have the full client compressed **in a rar file** and run the following command. +```bash +# Replace with the file path to the zipped client -Brick-By-Brick building requires `PATCHSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be achieved by pointing it to `localhost` while having `sudo python -m http.server 80` running in the background. +# If on Linux or MacOS +shasum -a 256 -### In-game commands -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](./dGame/dUtilities/SlashCommandHandler.cpp). +# If on Windows using the Command Prompt +certutil -hashfile SHA256 +``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Command - - Usage - - Description - - Admin Level Requirement -
- info - - /info - - Displays server info to the user, including where to find the server's source code. - -
- credits - - /credits - - Displays the names of the people behind Darkflame Universe. - -
- instanceinfo - - /instanceinfo - - Displays in the chat the current zone, clone, and instance id. - -
- gmlevel - - /gmlevel <level> - - Within the authorized range of levels for the current account, changes the character's game master level to the specified value. This is required to use certain commands. - -
- testmap - - /testmap <zone> (clone-id) - - Transfers you to the given zone by id and clone id. - - 1 -
- ban - - /ban <username> - - Bans a user from the server. - - 4 -
- gmadditem - - /gmadditem <id> (count) - - Adds the given item to your inventory by id. - - 8 -
- spawn - - /spawn <id> - - Spawns an object at your location by id. - - 8 -
- metrics - - /metrics - - Prints some information about the server's performance. - - 8 -
+Below are known good SHA256 checksums of the client: +* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) +* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) +* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) -## Credits -## Active Contributors -* [EmosewaMC](https://github.com/EmosewaMC) -* [Jettford](https://github.com/Jettford) +If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64. + +### Darkflame Universe Client +Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there. +This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. + +To verify that you are indeed using a Darkflame Universe client, make sure you have the full client compressed **in a zip file** and run the following command. + +```bash +# Replace with the file path to the zipped client + +# If on Linux or MacOS +shasum -a 1 + +# If on Windows using the Command Prompt +certutil -hashfile SHA1 +``` + +Known good *SHA1* checksum of the Darkflame Universe client: +- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) + +# Development Documentation +This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server +[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html) +[General system documentation](https://docs.lu-dev.net/en/latest/index.html) + +# Credits ## DLU Team * [DarwinAnim8or](https://github.com/DarwinAnim8or) @@ -429,26 +319,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b * [averysumner](https://github.com/codeshaunted) * [Jon002](https://github.com/jaller200) * [Jonny](https://github.com/cuzitsjonny) +* [Aaron K.](https://github.com/aronwk-aaron) + +### Research and Tools +* [lcdr](https://github.com/lcdr) +* [Xiphoseer](https://github.com/Xiphoseer) + +### Community Management +* [Neal](https://github.com/NealSpellman) + +### Logo +* Cole Peterson (BlasterBuilder) + +## Active Contributors +* [EmosewaMC](https://github.com/EmosewaMC) +* [Jettford](https://github.com/Jettford) + +## Former Contributors * TheMachine * Matthew * [Raine](https://github.com/Rainebannister) * Bricknave -### Research and tools -* [lcdr](https://github.com/lcdr) -* [Xiphoseer](https://github.com/Xiphoseer) - -### Community management -* [Neal](https://github.com/NealSpellman) - -### Former contributors -* TheMachine -* Matthew -* Raine -* Bricknave - -### Special thanks +## Special Thanks * humanoid24 * pwjones1969 -* BlasterBuilder for the logo -* ALL OF THE NETDEVIL AND LEGO TEAMS! +* [Simon](https://github.com/SimonNitzsche) +* [ALL OF THE NETDEVIL AND LEGO TEAMS!](https://www.mobygames.com/game/macintosh/lego-universe/credits) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..c4b40c5a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policy + +## Supported Versions + +At the moment, only the latest commit on the `main` branch will be supported for security vulnerabilities. Private server operators +should keep their instances up to date and forks should regularily rebase on `main`. + +| Branch | Supported | +| ------- | ------------------ | +| `main` | :white_check_mark: | + +## Reporting a Vulnerability + +If you found a security vulnerability in DLU, please send a message to [darkflame-security@googlegroups.com][darkflame-security]. You should get a +reply within *72 hours* that we have received your report and a tentative [CVSS score](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). +We will do a preliminary analysis to confirm that the vulnerability is a plausible claim and decline the report otherwise. + +If possible, please include + +1. reproducible steps on how to trigger the vulnerability +2. a description on why you are convinced that it exists. +3. any information you may have on active exploitation of the vulnerability (zero-day). + +## Security Advisories + +The project will release advisories on resolved vulnerabilities at + +## Receiving Security Updates + +We set up [darkflame-security-announce@googlegroups.com][darkflame-security-announce] for private server operators to receive updates on vulnerabilities +such as the release of [Security Advisories](#security-advisories) or early workarounds and recommendations to mitigate ongoing +vulnerabilities. + +Unfortunately, we cannot guarantee that announcements will be sent for every vulnerability. + +## Embargo + +We propose a 90 day (approx. 3 months) embargo on security vulnerabilities. That is, we ask everyone not to disclose the vulnerabilty +publicly until either: + +1. 90 days have passed from the time the first related email is sent to `darkflame-security@` +2. a security advisory related to the vulnerability has been published by the project. + +If you fail to comply with this embargo, you might be exluded from [receiving security updates](#receiving-security-updates). + +## Bug Bounty + +Unfortunately we cannot provide bug bounties at this time. + +[darkflame-security]: mailto:darkflame-security@googlegroups.com +[darkflame-security-announce]: https://groups.google.com/g/darkflame-security-announce diff --git a/build.sh b/build.sh index 11562359..b8d33492 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,6 @@ +# Error if any command fails +set -e + # Create the build directory, preserving it if it already exists mkdir -p build cd build @@ -5,5 +8,6 @@ cd build # Run cmake to generate make files cmake .. -# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8` -make \ No newline at end of file +# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8' +cmake --build . --config Release $1 + diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index fef3124b..262886d7 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -11,61 +11,68 @@ #include "Database.h" #include "dConfig.h" #include "Diagnostics.h" +#include "BinaryPathFinder.h" //RakNet includes: #include "RakNetDefines.h" +#include //Auth includes: #include "AuthPackets.h" -#include "dMessageIdentifiers.h" +#include "eConnectionType.h" +#include "eServerMessageType.h" +#include "eAuthMessageType.h" #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + bool shouldShutdown = false; } dLogger* SetupLogger(); void HandlePacket(Packet* packet); int main(int argc, char** argv) { + constexpr uint32_t authFramerate = mediumFramerate; + constexpr uint32_t authFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Auth"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; - Game::logger->Log("AuthServer", "Starting Auth server...\n"); - Game::logger->Log("AuthServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); - Game::logger->Log("AuthServer", "Compiled on: %s\n", __TIMESTAMP__); + if (!Game::logger) return EXIT_FAILURE; //Read our config: - dConfig config("authconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + + Game::logger->Log("AuthServer", "Starting Auth server..."); + Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); + Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); - try { - Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); - } catch (sql::SQLException& ex) { - Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what()); + try { + Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); + } catch (sql::SQLException& ex) { + Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what()); Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return 0; - } + return EXIT_FAILURE; + } //Find out the master's IP: std::string masterIP; - int masterPort = 1500; + uint32_t masterPort = 1500; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -77,29 +84,30 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); - - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth); + uint32_t maxClients = 50; + uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); + + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= authFramerate) break; //Exit our loop, shut down. - } - else framesSinceMasterDisconnect = 0; + } else framesSinceMasterDisconnect = 0; //In world we'd update our other systems here. @@ -113,16 +121,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -134,11 +142,10 @@ int main(int argc, char** argv) { delete stmt; framesSinceLastSQLPing = 0; - } - else framesSinceLastSQLPing++; + } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps" + t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps" std::this_thread::sleep_until(t); } @@ -146,13 +153,13 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } -dLogger * SetupLogger() { - std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log"; +dLogger* SetupLogger() { + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -164,13 +171,15 @@ dLogger * SetupLogger() { } void HandlePacket(Packet* packet) { + if (packet->length < 4) return; + if (packet->data[0] == ID_USER_PACKET_ENUM) { - if (packet->data[1] == SERVER) { - if (packet->data[3] == MSG_SERVER_VERSION_CONFIRM) { + if (static_cast(packet->data[1]) == eConnectionType::SERVER) { + if (static_cast(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { AuthPackets::HandleHandshake(Game::server, packet); } - } else if (packet->data[1] == AUTH) { - if (packet->data[3] == MSG_AUTH_LOGIN_REQUEST) { + } else if (static_cast(packet->data[1]) == eConnectionType::AUTH) { + if (static_cast(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) { AuthPackets::HandleLoginRequest(Game::server, packet); } } diff --git a/dAuthServer/CMakeLists.txt b/dAuthServer/CMakeLists.txt new file mode 100644 index 00000000..00fa6e7a --- /dev/null +++ b/dAuthServer/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(AuthServer "AuthServer.cpp") +target_link_libraries(AuthServer ${COMMON_LIBRARIES}) diff --git a/dChatFilter/CMakeLists.txt b/dChatFilter/CMakeLists.txt new file mode 100644 index 00000000..24b5e428 --- /dev/null +++ b/dChatFilter/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DCHATFILTER_SOURCES "dChatFilter.cpp") + +add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES}) +target_link_libraries(dChatFilter dDatabase) diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index 7f8187a5..92da9556 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -8,9 +8,11 @@ #include #include "dCommonVars.h" -#include "Database.h" #include "dLogger.h" +#include "dConfig.h" +#include "Database.h" #include "Game.h" +#include "eGameMasterLevel.h" using namespace dChatFilterDCF; @@ -18,12 +20,15 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { m_DontGenerateDCF = dontGenerateDCF; if (!BinaryIO::DoesFileExist(filepath + ".dcf") || m_DontGenerateDCF) { - ReadWordlistPlaintext(filepath + ".txt"); - if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf"); + ReadWordlistPlaintext(filepath + ".txt", true); + if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf", true); + } else if (!ReadWordlistDCF(filepath + ".dcf", true)) { + ReadWordlistPlaintext(filepath + ".txt", true); + ExportWordlistToDCF(filepath + ".dcf", true); } - else if (!ReadWordlistDCF(filepath + ".dcf")) { - ReadWordlistPlaintext(filepath + ".txt"); - ExportWordlistToDCF(filepath + ".dcf"); + + if (BinaryIO::DoesFileExist("blacklist.dcf")) { + ReadWordlistDCF("blacklist.dcf", false); } //Read player names that are ok as well: @@ -32,29 +37,31 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { while (res->next()) { std::string line = res->getString(1).c_str(); std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase - m_Words.push_back(CalculateHash(line)); + m_ApprovedWords.push_back(CalculateHash(line)); } delete res; delete stmt; } dChatFilter::~dChatFilter() { - m_Words.clear(); + m_ApprovedWords.clear(); + m_DeniedWords.clear(); } -void dChatFilter::ReadWordlistPlaintext(const std::string& filepath) { +void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) { std::ifstream file(filepath); if (file) { std::string line; while (std::getline(file, line)) { line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase - m_Words.push_back(CalculateHash(line)); + if (whiteList) m_ApprovedWords.push_back(CalculateHash(line)); + else m_DeniedWords.push_back(CalculateHash(line)); } } } -bool dChatFilter::ReadWordlistDCF(const std::string& filepath) { +bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { std::ifstream file(filepath, std::ios::binary); if (file) { fileHeader hdr; @@ -67,17 +74,18 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath) { if (hdr.formatVersion == formatVersion) { size_t wordsToRead = 0; BinaryIO::BinaryRead(file, wordsToRead); - m_Words.reserve(wordsToRead); + if (whiteList) m_ApprovedWords.reserve(wordsToRead); + else m_DeniedWords.reserve(wordsToRead); size_t word = 0; for (size_t i = 0; i < wordsToRead; ++i) { BinaryIO::BinaryRead(file, word); - m_Words.push_back(word); + if (whiteList) m_ApprovedWords.push_back(word); + else m_DeniedWords.push_back(word); } return true; - } - else { + } else { file.close(); return false; } @@ -86,14 +94,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath) { return false; } -void dChatFilter::ExportWordlistToDCF(const std::string& filepath) { +void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) { std::ofstream file(filepath, std::ios::binary | std::ios_base::out); if (file) { BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); - BinaryIO::BinaryWrite(file, size_t(m_Words.size())); + BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size())); - for (size_t word : m_Words) { + for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) { BinaryIO::BinaryWrite(file, word); } @@ -101,31 +109,45 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath) { } } -bool dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel) { - if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return true; //If anything but a forum mod, return true. - if (message.empty()) return true; +std::vector> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) { + if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. + if (message.empty()) return { }; + if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; std::stringstream sMessage(message); std::string segment; std::regex reg("(!*|\\?*|\\;*|\\.*|\\,*)"); + std::vector> listOfBadSegments = std::vector>(); + + uint32_t position = 0; + while (std::getline(sMessage, segment, ' ')) { + std::string originalSegment = segment; + std::transform(segment.begin(), segment.end(), segment.begin(), ::tolower); //Transform to lowercase segment = std::regex_replace(segment, reg, ""); size_t hash = CalculateHash(segment); - if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end()) { - return false; + if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) { + listOfBadSegments.emplace_back(position, originalSegment.length()); } - if (!IsInWordlist(hash)) { + if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) { m_UserUnapprovedWordCache.push_back(hash); - return false; + listOfBadSegments.emplace_back(position, originalSegment.length()); } + + if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) { + m_UserUnapprovedWordCache.push_back(hash); + listOfBadSegments.emplace_back(position, originalSegment.length()); + } + + position += segment.length() + 1; } - return true; + return listOfBadSegments; } size_t dChatFilter::CalculateHash(const std::string& word) { @@ -135,7 +157,3 @@ size_t dChatFilter::CalculateHash(const std::string& word) { return value; } - -bool dChatFilter::IsInWordlist(size_t word) { - return std::find(m_Words.begin(), m_Words.end(), word) != m_Words.end(); -} diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index e8ae67d0..d00525ce 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -4,6 +4,7 @@ #include "dCommonVars.h" +enum class eGameMasterLevel : uint8_t; namespace dChatFilterDCF { static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24)); static const uint32_t formatVersion = 2; @@ -20,17 +21,17 @@ public: dChatFilter(const std::string& filepath, bool dontGenerateDCF); ~dChatFilter(); - void ReadWordlistPlaintext(const std::string & filepath); - bool ReadWordlistDCF(const std::string & filepath); - void ExportWordlistToDCF(const std::string & filepath); - bool IsSentenceOkay(const std::string& message, int gmLevel); + void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); + bool ReadWordlistDCF(const std::string& filepath, bool whiteList); + void ExportWordlistToDCF(const std::string& filepath, bool whiteList); + std::vector> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true); private: bool m_DontGenerateDCF; - std::vector m_Words; + std::vector m_DeniedWords; + std::vector m_ApprovedWords; std::vector m_UserUnapprovedWordCache; //Private functions: size_t CalculateHash(const std::string& word); - bool IsInWordlist(size_t word); }; diff --git a/dChatServer/CMakeLists.txt b/dChatServer/CMakeLists.txt new file mode 100644 index 00000000..9a47803d --- /dev/null +++ b/dChatServer/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DCHATSERVER_SOURCES + "ChatPacketHandler.cpp" + "PlayerContainer.cpp" +) + +add_executable(ChatServer "ChatServer.cpp") +add_library(dChatServer ${DCHATSERVER_SOURCES}) + +target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) +target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer) diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 899fd355..878cc71c 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -3,64 +3,69 @@ #include "Database.h" #include #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "Game.h" #include "dServer.h" #include "GeneralUtils.h" #include "dLogger.h" +#include "eAddFriendResponseCode.h" +#include "eAddFriendResponseType.h" +#include "RakString.h" +#include "dConfig.h" +#include "eObjectBits.h" +#include "eConnectionType.h" +#include "eChatMessageType.h" +#include "eChatInternalMessageType.h" +#include "eClientMessageType.h" +#include "eGameMessageType.h" extern PlayerContainer playerContainer; void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { //Get from the packet which player we want to do something with: - CINSTREAM; + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = 0; inStream.Read(playerID); - inStream.Read(playerID); auto player = playerContainer.GetPlayerData(playerID); if (!player) return; - //Get our friends list from the Db: - auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?"); - stmt->setUInt64(1, playerID); - stmt->setUInt64(2, playerID); + //Get our friends list from the Db. Using a derived table since the friend of a player can be in either column. + std::unique_ptr stmt(Database::CreatePreppedStmt( + "SELECT fr.requested_player, best_friend, ci.name FROM " + "(SELECT CASE " + "WHEN player_id = ? THEN friend_id " + "WHEN friend_id = ? THEN player_id " + "END AS requested_player, best_friend FROM friends) AS fr " + "JOIN charinfo AS ci ON ci.id = fr.requested_player " + "WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?;")); + stmt->setUInt(1, static_cast(playerID)); + stmt->setUInt(2, static_cast(playerID)); + stmt->setUInt(3, static_cast(playerID)); std::vector friends; - auto res = stmt->executeQuery(); + std::unique_ptr res(stmt->executeQuery()); while (res->next()) { FriendData fd; fd.isFTP = false; // not a thing in DLU - fd.friendID = res->getInt64(1); - if (fd.friendID == playerID) fd.friendID = res->getUInt64(2); + fd.friendID = res->getUInt(1); + GeneralUtils::SetBit(fd.friendID, eObjectBits::PERSISTENT); + GeneralUtils::SetBit(fd.friendID, eObjectBits::CHARACTER); - fd.isBestFriend = res->getInt(3) == 2; //0 = friends, 1 = requested, 2 = bffs - - //We need to find their name as well: - { - auto stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE id=? limit 1"); - stmt->setInt(1, fd.friendID); - - auto res = stmt->executeQuery(); - while (res->next()) { - fd.friendName = res->getString(1); - } - - delete res; - delete stmt; - } + fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs + if (fd.isBestFriend) player->countOfBestFriends += 1; + fd.friendName = res->getString(3); //Now check if they're online: auto fr = playerContainer.GetPlayerData(fd.friendID); + if (fr) { fd.isOnline = true; fd.zoneID = fr->zoneID; //Since this friend is online, we need to update them on the fact that we've just logged in: - SendFriendUpdate(fr, player, 1); - } - else { + SendFriendUpdate(fr, player, 1, fd.isBestFriend); + } else { fd.isOnline = false; fd.zoneID = LWOZONEID(); } @@ -68,20 +73,17 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { friends.push_back(fd); } - delete res; - delete stmt; - //Now, we need to send the friendlist to the server they came from: CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(playerID); //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_GET_FRIENDS_LIST_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE); bitStream.Write(0); bitStream.Write(1); //Length of packet -- just writing one as it doesn't matter, client skips it. bitStream.Write((uint16_t)friends.size()); - + for (auto& data : friends) { data.Serialize(bitStream); } @@ -93,112 +95,291 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { } void ChatPacketHandler::HandleFriendRequest(Packet* packet) { - CINSTREAM; - LWOOBJID playerID; - inStream.Read(playerID); - inStream.Read(playerID); - std::string playerName = PacketUtils::ReadString(0x14, packet, true); - //There's another bool here to determine if it's a best friend request, but we're not handling it right now. + auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends"); + // If this config option doesn't exist, default to 5 which is what live used. + auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U; + CINSTREAM_SKIP_HEADER; + LWOOBJID requestorPlayerID; + inStream.Read(requestorPlayerID); + uint32_t spacing{}; + inStream.Read(spacing); + std::string playerName = ""; + uint16_t character; + bool noMoreLettersInName = false; - //PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed()); - - //We need to check to see if the player is actually online or not: - auto targetData = playerContainer.GetPlayerData(playerName); - if (targetData) { - SendFriendRequest(targetData, playerContainer.GetPlayerData(playerID)); + for (uint32_t j = 0; j < 33; j++) { + inStream.Read(character); + if (character == '\0') noMoreLettersInName = true; + if (!noMoreLettersInName) playerName.push_back(static_cast(character)); } + + char isBestFriendRequest{}; + inStream.Read(isBestFriendRequest); + + auto requestor = playerContainer.GetPlayerData(requestorPlayerID); + if (requestor->playerName == playerName) { + SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN); + return; + }; + std::unique_ptr requestee(playerContainer.GetPlayerData(playerName)); + + // Check if player is online first + if (isBestFriendRequest && !requestee) { + for (auto friendDataCandidate : requestor->friends) { + if (friendDataCandidate.friendName == playerName) { + requestee.reset(new PlayerData()); + // Setup the needed info since you can add a best friend offline. + requestee->playerID = friendDataCandidate.friendID; + requestee->playerName = friendDataCandidate.friendName; + requestee->zoneID = LWOZONEID(); + + FriendData requesteeFriendData{}; + requesteeFriendData.friendID = requestor->playerID; + requesteeFriendData.friendName = requestor->playerName; + requesteeFriendData.isFTP = false; + requesteeFriendData.isOnline = false; + requesteeFriendData.zoneID = requestor->zoneID; + requestee->friends.push_back(requesteeFriendData); + requestee->sysAddr = UNASSIGNED_SYSTEM_ADDRESS; + break; + } + } + } + + // If at this point we dont have a target, then they arent online and we cant send the request. + // Send the response code that corresponds to what the error is. + if (!requestee) { + std::unique_ptr nameQuery(Database::CreatePreppedStmt("SELECT name from charinfo where name = ?;")); + nameQuery->setString(1, playerName); + std::unique_ptr result(nameQuery->executeQuery()); + + requestee.reset(new PlayerData()); + requestee->playerName = playerName; + + SendFriendResponse(requestor, requestee.get(), result->next() ? eAddFriendResponseType::NOTONLINE : eAddFriendResponseType::INVALIDCHARACTER); + return; + } + + if (isBestFriendRequest) { + std::unique_ptr friendUpdate(Database::CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + friendUpdate->setUInt(1, static_cast(requestorPlayerID)); + friendUpdate->setUInt(2, static_cast(requestee->playerID)); + friendUpdate->setUInt(3, static_cast(requestee->playerID)); + friendUpdate->setUInt(4, static_cast(requestorPlayerID)); + std::unique_ptr result(friendUpdate->executeQuery()); + + LWOOBJID queryPlayerID = LWOOBJID_EMPTY; + LWOOBJID queryFriendID = LWOOBJID_EMPTY; + uint8_t oldBestFriendStatus{}; + uint8_t bestFriendStatus{}; + + if (result->next()) { + // Get the IDs + queryPlayerID = result->getInt(1); + queryFriendID = result->getInt(2); + oldBestFriendStatus = result->getInt(3); + bestFriendStatus = oldBestFriendStatus; + + // Set the bits + GeneralUtils::SetBit(queryPlayerID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(queryPlayerID, eObjectBits::PERSISTENT); + GeneralUtils::SetBit(queryFriendID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(queryFriendID, eObjectBits::PERSISTENT); + + // Since this player can either be the friend of someone else or be friends with someone else + // their column in the database determines what bit gets set. When the value hits 3, they + // are now best friends with the other player. + if (queryPlayerID == requestorPlayerID) { + bestFriendStatus |= 1ULL << 0; + } else { + bestFriendStatus |= 1ULL << 1; + } + } + + // Only do updates if there was a change in the bff status. + if (oldBestFriendStatus != bestFriendStatus) { + if (requestee->countOfBestFriends >= maxNumberOfBestFriends || requestor->countOfBestFriends >= maxNumberOfBestFriends) { + if (requestee->countOfBestFriends >= maxNumberOfBestFriends) { + SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false); + } + if (requestor->countOfBestFriends >= maxNumberOfBestFriends) { + SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::YOURFRIENDSLISTFULL, false); + } + } else { + // Then update the database with this new info. + std::unique_ptr updateQuery(Database::CreatePreppedStmt("UPDATE friends SET best_friend = ? WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + updateQuery->setUInt(1, bestFriendStatus); + updateQuery->setUInt(2, static_cast(requestorPlayerID)); + updateQuery->setUInt(3, static_cast(requestee->playerID)); + updateQuery->setUInt(4, static_cast(requestee->playerID)); + updateQuery->setUInt(5, static_cast(requestorPlayerID)); + updateQuery->executeUpdate(); + // Sent the best friend update here if the value is 3 + if (bestFriendStatus == 3U) { + requestee->countOfBestFriends += 1; + requestor->countOfBestFriends += 1; + if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, eAddFriendResponseType::ACCEPTED, false, true); + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::ACCEPTED, false, true); + for (auto& friendData : requestor->friends) { + if (friendData.friendID == requestee->playerID) { + friendData.isBestFriend = true; + } + } + for (auto& friendData : requestee->friends) { + if (friendData.friendID == requestor->playerID) { + friendData.isBestFriend = true; + } + } + } + } + } else { + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true); + } + } else { + // Do not send this if we are requesting to be a best friend. + SendFriendRequest(requestee.get(), requestor); + } + + // If the player is actually a player and not a ghost one defined above, release it from being deleted. + if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) requestee.release(); } void ChatPacketHandler::HandleFriendResponse(Packet* packet) { - CINSTREAM; + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; inStream.Read(playerID); - inStream.Read(playerID); - - uint8_t responseCode = packet->data[0x14]; + + eAddFriendResponseCode clientResponseCode = static_cast(packet->data[0x14]); std::string friendName = PacketUtils::ReadString(0x15, packet, true); - Game::logger->Log("ChatPacketHandler", "Friend response code: %i\n", responseCode); - - if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table. - - PacketUtils::SavePacket("HandleFriendResponse.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed()); - //Now to try and find both of these: - auto goonA = playerContainer.GetPlayerData(playerID); - auto goonB = playerContainer.GetPlayerData(friendName); - if (!goonA || !goonB) return; + auto requestor = playerContainer.GetPlayerData(playerID); + auto requestee = playerContainer.GetPlayerData(friendName); + if (!requestor || !requestee) return; - SendFriendResponse(goonB, goonA, responseCode); - SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk. + eAddFriendResponseType serverResponseCode{}; + uint8_t isAlreadyBestFriends = 0U; + // We need to convert this response code to one we can actually send back to the client. + switch (clientResponseCode) { + case eAddFriendResponseCode::ACCEPTED: + serverResponseCode = eAddFriendResponseType::ACCEPTED; + break; + case eAddFriendResponseCode::BUSY: + serverResponseCode = eAddFriendResponseType::BUSY; + break; + case eAddFriendResponseCode::CANCELLED: + serverResponseCode = eAddFriendResponseType::CANCELLED; + break; + case eAddFriendResponseCode::REJECTED: + serverResponseCode = eAddFriendResponseType::DECLINED; + break; + } - auto stmt = Database::CreatePreppedStmt("INSERT INTO `friends`(`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)"); - stmt->setUInt64(1, goonA->playerID); - stmt->setUInt64(2, goonB->playerID); - stmt->setInt(3, 0); - stmt->execute(); - delete stmt; + // Now that we have handled the base cases, we need to check the other cases. + if (serverResponseCode == eAddFriendResponseType::ACCEPTED) { + for (auto friendData : requestor->friends) { + if (friendData.friendID == requestee->playerID) { + serverResponseCode = eAddFriendResponseType::ALREADYFRIEND; + if (friendData.isBestFriend) { + isAlreadyBestFriends = 1U; + } + } + } + } + + // This message is NOT sent for best friends and is handled differently for those requests. + if (serverResponseCode == eAddFriendResponseType::ACCEPTED) { + // Add the each player to the others friend list. + FriendData requestorData; + requestorData.zoneID = requestor->zoneID; + requestorData.friendID = requestor->playerID; + requestorData.friendName = requestor->playerName; + requestorData.isBestFriend = false; + requestorData.isFTP = false; + requestorData.isOnline = true; + requestee->friends.push_back(requestorData); + + FriendData requesteeData; + requesteeData.zoneID = requestee->zoneID; + requesteeData.friendID = requestee->playerID; + requesteeData.friendName = requestee->playerName; + requesteeData.isBestFriend = false; + requesteeData.isFTP = false; + requesteeData.isOnline = true; + requestor->friends.push_back(requesteeData); + + std::unique_ptr statement(Database::CreatePreppedStmt("INSERT IGNORE INTO `friends` (`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?);")); + statement->setUInt(1, static_cast(requestor->playerID)); + statement->setUInt(2, static_cast(requestee->playerID)); + statement->setInt(3, 0); + statement->execute(); + } + + if (serverResponseCode != eAddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends); + if (serverResponseCode != eAddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends); } void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { - CINSTREAM; + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; inStream.Read(playerID); - inStream.Read(playerID); - std::string friendName = PacketUtils::ReadString(16, packet, true); + std::string friendName = PacketUtils::ReadString(0x14, packet, true); //we'll have to query the db here to find the user, since you can delete them while they're offline. //First, we need to find their ID: - auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;"); + std::unique_ptr stmt(Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;")); stmt->setString(1, friendName.c_str()); LWOOBJID friendID = 0; - auto res = stmt->executeQuery(); + std::unique_ptr res(stmt->executeQuery()); while (res->next()) { - friendID = res->getUInt64(1); + friendID = res->getUInt(1); } - delete res; - delete stmt; + // Convert friendID to LWOOBJID + GeneralUtils::SetBit(friendID, eObjectBits::PERSISTENT); + GeneralUtils::SetBit(friendID, eObjectBits::CHARACTER); - //Set our bits to convert to the BIG BOY objectID. - friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER); - friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT); - - //YEET: - auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1"); - deletestmt->setUInt64(1, playerID); - deletestmt->setUInt64(2, friendID); + std::unique_ptr deletestmt(Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + deletestmt->setUInt(1, static_cast(playerID)); + deletestmt->setUInt(2, static_cast(friendID)); + deletestmt->setUInt(3, static_cast(friendID)); + deletestmt->setUInt(4, static_cast(playerID)); deletestmt->execute(); - delete deletestmt; - - //because I'm lazy and they can be reversed: - { - auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1"); - deletestmt->setUInt64(1, friendID); - deletestmt->setUInt64(2, playerID); - deletestmt->execute(); - delete deletestmt; - } //Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended: auto goonA = playerContainer.GetPlayerData(playerID); if (goonA) { + // Remove the friend from our list of friends + for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) { + if ((*friendData).friendID == friendID) { + if ((*friendData).isBestFriend) --goonA->countOfBestFriends; + goonA->friends.erase(friendData); + break; + } + } SendRemoveFriend(goonA, friendName, true); } - + auto goonB = playerContainer.GetPlayerData(friendID); if (!goonB) return; + // Do it again for other person + for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) { + if ((*friendData).friendID == playerID) { + if ((*friendData).isBestFriend) --goonB->countOfBestFriends; + goonB->friends.erase(friendData); + break; + } + } + std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID)); SendRemoveFriend(goonB, goonAName, true); } -void ChatPacketHandler::HandleChatMessage(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleChatMessage(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); auto* sender = playerContainer.GetPlayerData(playerID); @@ -206,18 +387,16 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) if (playerContainer.GetIsMuted(sender)) return; - const auto senderName = std::string(sender->playerName.C_String()); + const auto senderName = std::string(sender->playerName.c_str()); inStream.SetReadOffset(0x14 * 8); uint8_t channel = 0; inStream.Read(channel); - - std::string message = PacketUtils::ReadString(0x66, packet, true); - Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str()); + std::string message = PacketUtils::ReadString(0x66, packet, true, 512); - //PacketUtils::SavePacket("chat.bin", reinterpret_cast(packet->data), packet->length); + Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str()); if (channel != 8) return; @@ -225,19 +404,18 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) if (team == nullptr) return; - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = playerContainer.GetPlayerData(memberId); if (otherMember == nullptr) return; - const auto otherName = std::string(otherMember->playerName.C_String()); + const auto otherName = std::string(otherMember->playerName.c_str()); CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(otherMember->playerID); - PacketUtils::WriteHeader(bitStream, CHAT, MSG_CHAT_PRIVATE_CHAT_MESSAGE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); bitStream.Write(otherMember->playerID); bitStream.Write(8); bitStream.Write(69); @@ -258,7 +436,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { LWOOBJID senderID = PacketUtils::ReadPacketS64(0x08, packet); std::string receiverName = PacketUtils::ReadString(0x66, packet, true); - std::string message = PacketUtils::ReadString(0xAA, packet, true); + std::string message = PacketUtils::ReadString(0xAA, packet, true, 512); //Get the bois: auto goonA = playerContainer.GetPlayerData(senderID); @@ -267,16 +445,16 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { if (playerContainer.GetIsMuted(goonA)) return; - std::string goonAName = goonA->playerName.C_String(); - std::string goonBName = goonB->playerName.C_String(); + std::string goonAName = goonA->playerName.c_str(); + std::string goonBName = goonB->playerName.c_str(); //To the sender: { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(goonA->playerID); - PacketUtils::WriteHeader(bitStream, CHAT, MSG_CHAT_PRIVATE_CHAT_MESSAGE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); bitStream.Write(goonA->playerID); bitStream.Write(7); bitStream.Write(69); @@ -296,10 +474,10 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { //To the receiver: { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(goonB->playerID); - PacketUtils::WriteHeader(bitStream, CHAT, MSG_CHAT_PRIVATE_CHAT_MESSAGE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); bitStream.Write(goonA->playerID); bitStream.Write(7); bitStream.Write(69); @@ -317,58 +495,50 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { } } -void ChatPacketHandler::HandleTeamInvite(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamInvite(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; inStream.Read(playerID); - inStream.Read(playerID); std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true); auto* player = playerContainer.GetPlayerData(playerID); - if (player == nullptr) - { + if (player == nullptr) { return; } auto* team = playerContainer.GetTeam(playerID); - if (team == nullptr) - { + if (team == nullptr) { team = playerContainer.CreateTeam(playerID); } auto* other = playerContainer.GetPlayerData(invitedPlayer); - if (other == nullptr) - { + if (other == nullptr) { return; } - if (playerContainer.GetTeam(other->playerID) != nullptr) - { + if (playerContainer.GetTeam(other->playerID) != nullptr) { return; } if (team->memberIDs.size() > 3) { // no more teams greater than 4 - Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team\n"); + Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team"); return; } SendTeamInvite(other, player); - Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s\n", playerID, invitedPlayer.c_str()); + Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str()); } -void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); uint32_t size = 0; inStream.Read(size); char declined = 0; @@ -376,98 +546,82 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) LWOOBJID leaderID = LWOOBJID_EMPTY; inStream.Read(leaderID); - Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)\n", playerID, leaderID, declined); + Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined); - if (declined) - { + if (declined) { return; } auto* team = playerContainer.GetTeam(leaderID); - if (team == nullptr) - { - Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)\n", leaderID); + if (team == nullptr) { + Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID); team = playerContainer.GetTeam(playerID); } - - if (team == nullptr) - { - Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)\n", playerID); + + if (team == nullptr) { + Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID); return; } playerContainer.AddMember(team, playerID); } -void ChatPacketHandler::HandleTeamLeave(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamLeave(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); uint32_t size = 0; inStream.Read(size); auto* team = playerContainer.GetTeam(playerID); - Game::logger->Log("ChatPacketHandler", "(%llu) leaving team\n", playerID); + Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID); - if (team != nullptr) - { + if (team != nullptr) { playerContainer.RemoveMember(team, playerID, false, false, true); } } -void ChatPacketHandler::HandleTeamKick(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamKick(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); - + std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true); - Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team\n", playerID, kickedPlayer.c_str()); + Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str()); auto* kicked = playerContainer.GetPlayerData(kickedPlayer); LWOOBJID kickedId = LWOOBJID_EMPTY; - if (kicked != nullptr) - { + if (kicked != nullptr) { kickedId = kicked->playerID; - } - else - { - kickedId = playerContainer.GetId(GeneralUtils::ASCIIToUTF16(kickedPlayer)); + } else { + kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer)); } if (kickedId == LWOOBJID_EMPTY) return; auto* team = playerContainer.GetTeam(playerID); - if (team != nullptr) - { + if (team != nullptr) { if (team->leaderID != playerID || team->leaderID == kickedId) return; playerContainer.RemoveMember(team, kickedId, false, true, false); } - - //PacketUtils::SavePacket("kick.bin", reinterpret_cast(packet->data), packet->length); } -void ChatPacketHandler::HandleTeamPromote(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamPromote(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); - + std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true); - Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader\n", playerID, promotedPlayer.c_str()); + Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str()); auto* promoted = playerContainer.GetPlayerData(promotedPlayer); @@ -475,94 +629,75 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) auto* team = playerContainer.GetTeam(playerID); - if (team != nullptr) - { + if (team != nullptr) { if (team->leaderID != playerID) return; playerContainer.PromoteMember(team, promoted->playerID); } - - //PacketUtils::SavePacket("promote.bin", reinterpret_cast(packet->data), packet->length); } -void ChatPacketHandler::HandleTeamLootOption(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamLootOption(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); uint32_t size = 0; inStream.Read(size); - + char option; inStream.Read(option); auto* team = playerContainer.GetTeam(playerID); - if (team != nullptr) - { + if (team != nullptr) { if (team->leaderID != playerID) return; team->lootFlag = option; playerContainer.TeamStatusUpdate(team); - + playerContainer.UpdateTeamsOnWorld(team, false); } - - //PacketUtils::SavePacket("option.bin", reinterpret_cast(packet->data), packet->length); } -void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) -{ - CINSTREAM; +void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID = LWOOBJID_EMPTY; inStream.Read(playerID); - inStream.Read(playerID); auto* team = playerContainer.GetTeam(playerID); auto* data = playerContainer.GetPlayerData(playerID); - if (team != nullptr && data != nullptr) - { - if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) - { + if (team != nullptr && data != nullptr) { + if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) { playerContainer.RemoveMember(team, playerID, false, false, true, true); return; } - if (team->memberIDs.size() <= 1 && !team->local) - { + if (team->memberIDs.size() <= 1 && !team->local) { playerContainer.DisbandTeam(team); return; } - if (!team->local) - { + if (!team->local) { ChatPacketHandler::SendTeamSetLeader(data, team->leaderID); - } - else - { + } else { ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY); } playerContainer.TeamStatusUpdate(team); - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String())); + const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName); - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = playerContainer.GetPlayerData(memberId); if (memberId == playerID) continue; const auto memberName = playerContainer.GetName(memberId); - - //ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID); - if (otherMember != nullptr) - { + + if (otherMember != nullptr) { ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID); } ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0)); @@ -572,33 +707,31 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) } } -void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) -{ +void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TEAM_INVITE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE); - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); bitStream.Write(sender->playerID); SystemAddress sysAddr = receiver->sysAddr; SEND_PACKET; } -void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) -{ +void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_INVITE_CONFIRM); + bitStream.Write(eGameMessageType::TEAM_INVITE_CONFIRM); bitStream.Write(bLeaderIsFreeTrial); bitStream.Write(i64LeaderID); @@ -608,8 +741,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader bitStream.Write(ucNumOfOtherPlayers); bitStream.Write(ucResponseCode); bitStream.Write(static_cast(wsLeaderName.size())); - for (const auto character : wsLeaderName) - { + for (const auto character : wsLeaderName) { bitStream.Write(character); } @@ -617,17 +749,16 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader SEND_PACKET; } -void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) -{ +void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_GET_STATUS_RESPONSE); + bitStream.Write(eGameMessageType::TEAM_GET_STATUS_RESPONSE); bitStream.Write(i64LeaderID); bitStream.Write(i64LeaderZoneID); @@ -635,8 +766,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI bitStream.Write(ucLootFlag); bitStream.Write(ucNumOfOtherPlayers); bitStream.Write(static_cast(wsLeaderName.size())); - for (const auto character : wsLeaderName) - { + for (const auto character : wsLeaderName) { bitStream.Write(character); } @@ -644,17 +774,16 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI SEND_PACKET; } -void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) -{ +void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_LEADER); + bitStream.Write(eGameMessageType::TEAM_SET_LEADER); bitStream.Write(i64PlayerID); @@ -662,30 +791,27 @@ void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64Play SEND_PACKET; } -void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) -{ +void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_ADD_PLAYER); + bitStream.Write(eGameMessageType::TEAM_ADD_PLAYER); bitStream.Write(bIsFreeTrial); bitStream.Write(bLocal); bitStream.Write(bNoLootOnDeath); bitStream.Write(i64PlayerID); bitStream.Write(static_cast(wsPlayerName.size())); - for (const auto character : wsPlayerName) - { + for (const auto character : wsPlayerName) { bitStream.Write(character); } bitStream.Write1(); - if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) - { + if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) { zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0); } bitStream.Write(zoneID); @@ -694,17 +820,16 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria SEND_PACKET; } -void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) -{ +void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_REMOVE_PLAYER); + bitStream.Write(eGameMessageType::TEAM_REMOVE_PLAYER); bitStream.Write(bDisband); bitStream.Write(bIsKicked); @@ -713,8 +838,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband bitStream.Write(i64LeaderID); bitStream.Write(i64PlayerID); bitStream.Write(static_cast(wsPlayerName.size())); - for (const auto character : wsPlayerName) - { + for (const auto character : wsPlayerName) { bitStream.Write(character); } @@ -722,21 +846,19 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband SEND_PACKET; } -void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) -{ +void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - CMSGHEADER + CMSGHEADER; bitStream.Write(receiver->playerID); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_OFF_WORLD_FLAG); + bitStream.Write(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG); bitStream.Write(i64PlayerID); - if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) - { + if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) { zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0); } bitStream.Write(zoneID); @@ -745,7 +867,7 @@ void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i SEND_PACKET; } -void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType) { +void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend) { /*chat notification is displayed if log in / out and friend is updated in friends list [u8] - update type Update types @@ -760,76 +882,78 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla [bool] - is FTP*/ CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(friendData->playerID); //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY); bitStream.Write(notifyType); - std::string playerName = playerData->playerName.C_String(); + std::string playerName = playerData->playerName.c_str(); PacketUtils::WritePacketWString(playerName, 33, &bitStream); bitStream.Write(playerData->zoneID.GetMapID()); bitStream.Write(playerData->zoneID.GetInstanceID()); - if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID()) - { + if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID()) { bitStream.Write(0); - } - else - { + } else { bitStream.Write(playerData->zoneID.GetCloneID()); } - bitStream.Write(0); //isBFF + bitStream.Write(isBestFriend); //isBFF bitStream.Write(0); //isFTP SystemAddress sysAddr = friendData->sysAddr; SEND_PACKET; } -void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq) { +void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender) { if (!receiver || !sender) return; //Make sure people aren't requesting people that they're already friends with: for (auto fr : receiver->friends) { if (fr.friendID == sender->playerID) { + SendFriendResponse(sender, receiver, eAddFriendResponseType::ALREADYFRIEND, fr.isBestFriend); return; //we have this player as a friend, yeet this function so it doesn't send another request. } } CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST); - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); - bitStream.Write(0); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST); + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); + bitStream.Write(0); // This is a BFF flag however this is unused in live and does not have an implementation client side. SystemAddress sysAddr = receiver->sysAddr; SEND_PACKET; } -void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode) { +void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { if (!receiver || !sender) return; CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); - //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE); - bitStream.Write(responseCode); - bitStream.Write(1); //isOnline - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); - bitStream.Write(sender->playerID); - bitStream.Write(sender->zoneID); - bitStream.Write(0); //isBFF - bitStream.Write(0); //isFTP - + // Portion that will get routed: + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE); + bitStream.Write(responseCode); + // For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver. + bitStream.Write(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS); + // Then write the player name + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); + // Then if this is an acceptance code, write the following extra info. + if (responseCode == eAddFriendResponseType::ACCEPTED) { + bitStream.Write(sender->playerID); + bitStream.Write(sender->zoneID); + bitStream.Write(isBestFriendRequest); //isBFF + bitStream.Write(0); //isFTP + } SystemAddress sysAddr = receiver->sysAddr; SEND_PACKET; } @@ -838,11 +962,11 @@ void ChatPacketHandler::SendRemoveFriend(PlayerData* receiver, std::string& pers if (!receiver) return; CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); //portion that will get routed: - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_REMOVE_FRIEND_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE); bitStream.Write(isSuccessful); //isOnline PacketUtils::WritePacketWString(personToRemove, 33, &bitStream); diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index e38a65c1..f2d83502 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -4,6 +4,7 @@ #include "BitStream.h" struct PlayerData; +enum class eAddFriendResponseType : uint8_t; namespace ChatPacketHandler { void HandleFriendlistRequest(Packet* packet); @@ -31,10 +32,9 @@ namespace ChatPacketHandler { void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID); //FriendData is the player we're SENDING this stuff to. Player is the friend that changed state. - void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType); + void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend); - void SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq = false); - void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3); + void SendFriendRequest(PlayerData* receiver, PlayerData* sender); + void SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U); void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful); }; - diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 9ba3ba1b..b9fb8556 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -9,23 +9,32 @@ #include "dLogger.h" #include "Database.h" #include "dConfig.h" -#include "dMessageIdentifiers.h" #include "dChatFilter.h" #include "Diagnostics.h" - +#include "AssetManager.h" +#include "BinaryPathFinder.h" +#include "eConnectionType.h" #include "PlayerContainer.h" #include "ChatPacketHandler.h" +#include "eChatMessageType.h" +#include "eChatInternalMessageType.h" +#include "eWorldMessageType.h" #include "Game.h" -namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; - dChatFilter* chatFilter; -} //RakNet includes: #include "RakNetDefines.h" +#include + +namespace Game { + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + dChatFilter* chatFilter = nullptr; + AssetManager* assetManager = nullptr; + bool shouldShutdown = false; +} + dLogger* SetupLogger(); void HandlePacket(Packet* packet); @@ -33,43 +42,59 @@ void HandlePacket(Packet* packet); PlayerContainer playerContainer; int main(int argc, char** argv) { + constexpr uint32_t chatFramerate = mediumFramerate; + constexpr uint32_t chatFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Chat"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; - Game::logger->Log("ChatServer", "Starting Chat server...\n"); - Game::logger->Log("ChatServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); - Game::logger->Log("ChatServer", "Compiled on: %s\n", __TIMESTAMP__); + if (!Game::logger) return EXIT_FAILURE; //Read our config: - dConfig config("chatconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + + Game::logger->Log("ChatServer", "Starting Chat server..."); + Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); + Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); + + try { + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + + Game::assetManager = new AssetManager(clientPath); + } catch (std::runtime_error& ex) { + Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what()); + + return EXIT_FAILURE; + } //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); - } - catch (sql::SQLException& ex) { - Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what()); + } catch (sql::SQLException& ex) { + Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what()); Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: std::string masterIP; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -81,31 +106,32 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1501; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + uint32_t maxClients = 50; + uint32_t ourPort = 1501; + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown); - Game::chatFilter = new dChatFilter("./res/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= chatFramerate) break; //Exit our loop, shut down. - } - else framesSinceMasterDisconnect = 0; + } else framesSinceMasterDisconnect = 0; //In world we'd update our other systems here. @@ -119,17 +145,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; - } - else framesSinceLastFlush++; + } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -141,11 +166,10 @@ int main(int argc, char** argv) { delete stmt; framesSinceLastSQLPing = 0; - } - else framesSinceLastSQLPing++; + } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps" + t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps" std::this_thread::sleep_until(t); } @@ -153,13 +177,13 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } -dLogger * SetupLogger() { - std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log"; +dLogger* SetupLogger() { + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -172,32 +196,34 @@ dLogger * SetupLogger() { void HandlePacket(Packet* packet) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { - Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.\n"); + Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list."); } if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) { - Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.\n"); + Game::logger->Log("ChatServer", "A server is connecting, awaiting user list."); } - if (packet->data[1] == CHAT_INTERNAL) { - switch (packet->data[3]) { - case MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION: + if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue. + + if (static_cast(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { + switch (static_cast(packet->data[3])) { + case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION: playerContainer.InsertPlayer(packet); break; - case MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION: + case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION: playerContainer.RemovePlayer(packet); break; - case MSG_CHAT_INTERNAL_MUTE_UPDATE: + case eChatInternalMessageType::MUTE_UPDATE: playerContainer.MuteUpdate(packet); break; - case MSG_CHAT_INTERNAL_CREATE_TEAM: + case eChatInternalMessageType::CREATE_TEAM: playerContainer.CreateTeamServer(packet); break; - case MSG_CHAT_INTERNAL_ANNOUNCEMENT: { + case eChatInternalMessageType::ANNOUNCEMENT: { //we just forward this packet to every connected server CINSTREAM; Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin @@ -205,88 +231,88 @@ void HandlePacket(Packet* packet) { } default: - Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i\n", int(packet->data[3])); + Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3])); } } - if (packet->data[1] == CHAT) { - switch (packet->data[3]) { - case MSG_CHAT_GET_FRIENDS_LIST: + if (static_cast(packet->data[1]) == eConnectionType::CHAT) { + switch (static_cast(packet->data[3])) { + case eChatMessageType::GET_FRIENDS_LIST: ChatPacketHandler::HandleFriendlistRequest(packet); break; - case MSG_CHAT_GET_IGNORE_LIST: - Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.\n"); + case eChatMessageType::GET_IGNORE_LIST: + Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now."); break; - case MSG_CHAT_TEAM_GET_STATUS: + case eChatMessageType::TEAM_GET_STATUS: ChatPacketHandler::HandleTeamStatusRequest(packet); break; - case MSG_CHAT_ADD_FRIEND_REQUEST: + case eChatMessageType::ADD_FRIEND_REQUEST: //this involves someone sending the initial request, the response is below, response as in from the other player. //We basically just check to see if this player is online or not and route the packet. ChatPacketHandler::HandleFriendRequest(packet); break; - case MSG_CHAT_ADD_FRIEND_RESPONSE: + case eChatMessageType::ADD_FRIEND_RESPONSE: //This isn't the response a server sent, rather it is a player's response to a received request. //Here, we'll actually have to add them to eachother's friend lists depending on the response code. ChatPacketHandler::HandleFriendResponse(packet); break; - case MSG_CHAT_REMOVE_FRIEND: + case eChatMessageType::REMOVE_FRIEND: ChatPacketHandler::HandleRemoveFriend(packet); break; - case MSG_CHAT_GENERAL_CHAT_MESSAGE: + case eChatMessageType::GENERAL_CHAT_MESSAGE: ChatPacketHandler::HandleChatMessage(packet); break; - case MSG_CHAT_PRIVATE_CHAT_MESSAGE: + case eChatMessageType::PRIVATE_CHAT_MESSAGE: //This message is supposed to be echo'd to both the sender and the receiver //BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up. ChatPacketHandler::HandlePrivateChatMessage(packet); break; - case MSG_CHAT_TEAM_INVITE: + case eChatMessageType::TEAM_INVITE: ChatPacketHandler::HandleTeamInvite(packet); break; - case MSG_CHAT_TEAM_INVITE_RESPONSE: + case eChatMessageType::TEAM_INVITE_RESPONSE: ChatPacketHandler::HandleTeamInviteResponse(packet); break; - case MSG_CHAT_TEAM_LEAVE: + case eChatMessageType::TEAM_LEAVE: ChatPacketHandler::HandleTeamLeave(packet); break; - case MSG_CHAT_TEAM_SET_LEADER: + case eChatMessageType::TEAM_SET_LEADER: ChatPacketHandler::HandleTeamPromote(packet); break; - case MSG_CHAT_TEAM_KICK: + case eChatMessageType::TEAM_KICK: ChatPacketHandler::HandleTeamKick(packet); break; - case MSG_CHAT_TEAM_SET_LOOT: + case eChatMessageType::TEAM_SET_LOOT: ChatPacketHandler::HandleTeamLootOption(packet); break; - + default: - Game::logger->Log("ChatServer", "Unknown CHAT id: %i\n", int(packet->data[3])); + Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3])); } } - if (packet->data[1] == WORLD) { - switch (packet->data[3]) { - case MSG_WORLD_CLIENT_ROUTE_PACKET: { - printf("routing packet from world\n"); + if (static_cast(packet->data[1]) == eConnectionType::WORLD) { + switch (static_cast(packet->data[3])) { + case eWorldMessageType::ROUTE_PACKET: { + Game::logger->Log("ChatServer", "Routing packet from world"); break; } default: - Game::logger->Log("ChatServer", "Unknown World id: %i\n", int(packet->data[3])); + Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3])); } } } diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index d261b32f..689ffd77 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -6,9 +6,10 @@ #include "dLogger.h" #include "ChatPacketHandler.h" #include "GeneralUtils.h" -#include "dMessageIdentifiers.h" #include "PacketUtils.h" #include "Database.h" +#include "eConnectionType.h" +#include "eChatInternalMessageType.h" PlayerContainer::PlayerContainer() { } @@ -18,19 +19,26 @@ PlayerContainer::~PlayerContainer() { } void PlayerContainer::InsertPlayer(Packet* packet) { - CINSTREAM; + CINSTREAM_SKIP_HEADER; PlayerData* data = new PlayerData(); inStream.Read(data->playerID); - inStream.Read(data->playerID); - inStream.Read(data->playerName); + + uint32_t len; + inStream.Read(len); + + for (int i = 0; i < len; i++) { + char character; inStream.Read(character); + data->playerName += character; + } + inStream.Read(data->zoneID); inStream.Read(data->muteExpire); data->sysAddr = packet->systemAddress; - mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String())); + mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName); mPlayers.insert(std::make_pair(data->playerID, data)); - Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.C_String(), data->playerID, data->zoneID.GetMapID()); + Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID()); auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);"); @@ -43,45 +51,37 @@ void PlayerContainer::InsertPlayer(Packet* packet) { } void PlayerContainer::RemovePlayer(Packet* packet) { - CINSTREAM; + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; - inStream.Read(playerID); //skip header inStream.Read(playerID); //Before they get kicked, we need to also send a message to their friends saying that they disconnected. - auto player = this->GetPlayerData(playerID); + std::unique_ptr player(this->GetPlayerData(playerID)); if (player == nullptr) { return; } for (auto& fr : player->friends) { - //if (!fr.isOnline) continue; - auto fd = this->GetPlayerData(fr.friendID); - if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0); + if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend); } auto* team = GetTeam(playerID); - if (team != nullptr) - { - //TeamStatusUpdate(team); + if (team != nullptr) { + const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str())); - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String())); - - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = GetPlayerData(memberId); if (otherMember == nullptr) continue; - ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0}); - //ChatPacketHandler::SendTeamRemovePlayer(otherMember, false, false, true, false, team->leaderID, player->playerID, memberName); + ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 }); } } - Game::logger->Log("PlayerContainer", "Removed user: %llu\n", playerID); + Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID); mPlayers.erase(playerID); auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);"); @@ -94,20 +94,17 @@ void PlayerContainer::RemovePlayer(Packet* packet) { insertLog->executeUpdate(); } -void PlayerContainer::MuteUpdate(Packet* packet) -{ - CINSTREAM; +void PlayerContainer::MuteUpdate(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; - inStream.Read(playerID); //skip header inStream.Read(playerID); time_t expire = 0; inStream.Read(expire); auto* player = this->GetPlayerData(playerID); - if (player == nullptr) - { - Game::logger->Log("PlayerContainer", "Failed to find user: %llu\n", playerID); + if (player == nullptr) { + Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID); return; } @@ -117,11 +114,9 @@ void PlayerContainer::MuteUpdate(Packet* packet) BroadcastMuteUpdate(playerID, expire); } -void PlayerContainer::CreateTeamServer(Packet* packet) -{ - CINSTREAM; +void PlayerContainer::CreateTeamServer(Packet* packet) { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; - inStream.Read(playerID); //skip header inStream.Read(playerID); size_t membersSize = 0; inStream.Read(membersSize); @@ -130,8 +125,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet) members.reserve(membersSize); - for (size_t i = 0; i < membersSize; i++) - { + for (size_t i = 0; i < membersSize; i++) { LWOOBJID member; inStream.Read(member); members.push_back(member); @@ -140,21 +134,19 @@ void PlayerContainer::CreateTeamServer(Packet* packet) LWOZONEID zoneId; inStream.Read(zoneId); - + auto* team = CreateLocalTeam(members); - if (team != nullptr) - { + if (team != nullptr) { team->zoneId = zoneId; } UpdateTeamsOnWorld(team, false); } -void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) -{ +void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); bitStream.Write(player); bitStream.Write(time); @@ -162,30 +154,23 @@ void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); } -TeamData* PlayerContainer::CreateLocalTeam(std::vector members) -{ - if (members.empty()) - { +TeamData* PlayerContainer::CreateLocalTeam(std::vector members) { + if (members.empty()) { return nullptr; } TeamData* newTeam = nullptr; - for (const auto member : members) - { + for (const auto member : members) { auto* team = GetTeam(member); - if (team != nullptr) - { + if (team != nullptr) { RemoveMember(team, member, false, false, true); } - if (newTeam == nullptr) - { + if (newTeam == nullptr) { newTeam = CreateTeam(member, true); - } - else - { + } else { AddMember(newTeam, member); } } @@ -197,14 +182,13 @@ TeamData* PlayerContainer::CreateLocalTeam(std::vector members) return newTeam; } -TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) -{ +TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) { auto* team = new TeamData(); - + team->teamID = ++mTeamIDCounter; team->leaderID = leader; team->local = local; - + mTeams.push_back(team); AddMember(team, leader); @@ -212,20 +196,17 @@ TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) return team; } -TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) -{ - for (auto* team : mTeams) - { +TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) { + for (auto* team : mTeams) { if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue; return team; } - + return nullptr; } -void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) -{ +void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) { const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID); if (index != team->memberIDs.end()) return; @@ -237,64 +218,49 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) if (leader == nullptr || member == nullptr) return; - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String())); - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String())); + const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName); + const auto memberName = GeneralUtils::UTF8ToUTF16(member->playerName); ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName); - - /* - ChatPacketHandler::SendTeamAddPlayer(member, false, false, false, leader->playerID, leaderName, leader->zoneID); - Game::logger->Log("PlayerContainer", "Team invite successfully accepted, leader: %s, member: %s\n", leader->playerName.C_String(), member->playerName.C_String()); - */ - - if (!team->local) - { + if (!team->local) { ChatPacketHandler::SendTeamSetLeader(member, leader->playerID); - } - else - { + } else { ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY); } UpdateTeamsOnWorld(team, false); - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = GetPlayerData(memberId); if (otherMember == member) continue; const auto otherMemberName = GetName(memberId); - + ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0)); - if (otherMember != nullptr) - { + if (otherMember != nullptr) { ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID); } } } -void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent) -{ +void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent) { const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID); if (index == team->memberIDs.end()) return; auto* member = GetPlayerData(playerID); - - if (member != nullptr && !silent) - { + + if (member != nullptr && !silent) { ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY); } const auto memberName = GetName(playerID); - for (const auto memberId : team->memberIDs) - { - if (silent && memberId == playerID) - { + for (const auto memberId : team->memberIDs) { + if (silent && memberId == playerID) { continue; } @@ -309,25 +275,19 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba UpdateTeamsOnWorld(team, false); - if (team->memberIDs.size() <= 1) - { + if (team->memberIDs.size() <= 1) { DisbandTeam(team); - } - else - { - if (playerID == team->leaderID) - { + } else { + if (playerID == team->leaderID) { PromoteMember(team, team->memberIDs[0]); } } } -void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) -{ +void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) { team->leaderID = newLeader; - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = GetPlayerData(memberId); if (otherMember == nullptr) continue; @@ -336,24 +296,22 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) } } -void PlayerContainer::DisbandTeam(TeamData* team) -{ +void PlayerContainer::DisbandTeam(TeamData* team) { const auto index = std::find(mTeams.begin(), mTeams.end(), team); if (index == mTeams.end()) return; - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = GetPlayerData(memberId); if (otherMember == nullptr) continue; - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.C_String())); + const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember->playerName); ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName); } - + UpdateTeamsOnWorld(team, true); mTeams.erase(index); @@ -361,8 +319,7 @@ void PlayerContainer::DisbandTeam(TeamData* team) delete team; } -void PlayerContainer::TeamStatusUpdate(TeamData* team) -{ +void PlayerContainer::TeamStatusUpdate(TeamData* team) { const auto index = std::find(mTeams.begin(), mTeams.end(), team); if (index == mTeams.end()) return; @@ -371,41 +328,32 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) if (leader == nullptr) return; - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String())); + const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName); - for (const auto memberId : team->memberIDs) - { + for (const auto memberId : team->memberIDs) { auto* otherMember = GetPlayerData(memberId); if (otherMember == nullptr) continue; - if (!team->local) - { + if (!team->local) { ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName); } - else - { - //ChatPacketHandler::SendTeamStatus(otherMember, LWOOBJID_EMPTY, LWOZONEID(0, 0, 0), 1, 0, u""); - } } UpdateTeamsOnWorld(team, false); } -void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) -{ +void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_TEAM_UPDATE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE); bitStream.Write(team->teamID); bitStream.Write(deleteTeam); - if (!deleteTeam) - { + if (!deleteTeam) { bitStream.Write(team->lootFlag); bitStream.Write(static_cast(team->memberIDs.size())); - for (const auto memberID : team->memberIDs) - { + for (const auto memberID : team->memberIDs) { bitStream.Write(memberID); } } @@ -413,8 +361,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); } -std::u16string PlayerContainer::GetName(LWOOBJID playerID) -{ +std::u16string PlayerContainer::GetName(LWOOBJID playerID) { const auto& pair = mNames.find(playerID); if (pair == mNames.end()) return u""; @@ -422,20 +369,16 @@ std::u16string PlayerContainer::GetName(LWOOBJID playerID) return pair->second; } -LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) -{ - for (const auto& pair : mNames) - { - if (pair.second == playerName) - { +LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) { + for (const auto& pair : mNames) { + if (pair.second == playerName) { return pair.first; } } - + return LWOOBJID_EMPTY; } -bool PlayerContainer::GetIsMuted(PlayerData* data) -{ +bool PlayerContainer::GetIsMuted(PlayerData* data) { return data->muteExpire == 1 || data->muteExpire > time(NULL); } diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index dc78d3b0..0836eb59 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -9,17 +9,18 @@ struct PlayerData { LWOOBJID playerID; - RakNet::RakString playerName; + std::string playerName; SystemAddress sysAddr; LWOZONEID zoneID; std::vector friends; time_t muteExpire; + uint8_t countOfBestFriends = 0; }; struct TeamData { LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use LWOOBJID leaderID = LWOOBJID_EMPTY; - std::vector memberIDs {}; + std::vector memberIDs{}; uint8_t lootFlag = 0; bool local = false; LWOZONEID zoneId = {}; @@ -45,7 +46,7 @@ public: PlayerData* GetPlayerData(const std::string& playerName) { for (auto player : mPlayers) { if (player.second) { - std::string pn = player.second->playerName.C_String(); + std::string pn = player.second->playerName.c_str(); if (pn == playerName) return player.second; } } diff --git a/dCommon/AMFDeserialize.cpp b/dCommon/AMFDeserialize.cpp new file mode 100644 index 00000000..df4a7cb6 --- /dev/null +++ b/dCommon/AMFDeserialize.cpp @@ -0,0 +1,160 @@ +#include "AMFDeserialize.h" + +#include "AMFFormat.h" + +/** + * AMF3 Reference document https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf + * AMF3 Deserializer written by EmosewaMC + */ + +AMFValue* AMFDeserialize::Read(RakNet::BitStream* inStream) { + if (!inStream) return nullptr; + AMFValue* returnValue = nullptr; + // Read in the value type from the bitStream + int8_t marker; + inStream->Read(marker); + // Based on the typing, create the value associated with that and return the base value class + switch (marker) { + case AMFValueType::AMFUndefined: { + returnValue = new AMFUndefinedValue(); + break; + } + + case AMFValueType::AMFNull: { + returnValue = new AMFNullValue(); + break; + } + + case AMFValueType::AMFFalse: { + returnValue = new AMFFalseValue(); + break; + } + + case AMFValueType::AMFTrue: { + returnValue = new AMFTrueValue(); + break; + } + + case AMFValueType::AMFInteger: { + returnValue = ReadAmfInteger(inStream); + break; + } + + case AMFValueType::AMFDouble: { + returnValue = ReadAmfDouble(inStream); + break; + } + + case AMFValueType::AMFString: { + returnValue = ReadAmfString(inStream); + break; + } + + case AMFValueType::AMFArray: { + returnValue = ReadAmfArray(inStream); + break; + } + + // TODO We do not need these values, but if someone wants to implement them + // then please do so and add the corresponding unit tests. + case AMFValueType::AMFXMLDoc: + case AMFValueType::AMFDate: + case AMFValueType::AMFObject: + case AMFValueType::AMFXML: + case AMFValueType::AMFByteArray: + case AMFValueType::AMFVectorInt: + case AMFValueType::AMFVectorUInt: + case AMFValueType::AMFVectorDouble: + case AMFValueType::AMFVectorObject: + case AMFValueType::AMFDictionary: { + throw static_cast(marker); + break; + } + default: + throw static_cast(marker); + break; + } + return returnValue; +} + +uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) { + bool byteFlag = true; + uint32_t actualNumber{}; + uint8_t numberOfBytesRead{}; + while (byteFlag && numberOfBytesRead < 4) { + uint8_t byte{}; + inStream->Read(byte); + // Parse the byte + if (numberOfBytesRead < 3) { + byteFlag = byte & static_cast(1 << 7); + byte = byte << 1UL; + } + // Combine the read byte with our current read in number + actualNumber <<= 8UL; + actualNumber |= static_cast(byte); + // If we are not done reading in bytes, shift right 1 bit + if (numberOfBytesRead < 3) actualNumber = actualNumber >> 1UL; + numberOfBytesRead++; + } + return actualNumber; +} + +std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) { + auto length = ReadU29(inStream); + // Check if this is a reference + bool isReference = length % 2 == 1; + // Right shift by 1 bit to get index if reference or size of next string if value + length = length >> 1; + if (isReference) { + std::string value(length, 0); + inStream->Read(&value[0], length); + // Empty strings are never sent by reference + if (!value.empty()) accessedElements.push_back(value); + return value; + } else { + // Length is a reference to a previous index - use that as the read in value + return accessedElements[length]; + } +} + +AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) { + auto doubleValue = new AMFDoubleValue(); + double value; + inStream->Read(value); + doubleValue->SetDoubleValue(value); + return doubleValue; +} + +AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) { + auto arrayValue = new AMFArrayValue(); + + // Read size of dense array + auto sizeOfDenseArray = (ReadU29(inStream) >> 1); + + // Then read Key'd portion + while (true) { + auto key = ReadString(inStream); + // No more values when we encounter an empty string + if (key.size() == 0) break; + arrayValue->InsertValue(key, Read(inStream)); + } + + // Finally read dense portion + for (uint32_t i = 0; i < sizeOfDenseArray; i++) { + arrayValue->PushBackValue(Read(inStream)); + } + + return arrayValue; +} + +AMFValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) { + auto stringValue = new AMFStringValue(); + stringValue->SetStringValue(ReadString(inStream)); + return stringValue; +} + +AMFValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) { + auto integerValue = new AMFIntegerValue(); + integerValue->SetIntegerValue(ReadU29(inStream)); + return integerValue; +} diff --git a/dCommon/AMFDeserialize.h b/dCommon/AMFDeserialize.h new file mode 100644 index 00000000..a49cdcd2 --- /dev/null +++ b/dCommon/AMFDeserialize.h @@ -0,0 +1,71 @@ +#pragma once + +#include "BitStream.h" + +#include +#include + +class AMFValue; +class AMFDeserialize { +public: + /** + * Read an AMF3 value from a bitstream. + * + * @param inStream inStream to read value from. + * @return Returns an AMFValue with all the information from the bitStream in it. + */ + AMFValue* Read(RakNet::BitStream* inStream); +private: + /** + * @brief Private method to read a U29 integer from a bitstream + * + * @param inStream bitstream to read data from + * @return The number as an unsigned 29 bit integer + */ + uint32_t ReadU29(RakNet::BitStream* inStream); + + /** + * @brief Reads a string from a bitstream + * + * @param inStream bitStream to read data from + * @return The read string + */ + std::string ReadString(RakNet::BitStream* inStream); + + /** + * @brief Read an AMFDouble value from a bitStream + * + * @param inStream bitStream to read data from + * @return Double value represented as an AMFValue + */ + AMFValue* ReadAmfDouble(RakNet::BitStream* inStream); + + /** + * @brief Read an AMFArray from a bitStream + * + * @param inStream bitStream to read data from + * @return Array value represented as an AMFValue + */ + AMFValue* ReadAmfArray(RakNet::BitStream* inStream); + + /** + * @brief Read an AMFString from a bitStream + * + * @param inStream bitStream to read data from + * @return String value represented as an AMFValue + */ + AMFValue* ReadAmfString(RakNet::BitStream* inStream); + + /** + * @brief Read an AMFInteger from a bitStream + * + * @param inStream bitStream to read data from + * @return Integer value represented as an AMFValue + */ + AMFValue* ReadAmfInteger(RakNet::BitStream* inStream); + + /** + * List of strings read so far saved to be read by reference. + */ + std::vector accessedElements; +}; diff --git a/dCommon/AMFFormat.cpp b/dCommon/AMFFormat.cpp index d4cf6531..4407b29c 100644 --- a/dCommon/AMFFormat.cpp +++ b/dCommon/AMFFormat.cpp @@ -2,156 +2,155 @@ // AMFInteger void AMFIntegerValue::SetIntegerValue(uint32_t value) { - this->value = value; + this->value = value; } uint32_t AMFIntegerValue::GetIntegerValue() { - return this->value; + return this->value; } // AMFDouble void AMFDoubleValue::SetDoubleValue(double value) { - this->value = value; + this->value = value; } double AMFDoubleValue::GetDoubleValue() { - return this->value; + return this->value; } // AMFString void AMFStringValue::SetStringValue(const std::string& value) { - this->value = value; + this->value = value; } std::string AMFStringValue::GetStringValue() { - return this->value; + return this->value; } // AMFXMLDoc void AMFXMLDocValue::SetXMLDocValue(const std::string& value) { - this->xmlData = value; + this->xmlData = value; } std::string AMFXMLDocValue::GetXMLDocValue() { - return this->xmlData; + return this->xmlData; } // AMFDate void AMFDateValue::SetDateValue(uint64_t value) { - this->millisecondTimestamp = value; + this->millisecondTimestamp = value; } uint64_t AMFDateValue::GetDateValue() { - return this->millisecondTimestamp; + return this->millisecondTimestamp; } // AMFArray Insert Value void AMFArrayValue::InsertValue(const std::string& key, AMFValue* value) { - this->associative.insert(std::make_pair(key, value)); + this->associative.insert(std::make_pair(key, value)); } // AMFArray Remove Value void AMFArrayValue::RemoveValue(const std::string& key) { - _AMFArrayMap_::iterator it = this->associative.find(key); - if (it != this->associative.end()) { - this->associative.erase(it); - } -} - -// AMFArray Find Value -AMFValue* AMFArrayValue::FindValue(const std::string& key) { - _AMFArrayMap_::iterator it = this->associative.find(key); - if (it != this->associative.end()) { - return it->second; - } - - return nullptr; + _AMFArrayMap_::iterator it = this->associative.find(key); + if (it != this->associative.end()) { + this->associative.erase(it); + } } // AMFArray Get Associative Iterator Begin _AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() { - return this->associative.begin(); + return this->associative.begin(); } // AMFArray Get Associative Iterator End _AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueEnd() { - return this->associative.end(); + return this->associative.end(); } // AMFArray Push Back Value void AMFArrayValue::PushBackValue(AMFValue* value) { - this->dense.push_back(value); + this->dense.push_back(value); } // AMFArray Pop Back Value void AMFArrayValue::PopBackValue() { - this->dense.pop_back(); + this->dense.pop_back(); } // AMFArray Get Dense List Size uint32_t AMFArrayValue::GetDenseValueSize() { - return (uint32_t)this->dense.size(); -} - -// AMFArray Get value at index in Dense List -AMFValue* AMFArrayValue::GetValueAt(uint32_t index) { - return this->dense.at(index); + return (uint32_t)this->dense.size(); } // AMFArray Get Dense Iterator Begin _AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() { - return this->dense.begin(); + return this->dense.begin(); } // AMFArray Get Dense Iterator End _AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() { - return this->dense.end(); + return this->dense.end(); } +AMFArrayValue::~AMFArrayValue() { + for (auto valueToDelete : GetDenseArray()) { + if (valueToDelete) delete valueToDelete; + } + for (auto valueToDelete : GetAssociativeMap()) { + if (valueToDelete.second) delete valueToDelete.second; + } +} // AMFObject Constructor AMFObjectValue::AMFObjectValue(std::vector> traits) { - this->traits.reserve(traits.size()); - std::vector>::iterator it = traits.begin(); - while (it != traits.end()) { - this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue()))); - it++; - } + this->traits.reserve(traits.size()); + std::vector>::iterator it = traits.begin(); + while (it != traits.end()) { + this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue()))); + it++; + } } // AMFObject Set Value void AMFObjectValue::SetTraitValue(const std::string& trait, AMFValue* value) { - if (value) { - _AMFObjectTraits_::iterator it = this->traits.find(trait); - if (it != this->traits.end()) { - if (it->second.first == value->GetValueType()) { - it->second.second = value; - } - } - } + if (value) { + _AMFObjectTraits_::iterator it = this->traits.find(trait); + if (it != this->traits.end()) { + if (it->second.first == value->GetValueType()) { + it->second.second = value; + } + } + } } // AMFObject Get Value AMFValue* AMFObjectValue::GetTraitValue(const std::string& trait) { - _AMFObjectTraits_::iterator it = this->traits.find(trait); - if (it != this->traits.end()) { - return it->second.second; - } - - return nullptr; + _AMFObjectTraits_::iterator it = this->traits.find(trait); + if (it != this->traits.end()) { + return it->second.second; + } + + return nullptr; } // AMFObject Get Trait Iterator Begin _AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorBegin() { - return this->traits.begin(); + return this->traits.begin(); } // AMFObject Get Trait Iterator End _AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() { - return this->traits.end(); + return this->traits.end(); } // AMFObject Get Trait Size uint32_t AMFObjectValue::GetTraitArrayCount() { - return (uint32_t)this->traits.size(); + return (uint32_t)this->traits.size(); +} + +AMFObjectValue::~AMFObjectValue() { + for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) { + if (valueToDelete->second.second) delete valueToDelete->second.second; + } } diff --git a/dCommon/AMFFormat.h b/dCommon/AMFFormat.h index 95863594..6e479ef6 100644 --- a/dCommon/AMFFormat.h +++ b/dCommon/AMFFormat.h @@ -23,42 +23,43 @@ class AMFValue; // Forward declaration //! An enum for each AMF value type enum AMFValueType : unsigned char { - AMFUndefined = 0x00, //!< An undefined AMF Value - AMFNull = 0x01, //!< A null AMF value - AMFFalse = 0x02, //!< A false AMF value - AMFTrue = 0x03, //!< A true AMF value - AMFInteger = 0x04, //!< An integer AMF value - AMFDouble = 0x05, //!< A double AMF value - AMFString = 0x06, //!< A string AMF value - AMFXMLDoc = 0x07, //!< An XML Doc AMF value - AMFDate = 0x08, //!< A date AMF value - AMFArray = 0x09, //!< An array AMF value - AMFObject = 0x0A, //!< An object AMF value - AMFXML = 0x0B, //!< An XML AMF value - AMFByteArray = 0x0C, //!< A byte array AMF value - AMFVectorInt = 0x0D, //!< An integer vector AMF value - AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value - AMFVectorDouble = 0x0F, //!< A double vector AMF value - AMFVectorObject = 0x10, //!< An object vector AMF value - AMFDictionary = 0x11 //!< A dictionary AMF value + AMFUndefined = 0x00, //!< An undefined AMF Value + AMFNull = 0x01, //!< A null AMF value + AMFFalse = 0x02, //!< A false AMF value + AMFTrue = 0x03, //!< A true AMF value + AMFInteger = 0x04, //!< An integer AMF value + AMFDouble = 0x05, //!< A double AMF value + AMFString = 0x06, //!< A string AMF value + AMFXMLDoc = 0x07, //!< An XML Doc AMF value + AMFDate = 0x08, //!< A date AMF value + AMFArray = 0x09, //!< An array AMF value + AMFObject = 0x0A, //!< An object AMF value + AMFXML = 0x0B, //!< An XML AMF value + AMFByteArray = 0x0C, //!< A byte array AMF value + AMFVectorInt = 0x0D, //!< An integer vector AMF value + AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value + AMFVectorDouble = 0x0F, //!< A double vector AMF value + AMFVectorObject = 0x10, //!< An object vector AMF value + AMFDictionary = 0x11 //!< A dictionary AMF value }; //! An enum for the object value types enum AMFObjectValueType : unsigned char { - AMFObjectAnonymous = 0x01, - AMFObjectTyped = 0x02, - AMFObjectDynamic = 0x03, - AMFObjectExternalizable = 0x04 + AMFObjectAnonymous = 0x01, + AMFObjectTyped = 0x02, + AMFObjectDynamic = 0x03, + AMFObjectExternalizable = 0x04 }; //! The base AMF value class class AMFValue { public: - //! Returns the AMF value type - /*! - \return The AMF value type - */ - virtual AMFValueType GetValueType() = 0; + //! Returns the AMF value type + /*! + \return The AMF value type + */ + virtual AMFValueType GetValueType() = 0; + virtual ~AMFValue() {}; }; //! A typedef for a pointer to an AMF value @@ -70,299 +71,343 @@ typedef AMFValue* NDGFxValue; //! The undefined value AMF type class AMFUndefinedValue : public AMFValue { private: - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFUndefined; } + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } +public: + static const AMFValueType ValueType = AMFUndefined; }; //! The null value AMF type class AMFNullValue : public AMFValue { private: - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFNull; } + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } +public: + static const AMFValueType ValueType = AMFNull; }; //! The false value AMF type class AMFFalseValue : public AMFValue { private: - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFFalse; } + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } +public: + static const AMFValueType ValueType = AMFFalse; }; //! The true value AMF type class AMFTrueValue : public AMFValue { private: - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFTrue; } + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } +public: + static const AMFValueType ValueType = AMFTrue; }; //! The integer value AMF type class AMFIntegerValue : public AMFValue { private: - uint32_t value; //!< The value of the AMF type - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFInteger; } - + uint32_t value; //!< The value of the AMF type + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } + public: - //! Sets the integer value - /*! - \param value The value to set - */ - void SetIntegerValue(uint32_t value); - - //! Gets the integer value - /*! - \return The integer value - */ - uint32_t GetIntegerValue(); + static const AMFValueType ValueType = AMFInteger; + //! Sets the integer value + /*! + \param value The value to set + */ + void SetIntegerValue(uint32_t value); + + //! Gets the integer value + /*! + \return The integer value + */ + uint32_t GetIntegerValue(); }; //! The double value AMF type class AMFDoubleValue : public AMFValue { private: - double value; //!< The value of the AMF type - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFDouble; } - + double value; //!< The value of the AMF type + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } + public: - //! Sets the double value - /*! - \param value The value to set to - */ - void SetDoubleValue(double value); - - //! Gets the double value - /*! - \return The double value - */ - double GetDoubleValue(); + static const AMFValueType ValueType = AMFDouble; + //! Sets the double value + /*! + \param value The value to set to + */ + void SetDoubleValue(double value); + + //! Gets the double value + /*! + \return The double value + */ + double GetDoubleValue(); }; //! The string value AMF type class AMFStringValue : public AMFValue { private: - std::string value; //!< The value of the AMF type - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFString; } - + std::string value; //!< The value of the AMF type + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } + public: - //! Sets the string value - /*! - \param value The string value to set to - */ - void SetStringValue(const std::string& value); - - //! Gets the string value - /*! - \return The string value - */ - std::string GetStringValue(); + static const AMFValueType ValueType = AMFString; + //! Sets the string value + /*! + \param value The string value to set to + */ + void SetStringValue(const std::string& value); + + //! Gets the string value + /*! + \return The string value + */ + std::string GetStringValue(); }; //! The XML doc value AMF type class AMFXMLDocValue : public AMFValue { private: - std::string xmlData; //!< The value of the AMF type - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFXMLDoc; } - + std::string xmlData; //!< The value of the AMF type + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } + public: - //! Sets the XML Doc value - /*! - \param value The value to set to - */ - void SetXMLDocValue(const std::string& value); - - //! Gets the XML Doc value - /*! - \return The XML Doc value - */ - std::string GetXMLDocValue(); + static const AMFValueType ValueType = AMFXMLDoc; + //! Sets the XML Doc value + /*! + \param value The value to set to + */ + void SetXMLDocValue(const std::string& value); + + //! Gets the XML Doc value + /*! + \return The XML Doc value + */ + std::string GetXMLDocValue(); }; //! The date value AMF type class AMFDateValue : public AMFValue { private: - uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFDate; } - + uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() { return ValueType; } + public: - //! Sets the date time - /*! - \param value The value to set to - */ - void SetDateValue(uint64_t value); - - //! Gets the date value - /*! - \return The date value in milliseconds since the epoch - */ - uint64_t GetDateValue(); + static const AMFValueType ValueType = AMFDate; + //! Sets the date time + /*! + \param value The value to set to + */ + void SetDateValue(uint64_t value); + + //! Gets the date value + /*! + \return The date value in milliseconds since the epoch + */ + uint64_t GetDateValue(); }; //! The array value AMF type +// This object will manage it's own memory map and list. Do not delete its values. class AMFArrayValue : public AMFValue { private: - _AMFArrayMap_ associative; //!< The array map (associative part) - _AMFArrayList_ dense; //!< The array list (dense part) - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFArray; } - + _AMFArrayMap_ associative; //!< The array map (associative part) + _AMFArrayList_ dense; //!< The array list (dense part) + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() override { return ValueType; } + public: - //! Inserts an item into the array map for a specific key - /*! - \param key The key to set - \param value The value to add - */ - void InsertValue(const std::string& key, AMFValue* value); - - //! Removes an item for a specific key - /*! - \param key The key to remove - */ - void RemoveValue(const std::string& key); - - //! Finds an AMF value - /*! - \return The AMF value if found, nullptr otherwise - */ - AMFValue* FindValue(const std::string& key); - - //! Returns where the associative iterator begins - /*! - \return Where the array map iterator begins - */ - _AMFArrayMap_::iterator GetAssociativeIteratorValueBegin(); - - //! Returns where the associative iterator ends - /*! - \return Where the array map iterator ends - */ - _AMFArrayMap_::iterator GetAssociativeIteratorValueEnd(); - - //! Pushes back a value into the array list - /*! - \param value The value to push back - */ - void PushBackValue(AMFValue* value); - - //! Pops back the last value in the array list - void PopBackValue(); - - //! Gets the count of the dense list - /*! - \return The dense list size - */ - uint32_t GetDenseValueSize(); - - //! Gets a specific value from the list for the specified index - /*! - \param index The index to get - */ - AMFValue* GetValueAt(uint32_t index); - - //! Returns where the dense iterator begins - /*! - \return Where the iterator begins - */ - _AMFArrayList_::iterator GetDenseIteratorBegin(); - - //! Returns where the dense iterator ends - /*! - \return Where the iterator ends - */ - _AMFArrayList_::iterator GetDenseIteratorEnd(); + static const AMFValueType ValueType = AMFArray; + + ~AMFArrayValue() override; + //! Inserts an item into the array map for a specific key + /*! + \param key The key to set + \param value The value to add + */ + void InsertValue(const std::string& key, AMFValue* value); + + //! Removes an item for a specific key + /*! + \param key The key to remove + */ + void RemoveValue(const std::string& key); + + //! Finds an AMF value + /*! + \return The AMF value if found, nullptr otherwise + */ + template + T* FindValue(const std::string& key) const { + _AMFArrayMap_::const_iterator it = this->associative.find(key); + if (it != this->associative.end() && T::ValueType == it->second->GetValueType()) { + return dynamic_cast(it->second); + } + + return nullptr; + }; + + //! Returns where the associative iterator begins + /*! + \return Where the array map iterator begins + */ + _AMFArrayMap_::iterator GetAssociativeIteratorValueBegin(); + + //! Returns where the associative iterator ends + /*! + \return Where the array map iterator ends + */ + _AMFArrayMap_::iterator GetAssociativeIteratorValueEnd(); + + //! Pushes back a value into the array list + /*! + \param value The value to push back + */ + void PushBackValue(AMFValue* value); + + //! Pops back the last value in the array list + void PopBackValue(); + + //! Gets the count of the dense list + /*! + \return The dense list size + */ + uint32_t GetDenseValueSize(); + + //! Gets a specific value from the list for the specified index + /*! + \param index The index to get + */ + template + T* GetValueAt(uint32_t index) { + if (index >= this->dense.size()) return nullptr; + AMFValue* foundValue = this->dense.at(index); + return T::ValueType == foundValue->GetValueType() ? dynamic_cast(foundValue) : nullptr; + }; + + //! Returns where the dense iterator begins + /*! + \return Where the iterator begins + */ + _AMFArrayList_::iterator GetDenseIteratorBegin(); + + //! Returns where the dense iterator ends + /*! + \return Where the iterator ends + */ + _AMFArrayList_::iterator GetDenseIteratorEnd(); + + //! Returns the associative map + /*! + \return The associative map + */ + _AMFArrayMap_ GetAssociativeMap() { return this->associative; }; + + //! Returns the dense array + /*! + \return The dense array + */ + _AMFArrayList_ GetDenseArray() { return this->dense; }; }; //! The anonymous object value AMF type class AMFObjectValue : public AMFValue { private: - _AMFObjectTraits_ traits; //!< The object traits - - //! Returns the AMF value type - /*! - \return The AMF value type - */ - AMFValueType GetValueType() { return AMFObject; } - + _AMFObjectTraits_ traits; //!< The object traits + + //! Returns the AMF value type + /*! + \return The AMF value type + */ + AMFValueType GetValueType() override { return ValueType; } + ~AMFObjectValue() override; + public: - //! Constructor - /*! - \param traits The traits to set - */ - AMFObjectValue(std::vector> traits); - - //! Gets the object value type - /*! - \return The object value type - */ - virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; } - - //! Sets the value of a trait - /*! - \param trait The trait to set the value for - \param value The AMF value to set - */ - void SetTraitValue(const std::string& trait, AMFValue* value); - - //! Gets a trait value - /*! - \param trait The trait to get the value for - \return The trait value - */ - AMFValue* GetTraitValue(const std::string& trait); - - //! Gets the beginning of the object traits iterator - /*! - \return The AMF trait array iterator begin - */ - _AMFObjectTraits_::iterator GetTraitsIteratorBegin(); - - //! Gets the end of the object traits iterator - /*! - \return The AMF trait array iterator begin - */ - _AMFObjectTraits_::iterator GetTraitsIteratorEnd(); - - //! Gets the amount of traits - /*! - \return The amount of traits - */ - uint32_t GetTraitArrayCount(); + static const AMFValueType ValueType = AMFObject; + //! Constructor + /*! + \param traits The traits to set + */ + AMFObjectValue(std::vector> traits); + + //! Gets the object value type + /*! + \return The object value type + */ + virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; } + + //! Sets the value of a trait + /*! + \param trait The trait to set the value for + \param value The AMF value to set + */ + void SetTraitValue(const std::string& trait, AMFValue* value); + + //! Gets a trait value + /*! + \param trait The trait to get the value for + \return The trait value + */ + AMFValue* GetTraitValue(const std::string& trait); + + //! Gets the beginning of the object traits iterator + /*! + \return The AMF trait array iterator begin + */ + _AMFObjectTraits_::iterator GetTraitsIteratorBegin(); + + //! Gets the end of the object traits iterator + /*! + \return The AMF trait array iterator begin + */ + _AMFObjectTraits_::iterator GetTraitsIteratorEnd(); + + //! Gets the amount of traits + /*! + \return The amount of traits + */ + uint32_t GetTraitArrayCount(); }; diff --git a/dCommon/AMFFormat_BitStream.cpp b/dCommon/AMFFormat_BitStream.cpp index 57497951..dcb9197d 100644 --- a/dCommon/AMFFormat_BitStream.cpp +++ b/dCommon/AMFFormat_BitStream.cpp @@ -3,269 +3,257 @@ // Writes an AMFValue pointer to a RakNet::BitStream template<> void RakNet::BitStream::Write(AMFValue* value) { - if (value != nullptr) { - AMFValueType type = value->GetValueType(); - - switch (type) { - case AMFUndefined: { - AMFUndefinedValue* v = (AMFUndefinedValue*)value; - this->Write(*v); - break; - } - - case AMFNull: { - AMFNullValue* v = (AMFNullValue*)value; - this->Write(*v); - break; - } - - case AMFFalse: { - AMFFalseValue* v = (AMFFalseValue*)value; - this->Write(*v); - break; - } - - case AMFTrue: { - AMFTrueValue* v = (AMFTrueValue*)value; - this->Write(*v); - break; - } - - case AMFInteger: { - AMFIntegerValue* v = (AMFIntegerValue*)value; - this->Write(*v); - break; - } - - case AMFString: { - AMFStringValue* v = (AMFStringValue*)value; - this->Write(*v); - break; - } - - case AMFXMLDoc: { - AMFXMLDocValue* v = (AMFXMLDocValue*)value; - this->Write(*v); - break; - } - - case AMFDate: { - AMFDateValue* v = (AMFDateValue*)value; - this->Write(*v); - break; - } - - case AMFArray: { - AMFArrayValue* v = (AMFArrayValue*)value; - this->Write(*v); - break; - } - } - } + if (value != nullptr) { + AMFValueType type = value->GetValueType(); + + switch (type) { + case AMFUndefined: { + AMFUndefinedValue* v = (AMFUndefinedValue*)value; + this->Write(*v); + break; + } + + case AMFNull: { + AMFNullValue* v = (AMFNullValue*)value; + this->Write(*v); + break; + } + + case AMFFalse: { + AMFFalseValue* v = (AMFFalseValue*)value; + this->Write(*v); + break; + } + + case AMFTrue: { + AMFTrueValue* v = (AMFTrueValue*)value; + this->Write(*v); + break; + } + + case AMFInteger: { + AMFIntegerValue* v = (AMFIntegerValue*)value; + this->Write(*v); + break; + } + + case AMFDouble: { + AMFDoubleValue* v = (AMFDoubleValue*)value; + this->Write(*v); + break; + } + + case AMFString: { + AMFStringValue* v = (AMFStringValue*)value; + this->Write(*v); + break; + } + + case AMFXMLDoc: { + AMFXMLDocValue* v = (AMFXMLDocValue*)value; + this->Write(*v); + break; + } + + case AMFDate: { + AMFDateValue* v = (AMFDateValue*)value; + this->Write(*v); + break; + } + + case AMFArray: { + this->Write((AMFArrayValue*)value); + break; + } + case AMFObject: + case AMFXML: + case AMFByteArray: + case AMFVectorInt: + case AMFVectorUInt: + case AMFVectorDouble: + case AMFVectorObject: + case AMFDictionary: + break; + } + } } -// A private function to write an value to a RakNet::BitStream +/** + * A private function to write an value to a RakNet::BitStream + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { - unsigned char b4 = (unsigned char)v; - if (v < 0x00200000) { - b4 = b4 & 0x7F; - if (v > 0x7F) { - unsigned char b3; - v = v >> 7; - b3 = ((unsigned char)(v)) | 0x80; - if (v > 0x7F) { - unsigned char b2; - v = v >> 7; - b2 = ((unsigned char)(v)) | 0x80; - bs->Write(b2); - } - - bs->Write(b3); - } - } else { - unsigned char b1; - unsigned char b2; - unsigned char b3; - - v = v >> 8; - b3 = ((unsigned char)(v)) | 0x80; - v = v >> 7; - b2 = ((unsigned char)(v)) | 0x80; - v = v >> 7; - b1 = ((unsigned char)(v)) | 0x80; - - bs->Write(b1); - bs->Write(b2); - bs->Write(b3); - } - - bs->Write(b4); + unsigned char b4 = (unsigned char)v; + if (v < 0x00200000) { + b4 = b4 & 0x7F; + if (v > 0x7F) { + unsigned char b3; + v = v >> 7; + b3 = ((unsigned char)(v)) | 0x80; + if (v > 0x7F) { + unsigned char b2; + v = v >> 7; + b2 = ((unsigned char)(v)) | 0x80; + bs->Write(b2); + } + + bs->Write(b3); + } + } else { + unsigned char b1; + unsigned char b2; + unsigned char b3; + + v = v >> 8; + b3 = ((unsigned char)(v)) | 0x80; + v = v >> 7; + b2 = ((unsigned char)(v)) | 0x80; + v = v >> 7; + b1 = ((unsigned char)(v)) | 0x80; + + bs->Write(b1); + bs->Write(b2); + bs->Write(b3); + } + + bs->Write(b4); } -// Writes a flag number to a RakNet::BitStream +/** + * Writes a flag number to a RakNet::BitStream + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) { - v = (v << 1) | 0x01; - WriteUInt29(bs, v); + v = (v << 1) | 0x01; + WriteUInt29(bs, v); } -// Writes an AMFString to a RakNet::BitStream +/** + * Writes an AMFString to a RakNet::BitStream + * + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteAMFString(RakNet::BitStream* bs, const std::string& str) { - WriteFlagNumber(bs, (uint32_t)str.size()); - bs->Write(str.c_str(), (uint32_t)str.size()); + WriteFlagNumber(bs, (uint32_t)str.size()); + bs->Write(str.c_str(), (uint32_t)str.size()); } -// Writes an AMF U16 to a RakNet::BitStream +/** + * Writes an U16 to a bitstream + * + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) { - unsigned char b2; - b2 = (unsigned char)value; - value = value >> 8; - bs->Write((unsigned char)value); - bs->Write(b2); + bs->Write(value); } -// Writes an AMF U32 to RakNet::BitStream +/** + * Writes an U32 to a bitstream + * + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) { - unsigned char b2; - unsigned char b3; - unsigned char b4; - - b4 = (unsigned char)value; - value = value >> 8; - b3 = (unsigned char)value; - value = value >> 8; - b2 = (unsigned char)value; - value = value >> 8; - - bs->Write((unsigned char)value); - bs->Write(b2); - bs->Write(b3); - bs->Write(b4); + bs->Write(value); } -// Writes an AMF U64 to RakNet::BitStream +/** + * Writes an U64 to a bitstream + * + * RakNet writes in the correct byte order - do not reverse this. + */ void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) { - unsigned char b2; - unsigned char b3; - unsigned char b4; - unsigned char b5; - unsigned char b6; - unsigned char b7; - unsigned char b8; - - b8 = (unsigned char)value; - value = value >> 8; - b7 = (unsigned char)value; - value = value >> 8; - b6 = (unsigned char)value; - value = value >> 8; - b5 = (unsigned char)value; - value = value >> 8; - b4 = (unsigned char)value; - value = value >> 8; - b3 = (unsigned char)value; - value = value >> 8; - b2 = (unsigned char)value; - value = value >> 8; - - bs->Write((unsigned char)value); - bs->Write(b2); - bs->Write(b3); - bs->Write(b4); - bs->Write(b5); - bs->Write(b6); - bs->Write(b7); - bs->Write(b8); + bs->Write(value); } // Writes an AMFUndefinedValue to BitStream template<> void RakNet::BitStream::Write(AMFUndefinedValue value) { - this->Write(AMFUndefined); + this->Write(AMFUndefined); } // Writes an AMFNullValue to BitStream template<> void RakNet::BitStream::Write(AMFNullValue value) { - this->Write(AMFNull); + this->Write(AMFNull); } // Writes an AMFFalseValue to BitStream template<> void RakNet::BitStream::Write(AMFFalseValue value) { - this->Write(AMFFalse); + this->Write(AMFFalse); } // Writes an AMFTrueValue to BitStream template<> void RakNet::BitStream::Write(AMFTrueValue value) { - this->Write(AMFTrue); + this->Write(AMFTrue); } // Writes an AMFIntegerValue to BitStream template<> void RakNet::BitStream::Write(AMFIntegerValue value) { - this->Write(AMFInteger); - WriteUInt29(this, value.GetIntegerValue()); + this->Write(AMFInteger); + WriteUInt29(this, value.GetIntegerValue()); } // Writes an AMFDoubleValue to BitStream template<> void RakNet::BitStream::Write(AMFDoubleValue value) { - this->Write(AMFDouble); - double d = value.GetDoubleValue(); - WriteAMFU64(this, *((unsigned long long*)&d)); + this->Write(AMFDouble); + double d = value.GetDoubleValue(); + WriteAMFU64(this, *((unsigned long long*) & d)); } // Writes an AMFStringValue to BitStream template<> void RakNet::BitStream::Write(AMFStringValue value) { - this->Write(AMFString); - std::string v = value.GetStringValue(); - WriteAMFString(this, v); + this->Write(AMFString); + std::string v = value.GetStringValue(); + WriteAMFString(this, v); } // Writes an AMFXMLDocValue to BitStream template<> void RakNet::BitStream::Write(AMFXMLDocValue value) { - this->Write(AMFXMLDoc); - std::string v = value.GetXMLDocValue(); - WriteAMFString(this, v); + this->Write(AMFXMLDoc); + std::string v = value.GetXMLDocValue(); + WriteAMFString(this, v); } // Writes an AMFDateValue to BitStream template<> void RakNet::BitStream::Write(AMFDateValue value) { - this->Write(AMFDate); - uint64_t date = value.GetDateValue(); - WriteAMFU64(this, date); + this->Write(AMFDate); + uint64_t date = value.GetDateValue(); + WriteAMFU64(this, date); } // Writes an AMFArrayValue to BitStream template<> -void RakNet::BitStream::Write(AMFArrayValue value) { - this->Write(AMFArray); - uint32_t denseSize = value.GetDenseValueSize(); - WriteFlagNumber(this, denseSize); - - _AMFArrayMap_::iterator it = value.GetAssociativeIteratorValueBegin(); - _AMFArrayMap_::iterator end = value.GetAssociativeIteratorValueEnd(); - - while (it != end) { - WriteAMFString(this, it->first); - this->Write(it->second); - it++; - } - - this->Write(AMFNull); - - if (denseSize > 0) { - _AMFArrayList_::iterator it2 = value.GetDenseIteratorBegin(); - _AMFArrayList_::iterator end2 = value.GetDenseIteratorEnd(); - - while (it2 != end2) { - this->Write(*it2); - it2++; - } - } +void RakNet::BitStream::Write(AMFArrayValue* value) { + this->Write(AMFArray); + uint32_t denseSize = value->GetDenseValueSize(); + WriteFlagNumber(this, denseSize); + + _AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin(); + _AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd(); + + while (it != end) { + WriteAMFString(this, it->first); + this->Write(it->second); + it++; + } + + this->Write(AMFNull); + + if (denseSize > 0) { + _AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin(); + _AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd(); + + while (it2 != end2) { + this->Write(*it2); + it2++; + } + } } diff --git a/dCommon/AMFFormat_BitStream.h b/dCommon/AMFFormat_BitStream.h index 69dd0896..caa49337 100644 --- a/dCommon/AMFFormat_BitStream.h +++ b/dCommon/AMFFormat_BitStream.h @@ -7,86 +7,86 @@ #include /*! - \file AMFBitStream.hpp - \brief A class that implements native writing of AMF values to RakNet::BitStream + \file AMFFormat_BitStream.h + \brief A class that implements native writing of AMF values to RakNet::BitStream */ -// We are using the RakNet namespace + // We are using the RakNet namespace namespace RakNet { - //! Writes an AMFValue pointer to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFValue* value); - - //! Writes an AMFUndefinedValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFUndefinedValue value); - - //! Writes an AMFNullValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFNullValue value); - - //! Writes an AMFFalseValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFFalseValue value); - - //! Writes an AMFTrueValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFTrueValue value); - - //! Writes an AMFIntegerValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFIntegerValue value); - - //! Writes an AMFDoubleValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFDoubleValue value); - - //! Writes an AMFStringValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFStringValue value); - - //! Writes an AMFXMLDocValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFXMLDocValue value); - - //! Writes an AMFDateValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFDateValue value); - - //! Writes an AMFArrayValue to a RakNet::BitStream - /*! - \param value The value to write - */ - template<> - void RakNet::BitStream::Write(AMFArrayValue value); -} + //! Writes an AMFValue pointer to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFValue* value); + + //! Writes an AMFUndefinedValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFUndefinedValue value); + + //! Writes an AMFNullValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFNullValue value); + + //! Writes an AMFFalseValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFFalseValue value); + + //! Writes an AMFTrueValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFTrueValue value); + + //! Writes an AMFIntegerValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFIntegerValue value); + + //! Writes an AMFDoubleValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFDoubleValue value); + + //! Writes an AMFStringValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFStringValue value); + + //! Writes an AMFXMLDocValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFXMLDocValue value); + + //! Writes an AMFDateValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFDateValue value); + + //! Writes an AMFArrayValue to a RakNet::BitStream + /*! + \param value The value to write + */ + template <> + void RakNet::BitStream::Write(AMFArrayValue* value); +} // namespace RakNet diff --git a/dCommon/BinaryIO.cpp b/dCommon/BinaryIO.cpp index 8cad23a6..22e4de60 100644 --- a/dCommon/BinaryIO.cpp +++ b/dCommon/BinaryIO.cpp @@ -10,7 +10,7 @@ void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outs } //For reading null-terminated strings -std::string BinaryIO::ReadString(std::ifstream & instream) { +std::string BinaryIO::ReadString(std::istream& instream) { std::string toReturn; char buffer; @@ -25,7 +25,7 @@ std::string BinaryIO::ReadString(std::ifstream & instream) { } //For reading strings of a specific size -std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) { +std::string BinaryIO::ReadString(std::istream& instream, size_t size) { std::string toReturn; char buffer; @@ -37,7 +37,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) { return toReturn; } -std::string BinaryIO::ReadWString(std::ifstream & instream) { +std::string BinaryIO::ReadWString(std::istream& instream) { size_t size; BinaryRead(instream, size); //toReturn.resize(size); diff --git a/dCommon/BinaryIO.h b/dCommon/BinaryIO.h index 0c459f02..a117ad0d 100644 --- a/dCommon/BinaryIO.h +++ b/dCommon/BinaryIO.h @@ -9,17 +9,16 @@ namespace BinaryIO { } template - std::istream & BinaryRead(std::istream& stream, T& value) { - if (!stream.good()) - printf("bla"); + std::istream& BinaryRead(std::istream& stream, T& value) { + if (!stream.good()) throw std::runtime_error("Failed to read from istream."); return stream.read(reinterpret_cast(&value), sizeof(T)); } void WriteString(const std::string& stringToWrite, std::ofstream& outstream); - std::string ReadString(std::ifstream & instream); - std::string ReadString(std::ifstream& instream, size_t size); - std::string ReadWString(std::ifstream& instream); + std::string ReadString(std::istream& instream); + std::string ReadString(std::istream& instream, size_t size); + std::string ReadWString(std::istream& instream); inline bool DoesFileExist(const std::string& name) { std::ifstream f(name.c_str()); diff --git a/dCommon/BinaryPathFinder.cpp b/dCommon/BinaryPathFinder.cpp new file mode 100644 index 00000000..b1c2afef --- /dev/null +++ b/dCommon/BinaryPathFinder.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "BinaryPathFinder.h" +#include "dPlatforms.h" + +#if defined(DARKFLAME_PLATFORM_WIN32) +#include +#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS) +#include +#elif defined(DARKFLAME_PLATFORM_FREEBSD) +#include +#include +#include +#endif + +std::filesystem::path BinaryPathFinder::binaryDir; + +std::filesystem::path BinaryPathFinder::GetBinaryDir() { + if (!binaryDir.empty()) { + return binaryDir; + } + + std::string pathStr; + + // Derived from boost::dll::program_location, licensed under the Boost Software License: http://www.boost.org/LICENSE_1_0.txt +#if defined(DARKFLAME_PLATFORM_WIN32) + char path[MAX_PATH]; + GetModuleFileName(NULL, path, MAX_PATH); + pathStr = std::string(path); +#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS) + char path[1024]; + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size) == 0) { + pathStr = std::string(path); + } else { + // The filepath size is greater than our initial buffer size, so try again with the size + // that _NSGetExecutablePath told us it actually is + char *p = new char[size]; + if (_NSGetExecutablePath(p, &size) != 0) { + throw std::runtime_error("Failed to get binary path from _NSGetExecutablePath"); + } + + pathStr = std::string(p); + delete[] p; + } +#elif defined(DARKFLAME_PLATFORM_FREEBSD) + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[10240]; + size_t cb = sizeof(buf); + sysctl(mib, 4, buf, &cb, NULL, 0); + pathStr = std::string(buf); +#else // DARKFLAME_PLATFORM_LINUX || DARKFLAME_PLATFORM_UNIX || DARKFLAME_PLATFORM_ANDROID + pathStr = std::filesystem::read_symlink("/proc/self/exe"); +#endif + + // Some methods like _NSGetExecutablePath could return a symlink + // Either way, we need to get the parent path because we want the directory, not the binary itself + // We also ensure that it is an absolute path so that it is valid if we need to construct a path + // to exucute on unix systems (eg sudo BinaryPathFinder::GetBinaryDir() / WorldServer) + if (std::filesystem::is_symlink(pathStr)) { + binaryDir = std::filesystem::absolute(std::filesystem::read_symlink(pathStr).parent_path()); + } else { + binaryDir = std::filesystem::absolute(std::filesystem::path(pathStr).parent_path()); + } + + return binaryDir; +} diff --git a/dCommon/BinaryPathFinder.h b/dCommon/BinaryPathFinder.h new file mode 100644 index 00000000..c4ca6da2 --- /dev/null +++ b/dCommon/BinaryPathFinder.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef __BINARYPATHFINDER__H__ +#define __BINARYPATHFINDER__H__ + +#include + +class BinaryPathFinder { +private: + static std::filesystem::path binaryDir; +public: + static std::filesystem::path GetBinaryDir(); +}; + +#endif //!__BINARYPATHFINDER__H__ diff --git a/dCommon/Brick.h b/dCommon/Brick.h new file mode 100644 index 00000000..e8bd747e --- /dev/null +++ b/dCommon/Brick.h @@ -0,0 +1,11 @@ +#ifndef __BRICK__H__ +#define __BRICK__H__ + +#include + +struct Brick { + uint32_t designerID; + uint32_t materialID; +}; + +#endif //!__BRICK__H__ diff --git a/dCommon/BrickByBrickFix.cpp b/dCommon/BrickByBrickFix.cpp new file mode 100644 index 00000000..15194bf9 --- /dev/null +++ b/dCommon/BrickByBrickFix.cpp @@ -0,0 +1,180 @@ +#include "BrickByBrickFix.h" + +#include +#include +#include + +#include "tinyxml2.h" + +#include "Database.h" +#include "Game.h" +#include "ZCompression.h" +#include "dLogger.h" + +//! Forward declarations + +std::unique_ptr GetModelsFromDatabase(); +void WriteSd0Magic(char* input, uint32_t chunkSize); +bool CheckSd0Magic(sql::Blob* streamToCheck); + +/** + * @brief Truncates all models with broken data from the database. + * + * @return The number of models deleted + */ +uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() { + uint32_t modelsTruncated{}; + auto modelsToTruncate = GetModelsFromDatabase(); + bool previousCommitValue = Database::GetAutoCommit(); + Database::SetAutoCommit(false); + while (modelsToTruncate->next()) { + std::unique_ptr ugcModelToDelete(Database::CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;")); + std::unique_ptr pcModelToDelete(Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;")); + std::string completeUncompressedModel{}; + uint32_t chunkCount{}; + uint64_t modelId = modelsToTruncate->getInt(1); + std::unique_ptr modelAsSd0(modelsToTruncate->getBlob(2)); + // Check that header is sd0 by checking for the sd0 magic. + if (CheckSd0Magic(modelAsSd0.get())) { + while (true) { + uint32_t chunkSize{}; + modelAsSd0->read(reinterpret_cast(&chunkSize), sizeof(uint32_t)); // Extract chunk size from istream + + // Check if good here since if at the end of an sd0 file, this will have eof flagged. + if (!modelAsSd0->good()) break; + + std::unique_ptr compressedChunk(new uint8_t[chunkSize]); + for (uint32_t i = 0; i < chunkSize; i++) { + compressedChunk[i] = modelAsSd0->get(); + } + + // Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size. + std::unique_ptr uncompressedChunk(new uint8_t[ZCompression::MAX_SD0_CHUNK_SIZE]); + int32_t err{}; + int32_t actualUncompressedSize = ZCompression::Decompress( + compressedChunk.get(), chunkSize, uncompressedChunk.get(), ZCompression::MAX_SD0_CHUNK_SIZE, err); + + if (actualUncompressedSize != -1) { + uint32_t previousSize = completeUncompressedModel.size(); + completeUncompressedModel.append((char*)uncompressedChunk.get()); + completeUncompressedModel.resize(previousSize + actualUncompressedSize); + } else { + Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err); + break; + } + chunkCount++; + } + std::unique_ptr document = std::make_unique(); + if (!document) { + Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting."); + return 0; + } + + if (!(document->Parse(completeUncompressedModel.c_str(), completeUncompressedModel.size()) == tinyxml2::XML_SUCCESS)) { + if (completeUncompressedModel.find( + "", + completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos + ) { + Game::logger->Log("BrickByBrickFix", + "Brick-by-brick model %llu will be deleted!", modelId); + ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1)); + pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1)); + ugcModelToDelete->execute(); + pcModelToDelete->execute(); + modelsTruncated++; + } + } + } else { + Game::logger->Log("BrickByBrickFix", + "Brick-by-brick model %llu will be deleted!", modelId); + ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1)); + pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1)); + ugcModelToDelete->execute(); + pcModelToDelete->execute(); + modelsTruncated++; + } + } + + Database::Commit(); + Database::SetAutoCommit(previousCommitValue); + return modelsTruncated; +} + +/** + * @brief Updates all current models in the database to have the Segmented Data 0 (SD0) format. + * Any models that do not start with zlib and best compression magic will not be updated. + * + * @return The number of models updated to SD0 + */ +uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() { + uint32_t updatedModels = 0; + auto modelsToUpdate = GetModelsFromDatabase(); + auto previousAutoCommitState = Database::GetAutoCommit(); + Database::SetAutoCommit(false); + std::unique_ptr insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;")); + while (modelsToUpdate->next()) { + int64_t modelId = modelsToUpdate->getInt64(1); + std::unique_ptr oldLxfml(modelsToUpdate->getBlob(2)); + // Check if the stored blob starts with zlib magic (0x78 0xDA - best compression of zlib) + // If it does, convert it to sd0. + if (oldLxfml->get() == 0x78 && oldLxfml->get() == 0xDA) { + + // Get and save size of zlib compressed chunk. + oldLxfml->seekg(0, std::ios::end); + uint32_t oldLxfmlSize = static_cast(oldLxfml->tellg()); + oldLxfml->seekg(0); + + // Allocate 9 extra bytes. 5 for sd0 magic, 4 for the only zlib compressed size. + uint32_t oldLxfmlSizeWithHeader = oldLxfmlSize + 9; + std::unique_ptr sd0ConvertedModel(new char[oldLxfmlSizeWithHeader]); + + WriteSd0Magic(sd0ConvertedModel.get(), oldLxfmlSize); + for (uint32_t i = 9; i < oldLxfmlSizeWithHeader; i++) { + sd0ConvertedModel.get()[i] = oldLxfml->get(); + } + + std::string outputString(sd0ConvertedModel.get(), oldLxfmlSizeWithHeader); + std::istringstream outputStringStream(outputString); + + insertionStatement->setBlob(1, static_cast(&outputStringStream)); + insertionStatement->setInt64(2, modelId); + try { + insertionStatement->executeUpdate(); + Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId); + updatedModels++; + } catch (sql::SQLException exception) { + Game::logger->Log( + "BrickByBrickFix", + "Failed to update model %i. This model should be inspected manually to see why." + "The database error is %s", modelId, exception.what()); + } + } + } + Database::Commit(); + Database::SetAutoCommit(previousAutoCommitState); + return updatedModels; +} + +std::unique_ptr GetModelsFromDatabase() { + std::unique_ptr modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;")); + return std::unique_ptr(modelsRawDataQuery->executeQuery()); +} + +/** + * @brief Writes sd0 magic at the front of a char* + * + * @param input the char* to write at the front of + * @param chunkSize The size of the first chunk to write the size of + */ +void WriteSd0Magic(char* input, uint32_t chunkSize) { + input[0] = 's'; + input[1] = 'd'; + input[2] = '0'; + input[3] = 0x01; + input[4] = 0xFF; + *reinterpret_cast(input + 5) = chunkSize; // Write the integer to the character array +} + +bool CheckSd0Magic(sql::Blob* streamToCheck) { + return streamToCheck->get() == 's' && streamToCheck->get() == 'd' && streamToCheck->get() == '0' && streamToCheck->get() == 0x01 && streamToCheck->get() == 0xFF; +} diff --git a/dCommon/BrickByBrickFix.h b/dCommon/BrickByBrickFix.h new file mode 100644 index 00000000..7450fb71 --- /dev/null +++ b/dCommon/BrickByBrickFix.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace BrickByBrickFix { + /** + * @brief Deletes all broken BrickByBrick models that have invalid XML + * + * @return The number of BrickByBrick models that were truncated + */ + uint32_t TruncateBrokenBrickByBrickXml(); + + /** + * @brief Updates all BrickByBrick models in the database to be + * in the sd0 format as opposed to a zlib compressed format. + * + * @return The number of BrickByBrick models that were updated + */ + uint32_t UpdateBrickByBrickModelsToSd0(); +}; diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt new file mode 100644 index 00000000..549acfb2 --- /dev/null +++ b/dCommon/CMakeLists.txt @@ -0,0 +1,63 @@ +set(DCOMMON_SOURCES "AMFFormat.cpp" + "AMFDeserialize.cpp" + "AMFFormat_BitStream.cpp" + "BinaryIO.cpp" + "dConfig.cpp" + "Diagnostics.cpp" + "dLogger.cpp" + "GeneralUtils.cpp" + "LDFFormat.cpp" + "MD5.cpp" + "Metrics.cpp" + "NiPoint3.cpp" + "NiQuaternion.cpp" + "SHA512.cpp" + "Type.cpp" + "ZCompression.cpp" + "BrickByBrickFix.cpp" + "BinaryPathFinder.cpp" + "FdbToSqlite.cpp" +) + +add_subdirectory(dClient) + +foreach(file ${DCOMMON_DCLIENT_SOURCES}) + set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}") +endforeach() + +include_directories(${PROJECT_SOURCE_DIR}/dCommon/) + +add_library(dCommon STATIC ${DCOMMON_SOURCES}) + +target_link_libraries(dCommon bcrypt dDatabase tinyxml2) + +if (UNIX) + find_package(ZLIB REQUIRED) +elseif (WIN32) + include(FetchContent) + + # TODO Keep an eye on the zlib repository for an update to disable testing. Don't forget to update CMakePresets + FetchContent_Declare( + zlib + URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip + URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1 + ) + + # Disable warning about no project version. + set(CMAKE_POLICY_DEFAULT_CMP0048 NEW) + # Disable warning about the minimum version of cmake used for bcrypt being deprecated in the future + set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE) + + FetchContent_MakeAvailable(zlib) + + set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR}) + set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}") + add_library(ZLIB::ZLIB ALIAS zlib) +else () + message( + FATAL_ERROR + "This platform does not have a way to use zlib.\nCreate an issue on GitHub with your build system so it can be configured." + ) +endif () + +target_link_libraries(dCommon ZLIB::ZLIB) diff --git a/dCommon/Diagnostics.cpp b/dCommon/Diagnostics.cpp index 5963400d..58d558de 100644 --- a/dCommon/Diagnostics.cpp +++ b/dCommon/Diagnostics.cpp @@ -1,4 +1,6 @@ #include "Diagnostics.h" +#include "Game.h" +#include "dLogger.h" // If we're on Win32, we'll include our minidump writer #ifdef _WIN32 @@ -10,51 +12,51 @@ #include "dLogger.h" void make_minidump(EXCEPTION_POINTERS* e) { - auto hDbgHelp = LoadLibraryA("dbghelp"); - if (hDbgHelp == nullptr) - return; - auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if (pMiniDumpWriteDump == nullptr) - return; + auto hDbgHelp = LoadLibraryA("dbghelp"); + if (hDbgHelp == nullptr) + return; + auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); + if (pMiniDumpWriteDump == nullptr) + return; - char name[MAX_PATH]; - { - auto nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH); - SYSTEMTIME t; - GetSystemTime(&t); - wsprintfA(nameEnd - strlen(".exe"), - "_%4d%02d%02d_%02d%02d%02d.dmp", - t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); - } + char name[MAX_PATH]; + { + auto nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH); + SYSTEMTIME t; + GetSystemTime(&t); + wsprintfA(nameEnd - strlen(".exe"), + "_%4d%02d%02d_%02d%02d%02d.dmp", + t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); + } + Game::logger->Log("Diagnostics", "Creating crash dump %s", name); + auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == INVALID_HANDLE_VALUE) + return; - auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (hFile == INVALID_HANDLE_VALUE) - return; + MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; + exceptionInfo.ThreadId = GetCurrentThreadId(); + exceptionInfo.ExceptionPointers = e; + exceptionInfo.ClientPointers = FALSE; - MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; - exceptionInfo.ThreadId = GetCurrentThreadId(); - exceptionInfo.ExceptionPointers = e; - exceptionInfo.ClientPointers = FALSE; + auto dumped = pMiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), + e ? &exceptionInfo : nullptr, + nullptr, + nullptr); - auto dumped = pMiniDumpWriteDump( - GetCurrentProcess(), - GetCurrentProcessId(), - hFile, - MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), - e ? &exceptionInfo : nullptr, - nullptr, - nullptr); + CloseHandle(hFile); - CloseHandle(hFile); - - return; + return; } LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) { - make_minidump(e); - if (Game::logger) - Game::logger->Flush(); // Flush our log if we have one, before exiting. - return EXCEPTION_CONTINUE_SEARCH; + make_minidump(e); + if (Game::logger) + Game::logger->Flush(); // Flush our log if we have one, before exiting. + return EXCEPTION_CONTINUE_SEARCH; } #endif @@ -75,146 +77,147 @@ LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) { #include struct bt_ctx { - struct backtrace_state* state; - int error; + struct backtrace_state* state; + int error; }; static inline void Bt(struct backtrace_state* state) { - std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; - FILE* file = fopen(fileName.c_str(), "w+"); - if (file != nullptr) { - backtrace_print(state, 2, file); - fclose(file); - } + std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; + Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str()); + FILE* file = fopen(fileName.c_str(), "w+"); + if (file != nullptr) { + backtrace_print(state, 2, file); + fclose(file); + } - backtrace_print(state, 2, stdout); + backtrace_print(state, 2, stdout); } static void ErrorCallback(void* data, const char* msg, int errnum) { - auto* ctx = (struct bt_ctx*)data; - fprintf(stderr, "ERROR: %s (%d)", msg, errnum); - ctx->error = 1; + auto* ctx = (struct bt_ctx*)data; + fprintf(stderr, "ERROR: %s (%d)", msg, errnum); + ctx->error = 1; - std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; - FILE* file = fopen(fileName.c_str(), "w+"); - if (file != nullptr) { - fprintf(file, "ERROR: %s (%d)", msg, errnum); - fclose(file); - } + std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; + FILE* file = fopen(fileName.c_str(), "w+"); + if (file != nullptr) { + fprintf(file, "ERROR: %s (%d)", msg, errnum); + fclose(file); + } } #endif #include "Type.h" void GenerateDump() { - std::string cmd = "sudo gcore " + std::to_string(getpid()); - system(cmd.c_str()); + std::string cmd = "sudo gcore " + std::to_string(getpid()); + int ret = system(cmd.c_str()); // Saving a return just to prevent warning } void CatchUnhandled(int sig) { #ifndef __include_backtrace__ - if (Diagnostics::GetProduceMemoryDump()) { - GenerateDump(); - } + std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; + Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str()); + if (Diagnostics::GetProduceMemoryDump()) { + GenerateDump(); + } - void* array[10]; - size_t size; + void* array[10]; + size_t size; - // get void*'s for all entries on the stack - size = backtrace(array, 10); + // get void*'s for all entries on the stack + size = backtrace(array, 10); - printf("Fatal error %i\nStacktrace:\n", sig); #if defined(__GNUG__) and defined(__dynamic) - // Loop through the returned addresses, and get the symbols to be demangled - char** strings = backtrace_symbols(array, size); + // Loop through the returned addresses, and get the symbols to be demangled + char** strings = backtrace_symbols(array, size); - // Print the stack trace - for (size_t i = 0; i < size; i++) { - // Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name - std::string functionName = strings[i]; - std::string::size_type start = functionName.find('('); - std::string::size_type end = functionName.find('+'); - if (start != std::string::npos && end != std::string::npos) { - std::string demangled = functionName.substr(start + 1, end - start - 1); + // Print the stack trace + for (size_t i = 0; i < size; i++) { + // Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name + std::string functionName = strings[i]; + std::string::size_type start = functionName.find('('); + std::string::size_type end = functionName.find('+'); + if (start != std::string::npos && end != std::string::npos) { + std::string demangled = functionName.substr(start + 1, end - start - 1); - demangled = demangle(functionName.c_str()); + demangled = demangle(functionName.c_str()); - if (demangled.empty()) { - printf("[%02d] %s\n", i, demangled.c_str()); - } else { - printf("[%02d] %s\n", i, functionName.c_str()); - } - } else { - printf("[%02d] %s\n", i, functionName.c_str()); - } - } + if (demangled.empty()) { + Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str()); + } else { + Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str()); + } + } else { + Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str()); + } + } #else - backtrace_symbols_fd(array, size, STDOUT_FILENO); + backtrace_symbols_fd(array, size, STDOUT_FILENO); #endif - std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; - FILE* file = fopen(fileName.c_str(), "w+"); - if (file != NULL) { - // print out all the frames to stderr - fprintf(file, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, fileno(file)); - fclose(file); - } + FILE* file = fopen(fileName.c_str(), "w+"); + if (file != NULL) { + // print out all the frames to stderr + fprintf(file, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, fileno(file)); + fclose(file); + } #else - struct backtrace_state* state = backtrace_create_state( - Diagnostics::GetProcessFileName().c_str(), - BACKTRACE_SUPPORTS_THREADS, - ErrorCallback, - nullptr); + struct backtrace_state* state = backtrace_create_state( + Diagnostics::GetProcessFileName().c_str(), + BACKTRACE_SUPPORTS_THREADS, + ErrorCallback, + nullptr); - struct bt_ctx ctx = {state, 0}; - Bt(state); + struct bt_ctx ctx = { state, 0 }; + Bt(state); #endif - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } void CritErrHdlr(int sig_num, siginfo_t* info, void* ucontext) { - CatchUnhandled(sig_num); + CatchUnhandled(sig_num); } void OnTerminate() { - CatchUnhandled(-1); + CatchUnhandled(-1); } void MakeBacktrace() { - struct sigaction sigact; + struct sigaction sigact; - sigact.sa_sigaction = CritErrHdlr; - sigact.sa_flags = SA_RESTART | SA_SIGINFO; + sigact.sa_sigaction = CritErrHdlr; + sigact.sa_flags = SA_RESTART | SA_SIGINFO; - if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 || - sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 || - sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 || - sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) { - fprintf(stderr, "error setting signal handler for %d (%s)\n", - SIGSEGV, - strsignal(SIGSEGV)); + if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 || + sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 || + sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 || + sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) { + fprintf(stderr, "error setting signal handler for %d (%s)\n", + SIGSEGV, + strsignal(SIGSEGV)); - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } - std::set_terminate(OnTerminate); + std::set_terminate(OnTerminate); } #endif void Diagnostics::Initialize() { #ifdef _WIN32 - SetUnhandledExceptionFilter(unhandled_handler); + SetUnhandledExceptionFilter(unhandled_handler); #elif defined(__linux__) //&& !defined(__clang__) - MakeBacktrace(); + MakeBacktrace(); #else - fprintf(stderr, "Diagnostics not supported on this platform.\n"); + fprintf(stderr, "Diagnostics not supported on this platform.\n"); #endif } @@ -224,33 +227,33 @@ std::string Diagnostics::m_OutDirectory{}; bool Diagnostics::m_ProduceMemoryDump{}; void Diagnostics::SetProcessName(const std::string& name) { - m_ProcessName = name; + m_ProcessName = name; } void Diagnostics::SetProcessFileName(const std::string& name) { - m_ProcessFileName = name; + m_ProcessFileName = name; } void Diagnostics::SetOutDirectory(const std::string& path) { - m_OutDirectory = path; + m_OutDirectory = path; } void Diagnostics::SetProduceMemoryDump(bool value) { - m_ProduceMemoryDump = value; + m_ProduceMemoryDump = value; } const std::string& Diagnostics::GetProcessName() { - return m_ProcessName; + return m_ProcessName; } const std::string& Diagnostics::GetProcessFileName() { - return m_ProcessFileName; + return m_ProcessFileName; } const std::string& Diagnostics::GetOutDirectory() { - return m_OutDirectory; + return m_OutDirectory; } bool Diagnostics::GetProduceMemoryDump() { - return m_ProduceMemoryDump; + return m_ProduceMemoryDump; } diff --git a/dCommon/Diagnostics.h b/dCommon/Diagnostics.h index 41b7d177..fb6cc1a0 100644 --- a/dCommon/Diagnostics.h +++ b/dCommon/Diagnostics.h @@ -5,27 +5,27 @@ class Diagnostics { public: - static void Initialize(); + static void Initialize(); - static void SetProcessName(const std::string& name); + static void SetProcessName(const std::string& name); - static void SetProcessFileName(const std::string& name); + static void SetProcessFileName(const std::string& name); - static void SetOutDirectory(const std::string& path); + static void SetOutDirectory(const std::string& path); - static void SetProduceMemoryDump(bool value); + static void SetProduceMemoryDump(bool value); - static const std::string& GetProcessName(); + static const std::string& GetProcessName(); - static const std::string& GetProcessFileName(); + static const std::string& GetProcessFileName(); - static const std::string& GetOutDirectory(); + static const std::string& GetOutDirectory(); - static bool GetProduceMemoryDump(); + static bool GetProduceMemoryDump(); private: - static std::string m_ProcessName; - static std::string m_ProcessFileName; - static std::string m_OutDirectory; - static bool m_ProduceMemoryDump; + static std::string m_ProcessName; + static std::string m_ProcessFileName; + static std::string m_OutDirectory; + static bool m_ProduceMemoryDump; }; diff --git a/dCommon/FdbToSqlite.cpp b/dCommon/FdbToSqlite.cpp new file mode 100644 index 00000000..e05286a9 --- /dev/null +++ b/dCommon/FdbToSqlite.cpp @@ -0,0 +1,247 @@ +#include "FdbToSqlite.h" + +#include +#include +#include +#include + +#include "BinaryIO.h" +#include "CDClientDatabase.h" +#include "GeneralUtils.h" +#include "Game.h" +#include "dLogger.h" +#include "AssetManager.h" + +#include "eSqliteDataType.h" + +std::map FdbToSqlite::Convert::m_SqliteType = { + { eSqliteDataType::NONE, "none"}, + { eSqliteDataType::INT32, "int32"}, + { eSqliteDataType::REAL, "real"}, + { eSqliteDataType::TEXT_4, "text_4"}, + { eSqliteDataType::INT_BOOL, "int_bool"}, + { eSqliteDataType::INT64, "int64"}, + { eSqliteDataType::TEXT_8, "text_8"} +}; + +FdbToSqlite::Convert::Convert(std::string binaryOutPath) { + this->m_BinaryOutPath = binaryOutPath; +} + +bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) { + if (m_ConversionStarted) return false; + + std::istream cdClientBuffer(&buffer); + + this->m_ConversionStarted = true; + try { + CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); + + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); + + int32_t numberOfTables = ReadInt32(cdClientBuffer); + ReadTables(numberOfTables, cdClientBuffer); + + CDClientDatabase::ExecuteQuery("COMMIT;"); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage()); + return false; + } + + return true; +} + +int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) { + int32_t nextInt{}; + BinaryIO::BinaryRead(cdClientBuffer, nextInt); + return nextInt; +} + +int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int64_t value{}; + BinaryIO::BinaryRead(cdClientBuffer, value); + + cdClientBuffer.seekg(prevPosition); + return value; +} + +std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + auto readString = BinaryIO::ReadString(cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); + return readString; +} + +int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) { + int32_t position{}; + BinaryIO::BinaryRead(cdClientBuffer, position); + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); + return prevPosition; +} + +std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + std::string tableName = ReadString(cdClientBuffer); + + auto columns = ReadColumns(numberOfColumns, cdClientBuffer); + std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; + CDClientDatabase::ExecuteDML(newTable); + + cdClientBuffer.seekg(prevPosition); + + return tableName; +} + +void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + for (int32_t i = 0; i < numberOfTables; i++) { + auto columnHeader = ReadColumnHeader(cdClientBuffer); + ReadRowHeader(columnHeader, cdClientBuffer); + } + + cdClientBuffer.seekg(prevPosition); +} + +std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer) { + std::stringstream columnsToCreate; + int32_t prevPosition = SeekPointer(cdClientBuffer); + + std::string name{}; + eSqliteDataType dataType{}; + for (int32_t i = 0; i < numberOfColumns; i++) { + if (i != 0) columnsToCreate << ", "; + dataType = static_cast(ReadInt32(cdClientBuffer)); + name = ReadString(cdClientBuffer); + columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; + } + + cdClientBuffer.seekg(prevPosition); + return columnsToCreate.str(); +} + +void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfAllocatedRows = ReadInt32(cdClientBuffer); + if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size + ReadRows(numberOfAllocatedRows, tableName, cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t rowid = 0; + for (int32_t row = 0; row < numberOfAllocatedRows; row++) { + int32_t rowPointer = ReadInt32(cdClientBuffer); + if (rowPointer == -1) rowid++; + else ReadRow(rowPointer, tableName, cdClientBuffer); + } + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); + + while (true) { + ReadRowInfo(tableName, cdClientBuffer); + int32_t linked = ReadInt32(cdClientBuffer); + if (linked == -1) break; + cdClientBuffer.seekg(linked); + } + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + ReadRowValues(numberOfColumns, tableName, cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t emptyValue{}; + int32_t intValue{}; + float_t floatValue{}; + std::string stringValue{}; + int32_t boolValue{}; + int64_t int64Value{}; + bool insertedFirstEntry = false; + std::stringstream insertedRow; + insertedRow << "INSERT INTO " << tableName << " values ("; + + for (int32_t i = 0; i < numberOfColumns; i++) { + if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. + switch (static_cast(ReadInt32(cdClientBuffer))) { + case eSqliteDataType::NONE: + BinaryIO::BinaryRead(cdClientBuffer, emptyValue); + assert(emptyValue == 0); + insertedRow << "NULL"; + break; + + case eSqliteDataType::INT32: + intValue = ReadInt32(cdClientBuffer); + insertedRow << intValue; + break; + + case eSqliteDataType::REAL: + BinaryIO::BinaryRead(cdClientBuffer, floatValue); + insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number + break; + + case eSqliteDataType::TEXT_4: + case eSqliteDataType::TEXT_8: { + stringValue = ReadString(cdClientBuffer); + size_t position = 0; + + // Need to escape quote with a double of ". + while (position < stringValue.size()) { + if (stringValue.at(position) == '\"') { + stringValue.insert(position, "\""); + position++; + } + position++; + } + insertedRow << "\"" << stringValue << "\""; + break; + } + + case eSqliteDataType::INT_BOOL: + BinaryIO::BinaryRead(cdClientBuffer, boolValue); + insertedRow << static_cast(boolValue); + break; + + case eSqliteDataType::INT64: + int64Value = ReadInt64(cdClientBuffer); + insertedRow << std::to_string(int64Value); + break; + + default: + throw std::invalid_argument("Unsupported SQLite type encountered."); + break; + + } + } + + insertedRow << ");"; + + auto copiedString = insertedRow.str(); + CDClientDatabase::ExecuteDML(copiedString); + cdClientBuffer.seekg(prevPosition); +} diff --git a/dCommon/FdbToSqlite.h b/dCommon/FdbToSqlite.h new file mode 100644 index 00000000..7aad2703 --- /dev/null +++ b/dCommon/FdbToSqlite.h @@ -0,0 +1,145 @@ +#ifndef __FDBTOSQLITE__H__ +#define __FDBTOSQLITE__H__ + +#pragma once + +#include +#include +#include + +class AssetMemoryBuffer; + +enum class eSqliteDataType : int32_t; + +namespace FdbToSqlite { + class Convert { + public: + /** + * Create a new convert object with an input .fdb file and an output binary path. + * + * @param inputFile The file which ends in .fdb to be converted + * @param binaryPath The base path where the file will be saved + */ + Convert(std::string binaryOutPath); + + /** + * Converts the input file to sqlite. Calling multiple times is safe. + * + * @return true if the database was converted properly, false otherwise. + */ + bool ConvertDatabase(AssetMemoryBuffer& buffer); + + /** + * @brief Reads a 32 bit int from the fdb file. + * + * @return The read value + */ + int32_t ReadInt32(std::istream& cdClientBuffer); + + /** + * @brief Reads a 64 bit integer from the fdb file. + * + * @return The read value + */ + int64_t ReadInt64(std::istream& cdClientBuffer); + + /** + * @brief Reads a string from the fdb file. + * + * @return The read string + * + * TODO This needs to be translated to latin-1! + */ + std::string ReadString(std::istream& cdClientBuffer); + + /** + * @brief Seeks to a pointer position. + * + * @return The previous position before the seek + */ + int32_t SeekPointer(std::istream& cdClientBuffer); + + /** + * @brief Reads a column header from the fdb file and creates the table in the database + * + * @return The table name + */ + std::string ReadColumnHeader(std::istream& cdClientBuffer); + + /** + * @brief Read the tables from the fdb file. + * + * @param numberOfTables The number of tables to read + */ + void ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer); + + /** + * @brief Reads the columns from the fdb file. + * + * @param numberOfColumns The number of columns to read + * @return All columns of the table formatted for a sql query + */ + std::string ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer); + + /** + * @brief Reads the row header from the fdb file. + * + * @param tableName The tables name + */ + void ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Read the rows from the fdb file., + * + * @param numberOfAllocatedRows The number of rows that were allocated. Always a power of 2! + * @param tableName The tables name. + */ + void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads a row from the fdb file. + * + * @param position The position to seek in the fdb to + * @param tableName The tables name + */ + void ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads the row info from the fdb file. + * + * @param tableName The tables name + */ + void ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads each row and its values from the fdb file and inserts them into the database + * + * @param numberOfColumns The number of columns to read in + * @param tableName The tables name + */ + void ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer); + private: + + /** + * Maps each sqlite data type to its string equivalent. + */ + static std::map m_SqliteType; + + /** + * Base path of the folder containing the fdb file + */ + std::string m_BasePath{}; + + /** + * Whether or not a conversion was started. If one was started, do not attempt to convert the file again. + */ + bool m_ConversionStarted{}; + + /** + * The path where the CDServer will be stored + */ + std::string m_BinaryOutPath{}; + }; //! class FdbToSqlite +}; //! namespace FdbToSqlite + +#endif //!__FDBTOSQLITE__H__ diff --git a/dCommon/Game.h b/dCommon/Game.h index 912baeb7..66f3f6b7 100644 --- a/dCommon/Game.h +++ b/dCommon/Game.h @@ -5,22 +5,21 @@ class dServer; class dLogger; class InstanceManager; -class dpWorld; class dChatFilter; class dConfig; -class dLocale; class RakPeerInterface; +class AssetManager; struct SystemAddress; namespace Game { extern dLogger* logger; extern dServer* server; extern InstanceManager* im; - extern dpWorld* physicsWorld; extern dChatFilter* chatFilter; extern dConfig* config; - extern dLocale* locale; extern std::mt19937 randomEngine; extern RakPeerInterface* chatServer; + extern AssetManager* assetManager; extern SystemAddress chatSysAddr; -} \ No newline at end of file + extern bool shouldShutdown; +} diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index b3461e8a..99ca687a 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -4,168 +4,271 @@ #include #include #include +#include +#include template -inline size_t MinSize(size_t size, const std::basic_string& string) { - if (size == size_t(-1) || size > string.size()) { - return string.size(); - } else { - return size; - } +inline size_t MinSize(size_t size, const std::basic_string_view& string) { + if (size == size_t(-1) || size > string.size()) { + return string.size(); + } else { + return size; + } } inline bool IsLeadSurrogate(char16_t c) { - return (0xD800 <= c) && (c <= 0xDBFF); + return (0xD800 <= c) && (c <= 0xDBFF); } inline bool IsTrailSurrogate(char16_t c) { - return (0xDC00 <= c) && (c <= 0xDFFF); + return (0xDC00 <= c) && (c <= 0xDFFF); } inline void PushUTF8CodePoint(std::string& ret, char32_t cp) { - if (cp <= 0x007F) { - ret.push_back(cp); - } else if (cp <= 0x07FF) { - ret.push_back(0xC0 | (cp >> 6)); - ret.push_back(0x80 | (cp & 0x3F)); - } else if (cp <= 0xFFFF) { - ret.push_back(0xE0 | (cp >> 12)); - ret.push_back(0x80 | ((cp >> 6) & 0x3F)); - ret.push_back(0x80 | (cp & 0x3F)); - } else if (cp <= 0x10FFFF) { - ret.push_back(0xF0 | (cp >> 18)); - ret.push_back(0x80 | ((cp >> 12) & 0x3F)); - ret.push_back(0x80 | ((cp >> 6) & 0x3F)); - ret.push_back(0x80 | (cp & 0x3F)); - } else { - assert(false); - } + if (cp <= 0x007F) { + ret.push_back(static_cast(cp)); + } else if (cp <= 0x07FF) { + ret.push_back(0xC0 | (cp >> 6)); + ret.push_back(0x80 | (cp & 0x3F)); + } else if (cp <= 0xFFFF) { + ret.push_back(0xE0 | (cp >> 12)); + ret.push_back(0x80 | ((cp >> 6) & 0x3F)); + ret.push_back(0x80 | (cp & 0x3F)); + } else if (cp <= 0x10FFFF) { + ret.push_back(0xF0 | (cp >> 18)); + ret.push_back(0x80 | ((cp >> 12) & 0x3F)); + ret.push_back(0x80 | ((cp >> 6) & 0x3F)); + ret.push_back(0x80 | (cp & 0x3F)); + } else { + assert(false); + } +} + +constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD; + +bool _IsSuffixChar(uint8_t c) { + return (c & 0xC0) == 0x80; +} + +bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { + size_t rem = slice.length(); + if (slice.empty()) return false; + const uint8_t* bytes = (const uint8_t*)&slice.front(); + if (rem > 0) { + uint8_t first = bytes[0]; + if (first < 0x80) { // 1 byte character + out = static_cast(first & 0x7F); + slice.remove_prefix(1); + return true; + } else if (first < 0xC0) { + // middle byte, not valid at start, fall through + } else if (first < 0xE0) { // two byte character + if (rem > 1) { + uint8_t second = bytes[1]; + if (_IsSuffixChar(second)) { + out = (static_cast(first & 0x1F) << 6) + + static_cast(second & 0x3F); + slice.remove_prefix(2); + return true; + } + } + } else if (first < 0xF0) { // three byte character + if (rem > 2) { + uint8_t second = bytes[1]; + uint8_t third = bytes[2]; + if (_IsSuffixChar(second) && _IsSuffixChar(third)) { + out = (static_cast(first & 0x0F) << 12) + + (static_cast(second & 0x3F) << 6) + + static_cast(third & 0x3F); + slice.remove_prefix(3); + return true; + } + } + } else if (first < 0xF8) { // four byte character + if (rem > 3) { + uint8_t second = bytes[1]; + uint8_t third = bytes[2]; + uint8_t fourth = bytes[3]; + if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) { + out = (static_cast(first & 0x07) << 18) + + (static_cast(second & 0x3F) << 12) + + (static_cast(third & 0x3F) << 6) + + static_cast(fourth & 0x3F); + slice.remove_prefix(4); + return true; + } + } + } + out = static_cast(REPLACEMENT_CHARACTER); + slice.remove_prefix(1); + return true; + } + return false; +} + +/// See +bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) { + if (output.length() >= size) return false; + if (U < 0x10000) { + // If U < 0x10000, encode U as a 16-bit unsigned integer and terminate. + output.push_back(static_cast(U)); + return true; + } else if (U > 0x10FFFF) { + output.push_back(REPLACEMENT_CHARACTER); + return true; + } else if (output.length() + 1 < size) { + // Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF, + // U' must be less than or equal to 0xFFFFF. That is, U' can be + // represented in 20 bits. + uint32_t Ut = U - 0x10000; + + // Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and + // 0xDC00, respectively. These integers each have 10 bits free to + // encode the character value, for a total of 20 bits. + uint16_t W1 = 0xD800; + uint16_t W2 = 0xDC00; + + // Assign the 10 high-order bits of the 20-bit U' to the 10 low-order + // bits of W1 and the 10 low-order bits of U' to the 10 low-order + // bits of W2. + W1 += static_cast((Ut & 0x3FC00) >> 10); + W2 += static_cast((Ut & 0x3FF) >> 0); + + // Terminate. + output.push_back(W1); // high surrogate + output.push_back(W2); // low surrogate + return true; + } else return false; +} + +std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) { + size_t newSize = MinSize(size, string); + std::u16string output; + output.reserve(newSize); + std::string_view iterator = string; + + uint32_t c; + while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {} + return output; } //! Converts an std::string (ASCII) to UCS-2 / UTF-16 -std::u16string GeneralUtils::ASCIIToUTF16(const std::string& string, size_t size) { - size_t newSize = MinSize(size, string); - std::u16string ret; - ret.reserve(newSize); +std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) { + size_t newSize = MinSize(size, string); + std::u16string ret; + ret.reserve(newSize); - for (size_t i = 0; i < newSize; i++) { - char c = string[i]; - assert(c > 0 && c <= 127); - ret.push_back(static_cast(c)); - } + for (size_t i = 0; i < newSize; i++) { + char c = string[i]; + // Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t + ret.push_back((c > 0 && c <= 127) ? static_cast(c) : REPLACEMENT_CHARACTER); + } - return ret; + return ret; } //! Converts a (potentially-ill-formed) UTF-16 string to UTF-8 //! See: -std::string GeneralUtils::UTF16ToWTF8(const std::u16string& string, size_t size) { - size_t newSize = MinSize(size, string); - std::string ret; - ret.reserve(newSize); +std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) { + size_t newSize = MinSize(size, string); + std::string ret; + ret.reserve(newSize); - for (size_t i = 0; i < newSize; i++) { - char16_t u = string[i]; - if (IsLeadSurrogate(u) && (i + 1) < newSize) { - char16_t next = string[i + 1]; - if (IsTrailSurrogate(next)) { - i += 1; - char32_t cp = 0x10000 - + ((static_cast(u) - 0xD800) << 10) - + (static_cast(next) - 0xDC00); - PushUTF8CodePoint(ret, cp); - } else { - PushUTF8CodePoint(ret, u); - } - } else { - PushUTF8CodePoint(ret, u); - } - } + for (size_t i = 0; i < newSize; i++) { + char16_t u = string[i]; + if (IsLeadSurrogate(u) && (i + 1) < newSize) { + char16_t next = string[i + 1]; + if (IsTrailSurrogate(next)) { + i += 1; + char32_t cp = 0x10000 + + ((static_cast(u) - 0xD800) << 10) + + (static_cast(next) - 0xDC00); + PushUTF8CodePoint(ret, cp); + } else { + PushUTF8CodePoint(ret, u); + } + } else { + PushUTF8CodePoint(ret, u); + } + } - return ret; + return ret; } bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) { - return std::equal(a.begin(), a.end (), b.begin(), b.end(),[](char a, char b) { return tolower(a) == tolower(b); }); + return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); }); } // MARK: Bits //! Sets a specific bit in a signed 64-bit integer int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) { - return value |= 1ULL << index; + return value |= 1ULL << index; } //! Clears a specific bit in a signed 64-bit integer int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) { - return value &= ~(1ULL << index); + return value &= ~(1ULL << index); } //! Checks a specific bit in a signed 64-bit integer bool GeneralUtils::CheckBit(int64_t value, uint32_t index) { - return value & (1ULL << index); + return value & (1ULL << index); } bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) { - size_t start_pos = str.find(from); - if(start_pos == std::string::npos) - return false; - str.replace(start_pos, from.length(), to); - return true; + size_t start_pos = str.find(from); + if (start_pos == std::string::npos) + return false; + str.replace(start_pos, from.length(), to); + return true; } -std::vector GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) -{ - std::vector vector = std::vector(); - std::wstring current; +std::vector GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) { + std::vector vector = std::vector(); + std::wstring current; - for (const auto& c : str) { - if (c == delimiter) { - vector.push_back(current); - current = L""; - } else { - current += c; - } - } + for (const auto& c : str) { + if (c == delimiter) { + vector.push_back(current); + current = L""; + } else { + current += c; + } + } - vector.push_back(current); - return vector; + vector.push_back(current); + return vector; } -std::vector GeneralUtils::SplitString(std::u16string& str, char16_t delimiter) -{ - std::vector vector = std::vector(); - std::u16string current; +std::vector GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) { + std::vector vector = std::vector(); + std::u16string current; - for (const auto& c : str) { - if (c == delimiter) { - vector.push_back(current); - current = u""; - } else { - current += c; - } - } + for (const auto& c : str) { + if (c == delimiter) { + vector.push_back(current); + current = u""; + } else { + current += c; + } + } - vector.push_back(current); - return vector; + vector.push_back(current); + return vector; } -std::vector GeneralUtils::SplitString(const std::string& str, char delimiter) -{ +std::vector GeneralUtils::SplitString(const std::string& str, char delimiter) { std::vector vector = std::vector(); std::string current = ""; - for (size_t i = 0; i < str.length(); i++) - { + for (size_t i = 0; i < str.length(); i++) { char c = str[i]; - if (c == delimiter) - { + if (c == delimiter) { vector.push_back(current); current = ""; - } - else - { + } else { current += c; } } @@ -175,16 +278,48 @@ std::vector GeneralUtils::SplitString(const std::string& str, char return vector; } -std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) { - uint32_t length; - inStream->Read(length); +std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) { + uint32_t length; + inStream->Read(length); - std::u16string string; - for (auto i = 0; i < length; i++) { - uint16_t c; - inStream->Read(c); - string.push_back(c); - } + std::u16string string; + for (auto i = 0; i < length; i++) { + uint16_t c; + inStream->Read(c); + string.push_back(c); + } - return string; + return string; +} + +std::vector GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { + // Because we dont know how large the initial number before the first _ is we need to make it a map like so. + std::map filenames{}; + for (auto& t : std::filesystem::directory_iterator(folder)) { + auto filename = t.path().filename().string(); + auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); + filenames.insert(std::make_pair(index, filename)); + } + + // Now sort the map by the oldest migration. + std::vector sortedFiles{}; + auto fileIterator = filenames.begin(); + std::map::iterator oldest = filenames.begin(); + while (!filenames.empty()) { + if (fileIterator == filenames.end()) { + sortedFiles.push_back(oldest->second); + filenames.erase(oldest); + fileIterator = filenames.begin(); + oldest = filenames.begin(); + continue; + } + if (oldest->first > fileIterator->first) oldest = fileIterator; + fileIterator++; + } + + return sortedFiles; +} + +bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) { + return TryParse(x.c_str(), dst.x) && TryParse(y.c_str(), dst.y) && TryParse(z.c_str(), dst.z); } diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 58b9e962..0a8a0a16 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -10,201 +10,217 @@ #include #include #include +#include "NiPoint3.h" #include "Game.h" +#include "dLogger.h" + +enum eInventoryType : uint32_t; +enum class eObjectBits : size_t; +enum class eReplicaComponentType : uint32_t; /*! \file GeneralUtils.hpp \brief A namespace containing general utility functions */ -//! The general utils namespace + //! The general utils namespace namespace GeneralUtils { - //! Converts a plain ASCII string to a UTF-16 string - /*! - \param string The string to convert - \param size A size to trim the string to. Default is -1 (No trimming) - \return An UTF-16 representation of the string - */ - std::u16string ASCIIToUTF16(const std::string& string, size_t size = -1); + //! Converts a plain ASCII string to a UTF-16 string + /*! + \param string The string to convert + \param size A size to trim the string to. Default is -1 (No trimming) + \return An UTF-16 representation of the string + */ + std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1); - //! Converts a UTF-16 string to a UTF-8 string - /*! - \param string The string to convert - \param size A size to trim the string to. Default is -1 (No trimming) - \return An UTF-8 representation of the string - */ - std::string UTF16ToWTF8(const std::u16string& string, size_t size = -1); + //! Converts a UTF-8 String to a UTF-16 string + /*! + \param string The string to convert + \param size A size to trim the string to. Default is -1 (No trimming) + \return An UTF-16 representation of the string + */ + std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1); - /** - * Compares two basic strings but does so ignoring case sensitivity - * \param a the first string to compare against the second string - * \param b the second string to compare against the first string - * @return if the two strings are equal - */ - bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b); + //! Internal, do not use + bool _NextUTF8Char(std::string_view& slice, uint32_t& out); - // MARK: Bits + //! Converts a UTF-16 string to a UTF-8 string + /*! + \param string The string to convert + \param size A size to trim the string to. Default is -1 (No trimming) + \return An UTF-8 representation of the string + */ + std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1); - // MARK: Bits + /** + * Compares two basic strings but does so ignoring case sensitivity + * \param a the first string to compare against the second string + * \param b the second string to compare against the first string + * @return if the two strings are equal + */ + bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b); - //! Sets a bit on a numerical value - template - void SetBit(T& value, size_t index) { - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - - if (index > (sizeof(T) * 8) - 1) { - return; - } - - value |= static_cast(1) << index; - } - - //! Clears a bit on a numerical value - template - void ClearBit(T& value, size_t index) { - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - - if (index > (sizeof(T) * 8 - 1)) { - return; - } - - value &= ~(static_cast(1) << index); - } - - //! Sets a specific bit in a signed 64-bit integer - /*! - \param value The value to set the bit for - \param index The index of the bit - */ - int64_t SetBit(int64_t value, uint32_t index); - - //! Clears a specific bit in a signed 64-bit integer - /*! - \param value The value to clear the bit from - \param index The index of the bit - */ - int64_t ClearBit(int64_t value, uint32_t index); - - //! Checks a specific bit in a signed 64-bit integer - /*! - \parma value The value to check the bit in - \param index The index of the bit - \return Whether or not the bit is set - */ - bool CheckBit(int64_t value, uint32_t index); + // MARK: Bits - // MARK: Random Number Generation + // MARK: Bits - //! Generates a random number - /*! - \param min The minimum the generate from - \param max The maximum to generate to - */ - template - inline T GenerateRandomNumber(std::size_t min, std::size_t max) { - // Make sure it is a numeric type - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + //! Sets a bit on a numerical value + template + inline void SetBit(T& value, eObjectBits bits) { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + auto index = static_cast(bits); + if (index > (sizeof(T) * 8) - 1) { + return; + } - if constexpr (std::is_integral_v) { // constexpr only necessary on first statement - std::uniform_int_distribution distribution(min, max); - return distribution(Game::randomEngine); - } - else if (std::is_floating_point_v) { - std::uniform_real_distribution distribution(min, max); - return distribution(Game::randomEngine); - } + value |= static_cast(1) << index; + } + + //! Clears a bit on a numerical value + template + inline void ClearBit(T& value, eObjectBits bits) { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + auto index = static_cast(bits); + if (index > (sizeof(T) * 8 - 1)) { + return; + } + + value &= ~(static_cast(1) << index); + } + + //! Sets a specific bit in a signed 64-bit integer + /*! + \param value The value to set the bit for + \param index The index of the bit + */ + int64_t SetBit(int64_t value, uint32_t index); + + //! Clears a specific bit in a signed 64-bit integer + /*! + \param value The value to clear the bit from + \param index The index of the bit + */ + int64_t ClearBit(int64_t value, uint32_t index); + + //! Checks a specific bit in a signed 64-bit integer + /*! + \parma value The value to check the bit in + \param index The index of the bit + \return Whether or not the bit is set + */ + bool CheckBit(int64_t value, uint32_t index); + + // MARK: Random Number Generation + + //! Generates a random number + /*! + \param min The minimum the generate from + \param max The maximum to generate to + */ + template + inline T GenerateRandomNumber(std::size_t min, std::size_t max) { + // Make sure it is a numeric type + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + + if constexpr (std::is_integral_v) { // constexpr only necessary on first statement + std::uniform_int_distribution distribution(min, max); + return distribution(Game::randomEngine); + } else if (std::is_floating_point_v) { + std::uniform_real_distribution distribution(min, max); + return distribution(Game::randomEngine); + } + + return T(); + } - return T(); - } - bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); - std::u16string ReadWString(RakNet::BitStream *inStream); + std::u16string ReadWString(RakNet::BitStream* inStream); std::vector SplitString(std::wstring& str, wchar_t delimiter); - std::vector SplitString(std::u16string& str, char16_t delimiter); + std::vector SplitString(const std::u16string& str, char16_t delimiter); std::vector SplitString(const std::string& str, char delimiter); - template - T Parse(const char* value); + std::vector GetSqlFileNamesFromFolder(const std::string& folder); + + template + T Parse(const char* value); template <> - inline int32_t Parse(const char* value) - { - return std::stoi(value); + inline int32_t Parse(const char* value) { + return std::stoi(value); } - template <> - inline int64_t Parse(const char* value) - { - return std::stoll(value); - } + template <> + inline int64_t Parse(const char* value) { + return std::stoll(value); + } - template <> - inline float Parse(const char* value) - { - return std::stof(value); - } + template <> + inline float Parse(const char* value) { + return std::stof(value); + } - template <> - inline double Parse(const char* value) - { - return std::stod(value); - } - - template <> - inline uint32_t Parse(const char* value) - { - return std::stoul(value); - } + template <> + inline double Parse(const char* value) { + return std::stod(value); + } - template <> - inline uint64_t Parse(const char* value) - { - return std::stoull(value); - } - - template - bool TryParse(const char* value, T& dst) - { - try - { - dst = Parse(value); + template <> + inline uint32_t Parse(const char* value) { + return std::stoul(value); + } - return true; - } - catch (...) - { - return false; - } - } + template <> + inline uint64_t Parse(const char* value) { + return std::stoull(value); + } - template - T Parse(const std::string& value) - { - return Parse(value.c_str()); - } + template <> + inline eInventoryType Parse(const char* value) { + return static_cast(std::stoul(value)); + } - template - bool TryParse(const std::string& value, T& dst) - { - return TryParse(value.c_str(), dst); - } + template <> + inline eReplicaComponentType Parse(const char* value) { + return static_cast(std::stoul(value)); + } - template - std::u16string to_u16string(T value) - { - return GeneralUtils::ASCIIToUTF16(std::to_string(value)); - } + template + bool TryParse(const char* value, T& dst) { + try { + dst = Parse(value); - // From boost::hash_combine - template - void hash_combine(std::size_t& s, const T& v) - { - std::hash h; - s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); - } + return true; + } catch (...) { + return false; + } + } + + template + T Parse(const std::string& value) { + return Parse(value.c_str()); + } + + template + bool TryParse(const std::string& value, T& dst) { + return TryParse(value.c_str(), dst); + } + + bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst); + + template + std::u16string to_u16string(T value) { + return GeneralUtils::ASCIIToUTF16(std::to_string(value)); + } + + // From boost::hash_combine + template + void hash_combine(std::size_t& s, const T& v) { + std::hash h; + s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); + } } diff --git a/dCommon/LDFFormat.cpp b/dCommon/LDFFormat.cpp index 8290faec..cb921842 100644 --- a/dCommon/LDFFormat.cpp +++ b/dCommon/LDFFormat.cpp @@ -3,132 +3,174 @@ // Custom Classes #include "GeneralUtils.h" +#include "Game.h" +#include "dLogger.h" + // C++ -#include +#include #include -//! Returns a pointer to a LDFData value based on string format -LDFBaseData * LDFBaseData::DataFromString(const std::string& format) { - - // First, check the format - std::istringstream ssFormat(format); - std::string token; - - std::vector keyValueArray; - while (std::getline(ssFormat, token, '=')) { - keyValueArray.push_back(token); - } - - if (keyValueArray.size() == 2) { - std::u16string key = GeneralUtils::ASCIIToUTF16(keyValueArray[0]); - - std::vector dataArray; - std::istringstream ssData(keyValueArray[1]); - while (std::getline(ssData, token, ':')) { - dataArray.push_back(token); - } +using LDFKey = std::string_view; +using LDFTypeAndValue = std::string_view; - if (dataArray.size() > 2) { // hacky fix for strings with colons in them - std::vector newDataArray; - newDataArray.push_back(dataArray[0]); - std::string value = ""; - for (size_t i = 1; i < dataArray.size(); ++i) { - value += dataArray[i] + ':'; - } - value.pop_back(); // remove last colon - newDataArray.push_back(value); - dataArray = newDataArray; +using LDFType = std::string_view; +using LDFValue = std::string_view; + +//! Returns a pointer to a LDFData value based on string format +LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) { + // A valid LDF must be at least 3 characters long (=0:) is the shortest valid LDF (empty UTF-16 key with no initial value) + if (format.empty() || format.length() <= 2) return nullptr; + auto equalsPosition = format.find('='); + // You can have an empty key, just make sure the type and value might exist + if (equalsPosition == std::string::npos || equalsPosition == (format.size() - 1)) return nullptr; + + std::pair keyValue; + keyValue.first = format.substr(0, equalsPosition); + keyValue.second = format.substr(equalsPosition + 1, format.size()); + + std::u16string key = GeneralUtils::ASCIIToUTF16(keyValue.first); + + auto colonPosition = keyValue.second.find(':'); + + // If : is the first thing after an =, then this is an invalid LDF since + // we dont have a type to use. + if (colonPosition == std::string::npos || colonPosition == 0) return nullptr; + + std::pair ldfTypeAndValue; + ldfTypeAndValue.first = keyValue.second.substr(0, colonPosition); + ldfTypeAndValue.second = keyValue.second.substr(colonPosition + 1, keyValue.second.size()); + + // Only allow empty values for string values. + if (ldfTypeAndValue.second.size() == 0 && !(ldfTypeAndValue.first == "0" || ldfTypeAndValue.first == "13")) return nullptr; + + eLDFType type; + char* storage; + try { + type = static_cast(strtol(ldfTypeAndValue.first.data(), &storage, 10)); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data()); + return nullptr; + } + + LDFBaseData* returnValue = nullptr; + switch (type) { + case LDF_TYPE_UTF_16: { + std::u16string data = GeneralUtils::UTF8ToUTF16(ldfTypeAndValue.second); + returnValue = new LDFData(key, data); + break; + } + + case LDF_TYPE_S32: { + try { + int32_t data = static_cast(strtoul(ldfTypeAndValue.second.data(), &storage, 10)); + returnValue = new LDFData(key, data); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; } - - if ((dataArray[0] == "0" || dataArray[0] == "13") && dataArray.size() == 1) { - dataArray.push_back(""); - } - - if (dataArray.size() == 2) { - eLDFType type = static_cast(stoi(dataArray[0])); - - switch (type) { - case LDF_TYPE_UTF_16: { - std::u16string data = GeneralUtils::ASCIIToUTF16(dataArray[1]); - return new LDFData(key, data); - } - - case LDF_TYPE_S32: { - int32_t data = static_cast(stoull(dataArray[1])); - return new LDFData(key, data); - } - - case LDF_TYPE_FLOAT: { - float data = static_cast(stof(dataArray[1])); - return new LDFData(key, data); - } - - case LDF_TYPE_DOUBLE: { - double data = static_cast(stod(dataArray[1])); - return new LDFData(key, data); - } - - case LDF_TYPE_U32: - { - uint32_t data; - - if (dataArray[1] == "true") - { - data = 1; - } - else if (dataArray[1] == "false") - { - data = 0; - } - else - { - data = static_cast(stoul(dataArray[1])); - } - - return new LDFData(key, data); - } - - case LDF_TYPE_BOOLEAN: { - bool data; - - if (dataArray[1] == "true") - { - data = true; - } - else if (dataArray[1] == "false") - { - data = false; - } - else - { - data = static_cast(stoi(dataArray[1])); - } - - return new LDFData(key, data); - } - - case LDF_TYPE_U64: { - uint64_t data = static_cast(stoull(dataArray[1])); - return new LDFData(key, data); - } - - case LDF_TYPE_OBJID: { - LWOOBJID data = static_cast(stoll(dataArray[1])); - return new LDFData(key, data); - } - - case LDF_TYPE_UTF_8: { - std::string data = dataArray[1]; - return new LDFData(key, data); - } - - case LDF_TYPE_UNKNOWN: { - return nullptr; - } - } - } - } - - return nullptr; - + break; + } + + case LDF_TYPE_FLOAT: { + try { + float data = strtof(ldfTypeAndValue.second.data(), &storage); + returnValue = new LDFData(key, data); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + break; + } + + case LDF_TYPE_DOUBLE: { + try { + double data = strtod(ldfTypeAndValue.second.data(), &storage); + returnValue = new LDFData(key, data); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + break; + } + + case LDF_TYPE_U32: + { + uint32_t data; + + if (ldfTypeAndValue.second == "true") { + data = 1; + } else if (ldfTypeAndValue.second == "false") { + data = 0; + } else { + try { + data = static_cast(strtoul(ldfTypeAndValue.second.data(), &storage, 10)); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + } + + returnValue = new LDFData(key, data); + break; + } + + case LDF_TYPE_BOOLEAN: { + bool data; + + if (ldfTypeAndValue.second == "true") { + data = true; + } else if (ldfTypeAndValue.second == "false") { + data = false; + } else { + try { + data = static_cast(strtol(ldfTypeAndValue.second.data(), &storage, 10)); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + } + + returnValue = new LDFData(key, data); + break; + } + + case LDF_TYPE_U64: { + try { + uint64_t data = static_cast(strtoull(ldfTypeAndValue.second.data(), &storage, 10)); + returnValue = new LDFData(key, data); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + break; + } + + case LDF_TYPE_OBJID: { + try { + LWOOBJID data = static_cast(strtoll(ldfTypeAndValue.second.data(), &storage, 10)); + returnValue = new LDFData(key, data); + } catch (std::exception) { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + return nullptr; + } + break; + } + + case LDF_TYPE_UTF_8: { + std::string data = ldfTypeAndValue.second.data(); + returnValue = new LDFData(key, data); + break; + } + + case LDF_TYPE_UNKNOWN: { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); + break; + } + + default: { + Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data()); + break; + } + } + return returnValue; } diff --git a/dCommon/LDFFormat.h b/dCommon/LDFFormat.h index 0a8a99f3..0921d04c 100644 --- a/dCommon/LDFFormat.h +++ b/dCommon/LDFFormat.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef __LDFFORMAT__H__ +#define __LDFFORMAT__H__ // Custom Classes #include "dCommonVars.h" @@ -6,191 +7,162 @@ // C++ #include +#include #include // RakNet +#include "BitStream.h" -#include "../thirdparty/raknet/Source/BitStream.h" - -/*! - \file LDFFormat.hpp - \brief A collection of LDF format classes - */ - -//! An enum for LDF Data Types enum eLDFType { - LDF_TYPE_UNKNOWN = -1, //!< Unknown data type - LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type - LDF_TYPE_S32 = 1, //!< Signed 32-bit data type - LDF_TYPE_FLOAT = 3, //!< Float data type - LDF_TYPE_DOUBLE = 4, //!< Double data type - LDF_TYPE_U32 = 5, //!< Unsigned 32-bit data type - LDF_TYPE_BOOLEAN = 7, //!< Boolean data type - LDF_TYPE_U64 = 8, //!< Unsigned 64-bit data type (originally signed, templates won't work with both S64 & OBJID - LDF_TYPE_OBJID = 9, //!< Signed 64-bit data type (reserved for object IDs) - LDF_TYPE_UTF_8 = 13, //!< UTF-8 string data type + LDF_TYPE_UNKNOWN = -1, //!< Unknown data type + LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type + LDF_TYPE_S32 = 1, //!< Signed 32-bit data type + LDF_TYPE_FLOAT = 3, //!< Float data type + LDF_TYPE_DOUBLE = 4, //!< Double data type + LDF_TYPE_U32 = 5, //!< Unsigned 32-bit data type + LDF_TYPE_BOOLEAN = 7, //!< Boolean data type + LDF_TYPE_U64 = 8, //!< Unsigned 64-bit data type (originally signed, templates won't work with both S64 & OBJID + LDF_TYPE_OBJID = 9, //!< Signed 64-bit data type (reserved for object IDs) + LDF_TYPE_UTF_8 = 13, //!< UTF-8 string data type }; -//! A base class for the LDF data class LDFBaseData { public: - - //! Destructor - virtual ~LDFBaseData(void) { } - - //! Writes the data to a packet - /*! - \param packet The packet - */ - virtual void WriteToPacket(RakNet::BitStream * packet) = 0; - - //! Gets the key - /*! - \return The key - */ - virtual const std::u16string& GetKey(void) = 0; - - //! Gets the value type - /*! - \return The value type - */ - virtual eLDFType GetValueType(void) = 0; - - //! Gets a string from the key/value pair - /*! - \param includeKey Whether or not to include the key in the data - \param includeTypeId Whether or not to include the type id in the data - \return The string representation of the data - */ - virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0; - - virtual std::string GetValueAsString() = 0; - virtual LDFBaseData * Copy() = 0; - - // MARK: Functions - - //! Returns a pointer to a LDFData value based on string format - /*! - \param format The format - */ - static LDFBaseData * DataFromString(const std::string& format); + virtual ~LDFBaseData() {} + + virtual void WriteToPacket(RakNet::BitStream* packet) = 0; + + virtual const std::u16string& GetKey() = 0; + + virtual eLDFType GetValueType() = 0; + + /** Gets a string from the key/value pair + * @param includeKey Whether or not to include the key in the data + * @param includeTypeId Whether or not to include the type id in the data + * @return The string representation of the data + */ + virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0; + + virtual std::string GetValueAsString() = 0; + + virtual LDFBaseData* Copy() = 0; + + /** + * Given an input string, return the data as a LDF key. + */ + static LDFBaseData* DataFromString(const std::string_view& format); }; -//! A structure for an LDF key-value pair template -class LDFData : public LDFBaseData { +class LDFData: public LDFBaseData { private: - std::u16string key; - T value; - - //! Writes the key to the packet - void WriteKey(RakNet::BitStream * packet) { - packet->Write(static_cast(this->key.length() * sizeof(uint16_t))); - for (uint32_t i = 0; i < this->key.length(); ++i) { - packet->Write(static_cast(this->key[i])); - } - } - - //! Writes the value to the packet - void WriteValue(RakNet::BitStream * packet) { - packet->Write(static_cast(this->GetValueType())); - packet->Write(this->value); - } + std::u16string key; + T value; + + //! Writes the key to the packet + void WriteKey(RakNet::BitStream* packet) { + packet->Write(static_cast(this->key.length() * sizeof(uint16_t))); + for (uint32_t i = 0; i < this->key.length(); ++i) { + packet->Write(static_cast(this->key[i])); + } + } + + //! Writes the value to the packet + void WriteValue(RakNet::BitStream* packet) { + packet->Write(static_cast(this->GetValueType())); + packet->Write(this->value); + } public: - - //! Initializer - LDFData(const std::u16string& key, const T& value) { - this->key = key; - this->value = value; - } - - //! Destructor - ~LDFData(void) override { } - - //! Gets the value - /*! - \return The value - */ - const T& GetValue(void) { return this->value; } - - //! Sets the value - /*! - \param value The value to set to - */ - void SetValue(T value) { this->value = value; }; - //! Gets the value string - /*! - \return The value string - */ - std::string GetValueString(void) { return ""; } - - //! Writes the data to a packet - /*! - \param packet The packet - */ - void WriteToPacket(RakNet::BitStream * packet) override { - this->WriteKey(packet); - this->WriteValue(packet); - } - - //! Gets the key - /*! - \return The key - */ - const std::u16string& GetKey(void) override { return this->key; } - - //! Gets the LDF Type - /*! - \return The LDF value type - */ - eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; } - - //! Gets the string data - /*! - \param includeKey Whether or not to include the key in the data - \param includeTypeId Whether or not to include the type id in the data - \return The string representation of the data - */ - std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override { - if (GetValueType() == -1) { - return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:"; - } + //! Initializer + LDFData(const std::u16string& key, const T& value) { + this->key = key; + this->value = value; + } - std::stringstream stream; + //! Destructor + ~LDFData(void) override {} - if (includeKey) { - const std::string& sKey = GeneralUtils::UTF16ToWTF8(this->key, this->key.size()); - - stream << sKey << "="; - } + //! Gets the value + /*! + \return The value + */ + const T& GetValue(void) { return this->value; } - if (includeTypeId) { - const std::string& sType = std::to_string(this->GetValueType()); + //! Sets the value + /*! + \param value The value to set to + */ + void SetValue(T value) { this->value = value; }; - - stream << sType << ":"; - } + //! Gets the value string + /*! + \return The value string + */ + std::string GetValueString(void) { return ""; } - const std::string& sData = this->GetValueString(); - - stream << sData; + //! Writes the data to a packet + /*! + \param packet The packet + */ + void WriteToPacket(RakNet::BitStream* packet) override { + this->WriteKey(packet); + this->WriteValue(packet); + } - return stream.str(); - } - - std::string GetValueAsString() override { - return this->GetValueString(); - } - - LDFBaseData * Copy() override { - return new LDFData(key, value); - } - - inline static T Default = {}; + //! Gets the key + /*! + \return The key + */ + const std::u16string& GetKey(void) override { return this->key; } + + //! Gets the LDF Type + /*! + \return The LDF value type + */ + eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; } + + //! Gets the string data + /*! + \param includeKey Whether or not to include the key in the data + \param includeTypeId Whether or not to include the type id in the data + \return The string representation of the data + */ + std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override { + if (GetValueType() == -1) { + return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:"; + } + + std::stringstream stream; + + if (includeKey) { + const std::string& sKey = GeneralUtils::UTF16ToWTF8(this->key, this->key.size()); + stream << sKey << '='; + } + + if (includeTypeId) { + stream << this->GetValueType() << ':'; + } + + const std::string& sData = this->GetValueString(); + + stream << sData; + + return stream.str(); + } + + std::string GetValueAsString() override { + return this->GetValueString(); + } + + LDFBaseData* Copy() override { + return new LDFData(key, value); + } + + inline static T Default = {}; }; // LDF Types @@ -206,48 +178,46 @@ template<> inline eLDFType LDFData::GetValueType(void) { return LDF // The specialized version for std::u16string (UTF-16) template<> -inline void LDFData::WriteValue(RakNet::BitStream * packet) { - packet->Write(static_cast(this->GetValueType())); - - packet->Write(static_cast(this->value.length())); - for (uint32_t i = 0; i < this->value.length(); ++i) { - packet->Write(static_cast(this->value[i])); - } +inline void LDFData::WriteValue(RakNet::BitStream* packet) { + packet->Write(static_cast(this->GetValueType())); + + packet->Write(static_cast(this->value.length())); + for (uint32_t i = 0; i < this->value.length(); ++i) { + packet->Write(static_cast(this->value[i])); + } } // The specialized version for bool template<> -inline void LDFData::WriteValue(RakNet::BitStream * packet) { - packet->Write(static_cast(this->GetValueType())); - - packet->Write(static_cast(this->value)); +inline void LDFData::WriteValue(RakNet::BitStream* packet) { + packet->Write(static_cast(this->GetValueType())); + + packet->Write(static_cast(this->value)); } // The specialized version for std::string (UTF-8) template<> -inline void LDFData::WriteValue(RakNet::BitStream * packet) { - packet->Write(static_cast(this->GetValueType())); - - packet->Write(static_cast(this->value.length())); - for (uint32_t i = 0; i < this->value.length(); ++i) { - packet->Write(static_cast(this->value[i])); - } +inline void LDFData::WriteValue(RakNet::BitStream* packet) { + packet->Write(static_cast(this->GetValueType())); + + packet->Write(static_cast(this->value.length())); + for (uint32_t i = 0; i < this->value.length(); ++i) { + packet->Write(static_cast(this->value[i])); + } } -// MARK: String Data -template<> inline std::string LDFData::GetValueString(void) { - //std::string toReturn(this->value.begin(), this->value.end()); - //return toReturn; - +template<> inline std::string LDFData::GetValueString() { return GeneralUtils::UTF16ToWTF8(this->value, this->value.size()); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString(void) { return this->value; } +template<> inline std::string LDFData::GetValueString() { return this->value; } + +#endif //!__LDFFORMAT__H__ diff --git a/dCommon/MD5.cpp b/dCommon/MD5.cpp index 36c0d2cf..d02b540d 100644 --- a/dCommon/MD5.cpp +++ b/dCommon/MD5.cpp @@ -1,36 +1,36 @@ /* MD5 converted to C++ class by Frank Thilo (thilo@unix-ag.org) for bzflag (http://www.bzflag.org) - + based on: - + md5.h and md5.c reference implemantion of RFC 1321 - + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. - + License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. - + License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. - + RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. - + These notices must be retained in any copies of any part of this documentation and/or software. - + */ -/* interface header */ + /* interface header */ #include "MD5.h" /* system implementation headers */ @@ -59,304 +59,290 @@ // F, G, H and I are basic MD5 functions. inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { - return x&y | ~x&z; + return x & y | ~x & z; } inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { - return x&z | y&~z; + return x & z | y & ~z; } inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { - return x^y^z; + return x ^ y ^ z; } inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { - return y ^ (x | ~z); + return y ^ (x | ~z); } // rotate_left rotates x left n bits. inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { - return (x << n) | (x >> (32 - n)); + return (x << n) | (x >> (32 - n)); } // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. -inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { - a = rotate_left(a + F(b, c, d) + x + ac, s) + b; +inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + F(b, c, d) + x + ac, s) + b; } -inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { - a = rotate_left(a + G(b, c, d) + x + ac, s) + b; +inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + G(b, c, d) + x + ac, s) + b; } -inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { - a = rotate_left(a + H(b, c, d) + x + ac, s) + b; +inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + H(b, c, d) + x + ac, s) + b; } -inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { - a = rotate_left(a + I(b, c, d) + x + ac, s) + b; +inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + I(b, c, d) + x + ac, s) + b; } ////////////////////////////////////////////// // default ctor, just initailize -MD5::MD5() -{ - init(); +MD5::MD5() { + init(); } ////////////////////////////////////////////// // nifty shortcut ctor, compute MD5 for string and finalize it right away -MD5::MD5(const std::string &text) -{ - init(); - update(text.c_str(), text.length()); - finalize(); +MD5::MD5(const std::string& text) { + init(); + update(text.c_str(), text.length()); + finalize(); } ////////////////////////////// -void MD5::init() -{ - finalized = false; - - count[0] = 0; - count[1] = 0; - - // load magic initialization constants. - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; +void MD5::init() { + finalized = false; + + count[0] = 0; + count[1] = 0; + + // load magic initialization constants. + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; } ////////////////////////////// // decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. -void MD5::decode(uint4 output[], const uint1 input[], size_type len) -{ - for (unsigned int i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) | - (((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24); +void MD5::decode(uint4 output[], const uint1 input[], size_type len) { + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) | + (((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24); } ////////////////////////////// // encodes input (uint4) into output (unsigned char). Assumes len is // a multiple of 4. -void MD5::encode(uint1 output[], const uint4 input[], size_type len) -{ - for (size_type i = 0, j = 0; j < len; i++, j += 4) { - output[j] = input[i] & 0xff; - output[j + 1] = (input[i] >> 8) & 0xff; - output[j + 2] = (input[i] >> 16) & 0xff; - output[j + 3] = (input[i] >> 24) & 0xff; - } +void MD5::encode(uint1 output[], const uint4 input[], size_type len) { + for (size_type i = 0, j = 0; j < len; i++, j += 4) { + output[j] = input[i] & 0xff; + output[j + 1] = (input[i] >> 8) & 0xff; + output[j + 2] = (input[i] >> 16) & 0xff; + output[j + 3] = (input[i] >> 24) & 0xff; + } } ////////////////////////////// // apply MD5 algo on a block -void MD5::transform(const uint1 block[blocksize]) -{ - uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - decode(x, block, blocksize); - - /* Round 1 */ - FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - // Zeroize sensitive information. - memset(x, 0, sizeof x); +void MD5::transform(const uint1 block[blocksize]) { + uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + decode(x, block, blocksize); + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + memset(x, 0, sizeof x); } ////////////////////////////// // MD5 block update operation. Continues an MD5 message-digest // operation, processing another message block -void MD5::update(const unsigned char input[], size_type length) -{ - // compute number of bytes mod 64 - size_type index = count[0] / 8 % blocksize; - - // Update number of bits - if ((count[0] += (length << 3)) < (length << 3)) - count[1]++; - count[1] += (length >> 29); - - // number of bytes we need to fill in buffer - size_type firstpart = 64 - index; - - size_type i; - - // transform as many times as possible. - if (length >= firstpart) - { - // fill buffer first, transform - memcpy(&buffer[index], input, firstpart); - transform(buffer); - - // transform chunks of blocksize (64 bytes) - for (i = firstpart; i + blocksize <= length; i += blocksize) - transform(&input[i]); - - index = 0; - } - else - i = 0; - - // buffer remaining input - memcpy(&buffer[index], &input[i], length - i); +void MD5::update(const unsigned char input[], size_type length) { + // compute number of bytes mod 64 + size_type index = count[0] / 8 % blocksize; + + // Update number of bits + if ((count[0] += (length << 3)) < (length << 3)) + count[1]++; + count[1] += (length >> 29); + + // number of bytes we need to fill in buffer + size_type firstpart = 64 - index; + + size_type i; + + // transform as many times as possible. + if (length >= firstpart) { + // fill buffer first, transform + memcpy(&buffer[index], input, firstpart); + transform(buffer); + + // transform chunks of blocksize (64 bytes) + for (i = firstpart; i + blocksize <= length; i += blocksize) + transform(&input[i]); + + index = 0; + } else + i = 0; + + // buffer remaining input + memcpy(&buffer[index], &input[i], length - i); } ////////////////////////////// // for convenience provide a verson with signed char -void MD5::update(const char input[], size_type length) -{ - update((const unsigned char*)input, length); +void MD5::update(const char input[], size_type length) { + update((const unsigned char*)input, length); } ////////////////////////////// // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. -MD5& MD5::finalize() -{ - static unsigned char padding[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - if (!finalized) { - // Save number of bits - unsigned char bits[8]; - encode(bits, count, 8); - - // pad out to 56 mod 64. - size_type index = count[0] / 8 % 64; - size_type padLen = (index < 56) ? (56 - index) : (120 - index); - update(padding, padLen); - - // Append length (before padding) - update(bits, 8); - - // Store state in digest - encode(digest, state, 16); - - // Zeroize sensitive information. - memset(buffer, 0, sizeof buffer); - memset(count, 0, sizeof count); - - finalized = true; - } - - return *this; +MD5& MD5::finalize() { + static unsigned char padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (!finalized) { + // Save number of bits + unsigned char bits[8]; + encode(bits, count, 8); + + // pad out to 56 mod 64. + size_type index = count[0] / 8 % 64; + size_type padLen = (index < 56) ? (56 - index) : (120 - index); + update(padding, padLen); + + // Append length (before padding) + update(bits, 8); + + // Store state in digest + encode(digest, state, 16); + + // Zeroize sensitive information. + memset(buffer, 0, sizeof buffer); + memset(count, 0, sizeof count); + + finalized = true; + } + + return *this; } ////////////////////////////// // return hex representation of digest as string -std::string MD5::hexdigest() const -{ - if (!finalized) - return ""; - - char buf[33]; - for (int i = 0; i<16; i++) - sprintf(buf + i * 2, "%02x", digest[i]); - buf[32] = 0; - - return std::string(buf); +std::string MD5::hexdigest() const { + if (!finalized) + return ""; + + char buf[33]; + for (int i = 0; i < 16; i++) + sprintf(buf + i * 2, "%02x", digest[i]); + buf[32] = 0; + + return std::string(buf); } ////////////////////////////// -std::ostream& operator<<(std::ostream& out, MD5 md5) -{ - return out << md5.hexdigest(); +std::ostream& operator<<(std::ostream& out, MD5 md5) { + return out << md5.hexdigest(); } ////////////////////////////// -std::string md5(const std::string str) -{ - MD5 md5 = MD5(str); - - return md5.hexdigest(); +std::string md5(const std::string str) { + MD5 md5 = MD5(str); + + return md5.hexdigest(); } diff --git a/dCommon/MD5.h b/dCommon/MD5.h index 1ada98a5..30d178e1 100644 --- a/dCommon/MD5.h +++ b/dCommon/MD5.h @@ -1,33 +1,33 @@ /* MD5 converted to C++ class by Frank Thilo (thilo@unix-ag.org) for bzflag (http://www.bzflag.org) - + based on: - + md5.h and md5.c reference implementation of RFC 1321 - + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. - + License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. - + License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. - + RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. - + These notices must be retained in any copies of any part of this documentation and/or software. - + */ #ifndef BZF_MD5_H @@ -37,55 +37,55 @@ #include -// a small class for calculating MD5 hashes of strings or byte arrays -// it is not meant to be fast or secure -// -// usage: 1) feed it blocks of uchars with update() -// 2) finalize() -// 3) get hexdigest() string -// or -// MD5(std::string).hexdigest() -// -// assumes that char is 8 bit and int is 32 bit + // a small class for calculating MD5 hashes of strings or byte arrays + // it is not meant to be fast or secure + // + // usage: 1) feed it blocks of uchars with update() + // 2) finalize() + // 3) get hexdigest() string + // or + // MD5(std::string).hexdigest() + // + // assumes that char is 8 bit and int is 32 bit class MD5 { public: - typedef unsigned int size_type; // must be 32bit - - MD5(); - MD5(const std::string& text); - void update(const unsigned char *buf, size_type length); - void update(const char *buf, size_type length); - MD5& finalize(); - std::string hexdigest() const; - friend std::ostream& operator<<(std::ostream&, MD5 md5); - + typedef unsigned int size_type; // must be 32bit + + MD5(); + MD5(const std::string& text); + void update(const unsigned char* buf, size_type length); + void update(const char* buf, size_type length); + MD5& finalize(); + std::string hexdigest() const; + friend std::ostream& operator<<(std::ostream&, MD5 md5); + private: - void init(); - typedef unsigned char uint1; // 8bit - typedef unsigned int uint4; // 32bit - enum { blocksize = 64 }; // VC6 won't eat a const static int here - - void transform(const uint1 block[blocksize]); - static void decode(uint4 output[], const uint1 input[], size_type len); - static void encode(uint1 output[], const uint4 input[], size_type len); - - bool finalized; - uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk - uint4 count[2]; // 64bit counter for number of bits (lo, hi) - uint4 state[4]; // digest so far - uint1 digest[16]; // the result - - // low level logic operations - static inline uint4 F(uint4 x, uint4 y, uint4 z); - static inline uint4 G(uint4 x, uint4 y, uint4 z); - static inline uint4 H(uint4 x, uint4 y, uint4 z); - static inline uint4 I(uint4 x, uint4 y, uint4 z); - static inline uint4 rotate_left(uint4 x, int n); - static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); - static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); - static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); - static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + void init(); + typedef unsigned char uint1; // 8bit + typedef unsigned int uint4; // 32bit + enum { blocksize = 64 }; // VC6 won't eat a const static int here + + void transform(const uint1 block[blocksize]); + static void decode(uint4 output[], const uint1 input[], size_type len); + static void encode(uint1 output[], const uint4 input[], size_type len); + + bool finalized; + uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk + uint4 count[2]; // 64bit counter for number of bits (lo, hi) + uint4 state[4]; // digest so far + uint1 digest[16]; // the result + + // low level logic operations + static inline uint4 F(uint4 x, uint4 y, uint4 z); + static inline uint4 G(uint4 x, uint4 y, uint4 z); + static inline uint4 H(uint4 x, uint4 y, uint4 z); + static inline uint4 I(uint4 x, uint4 y, uint4 z); + static inline uint4 rotate_left(uint4 x, int n); + static inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); }; std::string md5(const std::string str); diff --git a/dCommon/Metrics.cpp b/dCommon/Metrics.cpp index a7adb998..b97b5435 100644 --- a/dCommon/Metrics.cpp +++ b/dCommon/Metrics.cpp @@ -4,174 +4,150 @@ std::unordered_map Metrics::m_Metrics = {}; std::vector Metrics::m_Variables = { - MetricVariable::GameLoop, - MetricVariable::PacketHandling, - MetricVariable::UpdateEntities, - MetricVariable::UpdateSpawners, - MetricVariable::Physics, - MetricVariable::UpdateReplica, - MetricVariable::Ghosting, - MetricVariable::CPUTime, - MetricVariable::Sleep, - MetricVariable::Frame, + MetricVariable::GameLoop, + MetricVariable::PacketHandling, + MetricVariable::UpdateEntities, + MetricVariable::UpdateSpawners, + MetricVariable::Physics, + MetricVariable::UpdateReplica, + MetricVariable::Ghosting, + MetricVariable::CPUTime, + MetricVariable::Sleep, + MetricVariable::Frame, }; -void Metrics::AddMeasurement(MetricVariable variable, int64_t value) -{ - const auto& iter = m_Metrics.find(variable); +void Metrics::AddMeasurement(MetricVariable variable, int64_t value) { + const auto& iter = m_Metrics.find(variable); - Metric* metric; + Metric* metric; - if (iter == m_Metrics.end()) - { - metric = new Metric(); + if (iter == m_Metrics.end()) { + metric = new Metric(); - m_Metrics[variable] = metric; - } - else - { - metric = iter->second; - } + m_Metrics[variable] = metric; + } else { + metric = iter->second; + } - AddMeasurement(metric, value); + AddMeasurement(metric, value); } -void Metrics::AddMeasurement(Metric* metric, int64_t value) -{ - const auto index = metric->measurementIndex; +void Metrics::AddMeasurement(Metric* metric, int64_t value) { + const auto index = metric->measurementIndex; - metric->measurements[index] = value; + metric->measurements[index] = value; - if (metric->max == -1 || value > metric->max) - { - metric->max = value; - } - else if (metric->min == -1 || metric->min > value) - { - metric->min = value; - } + if (metric->max == -1 || value > metric->max) { + metric->max = value; + } else if (metric->min == -1 || metric->min > value) { + metric->min = value; + } - if (metric->measurementSize < MAX_MEASURMENT_POINTS) - { - metric->measurementSize++; - } + if (metric->measurementSize < MAX_MEASURMENT_POINTS) { + metric->measurementSize++; + } - metric->measurementIndex = (index + 1) % MAX_MEASURMENT_POINTS; + metric->measurementIndex = (index + 1) % MAX_MEASURMENT_POINTS; } -const Metric* Metrics::GetMetric(MetricVariable variable) -{ - const auto& iter = m_Metrics.find(variable); +const Metric* Metrics::GetMetric(MetricVariable variable) { + const auto& iter = m_Metrics.find(variable); - if (iter == m_Metrics.end()) - { - return nullptr; - } + if (iter == m_Metrics.end()) { + return nullptr; + } - Metric* metric = iter->second; + Metric* metric = iter->second; - int64_t average = 0; + int64_t average = 0; - for (size_t i = 0; i < metric->measurementSize; i++) - { - average += metric->measurements[i]; - } + for (size_t i = 0; i < metric->measurementSize; i++) { + average += metric->measurements[i]; + } - average /= metric->measurementSize; + average /= metric->measurementSize; - metric->average = average; - - return metric; + metric->average = average; + + return metric; } -void Metrics::StartMeasurement(MetricVariable variable) -{ - const auto& iter = m_Metrics.find(variable); +void Metrics::StartMeasurement(MetricVariable variable) { + const auto& iter = m_Metrics.find(variable); - Metric* metric; + Metric* metric; - if (iter == m_Metrics.end()) - { - metric = new Metric(); + if (iter == m_Metrics.end()) { + metric = new Metric(); - m_Metrics[variable] = metric; - } - else - { - metric = iter->second; - } + m_Metrics[variable] = metric; + } else { + metric = iter->second; + } - metric->activeMeasurement = std::chrono::high_resolution_clock::now(); + metric->activeMeasurement = std::chrono::high_resolution_clock::now(); } -void Metrics::EndMeasurement(MetricVariable variable) -{ - const auto end = std::chrono::high_resolution_clock::now(); +void Metrics::EndMeasurement(MetricVariable variable) { + const auto end = std::chrono::high_resolution_clock::now(); - const auto& iter = m_Metrics.find(variable); + const auto& iter = m_Metrics.find(variable); - if (iter == m_Metrics.end()) - { - return; - } + if (iter == m_Metrics.end()) { + return; + } - Metric* metric = iter->second; + Metric* metric = iter->second; - const auto elapsed = end - metric->activeMeasurement; + const auto elapsed = end - metric->activeMeasurement; - const auto nanoseconds = std::chrono::duration_cast(elapsed).count(); + const auto nanoseconds = std::chrono::duration_cast(elapsed).count(); - AddMeasurement(metric, nanoseconds); + AddMeasurement(metric, nanoseconds); } -float Metrics::ToMiliseconds(int64_t nanoseconds) -{ - return (float) nanoseconds / 1e6; +float Metrics::ToMiliseconds(int64_t nanoseconds) { + return (float)nanoseconds / 1e6; } -std::string Metrics::MetricVariableToString(MetricVariable variable) -{ - switch (variable) - { - case MetricVariable::GameLoop: - return "GameLoop"; - case MetricVariable::PacketHandling: - return "PacketHandling"; - case MetricVariable::UpdateEntities: - return "UpdateEntities"; - case MetricVariable::UpdateSpawners: - return "UpdateSpawners"; - case MetricVariable::Physics: - return "Physics"; - case MetricVariable::UpdateReplica: - return "UpdateReplica"; - case MetricVariable::Sleep: - return "Sleep"; - case MetricVariable::CPUTime: - return "CPUTime"; - case MetricVariable::Frame: - return "Frame"; - case MetricVariable::Ghosting: - return "Ghosting"; - - default: - return "Invalid"; - } +std::string Metrics::MetricVariableToString(MetricVariable variable) { + switch (variable) { + case MetricVariable::GameLoop: + return "GameLoop"; + case MetricVariable::PacketHandling: + return "PacketHandling"; + case MetricVariable::UpdateEntities: + return "UpdateEntities"; + case MetricVariable::UpdateSpawners: + return "UpdateSpawners"; + case MetricVariable::Physics: + return "Physics"; + case MetricVariable::UpdateReplica: + return "UpdateReplica"; + case MetricVariable::Sleep: + return "Sleep"; + case MetricVariable::CPUTime: + return "CPUTime"; + case MetricVariable::Frame: + return "Frame"; + case MetricVariable::Ghosting: + return "Ghosting"; + + default: + return "Invalid"; + } } -const std::vector& Metrics::GetAllMetrics() -{ - return m_Variables; +const std::vector& Metrics::GetAllMetrics() { + return m_Variables; } -void Metrics::Clear() -{ - for (const auto& pair : m_Metrics) - { - delete pair.second; - } - - m_Metrics.clear(); +void Metrics::Clear() { + for (const auto& pair : m_Metrics) { + delete pair.second; + } + + m_Metrics.clear(); } /* RSS Memory utilities @@ -207,46 +183,44 @@ void Metrics::Clear() #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." #endif -/** - * Returns the peak (maximum so far) resident set size (physical - * memory use) measured in bytes, or zero if the value cannot be - * determined on this OS. - */ -size_t Metrics::GetPeakRSS() -{ + /** + * Returns the peak (maximum so far) resident set size (physical + * memory use) measured in bytes, or zero if the value cannot be + * determined on this OS. + */ +size_t Metrics::GetPeakRSS() { #if defined(_WIN32) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); - return (size_t)info.PeakWorkingSetSize; + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + return (size_t)info.PeakWorkingSetSize; #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) - /* AIX and Solaris ------------------------------------------ */ - struct psinfo psinfo; - int fd = -1; - if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) - return (size_t)0L; /* Can't open? */ - if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) - { - close( fd ); - return (size_t)0L; /* Can't read? */ - } - close( fd ); - return (size_t)(psinfo.pr_rssize * 1024L); + /* AIX and Solaris ------------------------------------------ */ + struct psinfo psinfo; + int fd = -1; + if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1) + return (size_t)0L; /* Can't open? */ + if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { + close(fd); + return (size_t)0L; /* Can't read? */ + } + close(fd); + return (size_t)(psinfo.pr_rssize * 1024L); #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) - /* BSD, Linux, and OSX -------------------------------------- */ - struct rusage rusage; - getrusage( RUSAGE_SELF, &rusage ); + /* BSD, Linux, and OSX -------------------------------------- */ + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); #if defined(__APPLE__) && defined(__MACH__) - return (size_t)rusage.ru_maxrss; + return (size_t)rusage.ru_maxrss; #else - return (size_t)(rusage.ru_maxrss * 1024L); + return (size_t)(rusage.ru_maxrss * 1024L); #endif #else - /* Unknown OS ----------------------------------------------- */ - return (size_t)0L; /* Unsupported. */ + /* Unknown OS ----------------------------------------------- */ + return (size_t)0L; /* Unsupported. */ #endif } @@ -255,49 +229,46 @@ size_t Metrics::GetPeakRSS() * Returns the current resident set size (physical memory use) measured * in bytes, or zero if the value cannot be determined on this OS. */ -size_t Metrics::GetCurrentRSS() -{ +size_t Metrics::GetCurrentRSS() { #if defined(_WIN32) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); - return (size_t)info.WorkingSetSize; + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + return (size_t)info.WorkingSetSize; #elif defined(__APPLE__) && defined(__MACH__) - /* OSX ------------------------------------------------------ */ - struct mach_task_basic_info info; - mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; - if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, - (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) - return (size_t)0L; /* Can't access? */ - return (size_t)info.resident_size; + /* OSX ------------------------------------------------------ */ + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, + (task_info_t)&info, &infoCount) != KERN_SUCCESS) + return (size_t)0L; /* Can't access? */ + return (size_t)info.resident_size; #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) - /* Linux ---------------------------------------------------- */ - long rss = 0L; - FILE* fp = NULL; - if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) - return (size_t)0L; /* Can't open? */ - if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) - { - fclose( fp ); - return (size_t)0L; /* Can't read? */ - } - fclose( fp ); - return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); + /* Linux ---------------------------------------------------- */ + long rss = 0L; + FILE* fp = NULL; + if ((fp = fopen("/proc/self/statm", "r")) == NULL) + return (size_t)0L; /* Can't open? */ + if (fscanf(fp, "%*s%ld", &rss) != 1) { + fclose(fp); + return (size_t)0L; /* Can't read? */ + } + fclose(fp); + return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE); #else - /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ - return (size_t)0L; /* Unsupported. */ + /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ + return (size_t)0L; /* Unsupported. */ #endif } -size_t Metrics::GetProcessID() -{ +size_t Metrics::GetProcessID() { #if defined(_WIN32) - return GetCurrentProcessId(); + return GetCurrentProcessId(); #else - return getpid(); + return getpid(); #endif } diff --git a/dCommon/Metrics.hpp b/dCommon/Metrics.hpp index b22632d2..c03c914f 100644 --- a/dCommon/Metrics.hpp +++ b/dCommon/Metrics.hpp @@ -10,52 +10,52 @@ enum class MetricVariable : int32_t { - GameLoop, - PacketHandling, - UpdateEntities, - UpdateSpawners, - Physics, - UpdateReplica, - Ghosting, - CPUTime, - Sleep, - Frame, + GameLoop, + PacketHandling, + UpdateEntities, + UpdateSpawners, + Physics, + UpdateReplica, + Ghosting, + CPUTime, + Sleep, + Frame, }; struct Metric { - int64_t measurements[MAX_MEASURMENT_POINTS] = {}; - size_t measurementIndex = 0; - size_t measurementSize = 0; - int64_t max = -1; - int64_t min = -1; - int64_t average = 0; - std::chrono::time_point activeMeasurement; + int64_t measurements[MAX_MEASURMENT_POINTS] = {}; + size_t measurementIndex = 0; + size_t measurementSize = 0; + int64_t max = -1; + int64_t min = -1; + int64_t average = 0; + std::chrono::time_point activeMeasurement; }; class Metrics { public: - ~Metrics(); + ~Metrics(); - static void AddMeasurement(MetricVariable variable, int64_t value); - static void AddMeasurement(Metric* metric, int64_t value); - static const Metric* GetMetric(MetricVariable variable); - static void StartMeasurement(MetricVariable variable); - static void EndMeasurement(MetricVariable variable); - static float ToMiliseconds(int64_t nanoseconds); - static std::string MetricVariableToString(MetricVariable variable); - static const std::vector& GetAllMetrics(); + static void AddMeasurement(MetricVariable variable, int64_t value); + static void AddMeasurement(Metric* metric, int64_t value); + static const Metric* GetMetric(MetricVariable variable); + static void StartMeasurement(MetricVariable variable); + static void EndMeasurement(MetricVariable variable); + static float ToMiliseconds(int64_t nanoseconds); + static std::string MetricVariableToString(MetricVariable variable); + static const std::vector& GetAllMetrics(); - static size_t GetPeakRSS(); - static size_t GetCurrentRSS(); - static size_t GetProcessID(); + static size_t GetPeakRSS(); + static size_t GetCurrentRSS(); + static size_t GetProcessID(); - static void Clear(); + static void Clear(); private: - Metrics(); + Metrics(); - static std::unordered_map m_Metrics; - static std::vector m_Variables; + static std::unordered_map m_Metrics; + static std::vector m_Variables; }; diff --git a/dCommon/NiPoint3.cpp b/dCommon/NiPoint3.cpp index 4baefa13..b2ffa0d1 100644 --- a/dCommon/NiPoint3.cpp +++ b/dCommon/NiPoint3.cpp @@ -13,23 +13,23 @@ const NiPoint3 NiPoint3::UNIT_ALL(1.0f, 1.0f, 1.0f); //! Initializer NiPoint3::NiPoint3(void) { - this->x = 0; - this->y = 0; - this->z = 0; + this->x = 0; + this->y = 0; + this->z = 0; } //! Initializer NiPoint3::NiPoint3(float x, float y, float z) { - this->x = x; - this->y = y; - this->z = z; + this->x = x; + this->y = y; + this->z = z; } //! Copy Constructor NiPoint3::NiPoint3(const NiPoint3& point) { - this->x = point.x; - this->y = point.y; - this->z = point.z; + this->x = point.x; + this->y = point.y; + this->z = point.z; } //! Destructor @@ -39,63 +39,63 @@ NiPoint3::~NiPoint3(void) {} //! Gets the X coordinate float NiPoint3::GetX(void) const { - return this->x; + return this->x; } //! Sets the X coordinate void NiPoint3::SetX(float x) { - this->x = x; + this->x = x; } //! Gets the Y coordinate float NiPoint3::GetY(void) const { - return this->y; + return this->y; } //! Sets the Y coordinate void NiPoint3::SetY(float y) { - this->y = y; + this->y = y; } //! Gets the Z coordinate float NiPoint3::GetZ(void) const { - return this->z; + return this->z; } //! Sets the Z coordinate void NiPoint3::SetZ(float z) { - this->z = z; + this->z = z; } // MARK: Functions //! Gets the length of the vector float NiPoint3::Length(void) const { - return sqrt(x*x + y*y + z*z); + return sqrt(x * x + y * y + z * z); } //! Gets the squared length of a vector float NiPoint3::SquaredLength(void) const { - return (x*x + y*y + z*z); + return (x * x + y * y + z * z); } //! Returns the dot product of the vector dotted with another vector float NiPoint3::DotProduct(const Vector3& vec) const { - return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z)); + return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z)); } //! Returns the cross product of the vector crossed with another vector Vector3 NiPoint3::CrossProduct(const Vector3& vec) const { - return Vector3(((this->y * vec.z) - (this->z * vec.y)), - ((this->z * vec.x) - (this->x * vec.z)), - ((this->x * vec.y) - (this->y * vec.x))); + return Vector3(((this->y * vec.z) - (this->z * vec.y)), + ((this->z * vec.x) - (this->x * vec.z)), + ((this->x * vec.y) - (this->y * vec.x))); } //! Unitize the vector NiPoint3 NiPoint3::Unitize(void) const { - float length = this->Length(); - - return length != 0 ? *this / length : NiPoint3::ZERO; + float length = this->Length(); + + return length != 0 ? *this / length : NiPoint3::ZERO; } @@ -103,57 +103,63 @@ NiPoint3 NiPoint3::Unitize(void) const { //! Operator to check for equality bool NiPoint3::operator==(const NiPoint3& point) const { - return point.x == this->x && point.y == this->y && point.z == this->z; + return point.x == this->x && point.y == this->y && point.z == this->z; } //! Operator to check for inequality bool NiPoint3::operator!=(const NiPoint3& point) const { - return !(*this == point); + return !(*this == point); } //! Operator for subscripting float& NiPoint3::operator[](int i) { - float * base = &x; - return (float&)base[i]; + float* base = &x; + return (float&)base[i]; } //! Operator for subscripting const float& NiPoint3::operator[](int i) const { - const float * base = &x; - return (float&)base[i]; + const float* base = &x; + return (float&)base[i]; } //! Operator for addition of vectors NiPoint3 NiPoint3::operator+(const NiPoint3& point) const { - return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); + return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); } +//! Operator for addition of vectors +NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const { + return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); +} + + //! Operator for subtraction of vectors NiPoint3 NiPoint3::operator-(const NiPoint3& point) const { - return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z); + return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z); } //! Operator for addition of a scalar on all vector components NiPoint3 NiPoint3::operator+(float fScalar) const { - return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar); + return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar); } //! Operator for subtraction of a scalar on all vector components NiPoint3 NiPoint3::operator-(float fScalar) const { - return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar); + return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar); } //! Operator for scalar multiplication of a vector NiPoint3 NiPoint3::operator*(float fScalar) const { - return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar); + return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar); } //! Operator for scalar division of a vector NiPoint3 NiPoint3::operator/(float fScalar) const { - float retX = this->x != 0 ? this->x / fScalar : 0; - float retY = this->y != 0 ? this->y / fScalar : 0; - float retZ = this->z != 0 ? this->z / fScalar : 0; - return NiPoint3(retX, retY, retZ); + float retX = this->x != 0 ? this->x / fScalar : 0; + float retY = this->y != 0 ? this->y / fScalar : 0; + float retZ = this->z != 0 ? this->z / fScalar : 0; + return NiPoint3(retX, retY, retZ); } @@ -161,96 +167,91 @@ NiPoint3 NiPoint3::operator/(float fScalar) const { //! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) { - if (this->x < minPoint.x) return false; - if (this->x > maxPoint.x) return false; - if (this->y < minPoint.y) return false; - if (this->y > maxPoint.y) return false; + if (this->x < minPoint.x) return false; + if (this->x > maxPoint.x) return false; + if (this->y < minPoint.y) return false; + if (this->y > maxPoint.y) return false; - return (this->z < maxPoint.z && this->z > minPoint.z); + return (this->z < maxPoint.z&& this->z > minPoint.z); } //! Checks to see if the point (or vector) is within a sphere bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) { - Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ()); - return (diffVec.SquaredLength() <= (radius * radius)); + Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ()); + return (diffVec.SquaredLength() <= (radius * radius)); } -NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) -{ - if (a == b) return a; +NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) { + if (a == b) return a; - const auto pa = p - a; - const auto ab = b - a; + const auto pa = p - a; + const auto ab = b - a; - const auto t = pa.DotProduct(ab) / ab.SquaredLength(); + const auto t = pa.DotProduct(ab) / ab.SquaredLength(); - if (t <= 0.0f) return a; - - if (t >= 1.0f) return b; - - return a + ab * t; + if (t <= 0.0f) return a; + + if (t >= 1.0f) return b; + + return a + ab * t; } -float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) -{ - const auto dot = a.DotProduct(b); - const auto lenA = a.SquaredLength(); - const auto lenB = a.SquaredLength(); - return acos(dot / sqrt(lenA * lenB)); +float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) { + const auto dot = a.DotProduct(b); + const auto lenA = a.SquaredLength(); + const auto lenB = a.SquaredLength(); + return acos(dot / sqrt(lenA * lenB)); } -float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) -{ - const auto dx = a.x - b.x; - const auto dy = a.y - b.y; - const auto dz = a.z - b.z; +float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) { + const auto dx = a.x - b.x; + const auto dy = a.y - b.y; + const auto dz = a.z - b.z; - return std::sqrt(dx * dx + dy * dy + dz * dz); + return std::sqrt(dx * dx + dy * dy + dz * dz); } -float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) -{ - const auto dx = a.x - b.x; - const auto dy = a.y - b.y; - const auto dz = a.z - b.z; +float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) { + const auto dx = a.x - b.x; + const auto dy = a.y - b.y; + const auto dz = a.z - b.z; - return dx * dx + dy * dy + dz * dz; + return dx * dx + dy * dy + dz * dz; } -NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) -{ - float dx = target.x - current.x; - float dy = target.y - current.y; - float dz = target.z - current.z; - float lengthSquared = (float) ((double) dx * (double) dx + (double) dy * (double) dy + (double) dz * (double) dz); - if ((double) lengthSquared == 0.0 || (double) maxDistanceDelta >= 0.0 && (double) lengthSquared <= (double) maxDistanceDelta * (double) maxDistanceDelta) - return target; - float length = (float) std::sqrt((double) lengthSquared); - return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta); +NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) { + float dx = target.x - current.x; + float dy = target.y - current.y; + float dz = target.z - current.z; + float lengthSquared = (float)((double)dx * (double)dx + (double)dy * (double)dy + (double)dz * (double)dz); + if ((double)lengthSquared == 0.0 || (double)maxDistanceDelta >= 0.0 && (double)lengthSquared <= (double)maxDistanceDelta * (double)maxDistanceDelta) + return target; + float length = (float)std::sqrt((double)lengthSquared); + return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta); } //This code is yoinked from the MS XNA code, so it should be right, even if it's horrible. NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) { - Vector3 vector; - float num12 = rotation.x + rotation.x; - float num2 = rotation.y + rotation.y; - float num = rotation.z + rotation.z; - float num11 = rotation.w * num12; - float num10 = rotation.w * num2; - float num9 = rotation.w * num; - float num8 = rotation.x * num12; - float num7 = rotation.x * num2; - float num6 = rotation.x * num; - float num5 = rotation.y * num2; - float num4 = rotation.y * num; - float num3 = rotation.z * num; + Vector3 vector; + float num12 = rotation.x + rotation.x; + float num2 = rotation.y + rotation.y; + float num = rotation.z + rotation.z; + float num11 = rotation.w * num12; + float num10 = rotation.w * num2; + float num9 = rotation.w * num; + float num8 = rotation.x * num12; + float num7 = rotation.x * num2; + float num6 = rotation.x * num; + float num5 = rotation.y * num2; + float num4 = rotation.y * num; + float num3 = rotation.z * num; - NiPoint3 value = *this; - float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10)); - float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11)); - float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5)); - vector.x = num15; - vector.y = num14; - vector.z = num13; - return vector; -} \ No newline at end of file + NiPoint3 value = *this; + float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10)); + float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11)); + float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5)); + vector.x = num15; + vector.y = num14; + vector.z = num13; + return vector; +} diff --git a/dCommon/NiPoint3.h b/dCommon/NiPoint3.h index 24e4e617..f76b9269 100644 --- a/dCommon/NiPoint3.h +++ b/dCommon/NiPoint3.h @@ -12,177 +12,180 @@ typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoin //! A custom class the defines a point in space class NiPoint3 { public: - float x; //!< The x position - float y; //!< The y position - float z; //!< The z position + float x; //!< The x position + float y; //!< The y position + float z; //!< The z position - //! Initializer - NiPoint3(void); + //! Initializer + NiPoint3(void); - //! Initializer - /*! - \param x The x coordinate - \param y The y coordinate - \param z The z coordinate - */ - NiPoint3(float x, float y, float z); + //! Initializer + /*! + \param x The x coordinate + \param y The y coordinate + \param z The z coordinate + */ + NiPoint3(float x, float y, float z); - //! Copy Constructor - /*! - \param point The point to copy - */ - NiPoint3(const NiPoint3& point); + //! Copy Constructor + /*! + \param point The point to copy + */ + NiPoint3(const NiPoint3& point); - //! Destructor - ~NiPoint3(void); + //! Destructor + ~NiPoint3(void); - // MARK: Constants - static const NiPoint3 ZERO; //!< Point(0, 0, 0) - static const NiPoint3 UNIT_X; //!< Point(1, 0, 0) - static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0) - static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1) - static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1) + // MARK: Constants + static const NiPoint3 ZERO; //!< Point(0, 0, 0) + static const NiPoint3 UNIT_X; //!< Point(1, 0, 0) + static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0) + static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1) + static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1) - // MARK: Getters / Setters + // MARK: Getters / Setters - //! Gets the X coordinate - /*! - \return The x coordinate - */ - float GetX(void) const; + //! Gets the X coordinate + /*! + \return The x coordinate + */ + float GetX(void) const; - //! Sets the X coordinate - /*! - \param x The x coordinate - */ - void SetX(float x); + //! Sets the X coordinate + /*! + \param x The x coordinate + */ + void SetX(float x); - //! Gets the Y coordinate - /*! - \return The y coordinate - */ - float GetY(void) const; + //! Gets the Y coordinate + /*! + \return The y coordinate + */ + float GetY(void) const; - //! Sets the Y coordinate - /*! - \param y The y coordinate - */ - void SetY(float y); + //! Sets the Y coordinate + /*! + \param y The y coordinate + */ + void SetY(float y); - //! Gets the Z coordinate - /*! - \return The z coordinate - */ - float GetZ(void) const; + //! Gets the Z coordinate + /*! + \return The z coordinate + */ + float GetZ(void) const; - //! Sets the Z coordinate - /*! - \param z The z coordinate - */ - void SetZ(float z); + //! Sets the Z coordinate + /*! + \param z The z coordinate + */ + void SetZ(float z); - // MARK: Member Functions + // MARK: Member Functions - //! Gets the length of the vector - /*! - \return The scalar length of the vector - */ - float Length(void) const; + //! Gets the length of the vector + /*! + \return The scalar length of the vector + */ + float Length(void) const; - //! Gets the squared length of a vector - /*! - \return The squared length of a vector - */ - float SquaredLength(void) const; + //! Gets the squared length of a vector + /*! + \return The squared length of a vector + */ + float SquaredLength(void) const; - //! Returns the dot product of the vector dotted with another vector - /*! - \param vec The second vector - \return The dot product of the two vectors - */ - float DotProduct(const Vector3& vec) const; + //! Returns the dot product of the vector dotted with another vector + /*! + \param vec The second vector + \return The dot product of the two vectors + */ + float DotProduct(const Vector3& vec) const; - //! Returns the cross product of the vector crossed with another vector - /*! - \param vec The second vector - \return The cross product of the two vectors - */ - Vector3 CrossProduct(const Vector3& vec) const; + //! Returns the cross product of the vector crossed with another vector + /*! + \param vec The second vector + \return The cross product of the two vectors + */ + Vector3 CrossProduct(const Vector3& vec) const; - //! Unitize the vector - /*! - \returns The current vector - */ - NiPoint3 Unitize(void) const; + //! Unitize the vector + /*! + \returns The current vector + */ + NiPoint3 Unitize(void) const; - // MARK: Operators + // MARK: Operators - //! Operator to check for equality - bool operator==(const NiPoint3& point) const; + //! Operator to check for equality + bool operator==(const NiPoint3& point) const; - //! Operator to check for inequality - bool operator!=(const NiPoint3& point) const; + //! Operator to check for inequality + bool operator!=(const NiPoint3& point) const; - //! Operator for subscripting - float& operator[](int i); + //! Operator for subscripting + float& operator[](int i); - //! Operator for subscripting - const float& operator[](int i) const; + //! Operator for subscripting + const float& operator[](int i) const; - //! Operator for addition of vectors - NiPoint3 operator+(const NiPoint3& point) const; + //! Operator for addition of vectors + NiPoint3 operator+(const NiPoint3& point) const; - //! Operator for subtraction of vectors - NiPoint3 operator-(const NiPoint3& point) const; + //! Operator for addition of vectors + NiPoint3 operator+=(const NiPoint3& point) const; - //! Operator for addition of a scalar on all vector components - NiPoint3 operator+(float fScalar) const; + //! Operator for subtraction of vectors + NiPoint3 operator-(const NiPoint3& point) const; - //! Operator for subtraction of a scalar on all vector components - NiPoint3 operator-(float fScalar) const; + //! Operator for addition of a scalar on all vector components + NiPoint3 operator+(float fScalar) const; - //! Operator for scalar multiplication of a vector - NiPoint3 operator*(float fScalar) const; + //! Operator for subtraction of a scalar on all vector components + NiPoint3 operator-(float fScalar) const; - //! Operator for scalar division of a vector - NiPoint3 operator/(float fScalar) const; + //! Operator for scalar multiplication of a vector + NiPoint3 operator*(float fScalar) const; + + //! Operator for scalar division of a vector + NiPoint3 operator/(float fScalar) const; - // MARK: Helper Functions + // MARK: Helper Functions - //! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box - /*! - \param minPoint The minimum point of the bounding box - \param maxPoint The maximum point of the bounding box - \return Whether or not this point lies within the box - */ - bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint); + //! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box + /*! + \param minPoint The minimum point of the bounding box + \param maxPoint The maximum point of the bounding box + \return Whether or not this point lies within the box + */ + bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint); - //! Checks to see if the point (or vector) is within a sphere - /*! - \param sphereCenter The sphere center - \param radius The radius - */ - bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius); + //! Checks to see if the point (or vector) is within a sphere + /*! + \param sphereCenter The sphere center + \param radius The radius + */ + bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius); - /*! - \param a Start of line - \param b End of line - \param p Refrence point - \return The point of line AB which is closest to P - */ - static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p); + /*! + \param a Start of line + \param b End of line + \param p Refrence point + \return The point of line AB which is closest to P + */ + static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p); - static float Angle(const NiPoint3& a, const NiPoint3& b); + static float Angle(const NiPoint3& a, const NiPoint3& b); - static float Distance(const NiPoint3& a, const NiPoint3& b); - - static float DistanceSquared(const NiPoint3& a, const NiPoint3& b); + static float Distance(const NiPoint3& a, const NiPoint3& b); - static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta); + static float DistanceSquared(const NiPoint3& a, const NiPoint3& b); - NiPoint3 RotateByQuaternion(const NiQuaternion& rotation); + static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta); + + NiPoint3 RotateByQuaternion(const NiQuaternion& rotation); }; diff --git a/dCommon/NiQuaternion.cpp b/dCommon/NiQuaternion.cpp index a8aa1dc8..33c5c976 100644 --- a/dCommon/NiQuaternion.cpp +++ b/dCommon/NiQuaternion.cpp @@ -8,18 +8,18 @@ const NiQuaternion NiQuaternion::IDENTITY(1, 0, 0, 0); //! The initializer NiQuaternion::NiQuaternion(void) { - this->w = 1; - this->x = 0; - this->y = 0; - this->z = 0; + this->w = 1; + this->x = 0; + this->y = 0; + this->z = 0; } //! The initializer NiQuaternion::NiQuaternion(float w, float x, float y, float z) { - this->w = w; - this->x = x; - this->y = y; - this->z = z; + this->w = w; + this->x = x; + this->y = y; + this->z = z; } //! Destructor @@ -30,42 +30,42 @@ NiQuaternion::~NiQuaternion(void) {} //! Gets the W coordinate float NiQuaternion::GetW(void) const { - return this->w; + return this->w; } //! Sets the W coordinate void NiQuaternion::SetW(float w) { - this->w = w; + this->w = w; } //! Gets the X coordinate float NiQuaternion::GetX(void) const { - return this->x; + return this->x; } //! Sets the X coordinate void NiQuaternion::SetX(float x) { - this->x = x; + this->x = x; } //! Gets the Y coordinate float NiQuaternion::GetY(void) const { - return this->y; + return this->y; } //! Sets the Y coordinate void NiQuaternion::SetY(float y) { - this->y = y; + this->y = y; } //! Gets the Z coordinate float NiQuaternion::GetZ(void) const { - return this->z; + return this->z; } //! Sets the Z coordinate void NiQuaternion::SetZ(float z) { - this->z = z; + this->z = z; } @@ -73,55 +73,54 @@ void NiQuaternion::SetZ(float z) { //! Returns the forward vector from the quaternion Vector3 NiQuaternion::GetForwardVector(void) const { - return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); + return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); } //! Returns the up vector from the quaternion Vector3 NiQuaternion::GetUpVector(void) const { - return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); + return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); } //! Returns the right vector from the quaternion Vector3 NiQuaternion::GetRightVector(void) const { - return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); + return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); } Vector3 NiQuaternion::GetEulerAngles() const { - Vector3 angles; + Vector3 angles; - // roll (x-axis rotation) - const float sinr_cosp = 2 * (w * x + y * z); - const float cosr_cosp = 1 - 2 * (x * x + y * y); - angles.x = std::atan2(sinr_cosp, cosr_cosp); + // roll (x-axis rotation) + const float sinr_cosp = 2 * (w * x + y * z); + const float cosr_cosp = 1 - 2 * (x * x + y * y); + angles.x = std::atan2(sinr_cosp, cosr_cosp); - // pitch (y-axis rotation) - const float sinp = 2 * (w * y - z * x); - - if (std::abs(sinp) >= 1) { - angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range - } - else { - angles.y = std::asin(sinp); - } + // pitch (y-axis rotation) + const float sinp = 2 * (w * y - z * x); - // yaw (z-axis rotation) - const float siny_cosp = 2 * (w * z + x * y); - const float cosy_cosp = 1 - 2 * (y * y + z * z); - angles.z = std::atan2(siny_cosp, cosy_cosp); + if (std::abs(sinp) >= 1) { + angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range + } else { + angles.y = std::asin(sinp); + } - return angles; + // yaw (z-axis rotation) + const float siny_cosp = 2 * (w * z + x * y); + const float cosy_cosp = 1 - 2 * (y * y + z * z); + angles.z = std::atan2(siny_cosp, cosy_cosp); + + return angles; } // MARK: Operators //! Operator to check for equality bool NiQuaternion::operator==(const NiQuaternion& rot) const { - return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w; + return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w; } //! Operator to check for inequality bool NiQuaternion::operator!=(const NiQuaternion& rot) const { - return !(*this == rot); + return !(*this == rot); } @@ -135,65 +134,63 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d source.y = 0.0f; dest.y = 0.0f; - NiPoint3 forwardVector = NiPoint3(dest - source).Unitize(); - - NiPoint3 posZ = NiPoint3::UNIT_Z; - NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); - - float dot = posZ.DotProduct(forwardVector); - float rotAngle = static_cast(acos(dot)); - - NiPoint3 vecB = vecA.CrossProduct(posZ); - - if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle; - return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); + NiPoint3 forwardVector = NiPoint3(dest - source).Unitize(); + + NiPoint3 posZ = NiPoint3::UNIT_Z; + NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); + + float dot = posZ.DotProduct(forwardVector); + float rotAngle = static_cast(acos(dot)); + + NiPoint3 vecB = vecA.CrossProduct(posZ); + + if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle; + return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); } -NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) -{ - NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize(); - - NiPoint3 posZ = NiPoint3::UNIT_Z; - NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); - - float dot = posZ.DotProduct(forwardVector); - float rotAngle = static_cast(acos(dot)); - - NiPoint3 vecB = vecA.CrossProduct(posZ); - - if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle; - return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); +NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) { + NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize(); + + NiPoint3 posZ = NiPoint3::UNIT_Z; + NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); + + float dot = posZ.DotProduct(forwardVector); + float rotAngle = static_cast(acos(dot)); + + NiPoint3 vecB = vecA.CrossProduct(posZ); + + if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle; + return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); } //! Creates a Quaternion from a specific axis and angle relative to that axis NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle) { - float halfAngle = angle * 0.5f; - float s = static_cast(sin(halfAngle)); - - NiQuaternion q; - q.x = axis.GetX() * s; - q.y = axis.GetY() * s; - q.z = axis.GetZ() * s; - q.w = static_cast(cos(halfAngle)); - - return q; + float halfAngle = angle * 0.5f; + float s = static_cast(sin(halfAngle)); + + NiQuaternion q; + q.x = axis.GetX() * s; + q.y = axis.GetY() * s; + q.z = axis.GetZ() * s; + q.w = static_cast(cos(halfAngle)); + + return q; } -NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles) -{ - // Abbreviations for the various angular functions - float cy = cos(eulerAngles.z * 0.5); - float sy = sin(eulerAngles.z * 0.5); - float cp = cos(eulerAngles.y * 0.5); - float sp = sin(eulerAngles.y * 0.5); - float cr = cos(eulerAngles.x * 0.5); - float sr = sin(eulerAngles.x * 0.5); +NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles) { + // Abbreviations for the various angular functions + float cy = cos(eulerAngles.z * 0.5); + float sy = sin(eulerAngles.z * 0.5); + float cp = cos(eulerAngles.y * 0.5); + float sp = sin(eulerAngles.y * 0.5); + float cr = cos(eulerAngles.x * 0.5); + float sr = sin(eulerAngles.x * 0.5); - NiQuaternion q; - q.w = cr * cp * cy + sr * sp * sy; - q.x = sr * cp * cy - cr * sp * sy; - q.y = cr * sp * cy + sr * cp * sy; - q.z = cr * cp * sy - sr * sp * cy; + NiQuaternion q; + q.w = cr * cp * cy + sr * sp * sy; + q.x = sr * cp * cy - cr * sp * sy; + q.y = cr * sp * cy + sr * cp * sy; + q.z = cr * cp * sy - sr * sp * cy; - return q; + return q; } diff --git a/dCommon/NiQuaternion.h b/dCommon/NiQuaternion.h index f479501a..b7d60f4e 100644 --- a/dCommon/NiQuaternion.h +++ b/dCommon/NiQuaternion.h @@ -14,138 +14,138 @@ typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version o //! A class that defines a rotation in space class NiQuaternion { public: - float w; //!< The w coordinate - float x; //!< The x coordinate - float y; //!< The y coordinate - float z; //!< The z coordinate - - - //! The initializer - NiQuaternion(void); - - //! The initializer - /*! - \param w The w coordinate - \param x The x coordinate - \param y The y coordinate - \param z The z coordinate - */ - NiQuaternion(float w, float x, float y, float z); - - //! Destructor - ~NiQuaternion(void); - - // MARK: Constants - static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0) - - // MARK: Setters / Getters - - //! Gets the W coordinate - /*! - \return The w coordinate - */ - float GetW(void) const; - - //! Sets the W coordinate - /*! - \param w The w coordinate - */ - void SetW(float w); - - //! Gets the X coordinate - /*! - \return The x coordinate - */ - float GetX(void) const; - - //! Sets the X coordinate - /*! - \param x The x coordinate - */ - void SetX(float x); - - //! Gets the Y coordinate - /*! - \return The y coordinate - */ - float GetY(void) const; - - //! Sets the Y coordinate - /*! - \param y The y coordinate - */ - void SetY(float y); - - //! Gets the Z coordinate - /*! - \return The z coordinate - */ - float GetZ(void) const; - - //! Sets the Z coordinate - /*! - \param z The z coordinate - */ - void SetZ(float z); - - - // MARK: Member Functions - - //! Returns the forward vector from the quaternion - /*! - \return The forward vector of the quaternion - */ - Vector3 GetForwardVector(void) const; - - //! Returns the up vector from the quaternion - /*! - \return The up vector fo the quaternion - */ - Vector3 GetUpVector(void) const; - - //! Returns the right vector from the quaternion - /*! - \return The right vector of the quaternion - */ - Vector3 GetRightVector(void) const; + float w; //!< The w coordinate + float x; //!< The x coordinate + float y; //!< The y coordinate + float z; //!< The z coordinate - Vector3 GetEulerAngles() const; - - - // MARK: Operators - - //! Operator to check for equality - bool operator==(const NiQuaternion& rot) const; - - //! Operator to check for inequality - bool operator!=(const NiQuaternion& rot) const; - - - // MARK: Helper Functions - - //! Look from a specific point in space to another point in space (Y-locked) - /*! - \param sourcePoint The source location - \param destPoint The destination location - \return The Quaternion with the rotation towards the destination - */ - static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint); - - //! Look from a specific point in space to another point in space - /*! - \param sourcePoint The source location - \param destPoint The destination location - \return The Quaternion with the rotation towards the destination - */ - static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint); - - //! Creates a Quaternion from a specific axis and angle relative to that axis - /*! - \param axis The axis that is used - \param angle The angle relative to this axis - \return A quaternion created from the axis and angle - */ - static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle); - static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles); + //! The initializer + NiQuaternion(void); + + //! The initializer + /*! + \param w The w coordinate + \param x The x coordinate + \param y The y coordinate + \param z The z coordinate + */ + NiQuaternion(float w, float x, float y, float z); + + //! Destructor + ~NiQuaternion(void); + + // MARK: Constants + static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0) + + // MARK: Setters / Getters + + //! Gets the W coordinate + /*! + \return The w coordinate + */ + float GetW(void) const; + + //! Sets the W coordinate + /*! + \param w The w coordinate + */ + void SetW(float w); + + //! Gets the X coordinate + /*! + \return The x coordinate + */ + float GetX(void) const; + + //! Sets the X coordinate + /*! + \param x The x coordinate + */ + void SetX(float x); + + //! Gets the Y coordinate + /*! + \return The y coordinate + */ + float GetY(void) const; + + //! Sets the Y coordinate + /*! + \param y The y coordinate + */ + void SetY(float y); + + //! Gets the Z coordinate + /*! + \return The z coordinate + */ + float GetZ(void) const; + + //! Sets the Z coordinate + /*! + \param z The z coordinate + */ + void SetZ(float z); + + + // MARK: Member Functions + + //! Returns the forward vector from the quaternion + /*! + \return The forward vector of the quaternion + */ + Vector3 GetForwardVector(void) const; + + //! Returns the up vector from the quaternion + /*! + \return The up vector fo the quaternion + */ + Vector3 GetUpVector(void) const; + + //! Returns the right vector from the quaternion + /*! + \return The right vector of the quaternion + */ + Vector3 GetRightVector(void) const; + + Vector3 GetEulerAngles() const; + + + // MARK: Operators + + //! Operator to check for equality + bool operator==(const NiQuaternion& rot) const; + + //! Operator to check for inequality + bool operator!=(const NiQuaternion& rot) const; + + + // MARK: Helper Functions + + //! Look from a specific point in space to another point in space (Y-locked) + /*! + \param sourcePoint The source location + \param destPoint The destination location + \return The Quaternion with the rotation towards the destination + */ + static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint); + + //! Look from a specific point in space to another point in space + /*! + \param sourcePoint The source location + \param destPoint The destination location + \return The Quaternion with the rotation towards the destination + */ + static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint); + + //! Creates a Quaternion from a specific axis and angle relative to that axis + /*! + \param axis The axis that is used + \param angle The angle relative to this axis + \return A quaternion created from the axis and angle + */ + static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle); + + static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles); }; diff --git a/dCommon/PermissionMap.h b/dCommon/PermissionMap.h deleted file mode 100644 index 177f4884..00000000 --- a/dCommon/PermissionMap.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -/** - * Bitmap of permissions and restrictions for characters. - */ -enum class PermissionMap : uint64_t -{ - /** - * Reserved for future use, bit 0-3. - */ - - /** - * The character has restricted trade acccess, bit 4. - */ - RestrictedTradeAccess = 0x1 << 4, - - /** - * The character has restricted mail access, bit 5. - */ - RestrictedMailAccess = 0x1 << 5, - - /** - * The character has restricted chat access, bit 6. - */ - RestrictedChatAccess = 0x1 << 6, - - // - // Combined permissions - // - - /** - * The character is marked as 'old', restricted from trade and mail. - */ - Old = RestrictedTradeAccess | RestrictedMailAccess, - - /** - * The character is soft banned, restricted from trade, mail, and chat. - */ - SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess, -}; diff --git a/dCommon/SHA512.cpp b/dCommon/SHA512.cpp index 6daf44f6..f5a71d99 100644 --- a/dCommon/SHA512.cpp +++ b/dCommon/SHA512.cpp @@ -5,153 +5,148 @@ const unsigned long long SHA512::sha512_k[80] = //ULL = uint64 { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; -void SHA512::transform(const unsigned char *message, unsigned int block_nb) -{ - uint64 w[80]; - uint64 wv[8]; - uint64 t1, t2; - const unsigned char *sub_block; - int i, j; - for (i = 0; i < (int)block_nb; i++) { - sub_block = message + (i << 7); - for (j = 0; j < 16; j++) { - SHA2_PACK64(&sub_block[j << 3], &w[j]); - } - for (j = 16; j < 80; j++) { - w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16]; - } - for (j = 0; j < 8; j++) { - wv[j] = m_h[j]; - } - for (j = 0; j < 80; j++) { - t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) - + sha512_k[j] + w[j]; - t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]); - wv[7] = wv[6]; - wv[6] = wv[5]; - wv[5] = wv[4]; - wv[4] = wv[3] + t1; - wv[3] = wv[2]; - wv[2] = wv[1]; - wv[1] = wv[0]; - wv[0] = t1 + t2; - } - for (j = 0; j < 8; j++) { - m_h[j] += wv[j]; - } - - } +void SHA512::transform(const unsigned char* message, unsigned int block_nb) { + uint64 w[80]; + uint64 wv[8]; + uint64 t1, t2; + const unsigned char* sub_block; + int i, j; + for (i = 0; i < (int)block_nb; i++) { + sub_block = message + (i << 7); + for (j = 0; j < 16; j++) { + SHA2_PACK64(&sub_block[j << 3], &w[j]); + } + for (j = 16; j < 80; j++) { + w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16]; + } + for (j = 0; j < 8; j++) { + wv[j] = m_h[j]; + } + for (j = 0; j < 80; j++) { + t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + + sha512_k[j] + w[j]; + t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + for (j = 0; j < 8; j++) { + m_h[j] += wv[j]; + } + + } } -void SHA512::init() -{ - m_h[0] = 0x6a09e667f3bcc908ULL; - m_h[1] = 0xbb67ae8584caa73bULL; - m_h[2] = 0x3c6ef372fe94f82bULL; - m_h[3] = 0xa54ff53a5f1d36f1ULL; - m_h[4] = 0x510e527fade682d1ULL; - m_h[5] = 0x9b05688c2b3e6c1fULL; - m_h[6] = 0x1f83d9abfb41bd6bULL; - m_h[7] = 0x5be0cd19137e2179ULL; - m_len = 0; - m_tot_len = 0; +void SHA512::init() { + m_h[0] = 0x6a09e667f3bcc908ULL; + m_h[1] = 0xbb67ae8584caa73bULL; + m_h[2] = 0x3c6ef372fe94f82bULL; + m_h[3] = 0xa54ff53a5f1d36f1ULL; + m_h[4] = 0x510e527fade682d1ULL; + m_h[5] = 0x9b05688c2b3e6c1fULL; + m_h[6] = 0x1f83d9abfb41bd6bULL; + m_h[7] = 0x5be0cd19137e2179ULL; + m_len = 0; + m_tot_len = 0; } -void SHA512::update(const unsigned char *message, unsigned int len) -{ - unsigned int block_nb; - unsigned int new_len, rem_len, tmp_len; - const unsigned char *shifted_message; - tmp_len = SHA384_512_BLOCK_SIZE - m_len; - rem_len = len < tmp_len ? len : tmp_len; - memcpy(&m_block[m_len], message, rem_len); - if (m_len + len < SHA384_512_BLOCK_SIZE) { - m_len += len; - return; - } - new_len = len - rem_len; - block_nb = new_len / SHA384_512_BLOCK_SIZE; - shifted_message = message + rem_len; - transform(m_block, 1); - transform(shifted_message, block_nb); - rem_len = new_len % SHA384_512_BLOCK_SIZE; - memcpy(m_block, &shifted_message[block_nb << 7], rem_len); - m_len = rem_len; - m_tot_len += (block_nb + 1) << 7; +void SHA512::update(const unsigned char* message, unsigned int len) { + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char* shifted_message; + tmp_len = SHA384_512_BLOCK_SIZE - m_len; + rem_len = len < tmp_len ? len : tmp_len; + memcpy(&m_block[m_len], message, rem_len); + if (m_len + len < SHA384_512_BLOCK_SIZE) { + m_len += len; + return; + } + new_len = len - rem_len; + block_nb = new_len / SHA384_512_BLOCK_SIZE; + shifted_message = message + rem_len; + transform(m_block, 1); + transform(shifted_message, block_nb); + rem_len = new_len % SHA384_512_BLOCK_SIZE; + memcpy(m_block, &shifted_message[block_nb << 7], rem_len); + m_len = rem_len; + m_tot_len += (block_nb + 1) << 7; } -void SHA512::final(unsigned char *digest) -{ - unsigned int block_nb; - unsigned int pm_len; - unsigned int len_b; - int i; - block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17) - < (m_len % SHA384_512_BLOCK_SIZE)); - len_b = (m_tot_len + m_len) << 3; - pm_len = block_nb << 7; - memset(m_block + m_len, 0, pm_len - m_len); - m_block[m_len] = 0x80; - SHA2_UNPACK32(len_b, m_block + pm_len - 4); - transform(m_block, block_nb); - for (i = 0; i < 8; i++) { - SHA2_UNPACK64(m_h[i], &digest[i << 3]); - } +void SHA512::final(unsigned char* digest) { + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + int i; + block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17) + < (m_len % SHA384_512_BLOCK_SIZE)); + len_b = (m_tot_len + m_len) << 3; + pm_len = block_nb << 7; + memset(m_block + m_len, 0, pm_len - m_len); + m_block[m_len] = 0x80; + SHA2_UNPACK32(len_b, m_block + pm_len - 4); + transform(m_block, block_nb); + for (i = 0; i < 8; i++) { + SHA2_UNPACK64(m_h[i], &digest[i << 3]); + } } -std::string sha512(std::string input) -{ - unsigned char digest[SHA512::DIGEST_SIZE]; - memset(digest, 0, SHA512::DIGEST_SIZE); - class SHA512 ctx; - ctx.init(); - ctx.update((unsigned char*)input.c_str(), input.length()); - ctx.final(digest); +std::string sha512(std::string input) { + unsigned char digest[SHA512::DIGEST_SIZE]; + memset(digest, 0, SHA512::DIGEST_SIZE); + class SHA512 ctx; + ctx.init(); + ctx.update((unsigned char*)input.c_str(), input.length()); + ctx.final(digest); - char buf[2 * SHA512::DIGEST_SIZE + 1]; - buf[2 * SHA512::DIGEST_SIZE] = 0; - for (int i = 0; i < SHA512::DIGEST_SIZE; i++) - sprintf(buf + i * 2, "%02x", digest[i]); + char buf[2 * SHA512::DIGEST_SIZE + 1]; + buf[2 * SHA512::DIGEST_SIZE] = 0; + for (int i = 0; i < SHA512::DIGEST_SIZE; i++) + sprintf(buf + i * 2, "%02x", digest[i]); - return std::string(buf); + return std::string(buf); } diff --git a/dCommon/SHA512.h b/dCommon/SHA512.h index aba80432..512fa645 100644 --- a/dCommon/SHA512.h +++ b/dCommon/SHA512.h @@ -5,25 +5,25 @@ class SHA512 { protected: - typedef unsigned char uint8; - typedef unsigned int uint32; - typedef unsigned long long uint64; - - const static uint64 sha512_k[]; - static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8); - + typedef unsigned char uint8; + typedef unsigned int uint32; + typedef unsigned long long uint64; + + const static uint64 sha512_k[]; + static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8); + public: - void init(); - void update(const unsigned char *message, unsigned int len); - void final(unsigned char *digest); - static const unsigned int DIGEST_SIZE = (512 / 8); - + void init(); + void update(const unsigned char* message, unsigned int len); + void final(unsigned char* digest); + static const unsigned int DIGEST_SIZE = (512 / 8); + protected: - void transform(const unsigned char *message, unsigned int block_nb); - unsigned int m_tot_len; - unsigned int m_len; - unsigned char m_block[2 * SHA384_512_BLOCK_SIZE]; - uint64 m_h[8]; + void transform(const unsigned char* message, unsigned int block_nb); + unsigned int m_tot_len; + unsigned int m_len; + unsigned char m_block[2 * SHA384_512_BLOCK_SIZE]; + uint64 m_h[8]; }; std::string sha512(std::string input); diff --git a/dPhysics/Singleton.h b/dCommon/Singleton.h similarity index 99% rename from dPhysics/Singleton.h rename to dCommon/Singleton.h index b923202f..750a4996 100644 --- a/dPhysics/Singleton.h +++ b/dCommon/Singleton.h @@ -16,4 +16,4 @@ public: protected: Singleton() = default; -}; \ No newline at end of file +}; diff --git a/dCommon/Type.cpp b/dCommon/Type.cpp index f89d090e..5cce9d66 100644 --- a/dCommon/Type.cpp +++ b/dCommon/Type.cpp @@ -6,22 +6,22 @@ std::string demangle(const char* name) { - int status = -4; // some arbitrary value to eliminate the compiler warning + int status = -4; // some arbitrary value to eliminate the compiler warning - // enable c++11 by passing the flag -std=c++11 to g++ - std::unique_ptr res { - abi::__cxa_demangle(name, NULL, NULL, &status), - std::free - }; + // enable c++11 by passing the flag -std=c++11 to g++ + std::unique_ptr res{ + abi::__cxa_demangle(name, NULL, NULL, &status), + std::free + }; - return (status==0) ? res.get() : name ; + return (status == 0) ? res.get() : name; } #else // does nothing if not g++ std::string demangle(const char* name) { - return name; + return name; } #endif diff --git a/dCommon/Type.h b/dCommon/Type.h index ea26d2ce..552bb09f 100644 --- a/dCommon/Type.h +++ b/dCommon/Type.h @@ -8,5 +8,5 @@ std::string demangle(const char* name); template std::string type(const T& t) { - return demangle(typeid(t).name()); + return demangle(typeid(t).name()); } diff --git a/dCommon/ZCompression.cpp b/dCommon/ZCompression.cpp index 3a66323d..d5d4c126 100644 --- a/dCommon/ZCompression.cpp +++ b/dCommon/ZCompression.cpp @@ -1,73 +1,50 @@ -#include "ZCompression.h" +#include "ZCompression.h" #include -namespace ZCompression -{ - int32_t GetMaxCompressedLength(int32_t nLenSrc) - { - int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block - return (nLenSrc + 6 + (n16kBlocks * 5)); - } +namespace ZCompression { + int32_t GetMaxCompressedLength(int32_t nLenSrc) { + int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block + return (nLenSrc + 6 + (n16kBlocks * 5)); + } - int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst) - { - z_stream zInfo = { 0 }; - zInfo.total_in = zInfo.avail_in = nLenSrc; - zInfo.total_out = zInfo.avail_out = nLenDst; - zInfo.next_in = const_cast(abSrc); - zInfo.next_out = abDst; + int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst) { + z_stream zInfo = { 0 }; + zInfo.total_in = zInfo.avail_in = nLenSrc; + zInfo.total_out = zInfo.avail_out = nLenDst; + zInfo.next_in = const_cast(abSrc); + zInfo.next_out = abDst; - int nErr, nRet = -1; - nErr = deflateInit(&zInfo, Z_DEFAULT_COMPRESSION); // zlib function - if (nErr == Z_OK) { - nErr = deflate(&zInfo, Z_FINISH); // zlib function - if (nErr == Z_STREAM_END) { - nRet = zInfo.total_out; - } - } - deflateEnd(&zInfo); // zlib function - return(nRet); + int nErr, nRet = -1; + nErr = deflateInit(&zInfo, Z_DEFAULT_COMPRESSION); // zlib function + if (nErr == Z_OK) { + nErr = deflate(&zInfo, Z_FINISH); // zlib function + if (nErr == Z_STREAM_END) { + nRet = zInfo.total_out; + } + } + deflateEnd(&zInfo); // zlib function + return(nRet); + } - } + int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr) { + // Get the size of the decompressed data + z_stream zInfo = { 0 }; + zInfo.total_in = zInfo.avail_in = nLenSrc; + zInfo.total_out = zInfo.avail_out = nLenDst; + zInfo.next_in = const_cast(abSrc); + zInfo.next_out = abDst; - int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr) - { - // Get the size of the decompressed data - z_stream zInfo = { 0 }; - zInfo.total_in = zInfo.avail_in = nLenSrc; - zInfo.total_out = zInfo.avail_out = nLenDst; - zInfo.next_in = const_cast(abSrc); - zInfo.next_out = abDst; + int nRet = -1; + nErr = inflateInit(&zInfo); // zlib function + if (nErr == Z_OK) { + nErr = inflate(&zInfo, Z_FINISH); // zlib function + if (nErr == Z_STREAM_END) { + nRet = zInfo.total_out; + } + } + inflateEnd(&zInfo); // zlib function + return(nRet); + } +} - int nRet = -1; - nErr = inflateInit(&zInfo); // zlib function - if (nErr == Z_OK) { - nErr = inflate(&zInfo, Z_FINISH); // zlib function - if (nErr == Z_STREAM_END) { - nRet = zInfo.total_out; - } - } - inflateEnd(&zInfo); // zlib function - return(nRet); - - /* - z_stream zInfo = { 0 }; - zInfo.total_in = zInfo.avail_in = nLenSrc; - zInfo.total_out = zInfo.avail_out = nLenDst; - zInfo.next_in = const_cast(abSrc); - zInfo.next_out = const_cast(abDst); - - int nRet = -1; - nErr = inflateInit(&zInfo); // zlib function - if (nErr == Z_OK) { - nErr = inflate(&zInfo, Z_FINISH); // zlib function - if (nErr == Z_STREAM_END) { - nRet = zInfo.total_out; - } - } - inflateEnd(&zInfo); // zlib function - return(nRet); // -1 or len of output - */ - } -} \ No newline at end of file diff --git a/dCommon/ZCompression.h b/dCommon/ZCompression.h index ec870fb8..84e8a9b4 100644 --- a/dCommon/ZCompression.h +++ b/dCommon/ZCompression.h @@ -1,12 +1,18 @@ -#pragma once +#pragma once #include -namespace ZCompression -{ +namespace ZCompression { int32_t GetMaxCompressedLength(int32_t nLenSrc); int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst); int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr); + + /** + * @brief Max size of an inflated sd0 zlib chunk + * + */ + constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256; } + diff --git a/dCommon/dClient/AssetManager.cpp b/dCommon/dClient/AssetManager.cpp new file mode 100644 index 00000000..00cedba9 --- /dev/null +++ b/dCommon/dClient/AssetManager.cpp @@ -0,0 +1,183 @@ +#include + +#include "AssetManager.h" +#include "Game.h" +#include "dLogger.h" + +#include + +AssetManager::AssetManager(const std::filesystem::path& path) { + if (!std::filesystem::is_directory(path)) { + throw std::runtime_error("Attempted to load asset bundle (" + path.string() + ") however it is not a valid directory."); + } + + m_Path = path; + + if (std::filesystem::exists(m_Path / "client") && std::filesystem::exists(m_Path / "versions")) { + m_AssetBundleType = eAssetBundleType::Packed; + + m_RootPath = m_Path; + m_ResPath = (m_Path / "client" / "res"); + } else if (std::filesystem::exists(m_Path / ".." / "versions") && std::filesystem::exists(m_Path / "res")) { + m_AssetBundleType = eAssetBundleType::Packed; + + m_RootPath = (m_Path / ".."); + m_ResPath = (m_Path / "res"); + } else if (std::filesystem::exists(m_Path / "pack") && std::filesystem::exists(m_Path / ".." / ".." / "versions")) { + m_AssetBundleType = eAssetBundleType::Packed; + + m_RootPath = (m_Path / ".." / ".."); + m_ResPath = m_Path; + } else if ((std::filesystem::exists(m_Path / "res" / "cdclient.fdb") || std::filesystem::exists(m_Path / "res" / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "res" / "pack")) { + m_AssetBundleType = eAssetBundleType::Unpacked; + + m_ResPath = (m_Path / "res"); + } else if ((std::filesystem::exists(m_Path / "cdclient.fdb") || std::filesystem::exists(m_Path / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "pack")) { + m_AssetBundleType = eAssetBundleType::Unpacked; + + m_ResPath = m_Path; + } + + if (m_AssetBundleType == eAssetBundleType::None) { + throw std::runtime_error("Failed to identify client type, cannot read client data."); + } + + switch (m_AssetBundleType) { + case eAssetBundleType::Packed: { + this->LoadPackIndex(); + break; + } + case eAssetBundleType::None: + case eAssetBundleType::Unpacked: { + break; + } + } +} + +void AssetManager::LoadPackIndex() { + m_PackIndex = new PackIndex(m_RootPath); +} + +std::filesystem::path AssetManager::GetResPath() { + return m_ResPath; +} + +eAssetBundleType AssetManager::GetAssetBundleType() { + return m_AssetBundleType; +} + +bool AssetManager::HasFile(const char* name) { + auto fixedName = std::string(name); + std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); }); + + // Special case for unpacked client have BrickModels in upper case + if (this->m_AssetBundleType == eAssetBundleType::Unpacked) GeneralUtils::ReplaceInString(fixedName, "brickmodels", "BrickModels"); + + std::replace(fixedName.begin(), fixedName.end(), '\\', '/'); + if (std::filesystem::exists(m_ResPath / fixedName)) return true; + + if (this->m_AssetBundleType == eAssetBundleType::Unpacked) return false; + + std::replace(fixedName.begin(), fixedName.end(), '/', '\\'); + if (fixedName.rfind("client\\res\\", 0) != 0) fixedName = "client\\res\\" + fixedName; + + uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size()); + crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4); + + for (const auto& item : this->m_PackIndex->GetPackFileIndices()) { + if (item.m_Crc == crc) { + return true; + } + } + + return false; +} + +bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) { + auto fixedName = std::string(name); + std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); }); + std::replace(fixedName.begin(), fixedName.end(), '\\', '/'); // On the off chance someone has the wrong slashes, force forward slashes + + // Special case for unpacked client have BrickModels in upper case + if (this->m_AssetBundleType == eAssetBundleType::Unpacked) GeneralUtils::ReplaceInString(fixedName, "brickmodels", "BrickModels"); + + if (std::filesystem::exists(m_ResPath / fixedName)) { + FILE* file; +#ifdef _WIN32 + fopen_s(&file, (m_ResPath / fixedName).string().c_str(), "rb"); +#elif __APPLE__ + // macOS has 64bit file IO by default + file = fopen((m_ResPath / fixedName).string().c_str(), "rb"); +#else + file = fopen64((m_ResPath / fixedName).string().c_str(), "rb"); +#endif + fseek(file, 0, SEEK_END); + *len = ftell(file); + *data = (char*)malloc(*len); + fseek(file, 0, SEEK_SET); + int32_t readInData = fread(*data, sizeof(uint8_t), *len, file); + fclose(file); + + return true; + } + + if (this->m_AssetBundleType == eAssetBundleType::Unpacked) return false; + + // The crc in side of the pack always uses backslashes, so we need to convert them again... + std::replace(fixedName.begin(), fixedName.end(), '/', '\\'); + if (fixedName.rfind("client\\res\\", 0) != 0) { + fixedName = "client\\res\\" + fixedName; + } + int32_t packIndex = -1; + uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size()); + crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4); + + for (const auto& item : this->m_PackIndex->GetPackFileIndices()) { + if (item.m_Crc == crc) { + packIndex = item.m_PackFileIndex; + crc = item.m_Crc; + break; + } + } + + if (packIndex == -1 || !crc) { + return false; + } + + auto packs = this->m_PackIndex->GetPacks(); + auto* pack = packs.at(packIndex); + + bool success = pack->ReadFileFromPack(crc, data, len); + + return success; +} + +AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) { + char* buf; + uint32_t len; + + bool success = this->GetFile(name, &buf, &len); + + return AssetMemoryBuffer(buf, len, success); +} + +uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) { + size_t i, j; + uint32_t crc, msb; + + crc = base; + for (i = 0; i < l; i++) { + // xor next byte to upper bits of crc + crc ^= (((unsigned int)message[i]) << 24); + for (j = 0; j < 8; j++) { // Do eight times. + msb = crc >> 31; + crc <<= 1; + crc ^= (0 - msb) & 0x04C11DB7; + } + } + return crc; // don't complement crc on output +} + +AssetManager::~AssetManager() { + delete m_PackIndex; +} diff --git a/dCommon/dClient/AssetManager.h b/dCommon/dClient/AssetManager.h new file mode 100644 index 00000000..bc7e5ff7 --- /dev/null +++ b/dCommon/dClient/AssetManager.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include + +#include "Pack.h" +#include "PackIndex.h" + +enum class eAssetBundleType { + None, + Unpacked, + Packed +}; + +struct AssetMemoryBuffer : std::streambuf { + char* m_Base; + bool m_Success; + + AssetMemoryBuffer(char* base, std::ptrdiff_t n, bool success) { + m_Base = base; + m_Success = success; + if (!m_Success) return; + this->setg(base, base, base + n); + } + + pos_type seekpos(pos_type sp, std::ios_base::openmode which) override { + return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which); + } + + pos_type seekoff(off_type off, + std::ios_base::seekdir dir, + std::ios_base::openmode which = std::ios_base::in) override { + if (dir == std::ios_base::cur) + gbump(off); + else if (dir == std::ios_base::end) + setg(eback(), egptr() + off, egptr()); + else if (dir == std::ios_base::beg) + setg(eback(), eback() + off, egptr()); + return gptr() - eback(); + } + + void close() { + delete m_Base; + } +}; + +class AssetManager { +public: + AssetManager(const std::filesystem::path& path); + ~AssetManager(); + + std::filesystem::path GetResPath(); + eAssetBundleType GetAssetBundleType(); + + bool HasFile(const char* name); + bool GetFile(const char* name, char** data, uint32_t* len); + AssetMemoryBuffer GetFileAsBuffer(const char* name); + +private: + void LoadPackIndex(); + + // Modified crc algorithm (mpeg2) + // Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2 + inline uint32_t crc32b(uint32_t base, uint8_t* message, size_t l); + + bool m_SuccessfullyLoaded; + + std::filesystem::path m_Path; + std::filesystem::path m_RootPath; + std::filesystem::path m_ResPath; + + eAssetBundleType m_AssetBundleType = eAssetBundleType::None; + + PackIndex* m_PackIndex; +}; diff --git a/dCommon/dClient/CMakeLists.txt b/dCommon/dClient/CMakeLists.txt new file mode 100644 index 00000000..69bb1712 --- /dev/null +++ b/dCommon/dClient/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DCOMMON_DCLIENT_SOURCES + "PackIndex.cpp" + "Pack.cpp" + "AssetManager.cpp" + PARENT_SCOPE +) diff --git a/dCommon/dClient/Pack.cpp b/dCommon/dClient/Pack.cpp new file mode 100644 index 00000000..11345fc9 --- /dev/null +++ b/dCommon/dClient/Pack.cpp @@ -0,0 +1,119 @@ +#include "Pack.h" + +#include "BinaryIO.h" +#include "ZCompression.h" + +Pack::Pack(const std::filesystem::path& filePath) { + m_FilePath = filePath; + + if (!std::filesystem::exists(filePath)) { + return; + } + + m_FileStream = std::ifstream(filePath, std::ios::in | std::ios::binary); + + m_FileStream.read(m_Version, 7); + + m_FileStream.seekg(-8, std::ios::end); // move file pointer to 8 bytes before the end (location of the address of the record count) + + uint32_t recordCountPos = 0; + BinaryIO::BinaryRead(m_FileStream, recordCountPos); + + m_FileStream.seekg(recordCountPos, std::ios::beg); + + BinaryIO::BinaryRead(m_FileStream, m_RecordCount); + + for (int i = 0; i < m_RecordCount; i++) { + PackRecord record; + BinaryIO::BinaryRead(m_FileStream, record); + + m_Records.push_back(record); + } + + m_FileStream.close(); +} + +bool Pack::HasFile(uint32_t crc) { + for (const auto& record : m_Records) { + if (record.m_Crc == crc) { + return true; + } + } + + return false; +} + +bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) { + // Time for some wacky C file reading for speed reasons + + PackRecord pkRecord{}; + + for (const auto& record : m_Records) { + if (record.m_Crc == crc) { + pkRecord = record; + break; + } + } + + if (pkRecord.m_Crc == 0) return false; + + size_t pos = 0; + pos += pkRecord.m_FilePointer; + + bool isCompressed = (pkRecord.m_IsCompressed & 0xff) > 0; + auto inPackSize = isCompressed ? pkRecord.m_CompressedSize : pkRecord.m_UncompressedSize; + + FILE* file; +#ifdef _WIN32 + fopen_s(&file, m_FilePath.string().c_str(), "rb"); +#elif __APPLE__ + // macOS has 64bit file IO by default + file = fopen(m_FilePath.string().c_str(), "rb"); +#else + file = fopen64(m_FilePath.string().c_str(), "rb"); +#endif + + fseek(file, pos, SEEK_SET); + + if (!isCompressed) { + char* tempData = (char*)malloc(pkRecord.m_UncompressedSize); + int32_t readInData = fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file); + + *data = tempData; + *len = pkRecord.m_UncompressedSize; + fclose(file); + + return true; + } + + pos += 5; // skip header + + fseek(file, pos, SEEK_SET); + + char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize); + uint32_t currentReadPos = 0; + + while (true) { + if (currentReadPos >= pkRecord.m_UncompressedSize) break; + + uint32_t size; + int32_t readInData = fread(&size, sizeof(uint32_t), 1, file); + pos += 4; // Move pointer position 4 to the right + + char* chunk = (char*)malloc(size); + int32_t readInData2 = fread(chunk, sizeof(int8_t), size, file); + pos += size; // Move pointer position the amount of bytes read to the right + + int32_t err; + currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err); + + free(chunk); + } + + *data = decompressedData; + *len = pkRecord.m_UncompressedSize; + + fclose(file); + + return true; +} diff --git a/dCommon/dClient/Pack.h b/dCommon/dClient/Pack.h new file mode 100644 index 00000000..3e95b00a --- /dev/null +++ b/dCommon/dClient/Pack.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +#pragma pack(push, 1) +struct PackRecord { + uint32_t m_Crc; + int32_t m_LowerCrc; + int32_t m_UpperCrc; + uint32_t m_UncompressedSize; + char m_UncompressedHash[32]; + uint32_t m_Padding1; + uint32_t m_CompressedSize; + char m_CompressedHash[32]; + uint32_t m_Padding2; + uint32_t m_FilePointer; + uint32_t m_IsCompressed; // u32 bool +}; +#pragma pack(pop) + +class Pack { +public: + Pack(const std::filesystem::path& filePath); + ~Pack() = default; + + bool HasFile(uint32_t crc); + bool ReadFileFromPack(uint32_t crc, char** data, uint32_t* len); +private: + std::ifstream m_FileStream; + std::filesystem::path m_FilePath; + + char m_Version[7]; + + uint32_t m_RecordCount; + std::vector m_Records; +}; diff --git a/dCommon/dClient/PackIndex.cpp b/dCommon/dClient/PackIndex.cpp new file mode 100644 index 00000000..5d96abeb --- /dev/null +++ b/dCommon/dClient/PackIndex.cpp @@ -0,0 +1,54 @@ +#include "PackIndex.h" +#include "BinaryIO.h" +#include "Game.h" +#include "dLogger.h" + +PackIndex::PackIndex(const std::filesystem::path& filePath) { + m_FileStream = std::ifstream(filePath / "versions" / "primary.pki", std::ios::in | std::ios::binary); + + BinaryIO::BinaryRead(m_FileStream, m_Version); + BinaryIO::BinaryRead(m_FileStream, m_PackPathCount); + + for (int i = 0; i < m_PackPathCount; i++) { + uint32_t stringLen = 0; + BinaryIO::BinaryRead(m_FileStream, stringLen); + + std::string path; + + for (int j = 0; j < stringLen; j++) { + char inChar; + BinaryIO::BinaryRead(m_FileStream, inChar); + + path += inChar; + } + + m_PackPaths.push_back(path); + } + + BinaryIO::BinaryRead(m_FileStream, m_PackFileIndexCount); + + for (int i = 0; i < m_PackFileIndexCount; i++) { + PackFileIndex packFileIndex; + BinaryIO::BinaryRead(m_FileStream, packFileIndex); + + m_PackFileIndices.push_back(packFileIndex); + } + + Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size()); + + for (auto& item : m_PackPaths) { + std::replace(item.begin(), item.end(), '\\', '/'); + + auto* pack = new Pack(filePath / item); + + m_Packs.push_back(pack); + } + + m_FileStream.close(); +} + +PackIndex::~PackIndex() { + for (const auto* item : m_Packs) { + delete item; + } +} diff --git a/dCommon/dClient/PackIndex.h b/dCommon/dClient/PackIndex.h new file mode 100644 index 00000000..bf10b809 --- /dev/null +++ b/dCommon/dClient/PackIndex.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include +#include +#include + +#include "Pack.h" + +#pragma pack(push, 1) +struct PackFileIndex { + uint32_t m_Crc; + int32_t m_LowerCrc; + int32_t m_UpperCrc; + uint32_t m_PackFileIndex; + uint32_t m_IsCompressed; // u32 bool? +}; +#pragma pack(pop) + +class PackIndex { +public: + PackIndex(const std::filesystem::path& filePath); + ~PackIndex(); + + const std::vector& GetPackPaths() { return m_PackPaths; } + const std::vector& GetPackFileIndices() { return m_PackFileIndices; } + const std::vector& GetPacks() { return m_Packs; } +private: + std::ifstream m_FileStream; + + uint32_t m_Version; + + uint32_t m_PackPathCount; + std::vector m_PackPaths; + uint32_t m_PackFileIndexCount; + std::vector m_PackFileIndices; + + std::vector m_Packs; +}; diff --git a/dCommon/dCommonVars.h b/dCommon/dCommonVars.h deleted file mode 100644 index 4cbdb61c..00000000 --- a/dCommon/dCommonVars.h +++ /dev/null @@ -1,676 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../thirdparty/raknet/Source/BitStream.h" - -#pragma warning (disable:4251) //Disables SQL warnings - -typedef int RESTICKET; - -const int highFrameRate = 16; //60fps -const int mediumFramerate = 33; //30fps -const int lowFramerate = 66; //15fps - -//========== MACROS =========== - -#define CBITSTREAM RakNet::BitStream bitStream; -#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); -#define CMSGHEADER PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_GAME_MSG); -#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false); -#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); - -//=========== TYPEDEFS ========== - -typedef int32_t LOT; //!< A LOT -typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok) -typedef int32_t TSkillID; //!< A skill ID -typedef uint32_t LWOCLONEID; //!< Used for Clone IDs -typedef uint16_t LWOMAPID; //!< Used for Map IDs -typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs -typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs - -typedef int32_t PetTamingPiece; //!< Pet Taming Pieces - -const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID -const LOT LOT_NULL = -1; //!< A null LOT -const int32_t LOOTTYPE_NONE = 0; //!< No loot type available -const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority -const uint32_t INVENTORY_INVALID = -1; //!< Invalid Inventory -const uint32_t INVENTORY_DEFAULT = -1; //!< Default Inventory -const uint32_t StatusChangeInfo = 0; //!< Status Change Info (???) -const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size -const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID -const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID -const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID -const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID - -typedef std::set TSetObjID; - -const float PI = 3.14159f; - -#if defined(__unix) || defined(__APPLE__) -//For Linux: -typedef __int64_t __int64; -#endif - -//============ STRUCTS ============== - -struct LWOSCENEID { -public: - LWOSCENEID() { m_sceneID = -1; m_layerID = 0; } - LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; } - LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; } - - LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; } - LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; } - - bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); } - bool operator<(const int rhs) const { return m_sceneID < rhs; } - - bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); } - bool operator==(const int rhs) const { return m_sceneID == rhs; } - - const int GetSceneID() const { return m_sceneID; } - const unsigned int GetLayerID() const { return m_layerID; } - - void SetSceneID(const int sceneID) { m_sceneID = sceneID; } - void SetLayerID(const unsigned int layerID) { m_layerID = layerID; } - -private: - int m_sceneID; - unsigned int m_layerID; -}; - -struct LWOZONEID { -public: - const LWOMAPID& GetMapID() const { return m_MapID; } - const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; } - const LWOCLONEID& GetCloneID() const { return m_CloneID; } - - //In order: def constr, constr, assign op - LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; } - LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } - LWOZONEID(const LWOZONEID& replacement) { *this = replacement; } - -private: - LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc... - LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process. - LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds. -}; - -const LWOSCENEID LWOSCENEID_INVALID = -1; - -struct LWONameValue { - uint32_t length = 0; //!< The length of the name - std::u16string name; //!< The name - - LWONameValue(void) {} - - LWONameValue(const std::u16string& name) { - this->name = name; - this->length = static_cast(name.length()); - } - - ~LWONameValue(void) {} -}; - -struct FriendData { -public: - bool isOnline = false; - bool isBestFriend = false; - bool isFTP = false; - LWOZONEID zoneID; - LWOOBJID friendID; - std::string friendName; - - void Serialize(RakNet::BitStream& bitStream) { - bitStream.Write(isOnline); - bitStream.Write(isBestFriend); - bitStream.Write(isFTP); - bitStream.Write(0); //??? - bitStream.Write(0); //??? - bitStream.Write(zoneID.GetMapID()); - bitStream.Write(zoneID.GetInstanceID()); - bitStream.Write(zoneID.GetCloneID()); - bitStream.Write(friendID); - - uint32_t maxSize = 33; - uint32_t size = static_cast(friendName.length()); - uint32_t remSize = static_cast(maxSize - size); - - if (size > maxSize) size = maxSize; - - for (uint32_t i = 0; i < size; ++i) { - bitStream.Write(static_cast(friendName[i])); - } - - for (uint32_t j = 0; j < remSize; ++j) { - bitStream.Write(static_cast(0)); - } - - bitStream.Write(0); //??? - bitStream.Write(0); //??? - } -}; - -struct Brick { - uint32_t designerID; - uint32_t materialID; -}; - -//This union is used by the behavior system -union suchar { - unsigned char usigned; - char svalue; -}; - -//=========== DLU ENUMS ============ - -enum eGameMasterLevel : int32_t { - GAME_MASTER_LEVEL_CIVILIAN = 0, // Normal player. - GAME_MASTER_LEVEL_FORUM_MODERATOR = 1, // No permissions on live servers. - GAME_MASTER_LEVEL_JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. - GAME_MASTER_LEVEL_MODERATOR = 3, // Can return lost items. - GAME_MASTER_LEVEL_SENIOR_MODERATOR = 4, // Can ban. - GAME_MASTER_LEVEL_LEAD_MODERATOR = 5, // Can approve properties. - GAME_MASTER_LEVEL_JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. - GAME_MASTER_LEVEL_INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. - GAME_MASTER_LEVEL_DEVELOPER = 8, // Active developer, full permissions on live. - GAME_MASTER_LEVEL_OPERATOR = 9 // Can shutdown server for restarts & updates. -}; - -//=========== LU ENUMS ============ - -//! An enum for object ID bits -enum eObjectBits : int32_t { - OBJECT_BIT_PERSISTENT = 32, //!< The 32 bit index - OBJECT_BIT_CLIENT = 46, //!< The 46 bit index - OBJECT_BIT_SPAWNED = 58, //!< The 58 bit index - OBJECT_BIT_CHARACTER = 60 //!< The 60 bit index -}; - -//! An enum for MatchUpdate types -enum eMatchUpdate : int { - MATCH_UPDATE_PLAYER_JOINED = 0, - MATCH_UPDATE_PLAYER_LEFT = 1, - MATCH_UPDATE_TIME = 3, - MATCH_UPDATE_TIME_START_DELAY = 4, - MATCH_UPDATE_PLAYER_READY = 5, - MATCH_UPDATE_PLAYER_UNREADY = 6 -}; - -//! An enum for camera cycling modes -enum eCyclingMode : uint32_t { - ALLOW_CYCLE_TEAMMATES, - DISALLOW_CYCLING -}; - -enum eCinematicEvent : uint32_t { - STARTED, - WAYPOINT, - ENDED, -}; - -//! An enum for character creation responses -enum eCreationResponse : uint8_t { - CREATION_RESPONSE_SUCCESS = 0, //!< The creation was successful - CREATION_RESPONSE_OBJECT_ID_UNAVAILABLE, //!< The Object ID can't be used - CREATION_RESPONSE_NAME_NOT_ALLOWED, //!< The name is not allowed - CREATION_RESPONSE_PREDEFINED_NAME_IN_USE, //!< The predefined name is already in use - CREATION_RESPONSE_CUSTOM_NAME_IN_USE //!< The custom name is already in use -}; - -//! An enum for login responses -enum eLoginResponse : uint8_t { - LOGIN_RESPONSE_GENERAL_FAILED = 0, - LOGIN_RESPONSE_SUCCESS = 1, - LOGIN_RESPONSE_BANNED = 2, - LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH = 5, - LOGIN_RESPONSE_WRONG_PASS_OR_USER = 6, - LOGIN_RESPONSE_ACCOUNT_LOCKED = 7 -}; - -//! An enum for character rename responses -enum eRenameResponse : uint8_t { - RENAME_RESPONSE_SUCCESS = 0, //!< The renaming was successful - RENAME_RESPONSE_UNKNOWN_ERROR, //!< There was an unknown error - RENAME_RESPONSE_NAME_UNAVAILABLE, //!< The name is unavailable - RENAME_RESPONSE_NAME_IN_USE //!< The name is already in use -}; - -//! A replica packet type -enum eReplicaPacketType { - PACKET_TYPE_CONSTRUCTION, //!< A construction packet - PACKET_TYPE_SERIALIZATION, //!< A serialization packet - PACKET_TYPE_DESTRUCTION //!< A destruction packet -}; - -enum ServerDisconnectIdentifiers { - SERVER_DISCON_UNKNOWN_SERVER_ERROR = 0, //!< Unknown server error - SERVER_DISCON_DUPLICATE_LOGIN = 4, //!< Used when another user with the same username is logged in (duplicate login) - SERVER_DISCON_SERVER_SHUTDOWN = 5, //!< Used when the server is shutdown - SERVER_DISCON_SERVER_MAP_LOAD_FAILURE = 6, //!< Used when the server cannot load a map - SERVER_DISCON_INVALID_SESSION_KEY = 7, //!< Used if the session is invalid - SERVER_DISCON_ACCOUNT_NOT_IN_PENDING_LIST = 8, //!< ??? - SERVER_DISCON_CHARACTER_NOT_FOUND = 9, //!< Used if a character that the server has is not found (i.e, corruption with user-player data) - SERVER_DISCON_CHARACTER_CORRUPTED = 10, //!< Similar to abovce - SERVER_DISCON_KICK = 11, //!< Used if the user is kicked from the server - SERVER_DISCON_FREE_TRIAL_EXPIRED = 12, //!< Used if the user's free trial expired - SERVER_DISCON_PLAY_SCHEDULE_TIME_DONE = 13 //!< Used if the user's play time is used up -}; - -//! The Behavior Types for use with the AI system -enum eCombatBehaviorTypes : uint32_t { - PASSIVE = 0, //!< The object is passive - AGGRESSIVE = 1, //!< The object is aggressive - PASSIVE_TURRET = 2, //!< The object is a passive turret - AGGRESSIVE_TURRET = 3 //!< The object is an aggressive turret -}; - -//! The Combat Role Type for use with the AI system -enum eCombatRoleType : uint32_t { - MELEE = 0, //!< Used for melee attacks - RANGED = 1, //!< Used for range attacks - SUPPORT = 2 //!< Used for support -}; - -//! The kill types for the Die packet -enum eKillType : uint32_t { - VIOLENT, - SILENT -}; - -//! The various world states used throughout the server -enum eObjectWorldState { - WORLDSTATE_INWORLD, //!< Probably used when the object is in the world - WORLDSTATE_ATTACHED, //!< Probably used when the object is attached to another object - WORLDSTATE_INVENTORY //!< Probably used when the object is in an inventory -}; - -//! The trigger stats (???) -enum eTriggerStat { - INVALID_STAT, //!< ??? - HEALTH, //!< Probably used for health - ARMOR, //!< Probably used for armor - IMAGINATION //!< Probably used for imagination -}; - -//! The trigger operations (???) -enum eTriggerOperator { - INVALID_OPER, //!< ??? - EQUAL, //!< ??? - NOT_EQUAL, //!< ??? - GREATER, //!< ??? - GREATER_EQUAL, //!< ??? - LESS, //!< ??? - LESS_EQUAL //!< ??? -}; - -//! The various build types -enum eBuildType { - BUILD_NOWHERE, //!< Used if something can't be built anywhere - BUILD_IN_WORLD, //!< Used if something can be built in the world - BUILD_ON_PROPERTY //!< Used if something can be build on a property -}; - -//! Quickbuild fail reasons -enum eFailReason : uint32_t { - REASON_NOT_GIVEN, - REASON_OUT_OF_IMAGINATION, - REASON_CANCELED_EARLY, - REASON_BUILD_ENDED -}; - -//! Terminate interaction type -enum eTerminateType : uint32_t { - RANGE, - USER, - FROM_INTERACTION -}; - -//! The combat state -enum eCombatState { - IDLE, //!< The AI is in an idle state - AGGRO, //!< The AI is in an aggressive state - TETHER, //!< The AI is being redrawn back to tether point - SPAWN, //!< The AI is spawning - DEAD //!< The AI is dead -}; - -enum eControlSceme { - SCHEME_A, - SCHEME_D, - SCHEME_GAMEPAD, - SCHEME_E, - SCHEME_FPS, - SCHEME_DRIVING, - SCHEME_TAMING, - SCHEME_MODULAR_BUILD, - SCHEME_WEAR_A_ROBOT //== freecam? -}; - -enum eStunState { - PUSH, - POP -}; - -enum eNotifyType { - NOTIFY_TYPE_SUCCESS, - NOTIFY_TYPE_QUIT, - NOTIFY_TYPE_FAILED, - NOTIFY_TYPE_BEGIN, - NOTIFY_TYPE_READY, - NOTIFY_TYPE_NAMINGPET -}; - -enum eReplicaComponentType : int32_t { - COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1, //!< The ControllablePhysics Component - COMPONENT_TYPE_RENDER = 2, //!< The Render Component - COMPONENT_TYPE_SIMPLE_PHYSICS = 3, //!< The SimplePhysics Component - COMPONENT_TYPE_CHARACTER = 4, //!< The Character Component - COMPONENT_TYPE_SCRIPT = 5, //!< The Script Component - COMPONENT_TYPE_BOUNCER = 6, //!< The Bouncer Component - COMPONENT_TYPE_BUFF = 7, //!< The Buff Component - COMPONENT_TYPE_SKILL = 9, //!< The Skill Component - COMPONENT_TYPE_ITEM = 11, //!< The Item Component - COMPONENT_TYPE_VENDOR = 16, //!< The Vendor Component - COMPONENT_TYPE_INVENTORY = 17, //!< The Inventory Component - COMPONENT_TYPE_SHOOTING_GALLERY = 19, //!< The Shooting Gallery Component - COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20, //!< The RigidBodyPhantomPhysics Component - COMPONENT_TYPE_COLLECTIBLE = 23, //!< The Collectible Component - COMPONENT_TYPE_MOVING_PLATFORM = 25, //!< The MovingPlatform Component - COMPONENT_TYPE_PET = 26, //!< The Pet Component - COMPONENT_TYPE_VEHICLE_PHYSICS = 30, //!< The VehiclePhysics Component - COMPONENT_TYPE_MOVEMENT_AI = 31, //!< The MovementAI Component - COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component - COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component - COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component - COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component - COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component - COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component - COMPONENT_TYPE_SWITCH = 49, //!< The Switch Component - COMPONENT_TYPE_ZONE_CONTROL = 50, //!< The ZoneControl Component - COMPONENT_TYPE_PACKAGE = 53, //!< The Package Component - COMPONENT_TYPE_PLAYER_FLAG = 58, //!< The PlayerFlag Component - COMPONENT_TYPE_BASE_COMBAT_AI = 60, //!< The BaseCombatAI Component - COMPONENT_TYPE_MODULE_ASSEMBLY = 61, //!< The ModuleAssembly Component - COMPONENT_TYPE_PROPERTY_VENDOR = 65, //!< The PropertyVendor Component - COMPONENT_TYPE_ROCKET_LAUNCH = 67, //!< The RocketLaunch Component - COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component - COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component - COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component - COMPONENT_TYPE_RACING_STATS = 74, //!< The Exhibit Component - COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component - COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component - COMPONENT_TYPE_MISSION = 84, //!< The Mission Component - COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen - COMPONENT_TYPE_RAIL_ACTIVATOR = 104, - COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component - COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component - COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component - COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component - - COMPONENT_TYPE_MODEL = 5398484 //look man idk -}; - -enum class UseItemResponse : uint32_t { - NoImaginationForPet = 1, - FailedPrecondition, - MountsNotAllowed -}; - -/** - * Represents the different types of inventories an entity may have - */ -enum eInventoryType : uint32_t { - ITEMS = 0, - VAULT_ITEMS, - BRICKS, - TEMP_ITEMS = 4, - MODELS, - TEMP_MODELS, - BEHAVIORS, - PROPERTY_DEEDS, - VENDOR_BUYBACK = 11, - HIDDEN = 12, //Used for missional items - VAULT_MODELS = 14, - ITEM_SETS, //internal - INVALID // made up, for internal use!!! -}; - -enum eItemType : int32_t { - ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type - ITEM_TYPE_BRICK = 1, //!< A brick - ITEM_TYPE_HAT = 2, //!< A hat / head item - ITEM_TYPE_HAIR = 3, //!< A hair item - ITEM_TYPE_NECK = 4, //!< A neck item - ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item - ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item - ITEM_TYPE_LEGS = 7, //!< A pants item - ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item - ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item - ITEM_TYPE_BEHAVIOR = 10, //!< A behavior - ITEM_TYPE_PROPERTY = 11, //!< A property - ITEM_TYPE_MODEL = 12, //!< A model - ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item - ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item - ITEM_TYPE_CHEST = 15, //!< A chest item - ITEM_TYPE_EGG = 16, //!< An egg - ITEM_TYPE_PET_FOOD = 17, //!< A pet food item - ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item - ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item - ITEM_TYPE_PACKAGE = 20, //!< A package - ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model - ITEM_TYPE_VEHICLE = 22, //!< A vehicle - ITEM_TYPE_CURRENCY = 23 //!< Currency -}; - -enum eRebuildState : uint32_t { - REBUILD_OPEN, - REBUILD_COMPLETED = 2, - REBUILD_RESETTING = 4, - REBUILD_BUILDING, - REBUILD_INCOMPLETE -}; - -/** - * The loot source's type. - */ -enum eLootSourceType : int32_t { - LOOT_SOURCE_NONE = 0, - LOOT_SOURCE_CHEST, - LOOT_SOURCE_MISSION, - LOOT_SOURCE_MAIL, - LOOT_SOURCE_CURRENCY, - LOOT_SOURCE_ACHIEVEMENT, - LOOT_SOURCE_TRADE, - LOOT_SOURCE_QUICKBUILD, - LOOT_SOURCE_DELETION, - LOOT_SOURCE_VENDOR, - LOOT_SOURCE_ACTIVITY, - LOOT_SOURCE_PICKUP, - LOOT_SOURCE_BRICK, - LOOT_SOURCE_PROPERTY, - LOOT_SOURCE_MODERATION, - LOOT_SOURCE_EXHIBIT, - LOOT_SOURCE_INVENTORY, - LOOT_SOURCE_CLAIMCODE, - LOOT_SOURCE_CONSUMPTION, - LOOT_SOURCE_CRAFTING, - LOOT_SOURCE_LEVEL_REWARD, - LOOT_SOURCE_RELOCATE -}; - -enum eGameActivities : uint32_t { - ACTIVITY_NONE, - ACTIVITY_QUICKBUILDING, - ACTIVITY_SHOOTING_GALLERY, - ACTIVITY_RACING, - ACTIVITY_PINBALL, - ACTIVITY_PET_TAMING -}; - -enum ePlayerFlags { - BTARR_TESTING = 0, - PLAYER_HAS_ENTERED_PET_RANCH = 1, - MINIMAP_UNLOCKED = 2, - ACTIVITY_REBUILDING_FAIL_TIME = 3, - ACTIVITY_REBUILDING_FAIL_RANGE = 4, - ACTIVITY_SHOOTING_GALLERY_HELP = 5, - HELP_WALKING_CONTROLS = 6, - FIRST_SMASHABLE = 7, - FIRST_IMAGINATION_PICKUP = 8, - FIRST_DAMAGE = 9, - FIRST_ITEM = 10, - FIRST_BRICK = 11, - FIRST_CONSUMABLE = 12, - FIRST_EQUIPPABLE = 13, - CHAT_HELP = 14, - FIRST_PET_TAMING_MINIGAME = 15, - FIRST_PET_ON_SWITCH = 16, - FIRST_PET_JUMPED_ON_SWITCH = 17, - FIRST_PET_FOUND_TREASURE = 18, - FIRST_PET_DUG_TREASURE = 19, - FIRST_PET_OWNER_ON_PET_BOUNCER = 20, - FIRST_PET_DESPAWN_NO_IMAGINATION = 21, - FIRST_PET_SELECTED_ENOUGH_BRICKS = 22, - FIRST_EMOTE_UNLOCKED = 23, - GF_PIRATE_REP = 24, - AG_BOB_CINEMATIC_EVENT = 25, - HELP_JUMPING_CONTROLS = 26, - HELP_DOUBLE_JUMP_CONTROLS = 27, - HELP_CAMERA_CONTROLS = 28, - HELP_ROTATE_CONTROLS = 29, - HELP_SMASH = 30, - MONUMENT_INTRO_MUSIC_PLAYED = 31, - BEGINNING_ZONE_SUMMARY_DISPLAYED = 32, - AG_FINISH_LINE_BUILT = 33, - AG_BOSS_AREA_FOUND = 34, - AG_LANDED_IN_BATTLEFIELD = 35, - GF_PLAYER_HAS_BEEN_TO_THE_RAVINE = 36, - MODULAR_BUILD_STARTED = 37, - MODULAR_BUILD_FINISHED_CLICK_BUTTON = 38, - THINKING_HAT_RECEIVED_GO_TO_MODULAR_BUILD_AREA = 39, - BUILD_AREA_ENTERED_MOD_NOT_ACTIVATED_PUT_ON_HAT = 40, - HAT_ON_INSIDE_OF_MOD_BUILD_EQUIP_A_MODULE_FROM_LEG = 41, - MODULE_EQUIPPED_PLACE_ON_GLOWING_BLUE_SPOT = 42, - FIRST_MODULE_PLACED_CORRECTLY_NOW_DO_THE_REST = 43, - ROCKET_COMPLETE_NOW_LAUNCH_FROM_PAD = 44, - JOINED_A_FACTION = 45, - VENTURE_FACTION = 46, - ASSEMBLY_FACTION = 47, - PARADOX_FACTION = 48, - SENTINEL_FACTION = 49, - LUP_WORLD_ACCESS = 50, - AG_FIRST_FLAG_COLLECTED = 51, - TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52, - MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53, - MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54, - AG_BEACON_QB,_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55, - GF_PET_DIG_FLAG_1 = 56, - GF_PET_DIG_FLAG_2 = 57, - GF_PET_DIG_FLAG_3 = 58, - SUPPRESS_SPACESHIP_CINEMATIC_FLYTHROUGH = 59, - GF_PLAYER_FALL_DEATH = 60, - GF_PLAYER_CAN_GET_FLAG_1 = 61, - GF_PLAYER_CAN_GET_FLAG_2 = 62, - GF_PLAYER_CAN_GET_FLAG_3 = 63, - ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64, - AG_FIRST_COMBAT_COMPLETE = 65, - AG_COMPLETE_BOB_MISSION = 66, - NJ_GARMADON_CINEMATIC_SEEN = 125, - ELEPHANT_PET_3050 = 801, - CAT_PET_3054 = 802, - TRICERATOPS_PET_3195 = 803, - TERRIER_PET_3254 = 804, - SKUNK_PET_3261 = 805, - LION_PET_3520 = 806, - BUNNY_PET_3672 = 807, - CROCODILE_PET_3994 = 808, - DOBERMAN_PET_5635 = 809, - BUFFALO_PET_5636 = 810, - ROBOT_DOG_PET_5637 = 811, - EUROPEAN_DRAGON_PET_5639 = 812, - TORTOISE_PET_5640 = 813, - ASIAN_DRAGON_PET_5641 = 814, - MANTIS_PET_5642 = 815, - PANDA_PET_5643 = 816, - WARTHOG_PET_6720 = 817, - GOAT_PET_7638 = 818, - CRAB_PET_7694 = 819, - AG_SPACE_SHIP_BINOC_AT_LAUNCH = 1001, - AG_SPACE_SHIP_BINOC_AT_LAUNCH_PLATFORM = 1002, - AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_LEFT_OF_START = 1003, - AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_RIGHT_OF_START = 1004, - AG_SPACE_SHIP_BINOC_AT_BOB = 1005, - AG_BATTLE_BINOC_FOR_TRICERETOPS = 1101, - AG_BATTLE_BINOC_AT_PARADOX = 1102, - AG_BATTLE_BINOC_AT_MISSION_GIVER = 1103, - AG_BATTLE_BINOC_AT_BECK = 1104, - AG_MONUMENT_BINOC_INTRO = 1105, - AG_MONUMENT_BINOC_OUTRO = 1106, - AG_LAUNCH_BINOC_INTRO = 1107, - AG_LAUNCH_BINOC_BISON = 1108, - AG_LAUNCH_BINOC_SHARK = 1109, - NS_BINOC_CONCERT_TRANSITION = 1201, - NS_BINOC_RACE_PLACE_TRANSITION = 1202, - NS_BINOC_BRICK_ANNEX_TRANSITION = 1203, - NS_BINOC_GF_LAUNCH = 1204, - NS_BINOC_FV_LAUNCH = 1205, - NS_BINOC_BRICK_ANNEX_WATER = 1206, - NS_BINOC_AG_LAUNCH_AT_RACE_PLACE = 1207, - NS_BINOC_AG_LAUNCH_AT_BRICK_ANNEX = 1208, - NS_BINOC_AG_LAUNCH_AT_PLAZA = 1209, - NS_BINOC_TBA = 1210, - NS_FLAG_COLLECTABLE_1_BY_JONNY_THUNDER = 1211, - NS_FLAG_COLLECTABLE_2_UNDER_CONCERT_BRIDGE = 1212, - NS_FLAG_COLLECTABLE_3_BY_FV_LAUNCH = 1213, - NS_FLAG_COLLECTABLE_4_IN_PLAZA_BEHIND_BUILDING = 1214, - NS_FLAG_COLLECTABLE_5_BY_GF_LAUNCH = 1215, - NS_FLAG_COLLECTABLE_6_BY_DUCK_SG = 1216, - NS_FLAG_COLLECTABLE_7_BY_LUP_LAUNCH = 1217, - NS_FLAG_COLLECTABLE_8_BY_NT_LUANCH = 1218, - NS_FLAG_COLLECTABLE_9_BY_RACE_BUILD = 1219, - NS_FLAG_COLLECTABLE_10_ON_AG_LAUNCH_PATH = 1220, - PR_BINOC_AT_LAUNCH_PAD = 1251, - PR_BINOC_AT_BEGINNING_OF_ISLAND_B = 1252, - PR_BINOC_AT_FIRST_PET_BOUNCER = 1253, - PR_BINOC_ON_BY_CROWS_NEST = 1254, - PR_PET_DIG_AT_BEGINNING_OF_ISLAND_B = 1261, - PR_PET_DIG_AT_THE_LOCATION_OF_OLD_BOUNCE_BACK = 1262, - PR_PET_DIG_UNDER_QB_BRIDGE = 1263, - PR_PET_DIG_BACK_SIDE_BY_PARTNER_BOUNCE = 1264, - PR_PET_DIG_BY_LAUNCH_PAD = 1265, - PR_PET_DIG_BY_FIRST_PET_BOUNCER = 1266, - GF_BINOC_ON_LANDING_PAD = 1301, - GF_BINOC_AT_RAVINE_START = 1302, - GF_BINOC_ON_TOP_OF_RAVINE_HEAD = 1303, - GF_BINOC_AT_TURTLE_AREA = 1304, - GF_BINOC_IN_TUNNEL_TO_ELEPHANTS = 1305, - GF_BINOC_IN_ELEPHANTS_AREA = 1306, - GF_BINOC_IN_RACING_AREA = 1307, - GF_BINOC_IN_CROC_AREA = 1308, - GF_BINOC_IN_JAIL_AREA = 1309, - GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310, - NT_FACTION_SPY_DUKE = 1974, - NT_FACTION_SPY_OVERBUILD = 1976, - NT_FACTION_SPY_HAEL = 1977, - NJ_EARTH_SPINJITZU = 2030, - NJ_LIGHTNING_SPINJITZU = 2031, - NJ_ICE_SPINJITZU = 2032, - NJ_FIRE_SPINJITZU = 2033, - NJ_WU_SHOW_DAILY_CHEST = 2099 -}; - - -//======== FUNC =========== - -template -inline T const& clamp(const T& val, const T& low, const T& high) { - if (val < low) return low; - else if (val > high) return high; - - return val; -} diff --git a/dCommon/dConfig.cpp b/dCommon/dConfig.cpp index b53b7166..f09a44c1 100644 --- a/dCommon/dConfig.cpp +++ b/dCommon/dConfig.cpp @@ -1,45 +1,53 @@ #include "dConfig.h" + #include +#include "BinaryPathFinder.h" +#include "GeneralUtils.h" + dConfig::dConfig(const std::string& filepath) { - m_EmptyString = ""; - std::ifstream in(filepath); + m_ConfigFilePath = filepath; + LoadConfig(); +} + +void dConfig::LoadConfig() { + std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath); if (!in.good()) return; - std::string line; + std::string line{}; while (std::getline(in, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } + if (!line.empty() && line.front() != '#') ProcessLine(line); } -} -dConfig::~dConfig(void) { + std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in); + if (!sharedConfig.good()) return; + + line.clear(); + while (std::getline(sharedConfig, line)) { + if (!line.empty() && line.front() != '#') ProcessLine(line); + } +} + +void dConfig::ReloadConfig() { + this->m_ConfigValues.clear(); + LoadConfig(); } const std::string& dConfig::GetValue(std::string key) { - for (size_t i = 0; i < m_Keys.size(); ++i) { - if (m_Keys[i] == key) return m_Values[i]; - } - - return m_EmptyString; + return this->m_ConfigValues[key]; } void dConfig::ProcessLine(const std::string& line) { - std::stringstream ss(line); - std::string segment; - std::vector seglist; + auto splitLine = GeneralUtils::SplitString(line, '='); - while (std::getline(ss, segment, '=')) { - seglist.push_back(segment); - } - - if (seglist.size() != 2) return; + if (splitLine.size() != 2) return; //Make sure that on Linux, we remove special characters: - if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r') - seglist[1].erase(seglist[1].size() - 1); + auto& key = splitLine.at(0); + auto& value = splitLine.at(1); + if (!value.empty() && value.at(value.size() - 1) == '\r') value.erase(value.size() - 1); - m_Keys.push_back(seglist[0]); - m_Values.push_back(seglist[1]); -} \ No newline at end of file + if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return; + + this->m_ConfigValues.insert(std::make_pair(key, value)); +} diff --git a/dCommon/dConfig.h b/dCommon/dConfig.h index 0e712499..562c1ce9 100644 --- a/dCommon/dConfig.h +++ b/dCommon/dConfig.h @@ -1,20 +1,33 @@ #pragma once #include +#include #include -#include class dConfig { public: dConfig(const std::string& filepath); - ~dConfig(void); + /** + * Gets the specified key from the config. Returns an empty string if the value is not found. + * + * @param key Key to find + * @return The keys value in the config + */ const std::string& GetValue(std::string key); + /** + * Loads the config from a file + */ + void LoadConfig(); + + /** + * Reloads the config file to reset values + */ + void ReloadConfig(); private: void ProcessLine(const std::string& line); private: - std::vector m_Keys; - std::vector m_Values; - std::string m_EmptyString; -}; \ No newline at end of file + std::map m_ConfigValues; + std::string m_ConfigFilePath; +}; diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h new file mode 100644 index 00000000..f67145da --- /dev/null +++ b/dCommon/dEnums/dCommonVars.h @@ -0,0 +1,162 @@ +#pragma once + +#ifndef __DCOMMONVARS__H__ +#define __DCOMMONVARS__H__ + +#include +#include +#include +#include "BitStream.h" +#include "eConnectionType.h" +#include "eClientMessageType.h" + +#pragma warning (disable:4251) //Disables SQL warnings + +// These are the same define, but they mean two different things in different contexts +// so a different define to distinguish what calculation is happening will help clarity. +#define FRAMES_TO_MS(x) 1000 / x +#define MS_TO_FRAMES(x) 1000 / x + +//=========== FRAME TIMINGS =========== +constexpr uint32_t highFramerate = 60; +constexpr uint32_t mediumFramerate = 30; +constexpr uint32_t lowFramerate = 15; + +constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate); +constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate); +constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); + +//========== MACROS =========== + +#define HEADER_SIZE 8 +#define CBITSTREAM RakNet::BitStream bitStream; +#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); +#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); +#define CMSGHEADER PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); +#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false); +#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + +//=========== TYPEDEFS ========== + +typedef int32_t LOT; //!< A LOT +typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok) +typedef int32_t TSkillID; //!< A skill ID +typedef uint32_t LWOCLONEID; //!< Used for Clone IDs +typedef uint16_t LWOMAPID; //!< Used for Map IDs +typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs +typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs +typedef uint32_t StripId; + +const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID +const LOT LOT_NULL = -1; //!< A null LOT +const int32_t LOOTTYPE_NONE = 0; //!< No loot type available +const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority +const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size +const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID +const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID +const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID +const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID + +const float PI = 3.14159f; + +//============ STRUCTS ============== + +struct LWOSCENEID { +public: + LWOSCENEID() { m_sceneID = -1; m_layerID = 0; } + LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; } + LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; } + + LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; } + LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; } + + bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); } + bool operator<(const int rhs) const { return m_sceneID < rhs; } + + bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); } + bool operator==(const int rhs) const { return m_sceneID == rhs; } + + const int GetSceneID() const { return m_sceneID; } + const unsigned int GetLayerID() const { return m_layerID; } + + void SetSceneID(const int sceneID) { m_sceneID = sceneID; } + void SetLayerID(const unsigned int layerID) { m_layerID = layerID; } + +private: + int m_sceneID; + unsigned int m_layerID; +}; + +struct LWOZONEID { +public: + const LWOMAPID& GetMapID() const { return m_MapID; } + const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; } + const LWOCLONEID& GetCloneID() const { return m_CloneID; } + + //In order: def constr, constr, assign op + LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; } + LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } + LWOZONEID(const LWOZONEID& replacement) { *this = replacement; } + +private: + LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc... + LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process. + LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds. +}; + +const LWOSCENEID LWOSCENEID_INVALID = -1; + +struct LWONameValue { + uint32_t length = 0; //!< The length of the name + std::u16string name; //!< The name + + LWONameValue(void) {} + + LWONameValue(const std::u16string& name) { + this->name = name; + this->length = static_cast(name.length()); + } + + ~LWONameValue(void) {} +}; + +struct FriendData { +public: + bool isOnline = false; + bool isBestFriend = false; + bool isFTP = false; + LWOZONEID zoneID; + LWOOBJID friendID; + std::string friendName; + + void Serialize(RakNet::BitStream& bitStream) { + bitStream.Write(isOnline); + bitStream.Write(isBestFriend); + bitStream.Write(isFTP); + bitStream.Write(0); //??? + bitStream.Write(0); //??? + bitStream.Write(zoneID.GetMapID()); + bitStream.Write(zoneID.GetInstanceID()); + bitStream.Write(zoneID.GetCloneID()); + bitStream.Write(friendID); + + uint32_t maxSize = 33; + uint32_t size = static_cast(friendName.length()); + uint32_t remSize = static_cast(maxSize - size); + + if (size > maxSize) size = maxSize; + + for (uint32_t i = 0; i < size; ++i) { + bitStream.Write(static_cast(friendName[i])); + } + + for (uint32_t j = 0; j < remSize; ++j) { + bitStream.Write(static_cast(0)); + } + + bitStream.Write(0); //??? + bitStream.Write(0); //??? + } +}; + +#endif //!__DCOMMONVARS__H__ diff --git a/dCommon/dEnums/dPlatforms.h b/dCommon/dEnums/dPlatforms.h new file mode 100644 index 00000000..bca7f9e0 --- /dev/null +++ b/dCommon/dEnums/dPlatforms.h @@ -0,0 +1,29 @@ +#pragma once + +#if defined(_WIN32) +#define DARKFLAME_PLATFORM_WIN32 +#elif defined(__APPLE__) && defined(__MACH__) +#include +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +#define DARKFLAME_PLATFORM_IOS +#elif TARGET_OS_MAC +#define DARKFLAME_PLATFORM_MACOS +#else +#error unknown Apple operating system +#endif +#elif defined(__unix__) +#define DARKFLAME_PLATFORM_UNIX +#if defined(__ANDROID__) +#define DARKFLAME_PLATFORM_ANDROID +#elif defined(__linux__) +#define DARKFLAME_PLATFORM_LINUX +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#define DARKFLAME_PLATFORM_FREEBSD +#elif defined(__CYGWIN__) +#define DARKFLAME_PLATFORM_CYGWIN +#else +#error unknown unix operating system +#endif +#else +#error unknown operating system +#endif diff --git a/dCommon/dEnums/dpCollisionGroups.h b/dCommon/dEnums/dpCollisionGroups.h new file mode 100644 index 00000000..ad9807b9 --- /dev/null +++ b/dCommon/dEnums/dpCollisionGroups.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +/* + * Collision Groups + */ + +enum eCollisionGroup : uint8_t +{ + COLLISION_GROUP_ALL = 0 << 0, + COLLISION_GROUP_NEUTRAL = 1 << 0, + COLLISION_GROUP_FRIENDLY = 1 << 1, + COLLISION_GROUP_ENEMY = 1 << 2, + COLLISION_GROUP_DYNAMIC = 1 << 3, +}; diff --git a/dPhysics/dpCommon.h b/dCommon/dEnums/dpCommon.h similarity index 96% rename from dPhysics/dpCommon.h rename to dCommon/dEnums/dpCommon.h index 344ad9c0..51583048 100644 --- a/dPhysics/dpCommon.h +++ b/dCommon/dEnums/dpCommon.h @@ -4,4 +4,4 @@ enum class dpShapeType : unsigned short { Invalid = 0, Sphere, Box -}; \ No newline at end of file +}; diff --git a/dCommon/dEnums/eAddFriendResponseCode.h b/dCommon/dEnums/eAddFriendResponseCode.h new file mode 100644 index 00000000..56304c82 --- /dev/null +++ b/dCommon/dEnums/eAddFriendResponseCode.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef __EADDFRIENDRESPONSECODE__H__ +#define __EADDFRIENDRESPONSECODE__H__ + +#include + +enum class eAddFriendResponseCode : uint8_t { + ACCEPTED = 0, + REJECTED, + BUSY, + CANCELLED +}; + +#endif //!__ADDFRIENDRESPONSECODE__H__ diff --git a/dCommon/dEnums/eAddFriendResponseType.h b/dCommon/dEnums/eAddFriendResponseType.h new file mode 100644 index 00000000..5568aafb --- /dev/null +++ b/dCommon/dEnums/eAddFriendResponseType.h @@ -0,0 +1,24 @@ +#pragma once + +#ifndef __EADDFRIENDRESPONSETYPE__H__ +#define __EADDFRIENDRESPONSETYPE__H__ + +#include + +enum class eAddFriendResponseType : uint8_t { + ACCEPTED = 0, + ALREADYFRIEND, + INVALIDCHARACTER, + GENERALERROR, + YOURFRIENDSLISTFULL, + THEIRFRIENDLISTFULL, + DECLINED, + BUSY, + NOTONLINE, + WAITINGAPPROVAL, + MYTHRAN, + CANCELLED, + FRIENDISFREETRIAL +}; + +#endif //!__EADDFRIENDRESPONSETYPE__H__ diff --git a/dCommon/dEnums/eAninmationFlags.h b/dCommon/dEnums/eAninmationFlags.h new file mode 100644 index 00000000..ce235ae9 --- /dev/null +++ b/dCommon/dEnums/eAninmationFlags.h @@ -0,0 +1,44 @@ +#pragma once + +#ifndef __EANINMATIONFLAGS__H__ +#define __EANINMATIONFLAGS__H__ + +#include + +enum class eAnimationFlags : uint32_t { + IDLE_NONE = 0, + IDLE_BASIC, + IDLE_SWIM, + IDLE_CARRY, + IDLE_SWORD, + IDLE_HAMMER, + IDLE_SPEAR, + IDLE_PISTOL, + IDLE_BOW, + IDLE_COMBAT, + IDLE_JETPACK, + IDLE_HORSE, + IDLE_SG, + IDLE_ORGAN, + IDLE_SKATEBOARD, + IDLE_DAREDEVIL, + IDLE_SAMURAI, + IDLE_SUMMONER, + IDLE_BUCCANEER, + IDLE_MISC, + IDLE_NINJA, + IDLE_MISC1, + IDLE_MISC2, + IDLE_MISC3, + IDLE_MISC4, + IDLE_MISC5, + IDLE_MISC6, + IDLE_MISC7, + IDLE_MISC8, + IDLE_MISC9, + IDLE_MISC10, + IDLE_MISC11, + IDLE_MISC12 +}; + +#endif //!__EANINMATIONFLAGS__H__ diff --git a/dCommon/dEnums/eAuthMessageType.h b/dCommon/dEnums/eAuthMessageType.h new file mode 100644 index 00000000..ecc17a37 --- /dev/null +++ b/dCommon/dEnums/eAuthMessageType.h @@ -0,0 +1,15 @@ +#ifndef __EAUTHMESSAGETYPE__H__ +#define __EAUTHMESSAGETYPE__H__ + +#include + +enum class eAuthMessageType : uint32_t { + LOGIN_REQUEST = 0, + LOGOUT_REQUEST, + CREATE_NEW_ACCOUNT_REQUEST, + LEGOINTERFACE_AUTH_RESPONSE, + SESSIONKEY_RECEIVED_CONFIRM, + RUNTIME_CONFIG +}; + +#endif //!__EAUTHMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eBasicAttackSuccessTypes.h b/dCommon/dEnums/eBasicAttackSuccessTypes.h new file mode 100644 index 00000000..8c06da8a --- /dev/null +++ b/dCommon/dEnums/eBasicAttackSuccessTypes.h @@ -0,0 +1,12 @@ +#ifndef __EBASICATTACKSUCCESSTYPES__H__ +#define __EBASICATTACKSUCCESSTYPES__H__ + +#include + +enum class eBasicAttackSuccessTypes : uint8_t { + SUCCESS = 1, + FAILARMOR, + FAILIMMUNE +}; + +#endif //!__EBASICATTACKSUCCESSTYPES__H__ diff --git a/dCommon/dEnums/eBlueprintSaveResponseType.h b/dCommon/dEnums/eBlueprintSaveResponseType.h new file mode 100644 index 00000000..29d15695 --- /dev/null +++ b/dCommon/dEnums/eBlueprintSaveResponseType.h @@ -0,0 +1,26 @@ +#pragma once + +#ifndef __EBLUEPRINTSAVERESPONSETYPE__H__ +#define __EBLUEPRINTSAVERESPONSETYPE__H__ + +#include + +enum class eBlueprintSaveResponseType : uint32_t { + EverythingWorked = 0, + SaveCancelled, + CantBeginTransaction, + SaveBlueprintFailed, + SaveUgobjectFailed, + CantEndTransaction, + SaveFilesFailed, + BadInput, + NotEnoughBricks, + InventoryFull, + ModelGenerationFailed, + PlacementFailed, + GmLevelInsufficient, + WaitForPreviousSave, + FindMatchesFailed +}; + +#endif //!__EBLUEPRINTSAVERESPONSETYPE__H__ diff --git a/dCommon/dEnums/eBubbleType.h b/dCommon/dEnums/eBubbleType.h new file mode 100644 index 00000000..9ceef4b5 --- /dev/null +++ b/dCommon/dEnums/eBubbleType.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef __EBUBBLETYPE__H__ +#define __EBUBBLETYPE__H__ + +#include + +enum class eBubbleType : uint32_t { + DEFAULT = 0, + ENERGY, + SKUNK +}; + +#endif //!__EBUBBLETYPE__H__ diff --git a/dCommon/dEnums/eBuildType.h b/dCommon/dEnums/eBuildType.h new file mode 100644 index 00000000..f28f43cc --- /dev/null +++ b/dCommon/dEnums/eBuildType.h @@ -0,0 +1,12 @@ +#ifndef __EBUILDTYPE__H__ +#define __EBUILDTYPE__H__ + +#include + +enum class eBuildType :uint32_t { + NOWHERE, + IN_WORLD, + ON_PROPERTY +}; + +#endif //!__EBUILDTYPE__H__ diff --git a/dCommon/dEnums/eCharacterCreationResponse.h b/dCommon/dEnums/eCharacterCreationResponse.h new file mode 100644 index 00000000..da1ec0f2 --- /dev/null +++ b/dCommon/dEnums/eCharacterCreationResponse.h @@ -0,0 +1,14 @@ +#ifndef __ECHARACTERCREATIONRESPONSE__H__ +#define __ECHARACTERCREATIONRESPONSE__H__ + +#include + +enum class eCharacterCreationResponse : uint8_t { + SUCCESS = 0, + OBJECT_ID_UNAVAILABLE, + NAME_NOT_ALLOWED, + PREDEFINED_NAME_IN_USE, + CUSTOM_NAME_IN_USE +}; + +#endif //!__ECHARACTERCREATIONRESPONSE__H__ diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h new file mode 100644 index 00000000..0fab4498 --- /dev/null +++ b/dCommon/dEnums/eCharacterVersion.h @@ -0,0 +1,21 @@ +#pragma once + +#ifndef __ECHARACTERVERSION__H__ +#define __ECHARACTERVERSION__H__ + +#include + +enum class eCharacterVersion : uint32_t { +// Versions from the live game + RELEASE = 0, // Initial release of the game + LIVE, // Fixes for the 1.9 release bug fixes for missions leading up to joining a faction +// New versions for DLU fixes + // Fixes the "Joined a faction" player flag not being set properly + PLAYER_FACTION_FLAGS, + // Fixes vault size value + VAULT_SIZE, + // Fixes speed base value in level component + UP_TO_DATE, // will become SPEED_BASE +}; + +#endif //!__ECHARACTERVERSION__H__ diff --git a/dCommon/dEnums/eChatInternalMessageType.h b/dCommon/dEnums/eChatInternalMessageType.h new file mode 100644 index 00000000..d3b7020b --- /dev/null +++ b/dCommon/dEnums/eChatInternalMessageType.h @@ -0,0 +1,31 @@ +#ifndef __ECHATINTERNALMESSAGETYPE__H__ +#define __ECHATINTERNALMESSAGETYPE__H__ + +#include + +enum eChatInternalMessageType : uint32_t { + PLAYER_ADDED_NOTIFICATION = 0, + PLAYER_REMOVED_NOTIFICATION, + ADD_FRIEND, + ADD_BEST_FRIEND, + ADD_TO_TEAM, + ADD_BLOCK, + REMOVE_FRIEND, + REMOVE_BLOCK, + REMOVE_FROM_TEAM, + DELETE_TEAM, + REPORT, + PRIVATE_CHAT, + PRIVATE_CHAT_RESPONSE, + ANNOUNCEMENT, + MAIL_COUNT_UPDATE, + MAIL_SEND_NOTIFY, + REQUEST_USER_LIST, + FRIEND_LIST, + ROUTE_TO_PLAYER, + TEAM_UPDATE, + MUTE_UPDATE, + CREATE_TEAM, +}; + +#endif //!__ECHATINTERNALMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eChatMessageType.h b/dCommon/dEnums/eChatMessageType.h new file mode 100644 index 00000000..52895ba3 --- /dev/null +++ b/dCommon/dEnums/eChatMessageType.h @@ -0,0 +1,78 @@ +#ifndef __ECHATMESSAGETYPE__H__ +#define __ECHATMESSAGETYPE__H__ + +#include + +//! The Internal Chat Packet Identifiers +enum class eChatMessageType :uint32_t { + LOGIN_SESSION_NOTIFY = 0, + GENERAL_CHAT_MESSAGE, + PRIVATE_CHAT_MESSAGE, + USER_CHANNEL_CHAT_MESSAGE, + WORLD_DISCONNECT_REQUEST, + WORLD_PROXIMITY_RESPONSE, + WORLD_PARCEL_RESPONSE, + ADD_FRIEND_REQUEST, + ADD_FRIEND_RESPONSE, + REMOVE_FRIEND, + GET_FRIENDS_LIST, + ADD_IGNORE, + REMOVE_IGNORE, + GET_IGNORE_LIST, + TEAM_MISSED_INVITE_CHECK, + TEAM_INVITE, + TEAM_INVITE_RESPONSE, + TEAM_KICK, + TEAM_LEAVE, + TEAM_SET_LOOT, + TEAM_SET_LEADER, + TEAM_GET_STATUS, + GUILD_CREATE, + GUILD_INVITE, + GUILD_INVITE_RESPONSE, + GUILD_LEAVE, + GUILD_KICK, + GUILD_GET_STATUS, + GUILD_GET_ALL, + SHOW_ALL, + BLUEPRINT_MODERATED, + BLUEPRINT_MODEL_READY, + PROPERTY_READY_FOR_APPROVAL, + PROPERTY_MODERATION_CHANGED, + PROPERTY_BUILDMODE_CHANGED, + PROPERTY_BUILDMODE_CHANGED_REPORT, + MAIL, + WORLD_INSTANCE_LOCATION_REQUEST, + REPUTATION_UPDATE, + SEND_CANNED_TEXT, + GMLEVEL_UPDATE, + CHARACTER_NAME_CHANGE_REQUEST, + CSR_REQUEST, + CSR_REPLY, + GM_KICK, + GM_ANNOUNCE, + GM_MUTE, + ACTIVITY_UPDATE, + WORLD_ROUTE_PACKET, + GET_ZONE_POPULATIONS, + REQUEST_MINIMUM_CHAT_MODE, + REQUEST_MINIMUM_CHAT_MODE_PRIVATE, + MATCH_REQUEST, + UGCMANIFEST_REPORT_MISSING_FILE, + UGCMANIFEST_REPORT_DONE_FILE, + UGCMANIFEST_REPORT_DONE_BLUEPRINT, + UGCC_REQUEST, + WHO, + WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE, + ACHIEVEMENT_NOTIFY, + GM_CLOSE_PRIVATE_CHAT_WINDOW, + UNEXPECTED_DISCONNECT, + PLAYER_READY, + GET_DONATION_TOTAL, + UPDATE_DONATION, + PRG_CSR_COMMAND, + HEARTBEAT_REQUEST_FROM_WORLD, + UPDATE_FREE_TRIAL_STATUS +}; + +#endif //!__ECHATMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eCinematicEvent.h b/dCommon/dEnums/eCinematicEvent.h new file mode 100644 index 00000000..7fb82ca7 --- /dev/null +++ b/dCommon/dEnums/eCinematicEvent.h @@ -0,0 +1,12 @@ +#ifndef __ECINEMATICEVENT__H__ +#define __ECINEMATICEVENT__H__ + +#include + +enum class eCinematicEvent : uint32_t { + STARTED, + WAYPOINT, + ENDED, +}; + +#endif //!__ECINEMATICEVENT__H__ diff --git a/dCommon/dEnums/eClientMessageType.h b/dCommon/dEnums/eClientMessageType.h new file mode 100644 index 00000000..aafccc36 --- /dev/null +++ b/dCommon/dEnums/eClientMessageType.h @@ -0,0 +1,76 @@ +#ifndef __ECLIENTMESSAGETYPE__H__ +#define __ECLIENTMESSAGETYPE__H__ + +#include + +enum class eClientMessageType : uint32_t { + LOGIN_RESPONSE = 0, + LOGOUT_RESPONSE, + LOAD_STATIC_ZONE, + CREATE_OBJECT, + CREATE_CHARACTER, + CREATE_CHARACTER_EXTENDED, + CHARACTER_LIST_RESPONSE, + CHARACTER_CREATE_RESPONSE, + CHARACTER_RENAME_RESPONSE, + CHAT_CONNECT_RESPONSE, + AUTH_ACCOUNT_CREATE_RESPONSE, + DELETE_CHARACTER_RESPONSE, + GAME_MSG, + CONNECT_CHAT, + TRANSFER_TO_WORLD, + IMPENDING_RELOAD_NOTIFY, + MAKE_GM_RESPONSE, + HTTP_MONITOR_INFO_RESPONSE, + SLASH_PUSH_MAP_RESPONSE, + SLASH_PULL_MAP_RESPONSE, + SLASH_LOCK_MAP_RESPONSE, + BLUEPRINT_SAVE_RESPONSE, + BLUEPRINT_LUP_SAVE_RESPONSE, + BLUEPRINT_LOAD_RESPONSE_ITEMID, + BLUEPRINT_GET_ALL_DATA_RESPONSE, + MODEL_INSTANTIATE_RESPONSE, + DEBUG_OUTPUT, + ADD_FRIEND_REQUEST, + ADD_FRIEND_RESPONSE, + REMOVE_FRIEND_RESPONSE, + GET_FRIENDS_LIST_RESPONSE, + UPDATE_FRIEND_NOTIFY, + ADD_IGNORE_RESPONSE, + REMOVE_IGNORE_RESPONSE, + GET_IGNORE_LIST_RESPONSE, + TEAM_INVITE, + TEAM_INVITE_INITIAL_RESPONSE, + GUILD_CREATE_RESPONSE, + GUILD_GET_STATUS_RESPONSE, + GUILD_INVITE, + GUILD_INVITE_INITIAL_RESPONSE, + GUILD_INVITE_FINAL_RESPONSE, + GUILD_INVITE_CONFIRM, + GUILD_ADD_PLAYER, + GUILD_REMOVE_PLAYER, + GUILD_LOGIN_LOGOUT, + GUILD_RANK_CHANGE, + GUILD_DATA, + GUILD_STATUS, + MAIL, + DB_PROXY_RESULT, + SHOW_ALL_RESPONSE, + WHO_RESPONSE, + SEND_CANNED_TEXT, + UPDATE_CHARACTER_NAME, + SET_NETWORK_SIMULATOR, + INVALID_CHAT_MESSAGE, + MINIMUM_CHAT_MODE_RESPONSE, + MINIMUM_CHAT_MODE_RESPONSE_PRIVATE, + CHAT_MODERATION_STRING, + UGC_MANIFEST_RESPONSE, + IN_LOGIN_QUEUE, + SERVER_STATES, + GM_CLOSE_TARGET_CHAT_WINDOW, + GENERAL_TEXT_FOR_LOCALIZATION, + UPDATE_FREE_TRIAL_STATUS, + UGC_DOWNLOAD_FAILED = 120 +}; + +#endif //!__ECLIENTMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eConnectionType.h b/dCommon/dEnums/eConnectionType.h new file mode 100644 index 00000000..ce1ff90c --- /dev/null +++ b/dCommon/dEnums/eConnectionType.h @@ -0,0 +1,14 @@ +#ifndef __ECONNECTIONTYPE__H__ +#define __ECONNECTIONTYPE__H__ + +enum class eConnectionType : uint16_t { + SERVER = 0, + AUTH, + CHAT, + CHAT_INTERNAL, + WORLD, + CLIENT, + MASTER +}; + +#endif //!__ECONNECTIONTYPE__H__ diff --git a/dCommon/dEnums/eControlScheme.h b/dCommon/dEnums/eControlScheme.h new file mode 100644 index 00000000..f7585ebb --- /dev/null +++ b/dCommon/dEnums/eControlScheme.h @@ -0,0 +1,18 @@ +#ifndef __ECONTROLSCHEME__H__ +#define __ECONTROLSCHEME__H__ + +#include + +enum class eControlScheme : uint32_t { + SCHEME_A, + SCHEME_D, + SCHEME_GAMEPAD, + SCHEME_E, + SCHEME_FPS, + SCHEME_DRIVING, + SCHEME_TAMING, + SCHEME_MODULAR_BUILD, + SCHEME_WEAR_A_ROBOT //== freecam? +}; + +#endif //!__ECONTROLSCHEME__H__ diff --git a/dCommon/dEnums/eCyclingMode.h b/dCommon/dEnums/eCyclingMode.h new file mode 100644 index 00000000..b5e3248b --- /dev/null +++ b/dCommon/dEnums/eCyclingMode.h @@ -0,0 +1,11 @@ +#ifndef __ECYCLINGMODE__H__ +#define __ECYCLINGMODE__H__ + +#include + +enum class eCyclingMode : uint32_t { + ALLOW_CYCLE_TEAMMATES, + DISALLOW_CYCLING +}; + +#endif //!__ECYCLINGMODE__H__ diff --git a/dCommon/dEnums/eEndBehavior.h b/dCommon/dEnums/eEndBehavior.h new file mode 100644 index 00000000..77afaab4 --- /dev/null +++ b/dCommon/dEnums/eEndBehavior.h @@ -0,0 +1,11 @@ +#ifndef __EENDBEHAVIOR__H__ +#define __EENDBEHAVIOR__H__ + +#include + +enum class eEndBehavior : uint32_t { + RETURN, + WAIT +}; + +#endif //!__EENDBEHAVIOR__H__ diff --git a/dCommon/dEnums/eGameActivity.h b/dCommon/dEnums/eGameActivity.h new file mode 100644 index 00000000..16b75380 --- /dev/null +++ b/dCommon/dEnums/eGameActivity.h @@ -0,0 +1,15 @@ +#ifndef __EGAMEACTIVITY__H__ +#define __EGAMEACTIVITY__H__ + +#include + +enum class eGameActivity : uint32_t { + NONE, + QUICKBUILDING, + SHOOTING_GALLERY, + RACING, + PINBALL, + PET_TAMING +}; + +#endif //!__EGAMEACTIVITY__H__ diff --git a/dCommon/dEnums/eGameMasterLevel.h b/dCommon/dEnums/eGameMasterLevel.h new file mode 100644 index 00000000..a63c1caf --- /dev/null +++ b/dCommon/dEnums/eGameMasterLevel.h @@ -0,0 +1,20 @@ +#ifndef __EGAMEMASTERLEVEL__H__ +#define __EGAMEMASTERLEVEL__H__ + +#include + +enum class eGameMasterLevel : uint8_t { + CIVILIAN = 0, // Normal player. + FORUM_MODERATOR = 1, // No permissions on live servers. + JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. + MODERATOR = 3, // Can return lost items. + SENIOR_MODERATOR = 4, // Can ban. + LEAD_MODERATOR = 5, // Can approve properties. + JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. + INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. + DEVELOPER = 8, // Active developer, full permissions on live. + OPERATOR = 9 // Can shutdown server for restarts & updates. +}; + + +#endif //!__EGAMEMASTERLEVEL__H__ diff --git a/dCommon/dEnums/eGameMessageType.h b/dCommon/dEnums/eGameMessageType.h new file mode 100644 index 00000000..051a5ae8 --- /dev/null +++ b/dCommon/dEnums/eGameMessageType.h @@ -0,0 +1,303 @@ +#ifndef __EGAMEMESSAGETYPE__H__ +#define __EGAMEMESSAGETYPE__H__ + +#include + +enum class eGameMessageType : uint16_t { + TELEPORT = 19, + SET_PLAYER_CONTROL_SCHEME = 26, + DROP_CLIENT_LOOT = 30, + DIE = 37, + REQUEST_DIE = 38, + PLAY_EMOTE = 41, + PLAY_ANIMATION = 43, + CONTROL_BEHAVIOR = 48, + SET_NAME = 72, + ECHO_START_SKILL = 118, + START_SKILL = 119, + VERIFY_ACK = 121, + ADD_SKILL = 127, + REMOVE_SKILL = 128, + SET_CURRENCY = 133, + PICKUP_CURRENCY = 137, + PICKUP_ITEM = 139, + TEAM_PICKUP_ITEM = 140, + PLAY_FX_EFFECT = 154, + STOP_FX_EFFECT = 155, + REQUEST_RESURRECT = 159, + RESURRECT = 160, + PUSH_EQUIPPED_ITEMS_STATE = 191, + POP_EQUIPPED_ITEMS_STATE = 192, + SET_GM_LEVEL = 193, + SET_STUNNED = 198, + SET_STUN_IMMUNITY = 200, + KNOCKBACK = 202, + REBUILD_CANCEL = 209, + ENABLE_REBUILD = 213, + MOVE_ITEM_IN_INVENTORY = 224, + ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227, + REMOVE_ITEM_FROM_INVENTORY = 230, + EQUIP_ITEM = 231, + UN_EQUIP_ITEM = 233, + OFFER_MISSION = 248, + RESPOND_TO_MISSION = 249, + NOTIFY_MISSION = 254, + NOTIFY_MISSION_TASK = 255, + REBUILD_NOTIFY_STATE = 336, + TERMINATE_INTERACTION = 357, + SERVER_TERMINATE_INTERACTION = 358, + REQUEST_USE = 364, + VENDOR_OPEN_WINDOW = 369, + BUY_FROM_VENDOR = 373, + SELL_TO_VENDOR = 374, + TEAM_SET_OFF_WORLD_FLAG = 383, + SET_INVENTORY_SIZE = 389, + ACKNOWLEDGE_POSSESSION = 391, + SET_SHOOTING_GALLERY_PARAMS = 400, + REQUEST_ACTIVITY_START_STOP = 402, + REQUEST_ACTIVITY_ENTER = 403, + REQUEST_ACTIVITY_EXIT = 404, + ACTIVITY_ENTER = 405, + ACTIVITY_EXIT = 406, + ACTIVITY_START = 407, + ACTIVITY_STOP = 408, + SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409, + SHOOTING_GALLERY_FIRE = 411, + REQUEST_VENDOR_STATUS_UPDATE = 416, + VENDOR_STATUS_UPDATE = 417, + NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425, + CONSUME_CLIENT_ITEM = 427, + CLIENT_ITEM_CONSUMED = 428, + UPDATE_SHOOTING_GALLERY_ROTATION = 448, + SET_FLAG = 471, + NOTIFY_CLIENT_FLAG_CHANGE = 472, + VENDOR_TRANSACTION_RESULT = 476, + HAS_BEEN_COLLECTED = 486, + DISPLAY_CHAT_BUBBLE = 495, + SPAWN_PET = 498, + DESPAWN_PET = 499, + PLAYER_LOADED = 505, + PLAYER_READY = 509, + REQUEST_LINKED_MISSION = 515, + INVALID_ZONE_TRANSFER_LIST = 519, + MISSION_DIALOGUE_OK = 520, + DISPLAY_MESSAGE_BOX = 529, + MESSAGE_BOX_RESPOND = 530, + CHOICE_BOX_RESPOND = 531, + SMASH = 537, + UNSMASH = 538, + PLACE_MODEL_RESPONSE = 547, + SET_SHOOTING_GALLERY_RETICULE_EFFECT = 548, + SET_JET_PACK_MODE = 561, + REGISTER_PET_ID = 565, + REGISTER_PET_DBID = 566, + SHOW_ACTIVITY_COUNTDOWN = 568, + START_ACTIVITY_TIME = 576, + ACTIVITY_PAUSE = 602, + USE_NON_EQUIPMENT_ITEM = 603, + USE_ITEM_RESULT = 607, + COMMAND_PET = 640, + PET_RESPONSE = 641, + REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 648, + SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 649, + NOTIFY_OBJECT = 656, + CLIENT_NOTIFY_PET = 659, + NOTIFY_PET = 660, + NOTIFY_PET_TAMING_MINIGAME = 661, + START_SERVER_PET_MINIGAME_TIMER = 662, + CLIENT_EXIT_TAMING_MINIGAME = 663, + PET_NAME_CHANGED = 686, + PET_TAMING_MINIGAME_RESULT = 667, + PET_TAMING_TRY_BUILD_RESULT = 668, + NOTIFY_TAMING_BUILD_SUCCESS = 673, + NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, + ACTIVATE_BUBBLE_BUFF = 678, + DEACTIVATE_BUBBLE_BUFF = 679, + ADD_PET_TO_PLAYER = 681, + REQUEST_SET_PET_NAME = 683, + SET_PET_NAME = 684, + NOTIFY_PET_TAMING_PUZZLE_SELECTED = 675, + SHOW_PET_ACTION_BUTTON = 692, + SET_EMOTE_LOCK_STATE = 693, + USE_ITEM_REQUIREMENTS_RESPONSE = 703, + PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, + DOWNLOAD_PROPERTY_DATA = 716, + QUERY_PROPERTY_DATA = 717, + PROPERTY_EDITOR_BEGIN = 724, + PROPERTY_EDITOR_END = 725, + IS_MINIFIG_IN_A_BUBBLE = 729, + START_PATHING = 733, + ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734, + DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735, + NOTIFY_CLIENT_ZONE_OBJECT = 737, + UPDATE_REPUTATION = 746, + PROPERTY_RENTAL_RESPONSE = 750, + REQUEST_PLATFORM_RESYNC = 760, + PLATFORM_RESYNC = 761, + PLAY_CINEMATIC = 762, + END_CINEMATIC = 763, + CINEMATIC_UPDATE = 764, + TOGGLE_GHOST_REFERENCE_OVERRIDE = 767, + SET_GHOST_REFERENCE_POSITION = 768, + FIRE_EVENT_SERVER_SIDE = 770, + SET_NETWORK_SCRIPT_VAR = 781, + UPDATE_MODEL_FROM_CLIENT = 793, + DELETE_MODEL_FROM_CLIENT = 794, + PLAY_ND_AUDIO_EMITTER = 821, + PLAY2_DAMBIENT_SOUND = 831, + ENTER_PROPERTY1 = 840, + ENTER_PROPERTY2 = 841, + PROPERTY_ENTRANCE_SYNC = 842, + PROPERTY_SELECT_QUERY = 845, + PARSE_CHAT_MESSAGE = 850, + BROADCAST_TEXT_TO_CHATBOX = 858, + OPEN_PROPERTY_MANAGEMENT = 860, + OPEN_PROPERTY_VENDOR = 861, + UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK = 863, + CLIENT_TRADE_REQUEST = 868, + SERVER_TRADE_REQUEST = 869, + SERVER_TRADE_INVITE = 870, + CLIENT_TRADE_REPLY = 871, + SERVER_TRADE_REPLY = 872, + SERVER_TRADE_INITIAL_REPLY = 873, + SERVER_TRADE_FINAL_REPLY = 874, + CLIENT_TRADE_UPDATE = 875, + SERVER_SIDE_TRADE_UPDATE = 876, + SERVER_TRADE_UPDATE = 877, + CLIENT_TRADE_CANCEL = 878, + CLIENT_SIDE_TRADE_CANCEL = 879, + CLIENT_TRADE_ACCEPT = 880, + SERVER_SIDE_TRADE_ACCEPT = 881, + SERVER_SIDE_TRADE_CANCEL = 882, + SERVER_TRADE_CANCEL = 883, + SERVER_TRADE_ACCEPT = 884, + READY_FOR_UPDATES = 888, + ORIENT_TO_OBJECT = 905, + ORIENT_TO_POSITION = 906, + ORIENT_TO_ANGLE = 907, + BOUNCER_ACTIVE_STATUS = 942, + UN_USE_BBB_MODEL = 999, + BBB_LOAD_ITEM_REQUEST = 1000, + BBB_SAVE_REQUEST = 1001, + BBB_SAVE_RESPONSE = 1006, + NOTIFY_CLIENT_OBJECT = 1042, + DISPLAY_ZONE_SUMMARY = 1043, + ZONE_SUMMARY_DISMISSED = 1044, + ACTIVITY_STATE_CHANGE_REQUEST = 1053, + MODIFY_PLAYER_ZONE_STATISTIC = 1046, + START_BUILDING_WITH_ITEM = 1057, + START_ARRANGING_WITH_ITEM = 1061, + FINISH_ARRANGING_WITH_ITEM = 1062, + DONE_ARRANGING_WITH_ITEM = 1063, + SET_BUILD_MODE = 1068, + BUILD_MODE_SET = 1069, + SET_BUILD_MODE_CONFIRMED = 1073, + NOTIFY_CLIENT_FAILED_PRECONDITION = 1081, + MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1093, + MODULAR_BUILD_BEGIN = 1094, + MODULAR_BUILD_END = 1095, + MODULAR_BUILD_MOVE_AND_EQUIP = 1096, + MODULAR_BUILD_FINISH = 1097, + REPORT_BUG = 1198, + MISSION_DIALOGUE_CANCELLED = 1129, + ECHO_SYNC_SKILL = 1144, + SYNC_SKILL = 1145, + REQUEST_SERVER_PROJECTILE_IMPACT = 1148, + DO_CLIENT_PROJECTILE_IMPACT = 1151, + MODULAR_BUILD_CONVERT_MODEL = 1155, + SET_PLAYER_ALLOWED_RESPAWN = 1165, + UI_MESSAGE_SERVER_TO_SINGLE_CLIENT = 1184, + UI_MESSAGE_SERVER_TO_ALL_CLIENTS = 1185, + PET_TAMING_TRY_BUILD = 1197, + REQUEST_SMASH_PLAYER = 1202, + FIRE_EVENT_CLIENT_SIDE = 1213, + TOGGLE_GM_INVIS = 1218, + CHANGE_OBJECT_WORLD_STATE = 1223, + VEHICLE_LOCK_INPUT = 1230, + VEHICLE_UNLOCK_INPUT = 1231, + RACING_RESET_PLAYER_TO_LAST_RESET = 1252, + RACING_SERVER_SET_PLAYER_LAP_AND_PLANE = 1253, + RACING_SET_PLAYER_RESET_INFO = 1254, + RACING_PLAYER_INFO_RESET_FINISHED = 1255, + LOCK_NODE_ROTATION = 1260, + VEHICLE_SET_WHEEL_LOCK_STATE = 1273, + NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, + SET_NAME_BILLBOARD_STATE = 1284, + PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, + HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE = 1300, + HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE = 1301, + PROPERTY_CONTENTS_FROM_CLIENT = 1305, + GET_MODELS_ON_PROPERTY = 1306, + MATCH_REQUEST = 1308, + MATCH_RESPONSE = 1309, + MATCH_UPDATE = 1310, + MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, + MODULE_ASSEMBLY_QUERY_DATA = 1132, + SHOW_BILLBOARD_INTERACT_ICON = 1337, + CHANGE_IDLE_FLAGS = 1338, + VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, + VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, + VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342, + VEHICLE_NOTIFY_SERVER_REMOVE_PASSIVE_BOOST_ACTION = 1343, + VEHICLE_ADD_SLOWDOWN_ACTION = 1344, + VEHICLE_REMOVE_SLOWDOWN_ACTION = 1345, + VEHICLE_NOTIFY_SERVER_ADD_SLOWDOWN_ACTION = 1346, + VEHICLE_NOTIFY_SERVER_REMOVE_SLOWDOWN_ACTION = 1347, + BUYBACK_FROM_VENDOR = 1350, + SET_PROPERTY_ACCESS = 1366, + ZONE_PROPERTY_MODEL_PLACED = 1369, + ZONE_PROPERTY_MODEL_ROTATED = 1370, + ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED = 1371, + ZONE_PROPERTY_MODEL_EQUIPPED = 1372, + ZONE_PROPERTY_MODEL_PICKED_UP = 1373, + ZONE_PROPERTY_MODEL_REMOVED = 1374, + NOTIFY_RACING_CLIENT = 1390, + RACING_PLAYER_HACK_CAR = 1391, + RACING_PLAYER_LOADED = 1392, + RACING_CLIENT_READY = 1393, + UPDATE_CHAT_MODE = 1395, + VEHICLE_NOTIFY_FINISHED_RACE = 1396, + SET_CONSUMABLE_ITEM = 1409, + SET_STATUS_IMMUNITY = 1435, + SET_PET_NAME_MODERATED = 1448, + MODIFY_LEGO_SCORE = 1459, + RESTORE_TO_POST_LOAD_STATS = 1468, + SET_RAIL_MOVEMENT = 1471, + START_RAIL_MOVEMENT = 1472, + CANCEL_RAIL_MOVEMENT = 1474, + CLIENT_RAIL_MOVEMENT_READY = 1476, + PLAYER_RAIL_ARRIVED_NOTIFICATION = 1477, + UPDATE_PLAYER_STATISTIC = 1481, + MODULAR_ASSEMBLY_NIF_COMPLETED = 1498, + NOTIFY_NOT_ENOUGH_INV_SPACE = 1516, + TEAM_SET_LEADER = 1557, + TEAM_INVITE_CONFIRM = 1558, + TEAM_GET_STATUS_RESPONSE = 1559, + TEAM_ADD_PLAYER = 1562, + TEAM_REMOVE_PLAYER = 1563, + START_CELEBRATION_EFFECT = 1618, + ADD_BUFF = 1647, + SERVER_DONE_LOADING_ALL_OBJECTS = 1642, + PLACE_PROPERTY_MODEL = 1170, + VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER = 1606, + ADD_RUN_SPEED_MODIFIER = 1505, + HANDLE_HOT_PROPERTY_DATA = 1511, + SEND_HOT_PROPERTY_DATA = 1510, + REMOVE_RUN_SPEED_MODIFIER = 1506, + UPDATE_PROPERTY_PERFORMANCE_COST = 1547, + PROPERTY_ENTRANCE_BEGIN = 1553, + SET_RESURRECT_RESTORE_VALUES = 1591, + VEHICLE_STOP_BOOST = 1617, + REMOVE_BUFF = 1648, + REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, + RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, + PLAYER_SET_CAMERA_CYCLING_MODE = 1676, + SET_MOUNT_INVENTORY_ID = 1726, + NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734, + NOTIFY_LEVEL_REWARDS = 1735, + DISMOUNT_COMPLETE = 1756, + MARK_INVENTORY_ITEM_AS_ACTIVE = 1767, + END +}; + +#endif //!__EGAMEMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eHelpType.h b/dCommon/dEnums/eHelpType.h new file mode 100644 index 00000000..d1838cc6 --- /dev/null +++ b/dCommon/dEnums/eHelpType.h @@ -0,0 +1,41 @@ + +#ifndef __EHELPTYPE__H__ +#define __EHELPTYPE__H__ + +#include + +enum class eHelpType : int32_t { + NONE = 0, + UNLOCK_MINIMAP = 2, + TOGGLETOOLTIP_OUTOFTIME_REBUILD = 3, + TOGGLETOOLTIP_LEAVELOSE_REBUILD = 4, + TOGGLECONTROLSTUTORIAL_WALKING = 6, + DISPLAYTUTORIAL_PASSPORT_1ST_SMASH = 7, + TOOLTIP_1ST_IMAGINATION_PICKUP = 8, + UNKNOWN9 = 9, + PETTAMINGMINIGAME_TUTORIAL_01 = 15, + PR_BOUNCER_TUTORIAL_03 = 16, + PR_TOOLTIP_1ST_PET_JUMPED_ON_SWITCH = 17, + PR_DIG_TUTORIAL_01 = 18, + PR_DIG_TUTORIAL_03 = 19, + PR_BOUNCER_TUTORIAL_01 = 20, + PR_NO_IMAGINATION_HIBERNATE = 21, + UNKNOWN22 = 22, + TOGGLECONTROLSTUTORIAL_JUMPING = 26, + TOGGLECONTROLSTUTORIAL_DOUBLEJUMPING = 27, + TOGGLECONTROLSTUTORIAL_CAMERA = 28, + TOGGLECONTROLSTUTORIAL_SMASH = 30, + UNKNOWN38 = 38, + UI_MOD_BUILD_PUT_ON_HAT = 40, + UI_MOD_BUILD_EQUIP_FIRST_MODULE = 41, + UNKNOWN42 = 42, + UNKNOWN43 = 43, + UI_MOD_BUILD_GO_LAUNCH_ROCKET = 44, + UI_MOD_BUILD_TALK_TO_SKYLANE = 45, + UNKNOWN53 = 53, + PET_DESPAWN_BY_OWNER_HIBERNATE = 69, + PET_DESPAWN_TAMING_NEW_PET = 70, + UI_INVENTORY_FULL_CANNOT_PICKUP_ITEM = 86 +}; + +#endif //!__EHELPTYPE__H__ diff --git a/dCommon/dEnums/eInventoryType.h b/dCommon/dEnums/eInventoryType.h new file mode 100644 index 00000000..12573aa4 --- /dev/null +++ b/dCommon/dEnums/eInventoryType.h @@ -0,0 +1,59 @@ +#pragma once + +#ifndef __EINVENTORYTYPE__H__ +#define __EINVENTORYTYPE__H__ + +#include +static const uint8_t NUMBER_OF_INVENTORIES = 17; +/** + * Represents the different types of inventories an entity may have + */ +enum eInventoryType : uint32_t { + ITEMS = 0, + VAULT_ITEMS, + BRICKS, + MODELS_IN_BBB, + TEMP_ITEMS, + MODELS, + TEMP_MODELS, + BEHAVIORS, + PROPERTY_DEEDS, + BRICKS_IN_BBB, + VENDOR, + VENDOR_BUYBACK, + QUEST, //Used for mission items + DONATION, + VAULT_MODELS, + ITEM_SETS, //internal, technically this is BankBehaviors. + INVALID // made up, for internal use!!!, Technically this called the ALL inventory. +}; + +class InventoryType { +public: + static const char* InventoryTypeToString(eInventoryType inventory) { + const char* eInventoryTypeTable[NUMBER_OF_INVENTORIES] = { + "ITEMS", + "VAULT_ITEMS", + "BRICKS", + "MODELS_IN_BBB", + "TEMP_ITEMS", + "MODELS", + "TEMP_MODELS", + "BEHAVIORS", + "PROPERTY_DEEDS", + "BRICKS_IN_BBB", + "VENDOR", + "VENDOR_BUYBACK", + "QUEST", //Used for mission items + "DONATION", + "VAULT_MODELS", + "ITEM_SETS", //internal, technically this is BankBehaviors. + "INVALID" // made up, for internal use!!!, Technically this called the ALL inventory. + }; + + if (inventory > NUMBER_OF_INVENTORIES - 1) return nullptr; + return eInventoryTypeTable[inventory]; + }; +}; + +#endif //!__EINVENTORYTYPE__H__ diff --git a/dCommon/dEnums/eItemSetPassiveAbilityID.h b/dCommon/dEnums/eItemSetPassiveAbilityID.h new file mode 100644 index 00000000..8641d0f2 --- /dev/null +++ b/dCommon/dEnums/eItemSetPassiveAbilityID.h @@ -0,0 +1,58 @@ +#pragma once + +#ifndef __EITEMSETPASSIVEABILITYID__H__ +#define __EITEMSETPASSIVEABILITYID__H__ + +enum class eItemSetPassiveAbilityID { + EngineerRank1 = 2, + EngineerRank2 = 3, + EngineerRank3 = 4, + KnightRank1 = 7, + KnightRank2 = 8, + KnightRank3 = 9, + SpaceRangerRank1 = 10, + SpaceRangerRank2 = 11, + SpaceRangerRank3 = 12, + SamuraiRank1 = 13, + SamuraiRank2 = 14, + SamuraiRank3 = 15, + SorcererRank1 = 16, + SorcererRank2 = 17, + SorcererRank3 = 18, + SpaceMarauderRank1 = 19, + SpaceMarauderRank2 = 20, + SpaceMarauderRank3 = 21, + ShinobiRank1 = 22, + ShinobiRank2 = 23, + ShinobiRank3 = 24, + InventorRank1 = 25, + InventorRank2 = 26, + InventorRank3 = 27, + SummonerRank1 = 28, + SummonerRank2 = 29, + SummonerRank3 = 30, + AdventurerRank1 = 31, + AdventurerRank2 = 32, + AdventurerRank3 = 33, + DaredevilRank1 = 34, + DaredevilRank2 = 35, + DaredevilRank3 = 36, + BuccaneerRank1 = 37, + BuccaneerRank2 = 38, + BuccaneerRank3 = 39, + BoneSuit = 40, + ImaginationSpinjitzu = 41, + BatLord = 42, + MosaicJester = 43, + ExplorienBot = 44, + Unnamed1 = 45, + Unnamed2 = 46, + Unnamed3 = 47, + EarthSpinjitzu = 48, + Unnamed4 = 49, + FireSpinjitzu = 50, + IceSpinjitzu = 51, + LightningSpinjitzu = 52 +}; + +#endif //!__EITEMSETPASSIVEABILITYID__H__ diff --git a/dCommon/dEnums/eItemType.h b/dCommon/dEnums/eItemType.h new file mode 100644 index 00000000..41c7765b --- /dev/null +++ b/dCommon/dEnums/eItemType.h @@ -0,0 +1,36 @@ +#pragma once + +#ifndef __EITEMTYPE__H__ +#define __EITEMTYPE__H__ + +#include + +enum class eItemType : int32_t { + UNKNOWN = -1, + BRICK = 1, + HAT, + HAIR, + NECK, + LEFT_HAND, + RIGHT_HAND, + LEGS, + LEFT_TRINKET, + RIGHT_TRINKET, + BEHAVIOR, + PROPERTY, + MODEL, + COLLECTIBLE, + CONSUMABLE, + CHEST, + EGG, + PET_FOOD, + QUEST_OBJECT, + PET_INVENTORY_ITEM, + PACKAGE, + LOOT_MODEL, + VEHICLE, + LUP_MODEL, + MOUNT +}; + +#endif //!__EITEMTYPE__H__ diff --git a/dCommon/dEnums/eKillType.h b/dCommon/dEnums/eKillType.h new file mode 100644 index 00000000..fe3908c8 --- /dev/null +++ b/dCommon/dEnums/eKillType.h @@ -0,0 +1,11 @@ +#ifndef __EKILLTYPE__H__ +#define __EKILLTYPE__H__ + +#include + +enum class eKillType : uint32_t { + VIOLENT, + SILENT +}; + +#endif //!__EKILLTYPE__H__ diff --git a/dCommon/dEnums/eLoginResponse.h b/dCommon/dEnums/eLoginResponse.h new file mode 100644 index 00000000..01bba3d5 --- /dev/null +++ b/dCommon/dEnums/eLoginResponse.h @@ -0,0 +1,24 @@ +#ifndef __ELOGINRESPONSE__H__ +#define __ELOGINRESPONSE__H__ + +#include + +enum class eLoginResponse : uint8_t { + GENERAL_FAILED = 0, + SUCCESS, + BANNED, + // Unused 3 + // Unused 4 + PERMISSIONS_NOT_HIGH_ENOUGH = 5, + INVALID_USER, + ACCOUNT_LOCKED, + WRONG_PASS, + ACCOUNT_ACTIVATION_PENDING, + ACCOUNT_DISABLED, + GAME_TIME_EXPIRED, + FREE_TRIAL_ENDED, + PLAY_SCHEDULE_TIME_UP, + ACCOUNT_NOT_ACTIVATED +}; + +#endif //!__ELOGINRESPONSE__H__ diff --git a/dCommon/dEnums/eLootSourceType.h b/dCommon/dEnums/eLootSourceType.h new file mode 100644 index 00000000..b8ecca4a --- /dev/null +++ b/dCommon/dEnums/eLootSourceType.h @@ -0,0 +1,31 @@ +#ifndef __ELOOTSOURCETYPE__H__ +#define __ELOOTSOURCETYPE__H__ + +#include + +enum class eLootSourceType : uint32_t { + NONE = 0, + CHEST, + MISSION, + MAIL, + CURRENCY, + ACHIEVEMENT, + TRADE, + QUICKBUILD, + DELETION, + VENDOR, + ACTIVITY, + PICKUP, + BRICK, + PROPERTY, + MODERATION, + EXHIBIT, + INVENTORY, + CLAIMCODE, + CONSUMPTION, + CRAFTING, + LEVEL_REWARD, + RELOCATE +}; + +#endif //!__ELOOTSOURCETYPE__H__ diff --git a/dCommon/dEnums/eMasterMessageType.h b/dCommon/dEnums/eMasterMessageType.h new file mode 100644 index 00000000..5c867d70 --- /dev/null +++ b/dCommon/dEnums/eMasterMessageType.h @@ -0,0 +1,36 @@ +#ifndef __EMASTERMESSAGETYPE__H__ +#define __EMASTERMESSAGETYPE__H__ + +#include + +enum class eMasterMessageType : uint32_t { + REQUEST_PERSISTENT_ID = 1, + REQUEST_PERSISTENT_ID_RESPONSE, + REQUEST_ZONE_TRANSFER, + REQUEST_ZONE_TRANSFER_RESPONSE, + SERVER_INFO, + REQUEST_SESSION_KEY, + SET_SESSION_KEY, + SESSION_KEY_RESPONSE, + PLAYER_ADDED, + PLAYER_REMOVED, + + CREATE_PRIVATE_ZONE, + REQUEST_PRIVATE_ZONE, + + WORLD_READY, + PREP_ZONE, + + SHUTDOWN, + SHUTDOWN_RESPONSE, + SHUTDOWN_IMMEDIATE, + + SHUTDOWN_UNIVERSE, + + AFFIRM_TRANSFER_REQUEST, + AFFIRM_TRANSFER_RESPONSE, + + NEW_SESSION_ALERT +}; + +#endif //!__EMASTERMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eMatchUpdate.h b/dCommon/dEnums/eMatchUpdate.h new file mode 100644 index 00000000..a42eecd3 --- /dev/null +++ b/dCommon/dEnums/eMatchUpdate.h @@ -0,0 +1,17 @@ +#ifndef __EMATCHUPDATE__H__ +#define __EMATCHUPDATE__H__ + +#include + +enum class eMatchUpdate : int32_t { + PLAYER_ADDED = 0, + PLAYER_REMOVED, + PHASE_CREATED, + PHASE_WAIT_READY, + PHASE_WAIT_START, + PLAYER_READY, + PLAYER_NOT_READY, + PLAYER_UPDATE +}; + +#endif //!__EMATCHUPDATE__H__ diff --git a/dCommon/dEnums/eMissionLockState.h b/dCommon/dEnums/eMissionLockState.h new file mode 100644 index 00000000..52752767 --- /dev/null +++ b/dCommon/dEnums/eMissionLockState.h @@ -0,0 +1,12 @@ +#pragma once + +#ifndef __EMISSIONLOCKSTATE__H__ +#define __EMISSIONLOCKSTATE__H__ + +enum class eMissionLockState : int { + LOCKED, + NEW, + UNLOCKED, +}; + +#endif //!__EMISSIONLOCKSTATE__H__ diff --git a/dCommon/dEnums/eMissionState.h b/dCommon/dEnums/eMissionState.h new file mode 100644 index 00000000..e080f455 --- /dev/null +++ b/dCommon/dEnums/eMissionState.h @@ -0,0 +1,56 @@ +#pragma once + +#ifndef __MISSIONSTATE__H__ +#define __MISSIONSTATE__H__ + +/** + * Represents the possible states a mission can be in + */ +enum class eMissionState : int { + /** + * The mission state is unknown + */ + UNKNOWN = -1, + + /** + * The mission is yielding rewards + */ + REWARDING = 0, + + /** + * The mission can be accepted + */ + AVAILABLE = 1, + + /** + * The mission has been accepted but not yet completed + */ + ACTIVE = 2, + + /** + * All the tasks for the mission have been completed and the entity can turn the mission in to complete it + */ + READY_TO_COMPLETE = 4, //!< The mission is ready to complete + + /** + * The mission has been completed + */ + COMPLETE = 8, + + /** + * The mission is available again and has been completed before. Used for daily missions. + */ + COMPLETE_AVAILABLE = 9, + + /** + * The mission is active and has been completed before. Used for daily missions. + */ + COMPLETE_ACTIVE = 10, + + /** + * The mission has been completed before and has now been completed again. Used for daily missions. + */ + COMPLETE_READY_TO_COMPLETE = 12 +}; + +#endif //!__MISSIONSTATE__H__ diff --git a/dCommon/dEnums/eMissionTaskType.h b/dCommon/dEnums/eMissionTaskType.h new file mode 100644 index 00000000..2636f88c --- /dev/null +++ b/dCommon/dEnums/eMissionTaskType.h @@ -0,0 +1,43 @@ +#pragma once + +#ifndef __EMISSIONTASKTYPE__H__ +#define __EMISSIONTASKTYPE__H__ + +enum class eMissionTaskType : int { + UNKNOWN = -1, + SMASH, + SCRIPT, + ACTIVITY, + COLLECTION, + TALK_TO_NPC, + EMOTE, + SHASH_CHAIN, + BUY, + SELL, + USE_ITEM, + USE_SKILL, + GATHER, + EXPLORE, + DELIVERY, + PERFORM_ACTIVITY, + INTERACT, + META, + EARN_REPUTATION, + VOTING, + SHOWCASE_DELIVERY, + REVIECE_CAST, + POWERUP, + PET_TAMING, + RACING, + PLAYER_FLAG, + PLACE_MODEL, + REMOVE_MODEL, + ADD_BEHAVIOR, + REMOVE_BEHAVIOR, + CLAIM_PROPERTY, + VISIT_PROPERTY, + TIME_PLAYED, + DONATION +}; + +#endif //!__EMISSIONTASKTYPE__H__ diff --git a/dCommon/dEnums/eMovementPlatformState.h b/dCommon/dEnums/eMovementPlatformState.h new file mode 100644 index 00000000..1df437d8 --- /dev/null +++ b/dCommon/dEnums/eMovementPlatformState.h @@ -0,0 +1,16 @@ +#ifndef __EMOVEMENTPLATFORMSTATE__H__ +#define __EMOVEMENTPLATFORMSTATE__H__ + +#include + +/** + * The different types of platform movement state, supposedly a bitmap + */ +enum class eMovementPlatformState : uint32_t +{ + Moving = 0b00010, + Stationary = 0b11001, + Stopped = 0b01100 +}; + +#endif //!__EMOVEMENTPLATFORMSTATE__H__ diff --git a/dCommon/dEnums/eObjectBits.h b/dCommon/dEnums/eObjectBits.h new file mode 100644 index 00000000..b978aad6 --- /dev/null +++ b/dCommon/dEnums/eObjectBits.h @@ -0,0 +1,13 @@ +#ifndef __EOBJECTBITS__H__ +#define __EOBJECTBITS__H__ + +#include + +enum class eObjectBits : size_t { + PERSISTENT = 32, + CLIENT = 46, + SPAWNED = 58, + CHARACTER = 60 +}; + +#endif //!__EOBJECTBITS__H__ diff --git a/dCommon/dEnums/eObjectWorldState.h b/dCommon/dEnums/eObjectWorldState.h new file mode 100644 index 00000000..9735a072 --- /dev/null +++ b/dCommon/dEnums/eObjectWorldState.h @@ -0,0 +1,12 @@ +#ifndef __EOBJECTWORLDSTATE__H__ +#define __EOBJECTWORLDSTATE__H__ + +#include + +enum class eObjectWorldState : uint32_t { + INWORLD, + ATTACHED, + INVENTORY +}; + +#endif //!__EOBJECTWORLDSTATE__H__ diff --git a/dCommon/dEnums/ePackageType.h b/dCommon/dEnums/ePackageType.h new file mode 100644 index 00000000..2c1c9977 --- /dev/null +++ b/dCommon/dEnums/ePackageType.h @@ -0,0 +1,13 @@ +#ifndef __EPACKAGETYPE__H__ +#define __EPACKAGETYPE__H__ + +enum class ePackageType { + INVALID = -1, + ITEM, + BRICKS, + MODELS, + CAR_MODELS +}; + + +#endif //!__EPACKAGETYPE__H__ diff --git a/dCommon/dEnums/ePermissionMap.h b/dCommon/dEnums/ePermissionMap.h new file mode 100644 index 00000000..d15c9fd3 --- /dev/null +++ b/dCommon/dEnums/ePermissionMap.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#ifndef __EPERMISSIONMAP__H__ +#define __EPERMISSIONMAP__H__ + +/** + * Bitmap of permissions and restrictions for characters. + */ +enum class ePermissionMap : uint64_t { + /** + * Reserved for future use, bit 0-3. + */ + + /** + * The character has restricted trade acccess, bit 4. + */ + RestrictedTradeAccess = 0x1 << 4, + + /** + * The character has restricted mail access, bit 5. + */ + RestrictedMailAccess = 0x1 << 5, + + /** + * The character has restricted chat access, bit 6. + */ + RestrictedChatAccess = 0x1 << 6, + + // + // Combined permissions + // + + /** + * The character is marked as 'old', restricted from trade and mail. + */ + Old = RestrictedTradeAccess | RestrictedMailAccess, + + /** + * The character is soft banned, restricted from trade, mail, and chat. + */ + SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess, +}; + +#endif //!__EPERMISSIONMAP__H__ diff --git a/dCommon/dEnums/ePetTamingNotifyType.h b/dCommon/dEnums/ePetTamingNotifyType.h new file mode 100644 index 00000000..564e932f --- /dev/null +++ b/dCommon/dEnums/ePetTamingNotifyType.h @@ -0,0 +1,15 @@ +#ifndef __EPETTAMINGNOTIFYTYPE__H__ +#define __EPETTAMINGNOTIFYTYPE__H__ + +#include + +enum class ePetTamingNotifyType : uint32_t { + SUCCESS, + QUIT, + FAILED, + BEGIN, + READY, + NAMINGPET +}; + +#endif //!__EPETTAMINGNOTIFYTYPE__H__ diff --git a/dCommon/dEnums/ePhysicsEffectType.h b/dCommon/dEnums/ePhysicsEffectType.h new file mode 100644 index 00000000..1aa68b34 --- /dev/null +++ b/dCommon/dEnums/ePhysicsEffectType.h @@ -0,0 +1,15 @@ +#ifndef __EPHYSICSEFFECTTYPE__H__ +#define __EPHYSICSEFFECTTYPE__H__ + + +#include + +enum class ePhysicsEffectType : uint32_t { + PUSH, + ATTRACT, + REPULSE, + GRAVITY_SCALE, + FRICTION +}; + +#endif //!__EPHYSICSEFFECTTYPE__H__ diff --git a/dCommon/dEnums/ePlayerFlag.h b/dCommon/dEnums/ePlayerFlag.h new file mode 100644 index 00000000..fefdfb67 --- /dev/null +++ b/dCommon/dEnums/ePlayerFlag.h @@ -0,0 +1,172 @@ +#ifndef __EPLAYERFLAG__H__ +#define __EPLAYERFLAG__H__ + +#include + +enum ePlayerFlag : int32_t { + BTARR_TESTING = 0, + PLAYER_HAS_ENTERED_PET_RANCH = 1, + MINIMAP_UNLOCKED = 2, + ACTIVITY_REBUILDING_FAIL_TIME = 3, + ACTIVITY_REBUILDING_FAIL_RANGE = 4, + ACTIVITY_SHOOTING_GALLERY_HELP = 5, + HELP_WALKING_CONTROLS = 6, + FIRST_SMASHABLE = 7, + FIRST_IMAGINATION_PICKUP = 8, + FIRST_DAMAGE = 9, + FIRST_ITEM = 10, + FIRST_BRICK = 11, + FIRST_CONSUMABLE = 12, + FIRST_EQUIPPABLE = 13, + CHAT_HELP = 14, + FIRST_PET_TAMING_MINIGAME = 15, + FIRST_PET_ON_SWITCH = 16, + FIRST_PET_JUMPED_ON_SWITCH = 17, + FIRST_PET_FOUND_TREASURE = 18, + FIRST_PET_DUG_TREASURE = 19, + FIRST_PET_OWNER_ON_PET_BOUNCER = 20, + FIRST_PET_DESPAWN_NO_IMAGINATION = 21, + FIRST_PET_SELECTED_ENOUGH_BRICKS = 22, + FIRST_EMOTE_UNLOCKED = 23, + GF_PIRATE_REP = 24, + AG_BOB_CINEMATIC_EVENT = 25, + HELP_JUMPING_CONTROLS = 26, + HELP_DOUBLE_JUMP_CONTROLS = 27, + HELP_CAMERA_CONTROLS = 28, + HELP_ROTATE_CONTROLS = 29, + HELP_SMASH = 30, + MONUMENT_INTRO_MUSIC_PLAYED = 31, + BEGINNING_ZONE_SUMMARY_DISPLAYED = 32, + AG_FINISH_LINE_BUILT = 33, + AG_BOSS_AREA_FOUND = 34, + AG_LANDED_IN_BATTLEFIELD = 35, + GF_PLAYER_HAS_BEEN_TO_THE_RAVINE = 36, + MODULAR_BUILD_STARTED = 37, + MODULAR_BUILD_FINISHED_CLICK_BUTTON = 38, + THINKING_HAT_RECEIVED_GO_TO_MODULAR_BUILD_AREA = 39, + BUILD_AREA_ENTERED_MOD_NOT_ACTIVATED_PUT_ON_HAT = 40, + HAT_ON_INSIDE_OF_MOD_BUILD_EQUIP_A_MODULE_FROM_LEG = 41, + MODULE_EQUIPPED_PLACE_ON_GLOWING_BLUE_SPOT = 42, + FIRST_MODULE_PLACED_CORRECTLY_NOW_DO_THE_REST = 43, + ROCKET_COMPLETE_NOW_LAUNCH_FROM_PAD = 44, + JOINED_A_FACTION = 45, + VENTURE_FACTION = 46, + ASSEMBLY_FACTION = 47, + PARADOX_FACTION = 48, + SENTINEL_FACTION = 49, + LUP_WORLD_ACCESS = 50, + AG_FIRST_FLAG_COLLECTED = 51, + TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52, + MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53, + MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54, + AG_BEACON_QB_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55, + GF_PET_DIG_FLAG_1 = 56, + GF_PET_DIG_FLAG_2 = 57, + GF_PET_DIG_FLAG_3 = 58, + SUPPRESS_SPACESHIP_CINEMATIC_FLYTHROUGH = 59, + GF_PLAYER_FALL_DEATH = 60, + GF_PLAYER_CAN_GET_FLAG_1 = 61, + GF_PLAYER_CAN_GET_FLAG_2 = 62, + GF_PLAYER_CAN_GET_FLAG_3 = 63, + ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64, + AG_FIRST_COMBAT_COMPLETE = 65, + AG_COMPLETE_BOB_MISSION = 66, + FIRST_MANUAL_PET_HIBERNATE = 69, + CAGED_SPIDER = 74, + IS_NEWS_SCREEN_VISIBLE = 114, + NJ_GARMADON_CINEMATIC_SEEN = 125, + EQUPPED_TRIAL_FACTION_GEAR = 126, + ELEPHANT_PET_3050 = 801, + CAT_PET_3054 = 803, + TRICERATOPS_PET_3195 = 806, + TERRIER_PET_3254 = 807, + SKUNK_PET_3261 = 811, + BUNNY_PET_3672 = 813, + CROCODILE_PET_3994 = 814, + DOBERMAN_PET_5635 = 815, + BUFFALO_PET_5636 = 816, + ROBOT_DOG_PET_5637 = 818, + RED_DRAGON_PET_5639 = 819, + TORTOISE_PET_5640 = 820, + GREEN_DRAGON_PET_5641 = 821, + PANDA_PET_5643 = 822, + MANTIS_PET_5642 = 823, + WARTHOG_PET_6720 = 824, + LION_PET_3520 = 825, + GOAT_PET_7638 = 818, + CRAB_PET_7694 = 827, + REINDEER_PET_12294 = 829, + STEGOSAURUS_PET_12431 = 830, + SABER_CAT_PET_12432 = 831, + GRYPHON_PET_12433 = 832, + ALINE_PET_12334 = 833, + UNKNOWN_PET = 834, + EARTH_DRAGON_PET_16210 = 836, + SKELETON_DRAGON_PET_13067 = 838, + AG_SPACE_SHIP_BINOC_AT_LAUNCH = 1001, + AG_SPACE_SHIP_BINOC_AT_LAUNCH_PLATFORM = 1002, + AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_LEFT_OF_START = 1003, + AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_RIGHT_OF_START = 1004, + AG_SPACE_SHIP_BINOC_AT_BOB = 1005, + AG_BATTLE_BINOC_FOR_TRICERETOPS = 1101, + AG_BATTLE_BINOC_AT_PARADOX = 1102, + AG_BATTLE_BINOC_AT_MISSION_GIVER = 1103, + AG_BATTLE_BINOC_AT_BECK = 1104, + AG_MONUMENT_BINOC_INTRO = 1105, + AG_MONUMENT_BINOC_OUTRO = 1106, + AG_LAUNCH_BINOC_INTRO = 1107, + AG_LAUNCH_BINOC_BISON = 1108, + AG_LAUNCH_BINOC_SHARK = 1109, + NS_BINOC_CONCERT_TRANSITION = 1201, + NS_BINOC_RACE_PLACE_TRANSITION = 1202, + NS_BINOC_BRICK_ANNEX_TRANSITION = 1203, + NS_BINOC_GF_LAUNCH = 1204, + NS_BINOC_FV_LAUNCH = 1205, + NS_BINOC_BRICK_ANNEX_WATER = 1206, + NS_BINOC_AG_LAUNCH_AT_RACE_PLACE = 1207, + NS_BINOC_AG_LAUNCH_AT_BRICK_ANNEX = 1208, + NS_BINOC_AG_LAUNCH_AT_PLAZA = 1209, + NS_BINOC_TBA = 1210, + NS_FLAG_COLLECTABLE_1_BY_JONNY_THUNDER = 1211, + NS_FLAG_COLLECTABLE_2_UNDER_CONCERT_BRIDGE = 1212, + NS_FLAG_COLLECTABLE_3_BY_FV_LAUNCH = 1213, + NS_FLAG_COLLECTABLE_4_IN_PLAZA_BEHIND_BUILDING = 1214, + NS_FLAG_COLLECTABLE_5_BY_GF_LAUNCH = 1215, + NS_FLAG_COLLECTABLE_6_BY_DUCK_SG = 1216, + NS_FLAG_COLLECTABLE_7_BY_LUP_LAUNCH = 1217, + NS_FLAG_COLLECTABLE_8_BY_NT_LUANCH = 1218, + NS_FLAG_COLLECTABLE_9_BY_RACE_BUILD = 1219, + NS_FLAG_COLLECTABLE_10_ON_AG_LAUNCH_PATH = 1220, + PR_BINOC_AT_LAUNCH_PAD = 1251, + PR_BINOC_AT_BEGINNING_OF_ISLAND_B = 1252, + PR_BINOC_AT_FIRST_PET_BOUNCER = 1253, + PR_BINOC_ON_BY_CROWS_NEST = 1254, + PR_PET_DIG_AT_BEGINNING_OF_ISLAND_B = 1261, + PR_PET_DIG_AT_THE_LOCATION_OF_OLD_BOUNCE_BACK = 1262, + PR_PET_DIG_UNDER_QB_BRIDGE = 1263, + PR_PET_DIG_BACK_SIDE_BY_PARTNER_BOUNCE = 1264, + PR_PET_DIG_BY_LAUNCH_PAD = 1265, + PR_PET_DIG_BY_FIRST_PET_BOUNCER = 1266, + GF_BINOC_ON_LANDING_PAD = 1301, + GF_BINOC_AT_RAVINE_START = 1302, + GF_BINOC_ON_TOP_OF_RAVINE_HEAD = 1303, + GF_BINOC_AT_TURTLE_AREA = 1304, + GF_BINOC_IN_TUNNEL_TO_ELEPHANTS = 1305, + GF_BINOC_IN_ELEPHANTS_AREA = 1306, + GF_BINOC_IN_RACING_AREA = 1307, + GF_BINOC_IN_CROC_AREA = 1308, + GF_BINOC_IN_JAIL_AREA = 1309, + GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310, + NT_HEART_OF_DARKNESS = 1911, + NT_PLINTH_REBUILD = 1919, + NT_FACTION_SPY_DUKE = 1974, + NT_FACTION_SPY_OVERBUILD = 1976, + NT_FACTION_SPY_HAEL = 1977, + NJ_EARTH_SPINJITZU = 2030, + NJ_LIGHTNING_SPINJITZU = 2031, + NJ_ICE_SPINJITZU = 2032, + NJ_FIRE_SPINJITZU = 2033, + NJ_WU_SHOW_DAILY_CHEST = 2099 +}; + +#endif //!__EPLAYERFLAG__H__ diff --git a/dCommon/dEnums/eQuickBuildFailReason.h b/dCommon/dEnums/eQuickBuildFailReason.h new file mode 100644 index 00000000..a6144bd5 --- /dev/null +++ b/dCommon/dEnums/eQuickBuildFailReason.h @@ -0,0 +1,13 @@ +#ifndef __EQUICKBUILDFAILREASON__H__ +#define __EQUICKBUILDFAILREASON__H__ + +#include + +enum class eQuickBuildFailReason : uint32_t { + NOT_GIVEN, + OUT_OF_IMAGINATION, + CANCELED_EARLY, + BUILD_ENDED +}; + +#endif //!__EQUICKBUILDFAILREASON__H__ diff --git a/dCommon/dEnums/eRacingTaskParam.h b/dCommon/dEnums/eRacingTaskParam.h new file mode 100644 index 00000000..df50e382 --- /dev/null +++ b/dCommon/dEnums/eRacingTaskParam.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef __ERACINGTASKPARAM__H__ +#define __ERACINGTASKPARAM__H__ + +#include + +enum class eRacingTaskParam : int32_t { + FINISH_WITH_PLACEMENT = 1, + LAP_TIME, + TOTAL_TRACK_TIME, + COMPLETE_ANY_RACING_TASK, + COMPLETE_TRACK_TASKS, + MODULAR_BUILDING, + SAFE_DRIVER = 10, + SMASHABLES, + COLLECT_IMAGINATION, + COMPETED_IN_RACE, + WIN_RACE_IN_WORLD, + FIRST_PLACE_MULTIPLE_TRACKS, + LAST_PLACE_FINISH, + SMASH_SPECIFIC_SMASHABLE +}; + +#endif //!__ERACINGTASKPARAM__H__ diff --git a/dCommon/dEnums/eRebuildState.h b/dCommon/dEnums/eRebuildState.h new file mode 100644 index 00000000..497bcb77 --- /dev/null +++ b/dCommon/dEnums/eRebuildState.h @@ -0,0 +1,15 @@ +#ifndef __EREBUILDSTATE__H__ +#define __EREBUILDSTATE__H__ + +#include + +enum class eRebuildState : uint32_t { + OPEN, + COMPLETED = 2, + RESETTING = 4, + BUILDING, + INCOMPLETE +}; + + +#endif //!__EREBUILDSTATE__H__ diff --git a/dCommon/dEnums/eRenameResponse.h b/dCommon/dEnums/eRenameResponse.h new file mode 100644 index 00000000..2298e922 --- /dev/null +++ b/dCommon/dEnums/eRenameResponse.h @@ -0,0 +1,15 @@ +#ifndef __ERENAMERESPONSE__H__ +#define __ERENAMERESPONSE__H__ + +#include + +//! An enum for character rename responses +enum class eRenameResponse : uint8_t { + SUCCESS = 0, + UNKNOWN_ERROR, + NAME_UNAVAILABLE, + NAME_IN_USE +}; + + +#endif //!__ERENAMERESPONSE__H__ diff --git a/dCommon/dEnums/eReplicaComponentType.h b/dCommon/dEnums/eReplicaComponentType.h new file mode 100644 index 00000000..3eee16f3 --- /dev/null +++ b/dCommon/dEnums/eReplicaComponentType.h @@ -0,0 +1,127 @@ +#ifndef __EREPLICACOMPONENTTYPE__H__ +#define __EREPLICACOMPONENTTYPE__H__ + +#include + +enum class eReplicaComponentType : uint32_t { + INVALID = 0, + CONTROLLABLE_PHYSICS, + RENDER, + SIMPLE_PHYSICS, + CHARACTER, + SCRIPT, + BOUNCER, + BUFF, // buff is really 98, this is DESTROYABLE + GHOST, + SKILL, + SPAWNER, + ITEM, + REBUILD, + REBUILD_START, + REBUILD_ACTIVATOR, + ICON_ONLY, + VENDOR, + INVENTORY, + PROJECTILE_PHYSICS, + SHOOTING_GALLERY, + RIGID_BODY_PHANTOM_PHYSICS, + DROP_EFFECT, + CHEST, + COLLECTIBLE, + BLUEPRINT, + MOVING_PLATFORM, + PET, + PLATFORM_BOUNDARY, + MODULE, + ARCADE, + VEHICLE_PHYSICS, // Havok demo based + MOVEMENT_AI, + EXHIBIT, + OVERHEAD_ICON, + PET_CONTROL, + MINIFIG, + PROPERTY, + PET_CREATOR, + MODEL_BUILDER, + SCRIPTED_ACTIVITY, + PHANTOM_PHYSICS, + SPRINGPAD, + MODEL, + PROPERTY_ENTRANCE, + FX, + PROPERTY_MANAGEMENT, + VEHICLE_PHYSICS_NEW, // internal physics based on havok + PHYSICS_SYSTEM, + QUICK_BUILD, + SWITCH, + ZONE_CONTROL, // Minigame + CHANGLING, + CHOICE_BUILD, + PACKAGE, + SOUND_REPEATER, + SOUND_AMBIENT_2D, + SOUND_AMBIENT_3D, + PRECONDITION, + PLAYER_FLAG, + CUSTOM_BUILD_ASSEMBLY, + BASE_COMBAT_AI, + MODULE_ASSEMBLY, + SHOWCASE_MODEL_HANDLER, + RACING_MODULE, + GENERIC_ACTIVATOR, + PROPERTY_VENDOR, + HF_LIGHT_DIRECTION_GADGET, + ROCKET_LAUNCH, + ROCKET_LANDING, + TRIGGER, + DROPPED_LOOT, + RACING_CONTROL, + FACTION_TRIGGER, + MISSION_OFFER, + RACING_STATS, + LUP_EXHIBIT, + BBB, + SOUND_TRIGGER, + PROXIMITY_MONITOR, + RACING_SOUND_TRIGGER, + CHAT, + FRIENDS_LIST, + GUILD, + LOCAL_SYSTEM, + MISSION, + MUTABLE_MODEL_BEHAVIORS, + PATHFINDING, + PET_TAMING_CONTROL, + PROPERTY_EDITOR, + SKINNED_RENDER, + SLASH_COMMAND, + STATUS_EFFECT, + TEAMS, + TEXT_EFFECT, + TRADE, + USER_CONTROL, + IGNORE_LIST, + ROCKET_LAUNCH_LUP, + BUFF_REAL, // the real buff component, should just be name BUFF + INTERACTION_MANAGER, + DONATION_VENDOR, + COMBAT_MEDIATOR, + COMMENDATION_VENDOR, + UNKNOWN_103, + RAIL_ACTIVATOR, + ROLLER, + PLAYER_FORCED_MOVEMENT, + CRAFTING, + POSSESSABLE, + LEVEL_PROGRESSION, + POSSESSOR, + MOUNT_CONTROL, + UNKNOWN_112, + PROPERTY_PLAQUE, + BUILD_BORDER, + UNKOWN_115, + CULLING_PLANE, + DESTROYABLE = 1000 // Actually 7 +}; + +#endif //!__EREPLICACOMPONENTTYPE__H__ diff --git a/dCommon/dEnums/eReplicaPacketType.h b/dCommon/dEnums/eReplicaPacketType.h new file mode 100644 index 00000000..2650fb30 --- /dev/null +++ b/dCommon/dEnums/eReplicaPacketType.h @@ -0,0 +1,12 @@ +#ifndef __EREPLICAPACKETTYPE__H__ +#define __EREPLICAPACKETTYPE__H__ + +#include + +enum class eReplicaPacketType : uint8_t { + CONSTRUCTION, + SERIALIZATION, + DESTRUCTION +}; + +#endif //!__EREPLICAPACKETTYPE__H__ diff --git a/dCommon/dEnums/eServerDisconnectIdentifiers.h b/dCommon/dEnums/eServerDisconnectIdentifiers.h new file mode 100644 index 00000000..99d2cd44 --- /dev/null +++ b/dCommon/dEnums/eServerDisconnectIdentifiers.h @@ -0,0 +1,24 @@ +#ifndef __ESERVERDISCONNECTIDENTIFIERS__H__ +#define __ESERVERDISCONNECTIDENTIFIERS__H__ + +#include + +enum class eServerDisconnectIdentifiers : uint32_t { + UNKNOWN_SERVER_ERROR = 0, + WRONG_GAME_VERSION, + WRONG_SERVER_VERSION, + CONNECTION_ON_INVALID_PORT, + DUPLICATE_LOGIN, + SERVER_SHUTDOWN, + SERVER_MAP_LOAD_FAILURE, + INVALID_SESSION_KEY, + ACCOUNT_NOT_IN_PENDING_LIST, + CHARACTER_NOT_FOUND, + CHARACTER_CORRUPTED, + KICK, + SAVE_FAILURE, + FREE_TRIAL_EXPIRED, + PLAY_SCHEDULE_TIME_DONE +}; + +#endif //!__ESERVERDISCONNECTIDENTIFIERS__H__ diff --git a/dCommon/dEnums/eServerMessageType.h b/dCommon/dEnums/eServerMessageType.h new file mode 100644 index 00000000..7f211ffb --- /dev/null +++ b/dCommon/dEnums/eServerMessageType.h @@ -0,0 +1,12 @@ +#ifndef __ESERVERMESSAGETYPE__H__ +#define __ESERVERMESSAGETYPE__H__ + +#include +//! The Internal Server Packet Identifiers +enum class eServerMessageType : uint32_t { + VERSION_CONFIRM = 0, + DISCONNECT_NOTIFY, + GENERAL_NOTIFY +}; + +#endif //!__ESERVERMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eSqliteDataType.h b/dCommon/dEnums/eSqliteDataType.h new file mode 100644 index 00000000..26e1233b --- /dev/null +++ b/dCommon/dEnums/eSqliteDataType.h @@ -0,0 +1,16 @@ +#ifndef __ESQLITEDATATYPE__H__ +#define __ESQLITEDATATYPE__H__ + +#include + +enum class eSqliteDataType : int32_t { + NONE = 0, + INT32, + REAL = 3, + TEXT_4, + INT_BOOL, + INT64, + TEXT_8 = 8 +}; + +#endif //!__ESQLITEDATATYPE__H__ diff --git a/dCommon/dEnums/eStateChangeType.h b/dCommon/dEnums/eStateChangeType.h new file mode 100644 index 00000000..e187e265 --- /dev/null +++ b/dCommon/dEnums/eStateChangeType.h @@ -0,0 +1,11 @@ +#ifndef __ESTATECHANGETYPE__H__ +#define __ESTATECHANGETYPE__H__ + +#include + +enum class eStateChangeType : uint32_t { + PUSH, + POP +}; + +#endif //!__ESTATECHANGETYPE__H__ diff --git a/dCommon/dEnums/eTerminateType.h b/dCommon/dEnums/eTerminateType.h new file mode 100644 index 00000000..189734f8 --- /dev/null +++ b/dCommon/dEnums/eTerminateType.h @@ -0,0 +1,12 @@ +#ifndef __ETERMINATETYPE__H__ +#define __ETERMINATETYPE__H__ + +#include + +enum class eTerminateType : uint32_t { + RANGE, + USER, + FROM_INTERACTION +}; + +#endif //!__ETERMINATETYPE__H__ diff --git a/dCommon/dEnums/eTriggerCommandType.h b/dCommon/dEnums/eTriggerCommandType.h new file mode 100644 index 00000000..fadfafb8 --- /dev/null +++ b/dCommon/dEnums/eTriggerCommandType.h @@ -0,0 +1,119 @@ +#ifndef __ETRIGGERCOMMANDTYPE__H__ +#define __ETRIGGERCOMMANDTYPE__H__ + +// For info about Trigger Command see: +// https://docs.lu-dev.net/en/latest/file-structures/lutriggers.html?highlight=trigger#possible-values-commands + +enum class eTriggerCommandType { + INVALID, + ZONE_PLAYER, + FIRE_EVENT, + DESTROY_OBJ, + TOGGLE_TRIGGER, + RESET_REBUILD, + SET_PATH, + SET_PICK_TYPE, + MOVE_OBJECT, + ROTATE_OBJECT, + PUSH_OBJECT, + REPEL_OBJECT, + SET_TIMER, + CANCEL_TIMER, + PLAY_CINEMATIC, + TOGGLE_BBB, + UPDATE_MISSION, + SET_BOUNCER_STATE, + BOUNCE_ALL_ON_BOUNCER, + TURN_AROUND_ON_PATH, + GO_FORWARD_ON_PATH, + GO_BACKWARD_ON_PATH, + STOP_PATHING, + START_PATHING, + LOCK_OR_UNLOCK_CONTROLS, + PLAY_EFFECT, + STOP_EFFECT, + ACTIVATE_MUSIC_CUE, + DEACTIVATE_MUSIC_CUE, + FLASH_MUSIC_CUE, + SET_MUSIC_PARAMETER, + PLAY_2D_AMBIENT_SOUND, + STOP_2D_AMBIENT_SOUND, + PLAY_3D_AMBIENT_SOUND, + STOP_3D_AMBIENT_SOUND, + ACTIVATE_MIXER_PROGRAM, + DEACTIVATE_MIXER_PROGRAM, + CAST_SKILL, + DISPLAY_ZONE_SUMMARY, + SET_PHYSICS_VOLUME_EFFECT, + SET_PHYSICS_VOLUME_STATUS, + SET_MODEL_TO_BUILD, + SPAWN_MODEL_BRICKS, + ACTIVATE_SPAWNER_NETWORK, + DEACTIVATE_SPAWNER_NETWORK, + RESET_SPAWNER_NETWORK, + DESTROY_SPAWNER_NETWORK_OBJECTS, + GO_TO_WAYPOINT, + ACTIVATE_PHYSICS +}; + + +class TriggerCommandType { +public: + static eTriggerCommandType StringToTriggerCommandType(std::string commandString) { + const std::map TriggerCommandMap = { + { "zonePlayer", eTriggerCommandType::ZONE_PLAYER}, + { "fireEvent", eTriggerCommandType::FIRE_EVENT}, + { "destroyObj", eTriggerCommandType::DESTROY_OBJ}, + { "toggleTrigger", eTriggerCommandType::TOGGLE_TRIGGER}, + { "resetRebuild", eTriggerCommandType::RESET_REBUILD}, + { "setPath", eTriggerCommandType::SET_PATH}, + { "setPickType", eTriggerCommandType::SET_PICK_TYPE}, + { "moveObject", eTriggerCommandType::MOVE_OBJECT}, + { "rotateObject", eTriggerCommandType::ROTATE_OBJECT}, + { "pushObject", eTriggerCommandType::PUSH_OBJECT}, + { "repelObject", eTriggerCommandType::REPEL_OBJECT}, + { "setTimer", eTriggerCommandType::SET_TIMER}, + { "cancelTimer", eTriggerCommandType::CANCEL_TIMER}, + { "playCinematic", eTriggerCommandType::PLAY_CINEMATIC}, + { "toggleBBB", eTriggerCommandType::TOGGLE_BBB}, + { "updateMission", eTriggerCommandType::UPDATE_MISSION}, + { "setBouncerState", eTriggerCommandType::SET_BOUNCER_STATE}, + { "bounceAllOnBouncer", eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER}, + { "turnAroundOnPath", eTriggerCommandType::TURN_AROUND_ON_PATH}, + { "goForwardOnPath", eTriggerCommandType::GO_FORWARD_ON_PATH}, + { "goBackwardOnPath", eTriggerCommandType::GO_BACKWARD_ON_PATH}, + { "stopPathing", eTriggerCommandType::STOP_PATHING}, + { "startPathing", eTriggerCommandType::START_PATHING}, + { "LockOrUnlockControls", eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS}, + { "PlayEffect", eTriggerCommandType::PLAY_EFFECT}, + { "StopEffect", eTriggerCommandType::STOP_EFFECT}, + { "activateMusicCue", eTriggerCommandType::ACTIVATE_MUSIC_CUE}, + { "deactivateMusicCue", eTriggerCommandType::DEACTIVATE_MUSIC_CUE}, + { "flashMusicCue", eTriggerCommandType::FLASH_MUSIC_CUE}, + { "setMusicParameter", eTriggerCommandType::SET_MUSIC_PARAMETER}, + { "play2DAmbientSound", eTriggerCommandType::PLAY_2D_AMBIENT_SOUND}, + { "stop2DAmbientSound", eTriggerCommandType::STOP_2D_AMBIENT_SOUND}, + { "play3DAmbientSound", eTriggerCommandType::PLAY_3D_AMBIENT_SOUND}, + { "stop3DAmbientSound", eTriggerCommandType::STOP_3D_AMBIENT_SOUND}, + { "activateMixerProgram", eTriggerCommandType::ACTIVATE_MIXER_PROGRAM}, + { "deactivateMixerProgram", eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM}, + { "CastSkill", eTriggerCommandType::CAST_SKILL}, + { "displayZoneSummary", eTriggerCommandType::DISPLAY_ZONE_SUMMARY}, + { "SetPhysicsVolumeEffect", eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT}, + { "SetPhysicsVolumeStatus", eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS}, + { "setModelToBuild", eTriggerCommandType::SET_MODEL_TO_BUILD}, + { "spawnModelBricks", eTriggerCommandType::SPAWN_MODEL_BRICKS}, + { "ActivateSpawnerNetwork", eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK}, + { "DeactivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK}, + { "ResetSpawnerNetwork", eTriggerCommandType::RESET_SPAWNER_NETWORK}, + { "DestroySpawnerNetworkObjects", eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS}, + { "Go_To_Waypoint", eTriggerCommandType::GO_TO_WAYPOINT}, + { "ActivatePhysics", eTriggerCommandType::ACTIVATE_PHYSICS} + }; + + auto intermed = TriggerCommandMap.find(commandString); + return (intermed != TriggerCommandMap.end()) ? intermed->second : eTriggerCommandType::INVALID; + }; +}; + +#endif //!__ETRIGGERCOMMANDTYPE__H__ diff --git a/dCommon/dEnums/eTriggerEventType.h b/dCommon/dEnums/eTriggerEventType.h new file mode 100644 index 00000000..a2daa256 --- /dev/null +++ b/dCommon/dEnums/eTriggerEventType.h @@ -0,0 +1,53 @@ +#ifndef __ETRIGGEREVENTTYPE__H__ +#define __ETRIGGEREVENTTYPE__H__ + +enum class eTriggerEventType { + INVALID, + DESTROY, + CUSTOM_EVENT, + ENTER, + EXIT, + CREATE, + HIT, + TIMER_DONE, + REBUILD_COMPLETE, + ACTIVATED, + DEACTIVATED, + ARRIVED, + ARRIVED_AT_END_OF_PATH, + ZONE_SUMMARY_DISMISSED, + ARRIVED_AT_DESIRED_WAYPOINT, + PET_ON_SWITCH, + PET_OFF_SWITCH, + INTERACT +}; + +class TriggerEventType { +public: + static eTriggerEventType StringToTriggerEventType(std::string commandString) { + const std::map TriggerEventMap = { + {"OnDestroy", eTriggerEventType::DESTROY}, + {"OnCustomEvent", eTriggerEventType::CUSTOM_EVENT}, + {"OnEnter", eTriggerEventType::ENTER}, + {"OnExit", eTriggerEventType::EXIT}, + {"OnCreate", eTriggerEventType::CREATE}, + {"OnHit", eTriggerEventType::HIT}, + {"OnTimerDone", eTriggerEventType::TIMER_DONE}, + {"OnRebuildComplete", eTriggerEventType::REBUILD_COMPLETE}, + {"OnActivated", eTriggerEventType::ACTIVATED}, + {"OnDectivated", eTriggerEventType::DEACTIVATED}, // Dectivated vs Deactivated + {"OnArrived", eTriggerEventType::ARRIVED}, + {"OnArrivedAtEndOfPath", eTriggerEventType::ARRIVED_AT_END_OF_PATH}, + {"OnZoneSummaryDismissed", eTriggerEventType::ZONE_SUMMARY_DISMISSED}, + {"OnArrivedAtDesiredWaypoint", eTriggerEventType::ARRIVED_AT_DESIRED_WAYPOINT}, + {"OnPetOnSwitch", eTriggerEventType::PET_ON_SWITCH}, + {"OnPetOffSwitch", eTriggerEventType::PET_OFF_SWITCH}, + {"OnInteract", eTriggerEventType::INTERACT}, + }; + + auto intermed = TriggerEventMap.find(commandString); + return (intermed != TriggerEventMap.end()) ? intermed->second : eTriggerEventType::INVALID; + }; +}; + +#endif //!__ETRIGGEREVENTTYPE__H__ diff --git a/dCommon/dEnums/eUnequippableActiveType.h b/dCommon/dEnums/eUnequippableActiveType.h new file mode 100644 index 00000000..8a6d29ba --- /dev/null +++ b/dCommon/dEnums/eUnequippableActiveType.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef __EUNEQUIPPABLEACTIVETYPE__H__ +#define __EUNEQUIPPABLEACTIVETYPE__H__ + +#include + +enum class eUnequippableActiveType : int32_t { + INVALID = -1, + PET = 0, + MOUNT +}; + +#endif //!__EUNEQUIPPABLEACTIVETYPE__H__ diff --git a/dCommon/dEnums/eUseItemResponse.h b/dCommon/dEnums/eUseItemResponse.h new file mode 100644 index 00000000..ba0ece7f --- /dev/null +++ b/dCommon/dEnums/eUseItemResponse.h @@ -0,0 +1,12 @@ +#ifndef __EUSEITEMRESPONSE__H__ +#define __EUSEITEMRESPONSE__H__ + +#include + +enum class eUseItemResponse : uint32_t { + NoImaginationForPet = 1, + FailedPrecondition, + MountsNotAllowed +}; + +#endif //!__EUSEITEMRESPONSE__H__ diff --git a/dCommon/dEnums/eWorldMessageType.h b/dCommon/dEnums/eWorldMessageType.h new file mode 100644 index 00000000..2a65fd98 --- /dev/null +++ b/dCommon/dEnums/eWorldMessageType.h @@ -0,0 +1,42 @@ +#ifndef __EWORLDMESSAGETYPE__H__ +#define __EWORLDMESSAGETYPE__H__ + +#include + +enum class eWorldMessageType : uint32_t { + VALIDATION = 1, // Session info + CHARACTER_LIST_REQUEST, + CHARACTER_CREATE_REQUEST, + LOGIN_REQUEST, // Character selected + GAME_MSG, + CHARACTER_DELETE_REQUEST, + CHARACTER_RENAME_REQUEST, + HAPPY_FLOWER_MODE_NOTIFY, + SLASH_RELOAD_MAP, // Reload map cmp + SLASH_PUSH_MAP_REQUEST, // Push map req cmd + SLASH_PUSH_MAP, // Push map cmd + SLASH_PULL_MAP, // Pull map cmd + LOCK_MAP_REQUEST, + GENERAL_CHAT_MESSAGE, // General chat message + HTTP_MONITOR_INFO_REQUEST, + SLASH_DEBUG_SCRIPTS, // Debug scripts cmd + MODELS_CLEAR, + EXHIBIT_INSERT_MODEL, + LEVEL_LOAD_COMPLETE, // Character data request + TMP_GUILD_CREATE, + ROUTE_PACKET, // Social? + POSITION_UPDATE, + MAIL, + WORD_CHECK, // Whitelist word check + STRING_CHECK, // Whitelist string check + GET_PLAYERS_IN_ZONE, + REQUEST_UGC_MANIFEST_INFO, + BLUEPRINT_GET_ALL_DATA_REQUEST, + CANCEL_MAP_QUEUE, + HANDLE_FUNNESS, + FAKE_PRG_CSR_MESSAGE, + REQUEST_FREE_TRIAL_REFRESH, + GM_SET_FREE_TRIAL_STATUS +}; + +#endif //!__EWORLDMESSAGETYPE__H__ diff --git a/dCommon/dLogger.cpp b/dCommon/dLogger.cpp index 825c10cb..7785a070 100644 --- a/dCommon/dLogger.cpp +++ b/dCommon/dLogger.cpp @@ -10,7 +10,7 @@ dLogger::dLogger(const std::string& outpath, bool logToConsole, bool logDebugSta if (!mFile) { printf("Couldn't open %s for writing!\n", outpath.c_str()); } #else fp = fopen(outpath.c_str(), "wt"); - if (fp == NULL) { printf("Couldn't open %s for writing!\n", outpath.c_str()); } + if (fp == NULL) { printf("Couldn't open %s for writing!\n", outpath.c_str()); } #endif } @@ -33,69 +33,69 @@ void dLogger::vLog(const char* format, va_list args) { char timeStr[70]; strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time); char message[2048]; - vsprintf_s(message, format, args); + vsnprintf(message, 2048, format, args); if (m_logToConsole) std::cout << "[" << timeStr << "] " << message; mFile << "[" << timeStr << "] " << message; #else time_t t = time(NULL); - struct tm * time = localtime(&t); - char timeStr[70]; - strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time); + struct tm* time = localtime(&t); + char timeStr[70]; + strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time); char message[2048]; - vsprintf(message, format, args); - - if (m_logToConsole) { + vsnprintf(message, 2048, format, args); + + if (m_logToConsole) { fputs("[", stdout); fputs(timeStr, stdout); fputs("] ", stdout); fputs(message, stdout); - } - - if (fp != nullptr) { + } + + if (fp != nullptr) { fputs("[", fp); fputs(timeStr, fp); fputs("] ", fp); fputs(message, fp); - } else { - printf("Logger not initialized!\n"); - } + } else { + printf("Logger not initialized!\n"); + } #endif } -void dLogger::LogBasic(const char * format, ...) { +void dLogger::LogBasic(const char* format, ...) { va_list args; va_start(args, format); vLog(format, args); va_end(args); } -void dLogger::LogBasic(const std::string & message) { +void dLogger::LogBasic(const std::string& message) { LogBasic(message.c_str()); } -void dLogger::Log(const char * className, const char * format, ...) { +void dLogger::Log(const char* className, const char* format, ...) { va_list args; - std::string log = "[" + std::string(className) + "] " + std::string(format); + std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n"; va_start(args, format); vLog(log.c_str(), args); va_end(args); } -void dLogger::Log(const std::string & className, const std::string & message) { +void dLogger::Log(const std::string& className, const std::string& message) { Log(className.c_str(), message.c_str()); } -void dLogger::LogDebug(const char * className, const char * format, ...) { +void dLogger::LogDebug(const char* className, const char* format, ...) { if (!m_logDebugStatements) return; va_list args; - std::string log = "[" + std::string(className) + "] " + std::string(format); + std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n"; va_start(args, format); vLog(log.c_str(), args); va_end(args); } -void dLogger::LogDebug(const std::string & className, const std::string & message) { +void dLogger::LogDebug(const std::string& className, const std::string& message) { LogDebug(className.c_str(), message.c_str()); } diff --git a/dCommon/dLogger.h b/dCommon/dLogger.h index 7448237e..6726c6f1 100644 --- a/dCommon/dLogger.h +++ b/dCommon/dLogger.h @@ -31,8 +31,8 @@ private: std::string m_outpath; std::ofstream mFile; - #ifndef _WIN32 - //Glorious linux can run with SPEED: - FILE* fp = nullptr; - #endif -}; \ No newline at end of file +#ifndef _WIN32 + //Glorious linux can run with SPEED: + FILE* fp = nullptr; +#endif +}; diff --git a/dDatabase/CDClientDatabase.cpp b/dDatabase/CDClientDatabase.cpp index d09b2daa..4c2df1d2 100644 --- a/dDatabase/CDClientDatabase.cpp +++ b/dDatabase/CDClientDatabase.cpp @@ -2,19 +2,24 @@ #include "CDComponentsRegistryTable.h" // Static Variables -static CppSQLite3DB * conn = new CppSQLite3DB(); +static CppSQLite3DB* conn = new CppSQLite3DB(); //! Opens a connection with the CDClient void CDClientDatabase::Connect(const std::string& filename) { - conn->open(filename.c_str()); + conn->open(filename.c_str()); } //! Queries the CDClient CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) { - return conn->execQuery(query.c_str()); + return conn->execQuery(query.c_str()); +} + +//! Updates the CDClient file with Data Manipulation Language (DML) commands. +int CDClientDatabase::ExecuteDML(const std::string& query) { + return conn->execDML(query.c_str()); } //! Makes prepared statements CppSQLite3Statement CDClientDatabase::CreatePreppedStmt(const std::string& query) { - return conn->compileStatement(query.c_str()); + return conn->compileStatement(query.c_str()); } diff --git a/dDatabase/CDClientDatabase.h b/dDatabase/CDClientDatabase.h index 91e9ee10..96f67d64 100644 --- a/dDatabase/CDClientDatabase.h +++ b/dDatabase/CDClientDatabase.h @@ -13,10 +13,10 @@ #include #include -// Enable this to cache all entries in each table for fast access, comes with more memory cost -//#define CDCLIENT_CACHE_ALL + // Enable this to cache all entries in each table for fast access, comes with more memory cost + //#define CDCLIENT_CACHE_ALL -// Enable this to skip some unused columns in some tables + // Enable this to skip some unused columns in some tables #define UNUSED(v) /*! @@ -24,26 +24,34 @@ \brief An interface between the CDClient.sqlite file and the server */ -//! The CDClient Database namespace + //! The CDClient Database namespace namespace CDClientDatabase { - - //! Opens a connection with the CDClient - /*! - \param filename The filename - */ - void Connect(const std::string& filename); - - //! Queries the CDClient - /*! - \param query The query - \return The results of the query - */ - CppSQLite3Query ExecuteQuery(const std::string& query); - - //! Queries the CDClient and parses arguments - /*! - \param query The query with formatted arguments - \return prepared SQLite Statement - */ - CppSQLite3Statement CreatePreppedStmt(const std::string& query); + + //! Opens a connection with the CDClient + /*! + \param filename The filename + */ + void Connect(const std::string& filename); + + //! Queries the CDClient + /*! + \param query The query + \return The results of the query + */ + CppSQLite3Query ExecuteQuery(const std::string& query); + + //! Updates the CDClient file with Data Manipulation Language (DML) commands. + /*! + \param query The DML command to run. DML command can be multiple queries in one string but only + the last one will return its number of updated rows. + \return The number of updated rows. + */ + int ExecuteDML(const std::string& query); + + //! Queries the CDClient and parses arguments + /*! + \param query The query with formatted arguments + \return prepared SQLite Statement + */ + CppSQLite3Statement CreatePreppedStmt(const std::string& query); }; diff --git a/dDatabase/CDClientManager.cpp b/dDatabase/CDClientManager.cpp index 7ad852bc..eeea686f 100644 --- a/dDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientManager.cpp @@ -1,46 +1,80 @@ #include "CDClientManager.h" +#include "CDActivityRewardsTable.h" +#include "CDAnimationsTable.h" +#include "CDBehaviorParameterTable.h" +#include "CDBehaviorTemplateTable.h" +#include "CDComponentsRegistryTable.h" +#include "CDCurrencyTableTable.h" +#include "CDDestructibleComponentTable.h" +#include "CDEmoteTable.h" +#include "CDInventoryComponentTable.h" +#include "CDItemComponentTable.h" +#include "CDItemSetsTable.h" +#include "CDItemSetSkillsTable.h" +#include "CDLevelProgressionLookupTable.h" +#include "CDLootMatrixTable.h" +#include "CDLootTableTable.h" +#include "CDMissionNPCComponentTable.h" +#include "CDMissionTasksTable.h" +#include "CDMissionsTable.h" +#include "CDObjectSkillsTable.h" +#include "CDObjectsTable.h" +#include "CDPhysicsComponentTable.h" +#include "CDRebuildComponentTable.h" +#include "CDScriptComponentTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDZoneTableTable.h" +#include "CDVendorComponentTable.h" +#include "CDActivitiesTable.h" +#include "CDPackageComponentTable.h" +#include "CDProximityMonitorComponentTable.h" +#include "CDMovementAIComponentTable.h" +#include "CDBrickIDTableTable.h" +#include "CDRarityTableTable.h" +#include "CDMissionEmailTable.h" +#include "CDRewardsTable.h" +#include "CDPropertyEntranceComponentTable.h" +#include "CDPropertyTemplateTable.h" +#include "CDFeatureGatingTable.h" +#include "CDRailActivatorComponent.h" -// Static Variables -CDClientManager * CDClientManager::m_Address = nullptr; - -//! Initializes the manager -void CDClientManager::Initialize(void) { - tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable())); - UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable()))); - tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable())); - UNUSED(tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable()))); - tables.insert(std::make_pair("ComponentsRegistry", new CDComponentsRegistryTable())); - tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable())); - tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable())); - tables.insert(std::make_pair("EmoteTable", new CDEmoteTableTable())); - tables.insert(std::make_pair("InventoryComponent", new CDInventoryComponentTable())); - tables.insert(std::make_pair("ItemComponent", new CDItemComponentTable())); - tables.insert(std::make_pair("ItemSets", new CDItemSetsTable())); - tables.insert(std::make_pair("ItemSetSkills", new CDItemSetSkillsTable())); - tables.insert(std::make_pair("LevelProgressionLookup", new CDLevelProgressionLookupTable())); - tables.insert(std::make_pair("LootMatrix", new CDLootMatrixTable())); - tables.insert(std::make_pair("LootTable", new CDLootTableTable())); - tables.insert(std::make_pair("MissionNPCComponent", new CDMissionNPCComponentTable())); - tables.insert(std::make_pair("MissionTasks", new CDMissionTasksTable())); - tables.insert(std::make_pair("Missions", new CDMissionsTable())); - tables.insert(std::make_pair("ObjectSkills", new CDObjectSkillsTable())); - tables.insert(std::make_pair("Objects", new CDObjectsTable())); - tables.insert(std::make_pair("PhysicsComponent", new CDPhysicsComponentTable())); - tables.insert(std::make_pair("RebuildComponent", new CDRebuildComponentTable())); - tables.insert(std::make_pair("ScriptComponent", new CDScriptComponentTable())); - tables.insert(std::make_pair("SkillBehavior", new CDSkillBehaviorTable())); - tables.insert(std::make_pair("ZoneTable", new CDZoneTableTable())); - tables.insert(std::make_pair("VendorComponent", new CDVendorComponentTable())); - tables.insert(std::make_pair("Activities", new CDActivitiesTable())); - tables.insert(std::make_pair("PackageComponent", new CDPackageComponentTable())); - tables.insert(std::make_pair("ProximityMonitorComponent", new CDProximityMonitorComponentTable())); - tables.insert(std::make_pair("MovementAIComponent", new CDMovementAIComponentTable())); - tables.insert(std::make_pair("BrickIDTable", new CDBrickIDTableTable())); - tables.insert(std::make_pair("RarityTable", new CDRarityTableTable())); - tables.insert(std::make_pair("MissionEmail", new CDMissionEmailTable())); - tables.insert(std::make_pair("Rewards", new CDRewardsTable())); - tables.insert(std::make_pair("PropertyEntranceComponent", new CDPropertyEntranceComponentTable())); - tables.insert(std::make_pair("PropertyTemplate", new CDPropertyTemplateTable())); - tables.insert(std::make_pair("FeatureGating", new CDFeatureGatingTable())); - tables.insert(std::make_pair("RailActivatorComponent", new CDRailActivatorComponentTable())); +CDClientManager::CDClientManager() { + CDActivityRewardsTable::Instance(); + UNUSED(CDAnimationsTable::Instance()); + CDBehaviorParameterTable::Instance(); + CDBehaviorTemplateTable::Instance(); + CDComponentsRegistryTable::Instance(); + CDCurrencyTableTable::Instance(); + CDDestructibleComponentTable::Instance(); + CDEmoteTableTable::Instance(); + CDInventoryComponentTable::Instance(); + CDItemComponentTable::Instance(); + CDItemSetsTable::Instance(); + CDItemSetSkillsTable::Instance(); + CDLevelProgressionLookupTable::Instance(); + CDLootMatrixTable::Instance(); + CDLootTableTable::Instance(); + CDMissionNPCComponentTable::Instance(); + CDMissionTasksTable::Instance(); + CDMissionsTable::Instance(); + CDObjectSkillsTable::Instance(); + CDObjectsTable::Instance(); + CDPhysicsComponentTable::Instance(); + CDRebuildComponentTable::Instance(); + CDScriptComponentTable::Instance(); + CDSkillBehaviorTable::Instance(); + CDZoneTableTable::Instance(); + CDVendorComponentTable::Instance(); + CDActivitiesTable::Instance(); + CDPackageComponentTable::Instance(); + CDProximityMonitorComponentTable::Instance(); + CDMovementAIComponentTable::Instance(); + CDBrickIDTableTable::Instance(); + CDRarityTableTable::Instance(); + CDMissionEmailTable::Instance(); + CDRewardsTable::Instance(); + CDPropertyEntranceComponentTable::Instance(); + CDPropertyTemplateTable::Instance(); + CDFeatureGatingTable::Instance(); + CDRailActivatorComponentTable::Instance(); } diff --git a/dDatabase/CDClientManager.h b/dDatabase/CDClientManager.h index f4530f90..1754fe99 100644 --- a/dDatabase/CDClientManager.h +++ b/dDatabase/CDClientManager.h @@ -1,96 +1,24 @@ #pragma once -// Custom Classes #include "CDTable.h" -// Tables -#include "CDActivityRewardsTable.h" -#include "CDAnimationsTable.h" -#include "CDBehaviorParameterTable.h" -#include "CDBehaviorTemplateTable.h" -#include "CDComponentsRegistryTable.h" -#include "CDCurrencyTableTable.h" -#include "CDDestructibleComponentTable.h" -#include "CDEmoteTable.h" -#include "CDInventoryComponentTable.h" -#include "CDItemComponentTable.h" -#include "CDItemSetsTable.h" -#include "CDItemSetSkillsTable.h" -#include "CDLevelProgressionLookupTable.h" -#include "CDLootMatrixTable.h" -#include "CDLootTableTable.h" -#include "CDMissionNPCComponentTable.h" -#include "CDMissionTasksTable.h" -#include "CDMissionsTable.h" -#include "CDObjectSkillsTable.h" -#include "CDObjectsTable.h" -#include "CDPhysicsComponentTable.h" -#include "CDRebuildComponentTable.h" -#include "CDScriptComponentTable.h" -#include "CDSkillBehaviorTable.h" -#include "CDZoneTableTable.h" -#include "CDVendorComponentTable.h" -#include "CDActivitiesTable.h" -#include "CDPackageComponentTable.h" -#include "CDProximityMonitorComponentTable.h" -#include "CDMovementAIComponentTable.h" -#include "CDBrickIDTableTable.h" -#include "CDRarityTableTable.h" -#include "CDMissionEmailTable.h" -#include "CDRewardsTable.h" -#include "CDPropertyEntranceComponentTable.h" -#include "CDPropertyTemplateTable.h" -#include "CDFeatureGatingTable.h" -#include "CDRailActivatorComponent.h" +#include "Singleton.h" -// C++ -#include -#include - -/*! - \file CDClientManager.hpp - \brief A manager for the CDClient tables +/** + * Initialize the CDClient tables so they are all loaded into memory. */ - -//! Manages all data from the CDClient -class CDClientManager { -private: - static CDClientManager * m_Address; //!< The singleton address - - std::unordered_map tables; //!< The tables - +class CDClientManager : public Singleton { public: - - //! The singleton method - static CDClientManager * Instance() { - if (m_Address == 0) { - m_Address = new CDClientManager; - } - - return m_Address; - } - - //! Initializes the manager - void Initialize(void); - - //! Fetches a CDClient table - /*! - This function uses typename T which must be a subclass of CDTable. - It returns the class that conforms to the class name - - \param tableName The table name - \return The class or nullptr - */ - template - T * GetTable(const std::string& tableName) { - static_assert(std::is_base_of::value, "T should inherit from CDTable!"); - - for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) { - if (itr->first == tableName) { - return dynamic_cast(itr->second); - } - } - - return nullptr; - } + CDClientManager(); + + /** + * Fetch a table from CDClient + * + * @tparam Table type to fetch + * @return A pointer to the requested table. + */ + template + T* GetTable() { + return &T::Instance(); + } }; diff --git a/dDatabase/CMakeLists.txt b/dDatabase/CMakeLists.txt new file mode 100644 index 00000000..9e55fbe2 --- /dev/null +++ b/dDatabase/CMakeLists.txt @@ -0,0 +1,13 @@ +set(DDATABASE_SOURCES "CDClientDatabase.cpp" + "CDClientManager.cpp" + "Database.cpp" + "MigrationRunner.cpp") + +add_subdirectory(Tables) + +foreach(file ${DDATABASE_TABLES_SOURCES}) + set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Tables/${file}") +endforeach() + +add_library(dDatabase STATIC ${DDATABASE_SOURCES}) +target_link_libraries(dDatabase sqlite3 mariadbConnCpp) diff --git a/dDatabase/Database.cpp b/dDatabase/Database.cpp index ef4faa52..1ce6966f 100644 --- a/dDatabase/Database.cpp +++ b/dDatabase/Database.cpp @@ -6,14 +6,14 @@ using namespace std; #pragma warning (disable:4251) //Disables SQL warnings -sql::Driver * Database::driver; -sql::Connection * Database::con; +sql::Driver* Database::driver; +sql::Connection* Database::con; +sql::Properties Database::props; +std::string Database::database; void Database::Connect(const string& host, const string& database, const string& username, const string& password) { //To bypass debug issues: - std::string newHost = "tcp://" + host; - const char* szHost = newHost.c_str(); const char* szDatabase = database.c_str(); const char* szUsername = username.c_str(); const char* szPassword = password.c_str(); @@ -21,18 +21,53 @@ void Database::Connect(const string& host, const string& database, const string& driver = sql::mariadb::get_driver_instance(); sql::Properties properties; - properties["hostName"] = szHost; + // The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where + // 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the + // presence of a / + // 2) even avoiding that, the connector still assumes you're connecting with a tcp socket + // So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost, + // which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate + // property manually (which the URL parsing fails to do) + const std::string UNIX_PROTO = "unix://"; + const std::string PIPE_PROTO = "pipe://"; + if (host.find(UNIX_PROTO) == 0) { + properties["hostName"] = "unix://localhost"; + properties["localSocket"] = host.substr(UNIX_PROTO.length()).c_str(); + } else if (host.find(PIPE_PROTO) == 0) { + properties["hostName"] = "pipe://localhost"; + properties["pipe"] = host.substr(PIPE_PROTO.length()).c_str(); + } else { + properties["hostName"] = host.c_str(); + } properties["user"] = szUsername; properties["password"] = szPassword; properties["autoReconnect"] = "true"; - con = driver->connect(properties); - con->setSchema(szDatabase); -} //Connect -void Database::Destroy(std::string source) { + Database::props = properties; + Database::database = database; + + Database::Connect(); +} + +void Database::Connect() { + // `connect(const Properties& props)` segfaults in windows debug, but + // `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly + if (Database::props.find("localSocket") != Database::props.end() || Database::props.find("pipe") != Database::props.end()) { + con = driver->connect(Database::props); + } else { + con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str()); + } + con->setSchema(Database::database.c_str()); +} + +void Database::Destroy(std::string source, bool log) { if (!con) return; - if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str()); - else Game::logger->Log("Database", "Destroying MySQL connection!\n"); + + if (log) { + if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!", source.c_str()); + else Game::logger->Log("Database", "Destroying MySQL connection!"); + } + con->close(); delete con; } //Destroy @@ -48,34 +83,36 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) { sql::SQLString str(test, size); if (!con) { - //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); - - Connect(mysql_host, mysql_database, mysql_username, mysql_password); - Game::logger->Log("Database", "Trying to reconnect to MySQL\n"); + Connect(); + Game::logger->Log("Database", "Trying to reconnect to MySQL"); } - if (!con->isValid() || con->isClosed()) - { + if (!con->isValid() || con->isClosed()) { delete con; con = nullptr; - //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); - - Connect(mysql_host, mysql_database, mysql_username, mysql_password); - Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n"); + Connect(); + Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection"); } - + auto* stmt = con->prepareStatement(str); return stmt; } //CreatePreppedStmt +void Database::Commit() { + Database::con->commit(); +} + +bool Database::GetAutoCommit() { + // TODO This should not just access a pointer. A future PR should update this + // to check for null and throw an error if the connection is not valid. + return con->getAutoCommit(); +} + +void Database::SetAutoCommit(bool value) { + // TODO This should not just access a pointer. A future PR should update this + // to check for null and throw an error if the connection is not valid. + Database::con->setAutoCommit(value); +} diff --git a/dDatabase/Database.h b/dDatabase/Database.h index e972b0ca..f4d13da3 100644 --- a/dDatabase/Database.h +++ b/dDatabase/Database.h @@ -11,12 +11,21 @@ public: class Database { private: - static sql::Driver *driver; - static sql::Connection *con; - + static sql::Driver* driver; + static sql::Connection* con; + static sql::Properties props; + static std::string database; public: static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password); - static void Destroy(std::string source=""); + static void Connect(); + static void Destroy(std::string source = "", bool log = true); + static sql::Statement* CreateStmt(); static sql::PreparedStatement* CreatePreppedStmt(const std::string& query); + static void Commit(); + static bool GetAutoCommit(); + static void SetAutoCommit(bool value); + + static std::string GetDatabase() { return database; } + static sql::Properties GetProperties() { return props; } }; diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp new file mode 100644 index 00000000..5e70c401 --- /dev/null +++ b/dDatabase/MigrationRunner.cpp @@ -0,0 +1,158 @@ +#include "MigrationRunner.h" + +#include "BrickByBrickFix.h" +#include "CDClientDatabase.h" +#include "Database.h" +#include "Game.h" +#include "GeneralUtils.h" +#include "dLogger.h" +#include "BinaryPathFinder.h" + +#include + +Migration LoadMigration(std::string path) { + Migration migration{}; + std::ifstream file(BinaryPathFinder::GetBinaryDir() / "migrations/" / path); + + if (file.is_open()) { + std::string line; + std::string total = ""; + + while (std::getline(file, line)) { + total += line; + } + + file.close(); + + migration.name = path; + migration.data = total; + } + + return migration; +} + +void MigrationRunner::RunMigrations() { + auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); + stmt->execute(); + delete stmt; + + sql::SQLString finalSQL = ""; + bool runSd0Migrations = false; + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) { + auto migration = LoadMigration("dlu/" + entry); + + if (migration.data.empty()) { + continue; + } + + stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); + stmt->setString(1, migration.name.c_str()); + auto* res = stmt->executeQuery(); + bool doExit = res->next(); + delete res; + delete stmt; + if (doExit) continue; + + Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str()); + if (migration.name == "dlu/5_brick_model_sd0.sql") { + runSd0Migrations = true; + } else { + finalSQL.append(migration.data.c_str()); + } + + stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + stmt->setString(1, migration.name.c_str()); + stmt->execute(); + delete stmt; + } + + if (finalSQL.empty() && !runSd0Migrations) { + Game::logger->Log("MigrationRunner", "Server database is up to date."); + return; + } + + if (!finalSQL.empty()) { + auto migration = GeneralUtils::SplitString(static_cast(finalSQL), ';'); + std::unique_ptr simpleStatement(Database::CreateStmt()); + for (auto& query : migration) { + try { + if (query.empty()) continue; + simpleStatement->execute(query.c_str()); + } catch (sql::SQLException& e) { + Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what()); + } + } + } + + // Do this last on the off chance none of the other migrations have been run yet. + if (runSd0Migrations) { + uint32_t numberOfUpdatedModels = BrickByBrickFix::UpdateBrickByBrickModelsToSd0(); + Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels); + uint32_t numberOfTruncatedModels = BrickByBrickFix::TruncateBrokenBrickByBrickXml(); + Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels); + } +} + +void MigrationRunner::RunSQLiteMigrations() { + auto cdstmt = CDClientDatabase::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);"); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + + auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); + stmt->execute(); + delete stmt; + + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) { + auto migration = LoadMigration("cdserver/" + entry); + + if (migration.data.empty()) continue; + + // Check if there is an entry in the migration history table on the cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + auto cdres = cdstmt.execQuery(); + bool doExit = !cdres.eof(); + cdres.finalize(); + cdstmt.finalize(); + + if (doExit) continue; + + // Check first if there is entry in the migration history table on the main database. + stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); + stmt->setString(1, migration.name.c_str()); + auto* res = stmt->executeQuery(); + doExit = res->next(); + delete res; + delete stmt; + if (doExit) { + // Insert into cdclient database if there is an entry in the main database but not the cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + continue; + } + + // Doing these 1 migration at a time since one takes a long time and some may think it is crashing. + // This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated". + Game::logger->Log("MigrationRunner", "Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str()); + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); + for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) { + if (dml.empty()) continue; + try { + CDClientDatabase::ExecuteDML(dml.c_str()); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("MigrationRunner", "Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage()); + } + } + + // Insert into cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + CDClientDatabase::ExecuteQuery("COMMIT;"); + } + + Game::logger->Log("MigrationRunner", "CDServer database is up to date."); +} diff --git a/dDatabase/MigrationRunner.h b/dDatabase/MigrationRunner.h new file mode 100644 index 00000000..0cb36d53 --- /dev/null +++ b/dDatabase/MigrationRunner.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +struct Migration { + std::string data; + std::string name; +}; + +namespace MigrationRunner { + void RunMigrations(); + void RunSQLiteMigrations(); +}; diff --git a/dDatabase/Tables/CDActivitiesTable.cpp b/dDatabase/Tables/CDActivitiesTable.cpp index daa07b52..e1660d66 100644 --- a/dDatabase/Tables/CDActivitiesTable.cpp +++ b/dDatabase/Tables/CDActivitiesTable.cpp @@ -1,6 +1,5 @@ #include "CDActivitiesTable.h" -//! Constructor CDActivitiesTable::CDActivitiesTable(void) { // First, get the size of the table @@ -21,25 +20,25 @@ CDActivitiesTable::CDActivitiesTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities"); while (!tableData.eof()) { CDActivities entry; - entry.ActivityID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.instanceMapID = tableData.getIntField(2, -1); - entry.minTeams = tableData.getIntField(3, -1); - entry.maxTeams = tableData.getIntField(4, -1); - entry.minTeamSize = tableData.getIntField(5, -1); - entry.maxTeamSize = tableData.getIntField(6, -1); - entry.waitTime = tableData.getIntField(7, -1); - entry.startDelay = tableData.getIntField(8, -1); - entry.requiresUniqueData = tableData.getIntField(9, -1); - entry.leaderboardType = tableData.getIntField(10, -1); - entry.localize = tableData.getIntField(11, -1); - entry.optionalCostLOT = tableData.getIntField(12, -1); - entry.optionalCostCount = tableData.getIntField(13, -1); - entry.showUIRewards = tableData.getIntField(14, -1); - entry.CommunityActivityFlagID = tableData.getIntField(15, -1); - entry.gate_version = tableData.getStringField(16, ""); - entry.noTeamLootOnDeath = tableData.getIntField(17, -1); - entry.optionalPercentage = tableData.getFloatField(18, -1.0f); + entry.ActivityID = tableData.getIntField("ActivityID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.instanceMapID = tableData.getIntField("instanceMapID", -1); + entry.minTeams = tableData.getIntField("minTeams", -1); + entry.maxTeams = tableData.getIntField("maxTeams", -1); + entry.minTeamSize = tableData.getIntField("minTeamSize", -1); + entry.maxTeamSize = tableData.getIntField("maxTeamSize", -1); + entry.waitTime = tableData.getIntField("waitTime", -1); + entry.startDelay = tableData.getIntField("startDelay", -1); + entry.requiresUniqueData = tableData.getIntField("requiresUniqueData", -1); + entry.leaderboardType = tableData.getIntField("leaderboardType", -1); + entry.localize = tableData.getIntField("localize", -1); + entry.optionalCostLOT = tableData.getIntField("optionalCostLOT", -1); + entry.optionalCostCount = tableData.getIntField("optionalCostCount", -1); + entry.showUIRewards = tableData.getIntField("showUIRewards", -1); + entry.CommunityActivityFlagID = tableData.getIntField("CommunityActivityFlagID", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1); + entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f); this->entries.push_back(entry); tableData.nextRow(); @@ -48,15 +47,6 @@ CDActivitiesTable::CDActivitiesTable(void) { tableData.finalize(); } -//! Destructor -CDActivitiesTable::~CDActivitiesTable(void) { } - -//! Returns the table's name -std::string CDActivitiesTable::GetName(void) const { - return "Activities"; -} - -//! Queries the table with a custom "where" clause std::vector CDActivitiesTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -66,7 +56,7 @@ std::vector CDActivitiesTable::Query(std::function CDActivitiesTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDActivitiesTable.h b/dDatabase/Tables/CDActivitiesTable.h index 51c560cf..4b60afbd 100644 --- a/dDatabase/Tables/CDActivitiesTable.h +++ b/dDatabase/Tables/CDActivitiesTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDActivitiesTable.hpp - \brief Contains data for the Activities table - */ - - //! Activities Entry Struct struct CDActivities { unsigned int ActivityID; unsigned int locStatus; @@ -31,36 +25,14 @@ struct CDActivities { float optionalPercentage; }; - -//! Activities table -class CDActivitiesTable : public CDTable { +class CDActivitiesTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDActivitiesTable(void); - - //! Destructor - ~CDActivitiesTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDActivitiesTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDActivityRewardsTable.cpp b/dDatabase/Tables/CDActivityRewardsTable.cpp index 03424de3..65ef1101 100644 --- a/dDatabase/Tables/CDActivityRewardsTable.cpp +++ b/dDatabase/Tables/CDActivityRewardsTable.cpp @@ -1,60 +1,50 @@ #include "CDActivityRewardsTable.h" -//! Constructor CDActivityRewardsTable::CDActivityRewardsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); - while (!tableData.eof()) { - CDActivityRewards entry; - entry.objectTemplate = tableData.getIntField(0, -1); - entry.ActivityRewardIndex = tableData.getIntField(1, -1); - entry.activityRating = tableData.getIntField(2, -1); - entry.LootMatrixIndex = tableData.getIntField(3, -1); - entry.CurrencyIndex = tableData.getIntField(4, -1); - entry.ChallengeRating = tableData.getIntField(5, -1); - entry.description = tableData.getStringField(6, ""); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); + while (!tableData.eof()) { + CDActivityRewards entry; + entry.objectTemplate = tableData.getIntField("objectTemplate", -1); + entry.ActivityRewardIndex = tableData.getIntField("ActivityRewardIndex", -1); + entry.activityRating = tableData.getIntField("activityRating", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.CurrencyIndex = tableData.getIntField("CurrencyIndex", -1); + entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1); + entry.description = tableData.getStringField("description", ""); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDActivityRewardsTable::~CDActivityRewardsTable(void) { } - -//! Returns the table's name -std::string CDActivityRewardsTable::GetName(void) const { - return "ActivityRewards"; -} - -//! Queries the table with a custom "where" clause std::vector CDActivityRewardsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDActivityRewardsTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDActivityRewardsTable.h b/dDatabase/Tables/CDActivityRewardsTable.h index fb3a5b09..b5503fb6 100644 --- a/dDatabase/Tables/CDActivityRewardsTable.h +++ b/dDatabase/Tables/CDActivityRewardsTable.h @@ -3,52 +3,25 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDActivityRewardsTable.hpp - \brief Contains data for the ActivityRewards table - */ - -//! ActivityRewards Entry Struct struct CDActivityRewards { - unsigned int objectTemplate; //!< The object template (?) - unsigned int ActivityRewardIndex; //!< The activity reward index - int activityRating; //!< The activity rating - unsigned int LootMatrixIndex; //!< The loot matrix index - unsigned int CurrencyIndex; //!< The currency index - unsigned int ChallengeRating; //!< The challenge rating - std::string description; //!< The description + unsigned int objectTemplate; //!< The object template (?) + unsigned int ActivityRewardIndex; //!< The activity reward index + int activityRating; //!< The activity rating + unsigned int LootMatrixIndex; //!< The loot matrix index + unsigned int CurrencyIndex; //!< The currency index + unsigned int ChallengeRating; //!< The challenge rating + std::string description; //!< The description }; - -//! ActivityRewards table -class CDActivityRewardsTable : public CDTable { +class CDActivityRewardsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDActivityRewardsTable(void); - - //! Destructor - ~CDActivityRewardsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDActivityRewardsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; + }; diff --git a/dDatabase/Tables/CDAnimationsTable.cpp b/dDatabase/Tables/CDAnimationsTable.cpp index 7056f710..e1227f39 100644 --- a/dDatabase/Tables/CDAnimationsTable.cpp +++ b/dDatabase/Tables/CDAnimationsTable.cpp @@ -1,66 +1,56 @@ #include "CDAnimationsTable.h" -//! Constructor CDAnimationsTable::CDAnimationsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Animations"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Animations"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); - while (!tableData.eof()) { - CDAnimations entry; - entry.animationGroupID = tableData.getIntField(0, -1); - entry.animation_type = tableData.getStringField(1, ""); - entry.animation_name = tableData.getStringField(2, ""); - entry.chance_to_play = tableData.getFloatField(3, -1.0f); - entry.min_loops = tableData.getIntField(4, -1); - entry.max_loops = tableData.getIntField(5, -1); - entry.animation_length = tableData.getFloatField(6, -1.0f); - entry.hideEquip = tableData.getIntField(7, -1) == 1 ? true : false; - entry.ignoreUpperBody = tableData.getIntField(8, -1) == 1 ? true : false; - entry.restartable = tableData.getIntField(9, -1) == 1 ? true : false; - entry.face_animation_name = tableData.getStringField(10, ""); - entry.priority = tableData.getFloatField(11, -1.0f); - entry.blendTime = tableData.getFloatField(12, -1.0f); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); + while (!tableData.eof()) { + CDAnimations entry; + entry.animationGroupID = tableData.getIntField("animationGroupID", -1); + entry.animation_type = tableData.getStringField("animation_type", ""); + entry.animation_name = tableData.getStringField("animation_name", ""); + entry.chance_to_play = tableData.getFloatField("chance_to_play", -1.0f); + entry.min_loops = tableData.getIntField("min_loops", -1); + entry.max_loops = tableData.getIntField("max_loops", -1); + entry.animation_length = tableData.getFloatField("animation_length", -1.0f); + entry.hideEquip = tableData.getIntField("hideEquip", -1) == 1 ? true : false; + entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", -1) == 1 ? true : false; + entry.restartable = tableData.getIntField("restartable", -1) == 1 ? true : false; + entry.face_animation_name = tableData.getStringField("face_animation_name", ""); + entry.priority = tableData.getFloatField("priority", -1.0f); + entry.blendTime = tableData.getFloatField("blendTime", -1.0f); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDAnimationsTable::~CDAnimationsTable(void) { } - -//! Returns the table's name -std::string CDAnimationsTable::GetName(void) const { - return "Animations"; -} - -//! Queries the table with a custom "where" clause std::vector CDAnimationsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDAnimationsTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDAnimationsTable.h b/dDatabase/Tables/CDAnimationsTable.h index 61638f74..43400abf 100644 --- a/dDatabase/Tables/CDAnimationsTable.h +++ b/dDatabase/Tables/CDAnimationsTable.h @@ -3,58 +3,31 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDAnimationsTable.hpp - \brief Contains data for the Animations table - */ - -//! Animations Entry Struct struct CDAnimations { - unsigned int animationGroupID; //!< The animation group ID - std::string animation_type; //!< The animation type - std::string animation_name; //!< The animation name - float chance_to_play; //!< The chance to play the animation - unsigned int min_loops; //!< The minimum number of loops - unsigned int max_loops; //!< The maximum number of loops - float animation_length; //!< The animation length - bool hideEquip; //!< Whether or not to hide the equip - bool ignoreUpperBody; //!< Whether or not to ignore the upper body - bool restartable; //!< Whether or not the animation is restartable - std::string face_animation_name; //!< The face animation name - float priority; //!< The priority - float blendTime; //!< The blend time + unsigned int animationGroupID; //!< The animation group ID + std::string animation_type; //!< The animation type + std::string animation_name; //!< The animation name + float chance_to_play; //!< The chance to play the animation + unsigned int min_loops; //!< The minimum number of loops + unsigned int max_loops; //!< The maximum number of loops + float animation_length; //!< The animation length + bool hideEquip; //!< Whether or not to hide the equip + bool ignoreUpperBody; //!< Whether or not to ignore the upper body + bool restartable; //!< Whether or not the animation is restartable + std::string face_animation_name; //!< The face animation name + float priority; //!< The priority + float blendTime; //!< The blend time }; -//! Animations table -class CDAnimationsTable : public CDTable { +class CDAnimationsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDAnimationsTable(void); - - //! Destructor - ~CDAnimationsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDAnimationsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index 4991ac82..0713e740 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -1,90 +1,56 @@ #include "CDBehaviorParameterTable.h" #include "GeneralUtils.h" -//! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { -#ifdef CDCLIENT_CACHE_ALL auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); + uint32_t uniqueParameterId = 0; + uint64_t hash = 0; while (!tableData.eof()) { CDBehaviorParameter entry; - entry.behaviorID = tableData.getIntField(0, -1); - entry.parameterID = tableData.getStringField(1, ""); - entry.value = tableData.getFloatField(2, -1.0f); - - //Check if we have an entry with this ID: - auto it = m_entries.find(entry.behaviorID); - if (it != m_entries.end()) { - it->second.insert(std::make_pair(entry.parameterID, entry.value)); + entry.behaviorID = tableData.getIntField("behaviorID", -1); + auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", "")); + auto parameter = m_ParametersList.find(candidateStringToAdd); + if (parameter != m_ParametersList.end()) { + entry.parameterID = parameter; + } else { + entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first; + uniqueParameterId++; } - else { - //Otherwise, insert it: - m_entries.insert(std::make_pair(entry.behaviorID, std::map())); - auto jit = m_entries.find(entry.behaviorID); + hash = entry.behaviorID; + hash = (hash << 31U) | entry.parameterID->second; + entry.value = tableData.getFloatField("value", -1.0f); - //Add our value as well: - jit->second.insert(std::make_pair(entry.parameterID, entry.value)); - } + m_Entries.insert(std::make_pair(hash, entry)); tableData.nextRow(); } - tableData.finalize(); -#endif } -//! Destructor -CDBehaviorParameterTable::~CDBehaviorParameterTable(void) { } +float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { + auto parameterID = this->m_ParametersList.find(name); + if (parameterID == this->m_ParametersList.end()) return defaultValue; -//! Returns the table's name -std::string CDBehaviorParameterTable::GetName(void) const { - return "BehaviorParameter"; -} + uint64_t hash = behaviorID; -float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) -{ - size_t hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, name); + hash = (hash << 31U) | parameterID->second; // Search for specific parameter const auto& it = m_Entries.find(hash); - if (it != m_Entries.end()) { - return it->second; - } - - // Check if this behavior has already been checked - const auto& itChecked = m_Entries.find(behaviorID); - if (itChecked != m_Entries.end()) { - return defaultValue; - } - -#ifndef CDCLIENT_CACHE_ALL - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = ?;"); - query.bind(1, (int) behaviorID); - - auto tableData = query.execQuery(); - - m_Entries.insert_or_assign(behaviorID, 0); - - while (!tableData.eof()) { - const std::string parameterID = tableData.getStringField(0, ""); - const float value = tableData.getFloatField(1, 0); - - size_t parameterHash = 0; - GeneralUtils::hash_combine(parameterHash, behaviorID); - GeneralUtils::hash_combine(parameterHash, parameterID); - - m_Entries.insert_or_assign(parameterHash, value); - - tableData.nextRow(); - } - - const auto& it2 = m_Entries.find(hash); - if (it2 != m_Entries.end()) { - return it2->second; - } -#endif - - return defaultValue; + return it != m_Entries.end() ? it->second.value : defaultValue; } + +std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { + uint64_t hashBase = behaviorID; + std::map returnInfo; + uint64_t hash; + for (auto& parameterCandidate : m_ParametersList) { + hash = (hashBase << 31U) | parameterCandidate.second; + auto infoCandidate = m_Entries.find(hash); + if (infoCandidate != m_Entries.end()) { + returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value)); + } + } + return returnInfo; +} + diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index 3d14d66d..b0715684 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -2,38 +2,22 @@ // Custom Classes #include "CDTable.h" -#include +#include +#include -/*! - \file CDBehaviorParameterTable.hpp - \brief Contains data for the BehaviorParameter table - */ - -//! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::string parameterID; //!< The Parameter ID - float value; //!< The value of the behavior template + unsigned int behaviorID; //!< The Behavior ID + std::unordered_map::iterator parameterID; //!< The Parameter ID + float value; //!< The value of the behavior template }; -//! BehaviorParameter table -class CDBehaviorParameterTable : public CDTable { +class CDBehaviorParameterTable : public CDTable { private: - std::map m_Entries; - + std::unordered_map m_Entries; + std::unordered_map m_ParametersList; public: - - //! Constructor - CDBehaviorParameterTable(void); - - //! Destructor - ~CDBehaviorParameterTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - float GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + CDBehaviorParameterTable(); + float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + + std::map GetParametersByBehaviorID(uint32_t behaviorID); }; diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.cpp b/dDatabase/Tables/CDBehaviorTemplateTable.cpp index f9830317..08bc86d1 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.cpp +++ b/dDatabase/Tables/CDBehaviorTemplateTable.cpp @@ -1,57 +1,67 @@ #include "CDBehaviorTemplateTable.h" -//! Constructor CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); - while (!tableData.eof()) { - CDBehaviorTemplate entry; - entry.behaviorID = tableData.getIntField(0, -1); - entry.templateID = tableData.getIntField(1, -1); - entry.effectID = tableData.getIntField(2, -1); - entry.effectHandle = tableData.getStringField(3, ""); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); + while (!tableData.eof()) { + CDBehaviorTemplate entry; + entry.behaviorID = tableData.getIntField("behaviorID", -1); + entry.templateID = tableData.getIntField("templateID", -1); + entry.effectID = tableData.getIntField("effectID", -1); + auto candidateToAdd = tableData.getStringField(3, ""); + auto parameter = m_EffectHandles.find(candidateToAdd); + if (parameter != m_EffectHandles.end()) { + entry.effectHandle = parameter; + } else { + entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first; + } + + this->entries.push_back(entry); + this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry)); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) { } - -//! Returns the table's name -std::string CDBehaviorTemplateTable::GetName(void) const { - return "BehaviorTemplate"; -} - -//! Queries the table with a custom "where" clause std::vector CDBehaviorTemplateTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDBehaviorTemplateTable::GetEntries(void) const { - return this->entries; + return this->entries; } + +const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) { + auto entry = this->entriesMappedByBehaviorID.find(behaviorID); + if (entry == this->entriesMappedByBehaviorID.end()) { + CDBehaviorTemplate entryToReturn; + entryToReturn.behaviorID = 0; + entryToReturn.effectHandle = m_EffectHandles.end(); + entryToReturn.effectID = 0; + return entryToReturn; + } else { + return entry->second; + } +} + diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.h b/dDatabase/Tables/CDBehaviorTemplateTable.h index a63c2160..f9ac9a09 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.h +++ b/dDatabase/Tables/CDBehaviorTemplateTable.h @@ -2,50 +2,28 @@ // Custom Classes #include "CDTable.h" +#include +#include -/*! - \file CDBehaviorTemplateTable.hpp - \brief Contains data for the BehaviorTemplate table - */ - -//! BehaviorTemplate Entry Struct struct CDBehaviorTemplate { - unsigned int behaviorID; //!< The Behavior ID - unsigned int templateID; //!< The Template ID (LOT) - unsigned int effectID; //!< The Effect ID attached - std::string effectHandle; //!< The effect handle + unsigned int behaviorID; //!< The Behavior ID + unsigned int templateID; //!< The Template ID (LOT) + unsigned int effectID; //!< The Effect ID attached + std::unordered_set::iterator effectHandle; //!< The effect handle }; -//! BehaviorTemplate table -class CDBehaviorTemplateTable : public CDTable { +class CDBehaviorTemplateTable : public CDTable { private: - std::vector entries; - + std::vector entries; + std::unordered_map entriesMappedByBehaviorID; + std::unordered_set m_EffectHandles; public: - - //! Constructor - CDBehaviorTemplateTable(void); - - //! Destructor - ~CDBehaviorTemplateTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDBehaviorTemplateTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; + + const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); }; diff --git a/dDatabase/Tables/CDBrickIDTableTable.cpp b/dDatabase/Tables/CDBrickIDTableTable.cpp index a3fc860e..9ad24d39 100644 --- a/dDatabase/Tables/CDBrickIDTableTable.cpp +++ b/dDatabase/Tables/CDBrickIDTableTable.cpp @@ -1,6 +1,5 @@ #include "CDBrickIDTableTable.h" -//! Constructor CDBrickIDTableTable::CDBrickIDTableTable(void) { // First, get the size of the table @@ -11,9 +10,9 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) { tableSize.nextRow(); } - + tableSize.finalize(); - + // Reserve the size this->entries.reserve(size); @@ -21,8 +20,8 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable"); while (!tableData.eof()) { CDBrickIDTable entry; - entry.NDObjectID = tableData.getIntField(0, -1); - entry.LEGOBrickID = tableData.getIntField(1, -1); + entry.NDObjectID = tableData.getIntField("NDObjectID", -1); + entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -31,15 +30,6 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) { tableData.finalize(); } -//! Destructor -CDBrickIDTableTable::~CDBrickIDTableTable(void) { } - -//! Returns the table's name -std::string CDBrickIDTableTable::GetName(void) const { - return "BrickIDTable"; -} - -//! Queries the table with a custom "where" clause std::vector CDBrickIDTableTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -49,7 +39,7 @@ std::vector CDBrickIDTableTable::Query(std::function CDBrickIDTableTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDBrickIDTableTable.h b/dDatabase/Tables/CDBrickIDTableTable.h index aefe332c..e2084caf 100644 --- a/dDatabase/Tables/CDBrickIDTableTable.h +++ b/dDatabase/Tables/CDBrickIDTableTable.h @@ -16,34 +16,14 @@ struct CDBrickIDTable { //! BrickIDTable table -class CDBrickIDTableTable : public CDTable { +class CDBrickIDTableTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDBrickIDTableTable(void); - - //! Destructor - ~CDBrickIDTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDBrickIDTableTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDComponentsRegistryTable.cpp b/dDatabase/Tables/CDComponentsRegistryTable.cpp index 7e746fb0..32012f6c 100644 --- a/dDatabase/Tables/CDComponentsRegistryTable.cpp +++ b/dDatabase/Tables/CDComponentsRegistryTable.cpp @@ -1,103 +1,65 @@ #include "CDComponentsRegistryTable.h" +#include "eReplicaComponentType.h" #define CDCLIENT_CACHE_ALL -//! Constructor CDComponentsRegistryTable::CDComponentsRegistryTable(void) { - + #ifdef CDCLIENT_CACHE_ALL - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ComponentsRegistry"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ComponentsRegistry"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - //this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); - while (!tableData.eof()) { - CDComponentsRegistry entry; - entry.id = tableData.getIntField(0, -1); - entry.component_type = tableData.getIntField(1, -1); - entry.component_id = tableData.getIntField(2, -1); - this->mappedEntries.insert_or_assign(((uint64_t) entry.component_type) << 32 | ((uint64_t) entry.id), entry.component_id); - - //this->entries.push_back(entry); + // Reserve the size + //this->entries.reserve(size); - /* - //Darwin's stuff: - const auto& it = this->mappedEntries.find(entry.id); - if (it != mappedEntries.end()) { - const auto& iter = it->second.find(entry.component_type); - if (iter == it->second.end()) { - it->second.insert(std::make_pair(entry.component_type, entry.component_id)); - } - } - else { - std::map map; - map.insert(std::make_pair(entry.component_type, entry.component_id)); - this->mappedEntries.insert(std::make_pair(entry.id, map)); - } - */ + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); + while (!tableData.eof()) { + CDComponentsRegistry entry; + entry.id = tableData.getIntField("id", -1); + entry.component_type = static_cast(tableData.getIntField("component_type", 0)); + entry.component_id = tableData.getIntField("component_id", -1); - tableData.nextRow(); - } + this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id); + + tableData.nextRow(); + } tableData.finalize(); #endif } -//! Destructor -CDComponentsRegistryTable::~CDComponentsRegistryTable(void) { } +int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) { + const auto& iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id)); -//! Returns the table's name -std::string CDComponentsRegistryTable::GetName(void) const { - return "ComponentsRegistry"; -} - -int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue) -{ - const auto& iter = this->mappedEntries.find(((uint64_t) componentType) << 32 | ((uint64_t) id)); - - if (iter == this->mappedEntries.end()) - { + if (iter == this->mappedEntries.end()) { return defaultValue; } return iter->second; - /* - const auto& it = this->mappedEntries.find(id); - if (it != mappedEntries.end()) { - const auto& iter = it->second.find(componentType); - if (iter != it->second.end()) { - return iter->second; - } - } - */ - #ifndef CDCLIENT_CACHE_ALL - // Now get the data + // Now get the data std::stringstream query; query << "SELECT * FROM ComponentsRegistry WHERE id = " << std::to_string(id); auto tableData = CDClientDatabase::ExecuteQuery(query.str()); - while (!tableData.eof()) { - CDComponentsRegistry entry; - entry.id = tableData.getIntField(0, -1); - entry.component_type = tableData.getIntField(1, -1); - entry.component_id = tableData.getIntField(2, -1); - - //this->entries.push_back(entry); + while (!tableData.eof()) { + CDComponentsRegistry entry; + entry.id = tableData.getIntField("id", -1); + entry.component_type = tableData.getIntField("component_type", -1); + entry.component_id = tableData.getIntField("component_id", -1); + + //this->entries.push_back(entry); //Darwin's stuff: const auto& it = this->mappedEntries.find(entry.id); @@ -106,15 +68,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen if (iter == it->second.end()) { it->second.insert(std::make_pair(entry.component_type, entry.component_id)); } - } - else { + } else { std::map map; map.insert(std::make_pair(entry.component_type, entry.component_id)); this->mappedEntries.insert(std::make_pair(entry.id, map)); } - tableData.nextRow(); - } + tableData.nextRow(); + } tableData.finalize(); @@ -129,3 +90,4 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen return defaultValue; #endif } + diff --git a/dDatabase/Tables/CDComponentsRegistryTable.h b/dDatabase/Tables/CDComponentsRegistryTable.h index 4a02bf94..990072c9 100644 --- a/dDatabase/Tables/CDComponentsRegistryTable.h +++ b/dDatabase/Tables/CDComponentsRegistryTable.h @@ -3,38 +3,19 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDComponentsRegistryTable.hpp - \brief Contains data for the ComponentsRegistry table - */ - -//! ComponentsRegistry Entry Struct +enum class eReplicaComponentType : uint32_t; struct CDComponentsRegistry { - unsigned int id; //!< The LOT is used as the ID - unsigned int component_type; //!< See ComponentTypes enum for values - unsigned int component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0 + unsigned int id; //!< The LOT is used as the ID + eReplicaComponentType component_type; //!< See ComponentTypes enum for values + unsigned int component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0 }; -//! ComponentsRegistry table -class CDComponentsRegistryTable : public CDTable { +class CDComponentsRegistryTable : public CDTable { private: - //std::vector entries; - std::map mappedEntries; //id, component_type, component_id - -public: - - //! Constructor - CDComponentsRegistryTable(void); - - //! Destructor - ~CDComponentsRegistryTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; + std::map mappedEntries; //id, component_type, component_id - int32_t GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue = 0); +public: + CDComponentsRegistryTable(); + int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0); }; diff --git a/dDatabase/Tables/CDCurrencyTableTable.cpp b/dDatabase/Tables/CDCurrencyTableTable.cpp index cfe26e73..78a716f9 100644 --- a/dDatabase/Tables/CDCurrencyTableTable.cpp +++ b/dDatabase/Tables/CDCurrencyTableTable.cpp @@ -2,57 +2,48 @@ //! Constructor CDCurrencyTableTable::CDCurrencyTableTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM CurrencyTable"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM CurrencyTable"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); - while (!tableData.eof()) { - CDCurrencyTable entry; - entry.currencyIndex = tableData.getIntField(0, -1); - entry.npcminlevel = tableData.getIntField(1, -1); - entry.minvalue = tableData.getIntField(2, -1); - entry.maxvalue = tableData.getIntField(3, -1); - entry.id = tableData.getIntField(4, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); + while (!tableData.eof()) { + CDCurrencyTable entry; + entry.currencyIndex = tableData.getIntField("currencyIndex", -1); + entry.npcminlevel = tableData.getIntField("npcminlevel", -1); + entry.minvalue = tableData.getIntField("minvalue", -1); + entry.maxvalue = tableData.getIntField("maxvalue", -1); + entry.id = tableData.getIntField("id", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDCurrencyTableTable::~CDCurrencyTableTable(void) { } - -//! Returns the table's name -std::string CDCurrencyTableTable::GetName(void) const { - return "CurrencyTable"; -} - -//! Queries the table with a custom "where" clause std::vector CDCurrencyTableTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDCurrencyTableTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDCurrencyTableTable.h b/dDatabase/Tables/CDCurrencyTableTable.h index b980a18a..ec700320 100644 --- a/dDatabase/Tables/CDCurrencyTableTable.h +++ b/dDatabase/Tables/CDCurrencyTableTable.h @@ -8,44 +8,24 @@ \brief Contains data for the CurrencyTable table */ -//! CurrencyTable Struct + //! CurrencyTable Struct struct CDCurrencyTable { - unsigned int currencyIndex; //!< The Currency Index - unsigned int npcminlevel; //!< The minimum level of the npc - unsigned int minvalue; //!< The minimum currency - unsigned int maxvalue; //!< The maximum currency - unsigned int id; //!< The ID of the currency index + unsigned int currencyIndex; //!< The Currency Index + unsigned int npcminlevel; //!< The minimum level of the npc + unsigned int minvalue; //!< The minimum currency + unsigned int maxvalue; //!< The maximum currency + unsigned int id; //!< The ID of the currency index }; //! CurrencyTable table -class CDCurrencyTableTable : public CDTable { +class CDCurrencyTableTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDCurrencyTableTable(void); - - //! Destructor - ~CDCurrencyTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDCurrencyTableTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDDestructibleComponentTable.cpp b/dDatabase/Tables/CDDestructibleComponentTable.cpp index 6eb64e7f..4bbc8242 100644 --- a/dDatabase/Tables/CDDestructibleComponentTable.cpp +++ b/dDatabase/Tables/CDDestructibleComponentTable.cpp @@ -2,66 +2,57 @@ //! Constructor CDDestructibleComponentTable::CDDestructibleComponentTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); - while (!tableData.eof()) { - CDDestructibleComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.faction = tableData.getIntField(1, -1); - entry.factionList = tableData.getStringField(2, ""); - entry.life = tableData.getIntField(3, -1); - entry.imagination = tableData.getIntField(4, -1); - entry.LootMatrixIndex = tableData.getIntField(5, -1); - entry.CurrencyIndex = tableData.getIntField(6, -1); - entry.level = tableData.getIntField(7, -1); - entry.armor = tableData.getFloatField(8, -1.0f); - entry.death_behavior = tableData.getIntField(9, -1); - entry.isnpc = tableData.getIntField(10, -1) == 1 ? true : false; - entry.attack_priority = tableData.getIntField(11, -1); - entry.isSmashable = tableData.getIntField(12, -1) == 1 ? true : false; - entry.difficultyLevel = tableData.getIntField(13, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); + while (!tableData.eof()) { + CDDestructibleComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.faction = tableData.getIntField("faction", -1); + entry.factionList = tableData.getStringField("factionList", ""); + entry.life = tableData.getIntField("life", -1); + entry.imagination = tableData.getIntField("imagination", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.CurrencyIndex = tableData.getIntField("CurrencyIndex", -1); + entry.level = tableData.getIntField("level", -1); + entry.armor = tableData.getFloatField("armor", -1.0f); + entry.death_behavior = tableData.getIntField("death_behavior", -1); + entry.isnpc = tableData.getIntField("isnpc", -1) == 1 ? true : false; + entry.attack_priority = tableData.getIntField("attack_priority", -1); + entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; + entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDDestructibleComponentTable::~CDDestructibleComponentTable(void) { } - -//! Returns the table's name -std::string CDDestructibleComponentTable::GetName(void) const { - return "DestructibleComponent"; -} - -//! Queries the table with a custom "where" clause std::vector CDDestructibleComponentTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDDestructibleComponentTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDDestructibleComponentTable.h b/dDatabase/Tables/CDDestructibleComponentTable.h index 9768b6df..e42cf486 100644 --- a/dDatabase/Tables/CDDestructibleComponentTable.h +++ b/dDatabase/Tables/CDDestructibleComponentTable.h @@ -3,58 +3,31 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDDestructibleComponentTable.hpp - \brief Contains data for the DestructibleComponent table - */ - -//! ItemComponent Struct struct CDDestructibleComponent { - unsigned int id; //!< The component ID from the ComponentsRegistry Table - int faction; //!< The Faction ID of the object - std::string factionList; //!< A list of the faction IDs - int life; //!< The amount of life of the object - unsigned int imagination; //!< The amount of imagination of the object - int LootMatrixIndex; //!< The Loot Matrix Index - int CurrencyIndex; //!< The Currency Index - unsigned int level; //!< ??? - float armor; //!< The amount of armor of the object - unsigned int death_behavior; //!< The behavior ID of the death behavior - bool isnpc; //!< Whether or not the object is an NPC - unsigned int attack_priority; //!< ??? - bool isSmashable; //!< Whether or not the object is smashable - int difficultyLevel; //!< ??? + unsigned int id; //!< The component ID from the ComponentsRegistry Table + int faction; //!< The Faction ID of the object + std::string factionList; //!< A list of the faction IDs + int life; //!< The amount of life of the object + unsigned int imagination; //!< The amount of imagination of the object + int LootMatrixIndex; //!< The Loot Matrix Index + int CurrencyIndex; //!< The Currency Index + unsigned int level; //!< ??? + float armor; //!< The amount of armor of the object + unsigned int death_behavior; //!< The behavior ID of the death behavior + bool isnpc; //!< Whether or not the object is an NPC + unsigned int attack_priority; //!< ??? + bool isSmashable; //!< Whether or not the object is smashable + int difficultyLevel; //!< ??? }; -//! ItemComponent table -class CDDestructibleComponentTable : public CDTable { +class CDDestructibleComponentTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDDestructibleComponentTable(void); - - //! Destructor - ~CDDestructibleComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDDestructibleComponentTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDEmoteTable.cpp b/dDatabase/Tables/CDEmoteTable.cpp index 63e985ee..aacbdd55 100644 --- a/dDatabase/Tables/CDEmoteTable.cpp +++ b/dDatabase/Tables/CDEmoteTable.cpp @@ -2,43 +2,39 @@ //! Constructor CDEmoteTableTable::CDEmoteTableTable(void) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); - while (!tableData.eof()) { - CDEmoteTable* entry = new CDEmoteTable(); - entry->ID = tableData.getIntField(0, -1); - entry->animationName = tableData.getStringField(1, ""); - entry->iconFilename = tableData.getStringField(2, ""); - entry->channel = tableData.getIntField(3, -1); - entry->locked = tableData.getIntField(5, -1) != 0; - entry->localize = tableData.getIntField(6, -1) != 0; - entry->locState = tableData.getIntField(7, -1); - entry->gateVersion = tableData.getIntField(8, -1); + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); + while (!tableData.eof()) { + CDEmoteTable* entry = new CDEmoteTable(); + entry->ID = tableData.getIntField("id", -1); + entry->animationName = tableData.getStringField("animationName", ""); + entry->iconFilename = tableData.getStringField("iconFilename", ""); + entry->channel = tableData.getIntField("channel", -1); + entry->locked = tableData.getIntField("locked", -1) != 0; + entry->localize = tableData.getIntField("localize", -1) != 0; + entry->locState = tableData.getIntField("locStatus", -1); + entry->gateVersion = tableData.getStringField("gate_version", ""); - entries.insert(std::make_pair(entry->ID, entry)); - tableData.nextRow(); - } + entries.insert(std::make_pair(entry->ID, entry)); + tableData.nextRow(); + } tableData.finalize(); } //! Destructor CDEmoteTableTable::~CDEmoteTableTable(void) { - for (auto e : entries) { - if (e.second) delete e.second; - } - - entries.clear(); + for (auto e : entries) { + if (e.second) delete e.second; + } + + entries.clear(); } -//! Returns the table's name -std::string CDEmoteTableTable::GetName(void) const { - return "Emotes"; +CDEmoteTable* CDEmoteTableTable::GetEmote(int id) { + for (auto e : entries) { + if (e.first == id) return e.second; + } + + return nullptr; } -CDEmoteTable * CDEmoteTableTable::GetEmote(int id) { - for (auto e : entries) { - if (e.first == id) return e.second; - } - - return nullptr; -} diff --git a/dDatabase/Tables/CDEmoteTable.h b/dDatabase/Tables/CDEmoteTable.h index 9fd19991..be40c86f 100644 --- a/dDatabase/Tables/CDEmoteTable.h +++ b/dDatabase/Tables/CDEmoteTable.h @@ -4,12 +4,6 @@ #include "CDTable.h" #include -/*! - \file CDEmoteTable.hpp - \brief Contains data for the CDEmoteTable table - */ - -//! CDEmoteEntry Struct struct CDEmoteTable { CDEmoteTable() { ID = -1; @@ -19,38 +13,26 @@ struct CDEmoteTable { channel = -1; locked = false; localize = false; - gateVersion = -1; + gateVersion = ""; } - int ID; - std::string animationName; - std::string iconFilename; - int locState; - int channel; - bool locked; - bool localize; - int gateVersion; + int ID; + std::string animationName; + std::string iconFilename; + int locState; + int channel; + bool locked; + bool localize; + std::string gateVersion; }; -//! CDEmoteTable table -class CDEmoteTableTable : public CDTable { +class CDEmoteTableTable : public CDTable { private: - std::map entries; + std::map entries; public: - - //! Constructor - CDEmoteTableTable(void); - - //! Destructor - ~CDEmoteTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Returns an emote by ID - CDEmoteTable* GetEmote(int id); + CDEmoteTableTable(); + ~CDEmoteTableTable(); + // Returns an emote by ID + CDEmoteTable* GetEmote(int id); }; diff --git a/dDatabase/Tables/CDFeatureGatingTable.cpp b/dDatabase/Tables/CDFeatureGatingTable.cpp index 6a370e8b..05fe69bf 100644 --- a/dDatabase/Tables/CDFeatureGatingTable.cpp +++ b/dDatabase/Tables/CDFeatureGatingTable.cpp @@ -2,70 +2,58 @@ //! Constructor CDFeatureGatingTable::CDFeatureGatingTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM FeatureGating"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM FeatureGating"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); - while (!tableData.eof()) { - CDFeatureGating entry; - entry.featureName = tableData.getStringField(0, ""); - entry.major = tableData.getIntField(1, -1); - entry.current = tableData.getIntField(2, -1); - entry.minor = tableData.getIntField(3, -1); - entry.description = tableData.getStringField(4, ""); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); + while (!tableData.eof()) { + CDFeatureGating entry; + entry.featureName = tableData.getStringField("featureName", ""); + entry.major = tableData.getIntField("major", -1); + entry.current = tableData.getIntField("current", -1); + entry.minor = tableData.getIntField("minor", -1); + entry.description = tableData.getStringField("description", ""); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDFeatureGatingTable::~CDFeatureGatingTable(void) { } - -//! Returns the table's name -std::string CDFeatureGatingTable::GetName(void) const { - return "FeatureGating"; -} - -//! Queries the table with a custom "where" clause std::vector CDFeatureGatingTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const -{ - for (const auto& entry : entries) - { - if (entry.featureName == feature) - { - return true; - } - } - - return false; +bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const { + for (const auto& entry : entries) { + if (entry.featureName == feature) { + return true; + } + } + + return false; } -//! Gets all the entries in the table std::vector CDFeatureGatingTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDFeatureGatingTable.h b/dDatabase/Tables/CDFeatureGatingTable.h index 11c25e67..7f536db5 100644 --- a/dDatabase/Tables/CDFeatureGatingTable.h +++ b/dDatabase/Tables/CDFeatureGatingTable.h @@ -3,50 +3,24 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDFeatureGatingTable.hpp - */ - -//! ItemComponent Struct struct CDFeatureGating { - std::string featureName; - int32_t major; - int32_t current; - int32_t minor; - std::string description; + std::string featureName; + int32_t major; + int32_t current; + int32_t minor; + std::string description; }; -//! ItemComponent table -class CDFeatureGatingTable : public CDTable { +class CDFeatureGatingTable : public CDTable { private: - std::vector entries; - -public: - - //! Constructor - CDFeatureGatingTable(void); - - //! Destructor - ~CDFeatureGatingTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); + std::vector entries; - bool FeatureUnlocked(const std::string& feature) const; - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - +public: + CDFeatureGatingTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + bool FeatureUnlocked(const std::string& feature) const; + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDInventoryComponentTable.cpp b/dDatabase/Tables/CDInventoryComponentTable.cpp index b0849a45..2dc375ab 100644 --- a/dDatabase/Tables/CDInventoryComponentTable.cpp +++ b/dDatabase/Tables/CDInventoryComponentTable.cpp @@ -2,56 +2,47 @@ //! Constructor CDInventoryComponentTable::CDInventoryComponentTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM InventoryComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM InventoryComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); - while (!tableData.eof()) { - CDInventoryComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.itemid = tableData.getIntField(1, -1); - entry.count = tableData.getIntField(2, -1); - entry.equip = tableData.getIntField(3, -1) == 1 ? true : false; - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); + while (!tableData.eof()) { + CDInventoryComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.itemid = tableData.getIntField("itemid", -1); + entry.count = tableData.getIntField("count", -1); + entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false; + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDInventoryComponentTable::~CDInventoryComponentTable(void) { } - -//! Returns the table's name -std::string CDInventoryComponentTable::GetName(void) const { - return "InventoryComponent"; -} - -//! Queries the table with a custom "where" clause std::vector CDInventoryComponentTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDInventoryComponentTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDInventoryComponentTable.h b/dDatabase/Tables/CDInventoryComponentTable.h index 3bce41f9..cbc04d99 100644 --- a/dDatabase/Tables/CDInventoryComponentTable.h +++ b/dDatabase/Tables/CDInventoryComponentTable.h @@ -3,48 +3,21 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDInventoryComponentTable.hpp - \brief Contains data for the InventoryComponent table - */ - -//! ItemComponent Struct struct CDInventoryComponent { - unsigned int id; //!< The component ID for this object - unsigned int itemid; //!< The LOT of the object - unsigned int count; //!< The count of the items the object has - bool equip; //!< Whether or not to equip the item + unsigned int id; //!< The component ID for this object + unsigned int itemid; //!< The LOT of the object + unsigned int count; //!< The count of the items the object has + bool equip; //!< Whether or not to equip the item }; -//! ItemComponent table -class CDInventoryComponentTable : public CDTable { +class CDInventoryComponentTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDInventoryComponentTable(void); - - //! Destructor - ~CDInventoryComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDInventoryComponentTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDItemComponentTable.cpp b/dDatabase/Tables/CDItemComponentTable.cpp index 698f72a4..54afc417 100644 --- a/dDatabase/Tables/CDItemComponentTable.cpp +++ b/dDatabase/Tables/CDItemComponentTable.cpp @@ -5,84 +5,76 @@ CDItemComponent CDItemComponentTable::Default = {}; //! Constructor CDItemComponentTable::CDItemComponentTable(void) { - Default = CDItemComponent(); - + Default = CDItemComponent(); + #ifdef CDCLIENT_CACHE_ALL - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); - while (!tableData.eof()) { - CDItemComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.equipLocation = tableData.getStringField(1, ""); - entry.baseValue = tableData.getIntField(2, -1); - entry.isKitPiece = tableData.getIntField(3, -1) == 1 ? true : false; - entry.rarity = tableData.getIntField(4, 0); - entry.itemType = tableData.getIntField(5, -1); - entry.itemInfo = tableData.getInt64Field(6, -1); - entry.inLootTable = tableData.getIntField(7, -1) == 1 ? true : false; - entry.inVendor = tableData.getIntField(8, -1) == 1 ? true : false; - entry.isUnique = tableData.getIntField(9, -1) == 1 ? true : false; - entry.isBOP = tableData.getIntField(10, -1) == 1 ? true : false; - entry.isBOE = tableData.getIntField(11, -1) == 1 ? true : false; - entry.reqFlagID = tableData.getIntField(12, -1); - entry.reqSpecialtyID = tableData.getIntField(13, -1); - entry.reqSpecRank = tableData.getIntField(14, -1); - entry.reqAchievementID = tableData.getIntField(15, -1); - entry.stackSize = tableData.getIntField(16, -1); - entry.color1 = tableData.getIntField(17, -1); - entry.decal = tableData.getIntField(18, -1); - entry.offsetGroupID = tableData.getIntField(19, -1); - entry.buildTypes = tableData.getIntField(20, -1); - entry.reqPrecondition = tableData.getStringField(21, ""); - entry.animationFlag = tableData.getIntField(22, -1); - entry.equipEffects = tableData.getIntField(23, -1); - entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; - entry.itemRating = tableData.getIntField(25, -1); - entry.isTwoHanded = tableData.getIntField(26, -1) == 1 ? true : false; - entry.minNumRequired = tableData.getIntField(27, -1); - entry.delResIndex = tableData.getIntField(28, -1); - entry.currencyLOT = tableData.getIntField(29, -1); - entry.altCurrencyCost = tableData.getIntField(30, -1); - entry.subItems = tableData.getStringField(31, ""); - entry.audioEventUse = tableData.getStringField(32, ""); - entry.noEquipAnimation = tableData.getIntField(33, -1) == 1 ? true : false; - entry.commendationLOT = tableData.getIntField(34, -1); - entry.commendationCost = tableData.getIntField(35, -1); - entry.audioEquipMetaEventSet = tableData.getStringField(36, ""); - entry.currencyCosts = tableData.getStringField(37, ""); - entry.ingredientInfo = tableData.getStringField(38, ""); - entry.locStatus = tableData.getIntField(39, -1); - entry.forgeType = tableData.getIntField(40, -1); - entry.SellMultiplier = tableData.getFloatField(41, -1.0f); - + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); + while (!tableData.eof()) { + CDItemComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.equipLocation = tableData.getStringField("equipLocation", ""); + entry.baseValue = tableData.getIntField("baseValue", -1); + entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false; + entry.rarity = tableData.getIntField("rarity", 0); + entry.itemType = tableData.getIntField("itemType", -1); + entry.itemInfo = tableData.getInt64Field("itemInfo", -1); + entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false; + entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false; + entry.isUnique = tableData.getIntField("isUnique", -1) == 1 ? true : false; + entry.isBOP = tableData.getIntField("isBOP", -1) == 1 ? true : false; + entry.isBOE = tableData.getIntField("isBOE", -1) == 1 ? true : false; + entry.reqFlagID = tableData.getIntField("reqFlagID", -1); + entry.reqSpecialtyID = tableData.getIntField("reqSpecialtyID", -1); + entry.reqSpecRank = tableData.getIntField("reqSpecRank", -1); + entry.reqAchievementID = tableData.getIntField("reqAchievementID", -1); + entry.stackSize = tableData.getIntField("stackSize", -1); + entry.color1 = tableData.getIntField("color1", -1); + entry.decal = tableData.getIntField("decal", -1); + entry.offsetGroupID = tableData.getIntField("offsetGroupID", -1); + entry.buildTypes = tableData.getIntField("buildTypes", -1); + entry.reqPrecondition = tableData.getStringField("reqPrecondition", ""); + entry.animationFlag = tableData.getIntField("animationFlag", 0); + entry.equipEffects = tableData.getIntField("equipEffects", -1); + entry.readyForQA = tableData.getIntField("readyForQA", -1) == 1 ? true : false; + entry.itemRating = tableData.getIntField("itemRating", -1); + entry.isTwoHanded = tableData.getIntField("isTwoHanded", -1) == 1 ? true : false; + entry.minNumRequired = tableData.getIntField("minNumRequired", -1); + entry.delResIndex = tableData.getIntField("delResIndex", -1); + entry.currencyLOT = tableData.getIntField("currencyLOT", -1); + entry.altCurrencyCost = tableData.getIntField("altCurrencyCost", -1); + entry.subItems = tableData.getStringField("subItems", ""); + entry.audioEventUse = tableData.getStringField("audioEventUse", ""); + entry.noEquipAnimation = tableData.getIntField("noEquipAnimation", -1) == 1 ? true : false; + entry.commendationLOT = tableData.getIntField("commendationLOT", -1); + entry.commendationCost = tableData.getIntField("commendationCost", -1); + entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", ""); + entry.currencyCosts = tableData.getStringField("currencyCosts", ""); + entry.ingredientInfo = tableData.getStringField("ingredientInfo", ""); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.forgeType = tableData.getIntField("forgeType", -1); + entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); + this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); - } + } tableData.finalize(); #endif } -//! Destructor -CDItemComponentTable::~CDItemComponentTable(void) { } - -//! Returns the table's name -std::string CDItemComponentTable::GetName(void) const { - return "ItemComponent"; -} - -const CDItemComponent & CDItemComponentTable::GetItemComponentByID(unsigned int skillID) { +const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) { const auto& it = this->entries.find(skillID); if (it != this->entries.end()) { return it->second; @@ -94,59 +86,59 @@ const CDItemComponent & CDItemComponentTable::GetItemComponentByID(unsigned int query << "SELECT * FROM ItemComponent WHERE id = " << std::to_string(skillID); auto tableData = CDClientDatabase::ExecuteQuery(query.str()); - if (tableData.eof()) { + if (tableData.eof()) { entries.insert(std::make_pair(skillID, Default)); return Default; } - while (!tableData.eof()) { - CDItemComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.equipLocation = tableData.getStringField(1, ""); - entry.baseValue = tableData.getIntField(2, -1); - entry.isKitPiece = tableData.getIntField(3, -1) == 1 ? true : false; - entry.rarity = tableData.getIntField(4, 0); - entry.itemType = tableData.getIntField(5, -1); - entry.itemInfo = tableData.getInt64Field(6, -1); - entry.inLootTable = tableData.getIntField(7, -1) == 1 ? true : false; - entry.inVendor = tableData.getIntField(8, -1) == 1 ? true : false; - entry.isUnique = tableData.getIntField(9, -1) == 1 ? true : false; - entry.isBOP = tableData.getIntField(10, -1) == 1 ? true : false; - entry.isBOE = tableData.getIntField(11, -1) == 1 ? true : false; - entry.reqFlagID = tableData.getIntField(12, -1); - entry.reqSpecialtyID = tableData.getIntField(13, -1); - entry.reqSpecRank = tableData.getIntField(14, -1); - entry.reqAchievementID = tableData.getIntField(15, -1); - entry.stackSize = tableData.getIntField(16, -1); - entry.color1 = tableData.getIntField(17, -1); - entry.decal = tableData.getIntField(18, -1); - entry.offsetGroupID = tableData.getIntField(19, -1); - entry.buildTypes = tableData.getIntField(20, -1); - entry.reqPrecondition = tableData.getStringField(21, ""); - entry.animationFlag = tableData.getIntField(22, -1); - entry.equipEffects = tableData.getIntField(23, -1); - entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; - entry.itemRating = tableData.getIntField(25, -1); - entry.isTwoHanded = tableData.getIntField(26, -1) == 1 ? true : false; - entry.minNumRequired = tableData.getIntField(27, -1); - entry.delResIndex = tableData.getIntField(28, -1); - entry.currencyLOT = tableData.getIntField(29, -1); - entry.altCurrencyCost = tableData.getIntField(30, -1); - entry.subItems = tableData.getStringField(31, ""); - UNUSED(entry.audioEventUse = tableData.getStringField(32, "")); - entry.noEquipAnimation = tableData.getIntField(33, -1) == 1 ? true : false; - entry.commendationLOT = tableData.getIntField(34, -1); - entry.commendationCost = tableData.getIntField(35, -1); - UNUSED(entry.audioEquipMetaEventSet = tableData.getStringField(36, "")); - entry.currencyCosts = tableData.getStringField(37, ""); - UNUSED(entry.ingredientInfo = tableData.getStringField(38, "")); - entry.locStatus = tableData.getIntField(39, -1); - entry.forgeType = tableData.getIntField(40, -1); - entry.SellMultiplier = tableData.getFloatField(41, -1.0f); - + while (!tableData.eof()) { + CDItemComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.equipLocation = tableData.getStringField("equipLocation", ""); + entry.baseValue = tableData.getIntField("baseValue", -1); + entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false; + entry.rarity = tableData.getIntField("rarity", 0); + entry.itemType = tableData.getIntField("itemType", -1); + entry.itemInfo = tableData.getInt64Field("itemInfo", -1); + entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false; + entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false; + entry.isUnique = tableData.getIntField("isUnique", -1) == 1 ? true : false; + entry.isBOP = tableData.getIntField("isBOP", -1) == 1 ? true : false; + entry.isBOE = tableData.getIntField("isBOE", -1) == 1 ? true : false; + entry.reqFlagID = tableData.getIntField("reqFlagID", -1); + entry.reqSpecialtyID = tableData.getIntField("reqSpecialtyID", -1); + entry.reqSpecRank = tableData.getIntField("reqSpecRank", -1); + entry.reqAchievementID = tableData.getIntField("reqAchievementID", -1); + entry.stackSize = tableData.getIntField("stackSize", -1); + entry.color1 = tableData.getIntField("color1", -1); + entry.decal = tableData.getIntField("decal", -1); + entry.offsetGroupID = tableData.getIntField("offsetGroupID", -1); + entry.buildTypes = tableData.getIntField("buildTypes", -1); + entry.reqPrecondition = tableData.getStringField("reqPrecondition", ""); + entry.animationFlag = tableData.getIntField("animationFlag", 0); + entry.equipEffects = tableData.getIntField("equipEffects", -1); + entry.readyForQA = tableData.getIntField("readyForQA", -1) == 1 ? true : false; + entry.itemRating = tableData.getIntField("itemRating", -1); + entry.isTwoHanded = tableData.getIntField("isTwoHanded", -1) == 1 ? true : false; + entry.minNumRequired = tableData.getIntField("minNumRequired", -1); + entry.delResIndex = tableData.getIntField("delResIndex", -1); + entry.currencyLOT = tableData.getIntField("currencyLOT", -1); + entry.altCurrencyCost = tableData.getIntField("altCurrencyCost", -1); + entry.subItems = tableData.getStringField("subItems", ""); + UNUSED(entry.audioEventUse = tableData.getStringField("audioEventUse", "")); + entry.noEquipAnimation = tableData.getIntField("noEquipAnimation", -1) == 1 ? true : false; + entry.commendationLOT = tableData.getIntField("commendationLOT", -1); + entry.commendationCost = tableData.getIntField("commendationCost", -1); + UNUSED(entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", "")); + entry.currencyCosts = tableData.getStringField("currencyCosts", ""); + UNUSED(entry.ingredientInfo = tableData.getStringField("ingredientInfo", "")); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.forgeType = tableData.getIntField("forgeType", -1); + entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); + this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); - } + } const auto& it2 = this->entries.find(skillID); if (it2 != this->entries.end()) { @@ -154,26 +146,27 @@ const CDItemComponent & CDItemComponentTable::GetItemComponentByID(unsigned int } #endif - return Default; + return Default; } std::map CDItemComponentTable::ParseCraftingCurrencies(const CDItemComponent& itemComponent) { - std::map currencies = {}; + std::map currencies = {}; - if (!itemComponent.currencyCosts.empty()) { - auto currencySplit = GeneralUtils::SplitString(itemComponent.currencyCosts, ','); - for (const auto& currencyAmount : currencySplit) { - auto amountSplit = GeneralUtils::SplitString(currencyAmount, ':'); + if (!itemComponent.currencyCosts.empty()) { + auto currencySplit = GeneralUtils::SplitString(itemComponent.currencyCosts, ','); + for (const auto& currencyAmount : currencySplit) { + auto amountSplit = GeneralUtils::SplitString(currencyAmount, ':'); - // Checking for 2 here, not sure what to do when there's more stuff than expected - if (amountSplit.size() == 2) { - currencies.insert({ - std::stoull(amountSplit[0]), - std::stoi(amountSplit[1]) - }); - } - } - } + // Checking for 2 here, not sure what to do when there's more stuff than expected + if (amountSplit.size() == 2) { + currencies.insert({ + std::stoull(amountSplit[0]), + std::stoi(amountSplit[1]) + }); + } + } + } - return currencies; + return currencies; } + diff --git a/dDatabase/Tables/CDItemComponentTable.h b/dDatabase/Tables/CDItemComponentTable.h index 83b66f91..11c34dd6 100644 --- a/dDatabase/Tables/CDItemComponentTable.h +++ b/dDatabase/Tables/CDItemComponentTable.h @@ -4,80 +4,61 @@ #include "CDTable.h" #include "dCommonVars.h" -/*! - \file CDItemComponentTable.hpp - \brief Contains data for the ItemComponent table - */ - -//! ItemComponent Struct struct CDItemComponent { - unsigned int id; //!< The Component ID - std::string equipLocation; //!< The equip location - unsigned int baseValue; //!< The monetary base value of the item - bool isKitPiece; //!< Whether or not the item belongs to a kit - unsigned int rarity; //!< The rarity of the item - unsigned int itemType; //!< The item type - int64_t itemInfo; //!< The item info - bool inLootTable; //!< Whether or not the item is in a loot table - bool inVendor; //!< Whether or not the item is in a vendor inventory - bool isUnique; //!< ??? - bool isBOP; //!< ??? - bool isBOE; //!< ??? - unsigned int reqFlagID; //!< User must have completed this flag to get the item - unsigned int reqSpecialtyID; //!< ??? - unsigned int reqSpecRank; //!< ??? - unsigned int reqAchievementID; //!< The required achievement must be completed - unsigned int stackSize; //!< The stack size of the item - unsigned int color1; //!< Something to do with item color... - unsigned int decal; //!< The decal of the item - unsigned int offsetGroupID; //!< Something to do with group IDs - unsigned int buildTypes; //!< Something to do with building - std::string reqPrecondition; //!< The required precondition - unsigned int animationFlag; //!< The Animation Flag - unsigned int equipEffects; //!< The effect played when the item is equipped - bool readyForQA; //!< ??? - unsigned int itemRating; //!< ??? - bool isTwoHanded; //!< Whether or not the item is double handed - unsigned int minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object? - unsigned int delResIndex; //!< ??? - unsigned int currencyLOT; //!< ??? - unsigned int altCurrencyCost; //!< ??? - std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set) - UNUSED(std::string audioEventUse); //!< ??? - bool noEquipAnimation; //!< Whether or not there is an equip animation - unsigned int commendationLOT; //!< The commendation LOT - unsigned int commendationCost; //!< The commendation cost - UNUSED(std::string audioEquipMetaEventSet); //!< ??? - std::string currencyCosts; //!< Used for crafting - UNUSED(std::string ingredientInfo); //!< Unused - unsigned int locStatus; //!< ??? - unsigned int forgeType; //!< Forge Type - float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) + unsigned int id; //!< The Component ID + std::string equipLocation; //!< The equip location + unsigned int baseValue; //!< The monetary base value of the item + bool isKitPiece; //!< Whether or not the item belongs to a kit + unsigned int rarity; //!< The rarity of the item + unsigned int itemType; //!< The item type + int64_t itemInfo; //!< The item info + bool inLootTable; //!< Whether or not the item is in a loot table + bool inVendor; //!< Whether or not the item is in a vendor inventory + bool isUnique; //!< ??? + bool isBOP; //!< ??? + bool isBOE; //!< ??? + unsigned int reqFlagID; //!< User must have completed this flag to get the item + unsigned int reqSpecialtyID; //!< ??? + unsigned int reqSpecRank; //!< ??? + unsigned int reqAchievementID; //!< The required achievement must be completed + unsigned int stackSize; //!< The stack size of the item + unsigned int color1; //!< Something to do with item color... + unsigned int decal; //!< The decal of the item + unsigned int offsetGroupID; //!< Something to do with group IDs + unsigned int buildTypes; //!< Something to do with building + std::string reqPrecondition; //!< The required precondition + unsigned int animationFlag; //!< The Animation Flag + unsigned int equipEffects; //!< The effect played when the item is equipped + bool readyForQA; //!< ??? + unsigned int itemRating; //!< ??? + bool isTwoHanded; //!< Whether or not the item is double handed + unsigned int minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object? + unsigned int delResIndex; //!< ??? + unsigned int currencyLOT; //!< ??? + unsigned int altCurrencyCost; //!< ??? + std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set) + UNUSED(std::string audioEventUse); //!< ??? + bool noEquipAnimation; //!< Whether or not there is an equip animation + unsigned int commendationLOT; //!< The commendation LOT + unsigned int commendationCost; //!< The commendation cost + UNUSED(std::string audioEquipMetaEventSet); //!< ??? + std::string currencyCosts; //!< Used for crafting + UNUSED(std::string ingredientInfo); //!< Unused + unsigned int locStatus; //!< ??? + unsigned int forgeType; //!< Forge Type + float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) }; -//! ItemComponent table -class CDItemComponentTable : public CDTable { +class CDItemComponentTable : public CDTable { private: - std::map entries; - -public: - - //! Constructor - CDItemComponentTable(void); - - //! Destructor - ~CDItemComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; + std::map entries; - static std::map ParseCraftingCurrencies(const CDItemComponent& itemComponent); - - //! Gets an entry by ID +public: + CDItemComponentTable(); + static std::map ParseCraftingCurrencies(const CDItemComponent& itemComponent); + + // Gets an entry by ID const CDItemComponent& GetItemComponentByID(unsigned int skillID); - - static CDItemComponent Default; + + static CDItemComponent Default; }; diff --git a/dDatabase/Tables/CDItemSetSkillsTable.cpp b/dDatabase/Tables/CDItemSetSkillsTable.cpp index b20fd1cb..f6b412ff 100644 --- a/dDatabase/Tables/CDItemSetSkillsTable.cpp +++ b/dDatabase/Tables/CDItemSetSkillsTable.cpp @@ -2,63 +2,52 @@ //! Constructor CDItemSetSkillsTable::CDItemSetSkillsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSetSkills"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSetSkills"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); - while (!tableData.eof()) { - CDItemSetSkills entry; - entry.SkillSetID = tableData.getIntField(0, -1); - entry.SkillID = tableData.getIntField(1, -1); - entry.SkillCastType = tableData.getIntField(2, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); + while (!tableData.eof()) { + CDItemSetSkills entry; + entry.SkillSetID = tableData.getIntField("SkillSetID", -1); + entry.SkillID = tableData.getIntField("SkillID", -1); + entry.SkillCastType = tableData.getIntField("SkillCastType", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDItemSetSkillsTable::~CDItemSetSkillsTable(void) { } - -//! Returns the table's name -std::string CDItemSetSkillsTable::GetName(void) const { - return "ItemSetSkills"; -} - -//! Queries the table with a custom "where" clause std::vector CDItemSetSkillsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDItemSetSkillsTable::GetEntries(void) const { - return this->entries; + return this->entries; } -std::vector CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) -{ +std::vector CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) { std::vector toReturn; - + for (CDItemSetSkills entry : this->entries) { if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry); if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed. diff --git a/dDatabase/Tables/CDItemSetSkillsTable.h b/dDatabase/Tables/CDItemSetSkillsTable.h index 78ce83ab..8328c66b 100644 --- a/dDatabase/Tables/CDItemSetSkillsTable.h +++ b/dDatabase/Tables/CDItemSetSkillsTable.h @@ -3,50 +3,22 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDItemSetSkillsTable.hpp - \brief Contains data for the ItemSetSkills table - */ - -//! ZoneTable Struct struct CDItemSetSkills { - unsigned int SkillSetID; //!< The skill set ID - unsigned int SkillID; //!< The skill ID - unsigned int SkillCastType; //!< The skill cast type + unsigned int SkillSetID; //!< The skill set ID + unsigned int SkillID; //!< The skill ID + unsigned int SkillCastType; //!< The skill cast type }; -//! ItemSets table -class CDItemSetSkillsTable : public CDTable { +class CDItemSetSkillsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDItemSetSkillsTable(void); - - //! Destructor - ~CDItemSetSkillsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; + CDItemSetSkillsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; std::vector GetBySkillID(unsigned int SkillSetID); - }; - diff --git a/dDatabase/Tables/CDItemSetsTable.cpp b/dDatabase/Tables/CDItemSetsTable.cpp index ad78ee3b..0632ef13 100644 --- a/dDatabase/Tables/CDItemSetsTable.cpp +++ b/dDatabase/Tables/CDItemSetsTable.cpp @@ -2,67 +2,58 @@ //! Constructor CDItemSetsTable::CDItemSetsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSets"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSets"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); - while (!tableData.eof()) { - CDItemSets entry; - entry.setID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.itemIDs = tableData.getStringField(2, ""); - entry.kitType = tableData.getIntField(3, -1); - entry.kitRank = tableData.getIntField(4, -1); - entry.kitImage = tableData.getIntField(5, -1); - entry.skillSetWith2 = tableData.getIntField(6, -1); - entry.skillSetWith3 = tableData.getIntField(7, -1); - entry.skillSetWith4 = tableData.getIntField(8, -1); - entry.skillSetWith5 = tableData.getIntField(9, -1); - entry.skillSetWith6 = tableData.getIntField(10, -1); - entry.localize = tableData.getIntField(11, -1) == 1 ? true : false; - entry.gate_version = tableData.getStringField(12, ""); - entry.kitID = tableData.getIntField(13, -1); - entry.priority = tableData.getFloatField(14, -1.0f); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); + while (!tableData.eof()) { + CDItemSets entry; + entry.setID = tableData.getIntField("setID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.itemIDs = tableData.getStringField("itemIDs", ""); + entry.kitType = tableData.getIntField("kitType", -1); + entry.kitRank = tableData.getIntField("kitRank", -1); + entry.kitImage = tableData.getIntField("kitImage", -1); + entry.skillSetWith2 = tableData.getIntField("skillSetWith2", -1); + entry.skillSetWith3 = tableData.getIntField("skillSetWith3", -1); + entry.skillSetWith4 = tableData.getIntField("skillSetWith4", -1); + entry.skillSetWith5 = tableData.getIntField("skillSetWith5", -1); + entry.skillSetWith6 = tableData.getIntField("skillSetWith6", -1); + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.kitID = tableData.getIntField("kitID", -1); + entry.priority = tableData.getFloatField("priority", -1.0f); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDItemSetsTable::~CDItemSetsTable(void) { } - -//! Returns the table's name -std::string CDItemSetsTable::GetName(void) const { - return "ItemSets"; -} - -//! Queries the table with a custom "where" clause std::vector CDItemSetsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table std::vector CDItemSetsTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDItemSetsTable.h b/dDatabase/Tables/CDItemSetsTable.h index 9e8b85e8..6756e7fa 100644 --- a/dDatabase/Tables/CDItemSetsTable.h +++ b/dDatabase/Tables/CDItemSetsTable.h @@ -3,60 +3,33 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDItemSetsTable.hpp - \brief Contains data for the ItemSets table - */ - -//! ZoneTable Struct struct CDItemSets { - unsigned int setID; //!< The item set ID - unsigned int locStatus; //!< The loc status - std::string itemIDs; //!< THe item IDs - unsigned int kitType; //!< The item kit type - unsigned int kitRank; //!< The item kit rank - unsigned int kitImage; //!< The item kit image - unsigned int skillSetWith2; //!< The skill set with 2 - unsigned int skillSetWith3; //!< The skill set with 3 - unsigned int skillSetWith4; //!< The skill set with 4 - unsigned int skillSetWith5; //!< The skill set with 5 - unsigned int skillSetWith6; //!< The skill set with 6 - bool localize; //!< Whether or localize - std::string gate_version; //!< The gate version - unsigned int kitID; //!< The kit ID - float priority; //!< The priority + unsigned int setID; //!< The item set ID + unsigned int locStatus; //!< The loc status + std::string itemIDs; //!< THe item IDs + unsigned int kitType; //!< The item kit type + unsigned int kitRank; //!< The item kit rank + unsigned int kitImage; //!< The item kit image + unsigned int skillSetWith2; //!< The skill set with 2 + unsigned int skillSetWith3; //!< The skill set with 3 + unsigned int skillSetWith4; //!< The skill set with 4 + unsigned int skillSetWith5; //!< The skill set with 5 + unsigned int skillSetWith6; //!< The skill set with 6 + bool localize; //!< Whether or localize + std::string gate_version; //!< The gate version + unsigned int kitID; //!< The kit ID + float priority; //!< The priority }; -//! ItemSets table -class CDItemSetsTable : public CDTable { +class CDItemSetsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDItemSetsTable(void); - - //! Destructor - ~CDItemSetsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDItemSetsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.cpp b/dDatabase/Tables/CDLevelProgressionLookupTable.cpp index 0070e787..47a8fc0e 100644 --- a/dDatabase/Tables/CDLevelProgressionLookupTable.cpp +++ b/dDatabase/Tables/CDLevelProgressionLookupTable.cpp @@ -2,55 +2,48 @@ //! Constructor CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LevelProgressionLookup"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LevelProgressionLookup"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); - while (!tableData.eof()) { - CDLevelProgressionLookup entry; - entry.id = tableData.getIntField(0, -1); - entry.requiredUScore = tableData.getIntField(1, -1); - entry.BehaviorEffect = tableData.getStringField(2, ""); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); + while (!tableData.eof()) { + CDLevelProgressionLookup entry; + entry.id = tableData.getIntField("id", -1); + entry.requiredUScore = tableData.getIntField("requiredUScore", -1); + entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", ""); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDLevelProgressionLookupTable::~CDLevelProgressionLookupTable(void) { } - -//! Returns the table's name -std::string CDLevelProgressionLookupTable::GetName(void) const { - return "LevelProgressionLookup"; -} - //! Queries the table with a custom "where" clause std::vector CDLevelProgressionLookupTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } //! Gets all the entries in the table std::vector CDLevelProgressionLookupTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.h b/dDatabase/Tables/CDLevelProgressionLookupTable.h index 4174cdff..070b2e0c 100644 --- a/dDatabase/Tables/CDLevelProgressionLookupTable.h +++ b/dDatabase/Tables/CDLevelProgressionLookupTable.h @@ -3,47 +3,21 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLevelProgressionLookupTable.hpp - \brief Contains data for the LevelProgressionLookup table - */ - -//! LevelProgressionLookup Entry Struct struct CDLevelProgressionLookup { - unsigned int id; //!< The Level ID - unsigned int requiredUScore; //!< The required LEGO Score - std::string BehaviorEffect; //!< The behavior effect attached to this + unsigned int id; //!< The Level ID + unsigned int requiredUScore; //!< The required LEGO Score + std::string BehaviorEffect; //!< The behavior effect attached to this }; -//! LevelProgressionLookup table -class CDLevelProgressionLookupTable : public CDTable { +class CDLevelProgressionLookupTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDLevelProgressionLookupTable(void); - - //! Destructor - ~CDLevelProgressionLookupTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDLevelProgressionLookupTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + // Gets all the entries in the table + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDLootMatrixTable.cpp b/dDatabase/Tables/CDLootMatrixTable.cpp index 17fd8313..8f25e8a3 100644 --- a/dDatabase/Tables/CDLootMatrixTable.cpp +++ b/dDatabase/Tables/CDLootMatrixTable.cpp @@ -2,61 +2,52 @@ //! Constructor CDLootMatrixTable::CDLootMatrixTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootMatrix"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootMatrix"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); - while (!tableData.eof()) { - CDLootMatrix entry; - entry.LootMatrixIndex = tableData.getIntField(0, -1); - entry.LootTableIndex = tableData.getIntField(1, -1); - entry.RarityTableIndex = tableData.getIntField(2, -1); - entry.percent = tableData.getFloatField(3, -1.0f); - entry.minToDrop = tableData.getIntField(4, -1); - entry.maxToDrop = tableData.getIntField(5, -1); - entry.id = tableData.getIntField(6, -1); - entry.flagID = tableData.getIntField(7, -1); - UNUSED(entry.gate_version = tableData.getStringField(8, "")); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); + while (!tableData.eof()) { + CDLootMatrix entry; + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1); + entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1); + entry.percent = tableData.getFloatField("percent", -1.0f); + entry.minToDrop = tableData.getIntField("minToDrop", -1); + entry.maxToDrop = tableData.getIntField("maxToDrop", -1); + entry.id = tableData.getIntField("id", -1); + entry.flagID = tableData.getIntField("flagID", -1); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDLootMatrixTable::~CDLootMatrixTable(void) { } - -//! Returns the table's name -std::string CDLootMatrixTable::GetName(void) const { - return "LootMatrix"; -} - -//! Queries the table with a custom "where" clause std::vector CDLootMatrixTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table const std::vector& CDLootMatrixTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDLootMatrixTable.h b/dDatabase/Tables/CDLootMatrixTable.h index f306324f..c6035841 100644 --- a/dDatabase/Tables/CDLootMatrixTable.h +++ b/dDatabase/Tables/CDLootMatrixTable.h @@ -3,54 +3,27 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLootMatrixTable.hpp - \brief Contains data for the ObjectSkills table - */ - -//! LootMatrix Struct struct CDLootMatrix { - unsigned int LootMatrixIndex; //!< The Loot Matrix Index - unsigned int LootTableIndex; //!< The Loot Table Index - unsigned int RarityTableIndex; //!< The Rarity Table Index - float percent; //!< The percent that this matrix is used? - unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop - unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop - unsigned int id; //!< The ID of the Loot Matrix - unsigned int flagID; //!< ??? - UNUSED(std::string gate_version); //!< The Gate Version + unsigned int LootMatrixIndex; //!< The Loot Matrix Index + unsigned int LootTableIndex; //!< The Loot Table Index + unsigned int RarityTableIndex; //!< The Rarity Table Index + float percent; //!< The percent that this matrix is used? + unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop + unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop + unsigned int id; //!< The ID of the Loot Matrix + unsigned int flagID; //!< ??? + UNUSED(std::string gate_version); //!< The Gate Version }; -//! MissionNPCComponent table -class CDLootMatrixTable : public CDTable { +class CDLootMatrixTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDLootMatrixTable(void); - - //! Destructor - ~CDLootMatrixTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; - + CDLootMatrixTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + const std::vector& GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDLootTableTable.cpp b/dDatabase/Tables/CDLootTableTable.cpp index 62727ade..0a46784a 100644 --- a/dDatabase/Tables/CDLootTableTable.cpp +++ b/dDatabase/Tables/CDLootTableTable.cpp @@ -2,58 +2,51 @@ //! Constructor CDLootTableTable::CDLootTableTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootTable"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootTable"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable"); - while (!tableData.eof()) { - CDLootTable entry; - entry.id = tableData.getIntField(0, -1); - entry.itemid = tableData.getIntField(0, -1); - entry.LootTableIndex = tableData.getIntField(1, -1); - entry.id = tableData.getIntField(2, -1); - entry.MissionDrop = tableData.getIntField(3, -1) == 1 ? true : false; - entry.sortPriority = tableData.getIntField(4, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable"); + while (!tableData.eof()) { + CDLootTable entry; + entry.id = tableData.getIntField("id", -1); + entry.itemid = tableData.getIntField("itemid", -1); + entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1); + entry.id = tableData.getIntField("id", -1); + entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false; + entry.sortPriority = tableData.getIntField("sortPriority", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDLootTableTable::~CDLootTableTable(void) { } - -//! Returns the table's name -std::string CDLootTableTable::GetName(void) const { - return "LootTable"; -} - //! Queries the table with a custom "where" clause std::vector CDLootTableTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } //! Gets all the entries in the table const std::vector& CDLootTableTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDLootTableTable.h b/dDatabase/Tables/CDLootTableTable.h index 750adcb4..ba6f207e 100644 --- a/dDatabase/Tables/CDLootTableTable.h +++ b/dDatabase/Tables/CDLootTableTable.h @@ -3,50 +3,23 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLootTableTable.hpp - \brief Contains data for the LootTable table - */ - -//! LootTable Struct struct CDLootTable { - unsigned int itemid; //!< The LOT of the item - unsigned int LootTableIndex; //!< The Loot Table Index - unsigned int id; //!< The ID - bool MissionDrop; //!< Whether or not this loot table is a mission drop - unsigned int sortPriority; //!< The sorting priority + unsigned int itemid; //!< The LOT of the item + unsigned int LootTableIndex; //!< The Loot Table Index + unsigned int id; //!< The ID + bool MissionDrop; //!< Whether or not this loot table is a mission drop + unsigned int sortPriority; //!< The sorting priority }; -//! LootTable table -class CDLootTableTable : public CDTable { +class CDLootTableTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDLootTableTable(void); - - //! Destructor - ~CDLootTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; - + CDLootTableTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + const std::vector& GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDMissionEmailTable.cpp b/dDatabase/Tables/CDMissionEmailTable.cpp index 2c5fc56a..ed855d8a 100644 --- a/dDatabase/Tables/CDMissionEmailTable.cpp +++ b/dDatabase/Tables/CDMissionEmailTable.cpp @@ -3,59 +3,52 @@ //! Constructor CDMissionEmailTable::CDMissionEmailTable(void) { - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } - tableSize.nextRow(); - } - tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail"); - while (!tableData.eof()) { - CDMissionEmail entry; - entry.ID = tableData.getIntField(0, -1); - entry.messageType = tableData.getIntField(1, -1); - entry.notificationGroup = tableData.getIntField(2, -1); - entry.missionID = tableData.getIntField(3, -1); - entry.attachmentLOT = tableData.getIntField(4, 0); - entry.localize = (bool)tableData.getIntField(5, -1); - entry.locStatus = tableData.getIntField(6, -1); - entry.gate_version = tableData.getStringField(7, ""); + // Reserve the size + this->entries.reserve(size); - this->entries.push_back(entry); - tableData.nextRow(); - } + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail"); + while (!tableData.eof()) { + CDMissionEmail entry; + entry.ID = tableData.getIntField("ID", -1); + entry.messageType = tableData.getIntField("messageType", -1); + entry.notificationGroup = tableData.getIntField("notificationGroup", -1); + entry.missionID = tableData.getIntField("missionID", -1); + entry.attachmentLOT = tableData.getIntField("attachmentLOT", 0); + entry.localize = (bool)tableData.getIntField("localize", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDMissionEmailTable::~CDMissionEmailTable(void) { } - -//! Returns the table's name -std::string CDMissionEmailTable::GetName(void) const { - return "MissionEmail"; -} - //! Queries the table with a custom "where" clause std::vector CDMissionEmailTable::Query(std::function predicate) { - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); - return data; + return data; } //! Gets all the entries in the table std::vector CDMissionEmailTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDMissionEmailTable.h b/dDatabase/Tables/CDMissionEmailTable.h index cd0a1285..db2310d4 100644 --- a/dDatabase/Tables/CDMissionEmailTable.h +++ b/dDatabase/Tables/CDMissionEmailTable.h @@ -3,53 +3,26 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionEmailTable.hpp - \brief Contains data for the MissionEmail table - */ - - //! MissionEmail Entry Struct struct CDMissionEmail { - unsigned int ID; - unsigned int messageType; - unsigned int notificationGroup; - unsigned int missionID; - unsigned int attachmentLOT; - bool localize; - unsigned int locStatus; - std::string gate_version; + unsigned int ID; + unsigned int messageType; + unsigned int notificationGroup; + unsigned int missionID; + unsigned int attachmentLOT; + bool localize; + unsigned int locStatus; + std::string gate_version; }; -//! MissionEmail table -class CDMissionEmailTable : public CDTable { +class CDMissionEmailTable : public CDTable { private: - std::vector entries; + std::vector entries; public: + CDMissionEmailTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); - //! Constructor - CDMissionEmailTable(void); - - //! Destructor - ~CDMissionEmailTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.cpp b/dDatabase/Tables/CDMissionNPCComponentTable.cpp index 9014585b..5672ed67 100644 --- a/dDatabase/Tables/CDMissionNPCComponentTable.cpp +++ b/dDatabase/Tables/CDMissionNPCComponentTable.cpp @@ -2,57 +2,50 @@ //! Constructor CDMissionNPCComponentTable::CDMissionNPCComponentTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionNPCComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionNPCComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); - while (!tableData.eof()) { - CDMissionNPCComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.missionID = tableData.getIntField(1, -1); - entry.offersMission = tableData.getIntField(2, -1) == 1 ? true : false; - entry.acceptsMission = tableData.getIntField(3, -1) == 1 ? true : false; - entry.gate_version = tableData.getStringField(4, ""); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); + while (!tableData.eof()) { + CDMissionNPCComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.missionID = tableData.getIntField("missionID", -1); + entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false; + entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false; + entry.gate_version = tableData.getStringField("gate_version", ""); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDMissionNPCComponentTable::~CDMissionNPCComponentTable(void) { } - -//! Returns the table's name -std::string CDMissionNPCComponentTable::GetName(void) const { - return "MissionNPCComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDMissionNPCComponentTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } //! Gets all the entries in the table std::vector CDMissionNPCComponentTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.h b/dDatabase/Tables/CDMissionNPCComponentTable.h index a31ba170..a7aeb145 100644 --- a/dDatabase/Tables/CDMissionNPCComponentTable.h +++ b/dDatabase/Tables/CDMissionNPCComponentTable.h @@ -3,50 +3,25 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionNPCComponentTable.hpp - \brief Contains data for the ObjectSkills table - */ - -//! MissionNPCComponent Struct struct CDMissionNPCComponent { - unsigned int id; //!< The ID - unsigned int missionID; //!< The Mission ID - bool offersMission; //!< Whether or not this NPC offers a mission - bool acceptsMission; //!< Whether or not this NPC accepts a mission - std::string gate_version; //!< The gate version + unsigned int id; //!< The ID + unsigned int missionID; //!< The Mission ID + bool offersMission; //!< Whether or not this NPC offers a mission + bool acceptsMission; //!< Whether or not this NPC accepts a mission + std::string gate_version; //!< The gate version }; -//! MissionNPCComponent table -class CDMissionNPCComponentTable : public CDTable { +class CDMissionNPCComponentTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDMissionNPCComponentTable(void); - - //! Destructor - ~CDMissionNPCComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDMissionNPCComponentTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + // Gets all the entries in the table + std::vector GetEntries(void) const; + }; diff --git a/dDatabase/Tables/CDMissionTasksTable.cpp b/dDatabase/Tables/CDMissionTasksTable.cpp index e79e6d02..f32dca1b 100644 --- a/dDatabase/Tables/CDMissionTasksTable.cpp +++ b/dDatabase/Tables/CDMissionTasksTable.cpp @@ -2,82 +2,70 @@ //! Constructor CDMissionTasksTable::CDMissionTasksTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionTasks"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionTasks"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks"); - while (!tableData.eof()) { - CDMissionTasks entry; - entry.id = tableData.getIntField(0, -1); - UNUSED(entry.locStatus = tableData.getIntField(1, -1)); - entry.taskType = tableData.getIntField(2, -1); - entry.target = tableData.getIntField(3, -1); - entry.targetGroup = tableData.getStringField(4, ""); - entry.targetValue = tableData.getIntField(5, -1); - entry.taskParam1 = tableData.getStringField(6, ""); - UNUSED(entry.largeTaskIcon = tableData.getStringField(7, "")); - UNUSED(entry.IconID = tableData.getIntField(8, -1)); - entry.uid = tableData.getIntField(9, -1); - UNUSED(entry.largeTaskIconID = tableData.getIntField(10, -1)); - UNUSED(entry.localize = tableData.getIntField(11, -1) == 1 ? true : false); - UNUSED(entry.gate_version = tableData.getStringField(12, "")); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks"); + while (!tableData.eof()) { + CDMissionTasks entry; + entry.id = tableData.getIntField("id", -1); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.taskType = tableData.getIntField("taskType", -1); + entry.target = tableData.getIntField("target", -1); + entry.targetGroup = tableData.getStringField("targetGroup", ""); + entry.targetValue = tableData.getIntField("targetValue", -1); + entry.taskParam1 = tableData.getStringField("taskParam1", ""); + UNUSED(entry.largeTaskIcon = tableData.getStringField("largeTaskIcon", "")); + UNUSED(entry.IconID = tableData.getIntField("IconID", -1)); + entry.uid = tableData.getIntField("uid", -1); + UNUSED(entry.largeTaskIconID = tableData.getIntField("largeTaskIconID", -1)); + UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDMissionTasksTable::~CDMissionTasksTable(void) { } - -//! Returns the table's name -std::string CDMissionTasksTable::GetName(void) const { - return "MissionTasks"; -} - -//! Queries the table with a custom "where" clause std::vector CDMissionTasksTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -std::vector CDMissionTasksTable::GetByMissionID(uint32_t missionID) -{ - std::vector tasks; +std::vector CDMissionTasksTable::GetByMissionID(uint32_t missionID) { + std::vector tasks; - for (auto& entry : this->entries) - { - if (entry.id == missionID) - { - CDMissionTasks* task = const_cast(&entry); + for (auto& entry : this->entries) { + if (entry.id == missionID) { + CDMissionTasks* task = const_cast(&entry); - tasks.push_back(task); - } - } + tasks.push_back(task); + } + } - return tasks; + return tasks; } -//! Gets all the entries in the table const std::vector& CDMissionTasksTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDMissionTasksTable.h b/dDatabase/Tables/CDMissionTasksTable.h index af84663e..fa213faf 100644 --- a/dDatabase/Tables/CDMissionTasksTable.h +++ b/dDatabase/Tables/CDMissionTasksTable.h @@ -3,59 +3,33 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionTasksTable.hpp - \brief Contains data for the MissionTasks table - */ - -//! ObjectSkills Struct struct CDMissionTasks { - unsigned int id; //!< The Mission ID that the task belongs to - UNUSED(unsigned int locStatus); //!< ??? - unsigned int taskType; //!< The task type - unsigned int target; //!< The mission target - std::string targetGroup; //!< The mission target group - int targetValue; //!< The target value - std::string taskParam1; //!< The task param 1 - UNUSED(std::string largeTaskIcon); //!< ??? - UNUSED(unsigned int IconID); //!< ??? - unsigned int uid; //!< ??? - UNUSED(unsigned int largeTaskIconID); //!< ??? - UNUSED(bool localize); //!< Whether or not the task should be localized - UNUSED(std::string gate_version); //!< ??? + unsigned int id; //!< The Mission ID that the task belongs to + UNUSED(unsigned int locStatus); //!< ??? + unsigned int taskType; //!< The task type + unsigned int target; //!< The mission target + std::string targetGroup; //!< The mission target group + int targetValue; //!< The target value + std::string taskParam1; //!< The task param 1 + UNUSED(std::string largeTaskIcon); //!< ??? + UNUSED(unsigned int IconID); //!< ??? + unsigned int uid; //!< ??? + UNUSED(unsigned int largeTaskIconID); //!< ??? + UNUSED(bool localize); //!< Whether or not the task should be localized + UNUSED(std::string gate_version); //!< ??? }; -//! ObjectSkills table -class CDMissionTasksTable : public CDTable { +class CDMissionTasksTable : public CDTable { private: - std::vector entries; - -public: - - //! Constructor - CDMissionTasksTable(void); - - //! Destructor - ~CDMissionTasksTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); + std::vector entries; - std::vector GetByMissionID(uint32_t missionID); - - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; +public: + CDMissionTasksTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetByMissionID(uint32_t missionID); + + const std::vector& GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDMissionsTable.cpp b/dDatabase/Tables/CDMissionsTable.cpp index 58243bd8..d4ee40ae 100644 --- a/dDatabase/Tables/CDMissionsTable.cpp +++ b/dDatabase/Tables/CDMissionsTable.cpp @@ -4,136 +4,121 @@ CDMissions CDMissionsTable::Default = {}; //! Constructor CDMissionsTable::CDMissionsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Missions"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Missions"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions"); - while (!tableData.eof()) { - CDMissions entry; - entry.id = tableData.getIntField(0, -1); - entry.defined_type = tableData.getStringField(1, ""); - entry.defined_subtype = tableData.getStringField(2, ""); - entry.UISortOrder = tableData.getIntField(3, -1); - entry.offer_objectID = tableData.getIntField(4, -1); - entry.target_objectID = tableData.getIntField(5, -1); - entry.reward_currency = tableData.getInt64Field(6, -1); - entry.LegoScore = tableData.getIntField(7, -1); - entry.reward_reputation = tableData.getIntField(8, -1); - entry.isChoiceReward = tableData.getIntField(9, -1) == 1 ? true : false; - entry.reward_item1 = tableData.getIntField(10, 0); - entry.reward_item1_count = tableData.getIntField(11, 0); - entry.reward_item2 = tableData.getIntField(12, 0); - entry.reward_item2_count = tableData.getIntField(13, 0); - entry.reward_item3 = tableData.getIntField(14, 0); - entry.reward_item3_count = tableData.getIntField(15, 0); - entry.reward_item4 = tableData.getIntField(16, 0); - entry.reward_item4_count = tableData.getIntField(17, 0); - entry.reward_emote = tableData.getIntField(18, -1); - entry.reward_emote2 = tableData.getIntField(19, -1); - entry.reward_emote3 = tableData.getIntField(20, -1); - entry.reward_emote4 = tableData.getIntField(21, -1); - entry.reward_maximagination = tableData.getIntField(22, -1); - entry.reward_maxhealth = tableData.getIntField(23, -1); - entry.reward_maxinventory = tableData.getIntField(24, -1); - entry.reward_maxmodel = tableData.getIntField(25, -1); - entry.reward_maxwidget = tableData.getIntField(26, -1); - entry.reward_maxwallet = tableData.getIntField(27, -1); - entry.repeatable = tableData.getIntField(28, -1) == 1 ? true : false; - entry.reward_currency_repeatable = tableData.getIntField(29, -1); - entry.reward_item1_repeatable = tableData.getIntField(30, -1); - entry.reward_item1_repeat_count = tableData.getIntField(31, -1); - entry.reward_item2_repeatable = tableData.getIntField(32, -1); - entry.reward_item2_repeat_count = tableData.getIntField(33, -1); - entry.reward_item3_repeatable = tableData.getIntField(34, -1); - entry.reward_item3_repeat_count = tableData.getIntField(35, -1); - entry.reward_item4_repeatable = tableData.getIntField(36, -1); - entry.reward_item4_repeat_count = tableData.getIntField(37, -1); - entry.time_limit = tableData.getIntField(38, -1); - entry.isMission = tableData.getIntField(39, -1) ? true : false; - entry.missionIconID = tableData.getIntField(40, -1); - entry.prereqMissionID = tableData.getStringField(41, ""); - entry.localize = tableData.getIntField(42, -1) == 1 ? true : false; - entry.inMOTD = tableData.getIntField(43, -1) == 1 ? true : false; - entry.cooldownTime = tableData.getInt64Field(44, -1); - entry.isRandom = tableData.getIntField(45, -1) == 1 ? true : false; - entry.randomPool = tableData.getStringField(46, ""); - entry.UIPrereqID = tableData.getIntField(47, -1); - UNUSED(entry.gate_version = tableData.getStringField(48, "")); - UNUSED(entry.HUDStates = tableData.getStringField(49, "")); - UNUSED(entry.locStatus = tableData.getIntField(50, -1)); - entry.reward_bankinventory = tableData.getIntField(51, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions"); + while (!tableData.eof()) { + CDMissions entry; + entry.id = tableData.getIntField("id", -1); + entry.defined_type = tableData.getStringField("defined_type", ""); + entry.defined_subtype = tableData.getStringField("defined_subtype", ""); + entry.UISortOrder = tableData.getIntField("UISortOrder", -1); + entry.offer_objectID = tableData.getIntField("offer_objectID", -1); + entry.target_objectID = tableData.getIntField("target_objectID", -1); + entry.reward_currency = tableData.getInt64Field("reward_currency", -1); + entry.LegoScore = tableData.getIntField("LegoScore", -1); + entry.reward_reputation = tableData.getIntField("reward_reputation", -1); + entry.isChoiceReward = tableData.getIntField("isChoiceReward", -1) == 1 ? true : false; + entry.reward_item1 = tableData.getIntField("reward_item1", 0); + entry.reward_item1_count = tableData.getIntField("reward_item1_count", 0); + entry.reward_item2 = tableData.getIntField("reward_item2", 0); + entry.reward_item2_count = tableData.getIntField("reward_item2_count", 0); + entry.reward_item3 = tableData.getIntField("reward_item3", 0); + entry.reward_item3_count = tableData.getIntField("reward_item3_count", 0); + entry.reward_item4 = tableData.getIntField("reward_item4", 0); + entry.reward_item4_count = tableData.getIntField("reward_item4_count", 0); + entry.reward_emote = tableData.getIntField("reward_emote", -1); + entry.reward_emote2 = tableData.getIntField("reward_emote2", -1); + entry.reward_emote3 = tableData.getIntField("reward_emote3", -1); + entry.reward_emote4 = tableData.getIntField("reward_emote4", -1); + entry.reward_maximagination = tableData.getIntField("reward_maximagination", -1); + entry.reward_maxhealth = tableData.getIntField("reward_maxhealth", -1); + entry.reward_maxinventory = tableData.getIntField("reward_maxinventory", -1); + entry.reward_maxmodel = tableData.getIntField("reward_maxmodel", -1); + entry.reward_maxwidget = tableData.getIntField("reward_maxwidget", -1); + entry.reward_maxwallet = tableData.getIntField("reward_maxwallet", -1); + entry.repeatable = tableData.getIntField("repeatable", -1) == 1 ? true : false; + entry.reward_currency_repeatable = tableData.getIntField("reward_currency_repeatable", -1); + entry.reward_item1_repeatable = tableData.getIntField("reward_item1_repeatable", -1); + entry.reward_item1_repeat_count = tableData.getIntField("reward_item1_repeat_count", -1); + entry.reward_item2_repeatable = tableData.getIntField("reward_item2_repeatable", -1); + entry.reward_item2_repeat_count = tableData.getIntField("reward_item2_repeat_count", -1); + entry.reward_item3_repeatable = tableData.getIntField("reward_item3_repeatable", -1); + entry.reward_item3_repeat_count = tableData.getIntField("reward_item3_repeat_count", -1); + entry.reward_item4_repeatable = tableData.getIntField("reward_item4_repeatable", -1); + entry.reward_item4_repeat_count = tableData.getIntField("reward_item4_repeat_count", -1); + entry.time_limit = tableData.getIntField("time_limit", -1); + entry.isMission = tableData.getIntField("isMission", -1) ? true : false; + entry.missionIconID = tableData.getIntField("missionIconID", -1); + entry.prereqMissionID = tableData.getStringField("prereqMissionID", ""); + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.inMOTD = tableData.getIntField("inMOTD", -1) == 1 ? true : false; + entry.cooldownTime = tableData.getInt64Field("cooldownTime", -1); + entry.isRandom = tableData.getIntField("isRandom", -1) == 1 ? true : false; + entry.randomPool = tableData.getStringField("randomPool", ""); + entry.UIPrereqID = tableData.getIntField("UIPrereqID", -1); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.HUDStates = tableData.getStringField("HUDStates", "")); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); - Default.id = -1; + Default.id = -1; } -//! Destructor -CDMissionsTable::~CDMissionsTable(void) { } - -//! Returns the table's name -std::string CDMissionsTable::GetName(void) const { - return "Missions"; -} - -//! Queries the table with a custom "where" clause std::vector CDMissionsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } -//! Gets all the entries in the table const std::vector& CDMissionsTable::GetEntries(void) const { - return this->entries; + return this->entries; } -const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const -{ - for (const auto& entry : entries) - { - if (entry.id == missionID) - { - return const_cast(&entry); - } - } +const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const { + for (const auto& entry : entries) { + if (entry.id == missionID) { + return const_cast(&entry); + } + } - return &Default; + return &Default; } -const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const -{ - for (const auto& entry : entries) - { - if (entry.id == missionID) - { - found = true; +const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const { + for (const auto& entry : entries) { + if (entry.id == missionID) { + found = true; - return entry; - } - } + return entry; + } + } - found = false; + found = false; - return Default; + return Default; } + diff --git a/dDatabase/Tables/CDMissionsTable.h b/dDatabase/Tables/CDMissionsTable.h index c961bb80..e6a44b02 100644 --- a/dDatabase/Tables/CDMissionsTable.h +++ b/dDatabase/Tables/CDMissionsTable.h @@ -5,102 +5,77 @@ #include #include -/*! - \file CDMissionsTable.hpp - \brief Contains data for the Missions table - */ - -//! Missions Struct struct CDMissions { - int id; //!< The Mission ID - std::string defined_type; //!< The type of mission - std::string defined_subtype; //!< The subtype of the mission - int UISortOrder; //!< The UI Sort Order for the mission - int offer_objectID; //!< The LOT of the mission giver - int target_objectID; //!< The LOT of the mission's target - int64_t reward_currency; //!< The amount of currency to reward the player - int LegoScore; //!< The amount of LEGO Score to reward the player - int64_t reward_reputation; //!< The reputation to award the player - bool isChoiceReward; //!< Whether or not the user has the option to choose their loot - int reward_item1; //!< The first rewarded item - int reward_item1_count; //!< The count of the first item to be rewarded - int reward_item2; //!< The second rewarded item - int reward_item2_count; //!< The count of the second item to be rewarded - int reward_item3; //!< The third rewarded item - int reward_item3_count; //!< The count of the third item to be rewarded - int reward_item4; //!< The fourth rewarded item - int reward_item4_count; //!< The count of the fourth item to be rewarded - int reward_emote; //!< The first emote to be rewarded - int reward_emote2; //!< The second emote to be rewarded - int reward_emote3; //!< The third emote to be rewarded - int reward_emote4; //!< The fourth emote to be rewarded - int reward_maximagination; //!< The amount of max imagination to reward - int reward_maxhealth; //!< The amount of max health to reward - int reward_maxinventory; //!< The amount of max inventory to reward - int reward_maxmodel; //!< ??? - int reward_maxwidget; //!< ??? - int reward_maxwallet; //!< ??? - bool repeatable; //!< Whether or not this mission can be repeated (for instance, is it a daily mission) - int64_t reward_currency_repeatable; //!< The repeatable reward - int reward_item1_repeatable; //!< The first rewarded item - int reward_item1_repeat_count; //!< The count of the first item to be rewarded - int reward_item2_repeatable; //!< The second rewarded item - int reward_item2_repeat_count; //!< The count of the second item to be rewarded - int reward_item3_repeatable; //!< The third rewarded item - int reward_item3_repeat_count; //!< The count of the third item to be rewarded - int reward_item4_repeatable; //!< The fourth rewarded item - int reward_item4_repeat_count; //!< The count of the fourth item to be rewarded - int time_limit; //!< The time limit of the mission - bool isMission; //!< Maybe to differentiate between missions and achievements? - int missionIconID; //!< The mission icon ID - std::string prereqMissionID; //!< A '|' seperated list of prerequisite missions - bool localize; //!< Whether or not to localize the mission - bool inMOTD; //!< In Match of the Day(?) - int64_t cooldownTime; //!< The mission cooldown time - bool isRandom; //!< ??? - std::string randomPool; //!< ??? - int UIPrereqID; //!< ??? - UNUSED(std::string gate_version); //!< The gate version - UNUSED(std::string HUDStates); //!< ??? - UNUSED(int locStatus); //!< ??? - int reward_bankinventory; //!< The amount of bank space this mission rewards + int id; //!< The Mission ID + std::string defined_type; //!< The type of mission + std::string defined_subtype; //!< The subtype of the mission + int UISortOrder; //!< The UI Sort Order for the mission + int offer_objectID; //!< The LOT of the mission giver + int target_objectID; //!< The LOT of the mission's target + int64_t reward_currency; //!< The amount of currency to reward the player + int LegoScore; //!< The amount of LEGO Score to reward the player + int64_t reward_reputation; //!< The reputation to award the player + bool isChoiceReward; //!< Whether or not the user has the option to choose their loot + int reward_item1; //!< The first rewarded item + int reward_item1_count; //!< The count of the first item to be rewarded + int reward_item2; //!< The second rewarded item + int reward_item2_count; //!< The count of the second item to be rewarded + int reward_item3; //!< The third rewarded item + int reward_item3_count; //!< The count of the third item to be rewarded + int reward_item4; //!< The fourth rewarded item + int reward_item4_count; //!< The count of the fourth item to be rewarded + int reward_emote; //!< The first emote to be rewarded + int reward_emote2; //!< The second emote to be rewarded + int reward_emote3; //!< The third emote to be rewarded + int reward_emote4; //!< The fourth emote to be rewarded + int reward_maximagination; //!< The amount of max imagination to reward + int reward_maxhealth; //!< The amount of max health to reward + int reward_maxinventory; //!< The amount of max inventory to reward + int reward_maxmodel; //!< ??? + int reward_maxwidget; //!< ??? + int reward_maxwallet; //!< ??? + bool repeatable; //!< Whether or not this mission can be repeated (for instance, is it a daily mission) + int64_t reward_currency_repeatable; //!< The repeatable reward + int reward_item1_repeatable; //!< The first rewarded item + int reward_item1_repeat_count; //!< The count of the first item to be rewarded + int reward_item2_repeatable; //!< The second rewarded item + int reward_item2_repeat_count; //!< The count of the second item to be rewarded + int reward_item3_repeatable; //!< The third rewarded item + int reward_item3_repeat_count; //!< The count of the third item to be rewarded + int reward_item4_repeatable; //!< The fourth rewarded item + int reward_item4_repeat_count; //!< The count of the fourth item to be rewarded + int time_limit; //!< The time limit of the mission + bool isMission; //!< Maybe to differentiate between missions and achievements? + int missionIconID; //!< The mission icon ID + std::string prereqMissionID; //!< A '|' seperated list of prerequisite missions + bool localize; //!< Whether or not to localize the mission + bool inMOTD; //!< In Match of the Day(?) + int64_t cooldownTime; //!< The mission cooldown time + bool isRandom; //!< ??? + std::string randomPool; //!< ??? + int UIPrereqID; //!< ??? + UNUSED(std::string gate_version); //!< The gate version + UNUSED(std::string HUDStates); //!< ??? + UNUSED(int locStatus); //!< ??? + int reward_bankinventory; //!< The amount of bank space this mission rewards }; -//! Missions table -class CDMissionsTable : public CDTable { +class CDMissionsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDMissionsTable(void); - - //! Destructor - ~CDMissionsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); + CDMissionsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; + // Gets all the entries in the table + const std::vector& GetEntries(void) const; - const CDMissions* GetPtrByMissionID(uint32_t missionID) const; + const CDMissions* GetPtrByMissionID(uint32_t missionID) const; - const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const; + const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const; - static CDMissions Default; + static CDMissions Default; }; diff --git a/dDatabase/Tables/CDMovementAIComponentTable.cpp b/dDatabase/Tables/CDMovementAIComponentTable.cpp index d4fe4881..3b9cc4f4 100644 --- a/dDatabase/Tables/CDMovementAIComponentTable.cpp +++ b/dDatabase/Tables/CDMovementAIComponentTable.cpp @@ -11,9 +11,9 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) { tableSize.nextRow(); } - + tableSize.finalize(); - + // Reserve the size this->entries.reserve(size); @@ -21,14 +21,14 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent"); while (!tableData.eof()) { CDMovementAIComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.MovementType = tableData.getStringField(1, ""); - entry.WanderChance = tableData.getFloatField(2, -1.0f); - entry.WanderDelayMin = tableData.getFloatField(3, -1.0f); - entry.WanderDelayMax = tableData.getFloatField(4, -1.0f); - entry.WanderSpeed = tableData.getFloatField(5, -1.0f); - entry.WanderRadius = tableData.getFloatField(6, -1.0f); - entry.attachedPath = tableData.getStringField(7, ""); + entry.id = tableData.getIntField("id", -1); + entry.MovementType = tableData.getStringField("MovementType", ""); + entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f); + entry.WanderDelayMin = tableData.getFloatField("WanderDelayMin", -1.0f); + entry.WanderDelayMax = tableData.getFloatField("WanderDelayMax", -1.0f); + entry.WanderSpeed = tableData.getFloatField("WanderSpeed", -1.0f); + entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f); + entry.attachedPath = tableData.getStringField("attachedPath", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -37,14 +37,6 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) { tableData.finalize(); } -//! Destructor -CDMovementAIComponentTable::~CDMovementAIComponentTable(void) { } - -//! Returns the table's name -std::string CDMovementAIComponentTable::GetName(void) const { - return "MovementAIComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDMovementAIComponentTable::Query(std::function predicate) { @@ -59,3 +51,4 @@ std::vector CDMovementAIComponentTable::Query(std::functi std::vector CDMovementAIComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDMovementAIComponentTable.h b/dDatabase/Tables/CDMovementAIComponentTable.h index 0064a98b..84896e2c 100644 --- a/dDatabase/Tables/CDMovementAIComponentTable.h +++ b/dDatabase/Tables/CDMovementAIComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMovementAIComponentTable.hpp - \brief Contains data for the MovementAIComponent table - */ - - //! MovementAIComponent Struct struct CDMovementAIComponent { unsigned int id; std::string MovementType; @@ -20,36 +14,15 @@ struct CDMovementAIComponent { std::string attachedPath; }; -//! MovementAIComponent table -class CDMovementAIComponentTable : public CDTable { +class CDMovementAIComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMovementAIComponentTable(void); - - //! Destructor - ~CDMovementAIComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMovementAIComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table std::vector GetEntries(void) const; - }; - diff --git a/dDatabase/Tables/CDObjectSkillsTable.cpp b/dDatabase/Tables/CDObjectSkillsTable.cpp index 4b133df8..2e8b3fb2 100644 --- a/dDatabase/Tables/CDObjectSkillsTable.cpp +++ b/dDatabase/Tables/CDObjectSkillsTable.cpp @@ -2,56 +2,48 @@ //! Constructor CDObjectSkillsTable::CDObjectSkillsTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ObjectSkills"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ObjectSkills"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills"); - while (!tableData.eof()) { - CDObjectSkills entry; - entry.objectTemplate = tableData.getIntField(0, -1); - entry.skillID = tableData.getIntField(1, -1); - entry.castOnType = tableData.getIntField(2, -1); - entry.AICombatWeight = tableData.getIntField(3, -1); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills"); + while (!tableData.eof()) { + CDObjectSkills entry; + entry.objectTemplate = tableData.getIntField("objectTemplate", -1); + entry.skillID = tableData.getIntField("skillID", -1); + entry.castOnType = tableData.getIntField("castOnType", -1); + entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDObjectSkillsTable::~CDObjectSkillsTable(void) { } - -//! Returns the table's name -std::string CDObjectSkillsTable::GetName(void) const { - return "ObjectSkills"; -} - //! Queries the table with a custom "where" clause std::vector CDObjectSkillsTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } //! Gets all the entries in the table std::vector CDObjectSkillsTable::GetEntries(void) const { - return this->entries; + return this->entries; } diff --git a/dDatabase/Tables/CDObjectSkillsTable.h b/dDatabase/Tables/CDObjectSkillsTable.h index 986d95d4..4ceaa447 100644 --- a/dDatabase/Tables/CDObjectSkillsTable.h +++ b/dDatabase/Tables/CDObjectSkillsTable.h @@ -3,49 +3,24 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDObjectSkillsTable.hpp - \brief Contains data for the ObjectSkills table - */ - -//! ObjectSkills Struct struct CDObjectSkills { - unsigned int objectTemplate; //!< The LOT of the item - unsigned int skillID; //!< The Skill ID of the object - unsigned int castOnType; //!< ??? - unsigned int AICombatWeight; //!< ??? + unsigned int objectTemplate; //!< The LOT of the item + unsigned int skillID; //!< The Skill ID of the object + unsigned int castOnType; //!< ??? + unsigned int AICombatWeight; //!< ??? }; -//! ObjectSkills table -class CDObjectSkillsTable : public CDTable { +class CDObjectSkillsTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDObjectSkillsTable(void); - - //! Destructor - ~CDObjectSkillsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDObjectSkillsTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + // Gets all the entries in the table + std::vector GetEntries(void) const; + }; diff --git a/dDatabase/Tables/CDObjectsTable.cpp b/dDatabase/Tables/CDObjectsTable.cpp index 5106f96a..c68c3e6a 100644 --- a/dDatabase/Tables/CDObjectsTable.cpp +++ b/dDatabase/Tables/CDObjectsTable.cpp @@ -3,39 +3,39 @@ //! Constructor CDObjectsTable::CDObjectsTable(void) { #ifdef CDCLIENT_CACHE_ALL - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Objects"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Objects"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects"); - while (!tableData.eof()) { - CDObjects entry; - entry.id = tableData.getIntField(0, -1); - entry.name = tableData.getStringField(1, ""); - entry.placeable = tableData.getIntField(2, -1); - entry.type = tableData.getStringField(3, ""); - entry.description = tableData.getStringField(4, ""); - entry.localize = tableData.getIntField(5, -1); - entry.npcTemplateID = tableData.getIntField(6, -1); - entry.displayName = tableData.getStringField(7, ""); - entry.interactionDistance = tableData.getFloatField(8, -1.0f); - entry.nametag = tableData.getIntField(9, -1); - entry._internalNotes = tableData.getStringField(10, ""); - entry.locStatus = tableData.getIntField(11, -1); - entry.gate_version = tableData.getStringField(12, ""); - entry.HQ_valid = tableData.getIntField(13, -1); - - this->entries.insert(std::make_pair(entry.id, entry)); - tableData.nextRow(); - } + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects"); + while (!tableData.eof()) { + CDObjects entry; + entry.id = tableData.getIntField("id", -1); + entry.name = tableData.getStringField("name", ""); + entry.placeable = tableData.getIntField("placeable", -1); + entry.type = tableData.getStringField("type", ""); + entry.description = tableData.getStringField("description", ""); + entry.localize = tableData.getIntField("localize", -1); + entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1); + entry.displayName = tableData.getStringField("displayName", ""); + entry.interactionDistance = tableData.getFloatField("interactionDistance", -1.0f); + entry.nametag = tableData.getIntField("nametag", -1); + entry._internalNotes = tableData.getStringField("_internalNotes", ""); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.HQ_valid = tableData.getIntField("HQ_valid", -1); + + this->entries.insert(std::make_pair(entry.id, entry)); + tableData.nextRow(); + } tableData.finalize(); #endif @@ -43,15 +43,7 @@ CDObjectsTable::CDObjectsTable(void) { m_default.id = 0; } -//! Destructor -CDObjectsTable::~CDObjectsTable(void) { } - -//! Returns the table's name -std::string CDObjectsTable::GetName(void) const { - return "Objects"; -} - -const CDObjects & CDObjectsTable::GetByID(unsigned int LOT) { +const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) { const auto& it = this->entries.find(LOT); if (it != this->entries.end()) { return it->second; @@ -63,32 +55,32 @@ const CDObjects & CDObjectsTable::GetByID(unsigned int LOT) { query << "SELECT * FROM Objects WHERE id = " << std::to_string(LOT); auto tableData = CDClientDatabase::ExecuteQuery(query.str()); - if (tableData.eof()) { - this->entries.insert(std::make_pair(LOT, m_default)); + if (tableData.eof()) { + this->entries.insert(std::make_pair(LOT, m_default)); return m_default; } - // Now get the data - while (!tableData.eof()) { - CDObjects entry; - entry.id = tableData.getIntField(0, -1); - entry.name = tableData.getStringField(1, ""); - UNUSED(entry.placeable = tableData.getIntField(2, -1)); - entry.type = tableData.getStringField(3, ""); - UNUSED(ntry.description = tableData.getStringField(4, "")); - UNUSED(entry.localize = tableData.getIntField(5, -1)); - UNUSED(entry.npcTemplateID = tableData.getIntField(6, -1)); - UNUSED(entry.displayName = tableData.getStringField(7, "")); - entry.interactionDistance = tableData.getFloatField(8, -1.0f); - UNUSED(entry.nametag = tableData.getIntField(9, -1)); - UNUSED(entry._internalNotes = tableData.getStringField(10, "")); - UNUSED(entry.locStatus = tableData.getIntField(11, -1)); - UNUSED(entry.gate_version = tableData.getStringField(12, "")); - UNUSED(entry.HQ_valid = tableData.getIntField(13, -1)); - - this->entries.insert(std::make_pair(entry.id, entry)); - tableData.nextRow(); - } + // Now get the data + while (!tableData.eof()) { + CDObjects entry; + entry.id = tableData.getIntField("id", -1); + entry.name = tableData.getStringField("name", ""); + UNUSED(entry.placeable = tableData.getIntField("placeable", -1)); + entry.type = tableData.getStringField("type", ""); + UNUSED(ntry.description = tableData.getStringField(4, "")); + UNUSED(entry.localize = tableData.getIntField("localize", -1)); + UNUSED(entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1)); + UNUSED(entry.displayName = tableData.getStringField("displayName", "")); + entry.interactionDistance = tableData.getFloatField("interactionDistance", -1.0f); + UNUSED(entry.nametag = tableData.getIntField("nametag", -1)); + UNUSED(entry._internalNotes = tableData.getStringField("_internalNotes", "")); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1)); + + this->entries.insert(std::make_pair(entry.id, entry)); + tableData.nextRow(); + } tableData.finalize(); @@ -99,4 +91,5 @@ const CDObjects & CDObjectsTable::GetByID(unsigned int LOT) { #endif return m_default; -} \ No newline at end of file +} + diff --git a/dDatabase/Tables/CDObjectsTable.h b/dDatabase/Tables/CDObjectsTable.h index c6dbc662..171eddef 100644 --- a/dDatabase/Tables/CDObjectsTable.h +++ b/dDatabase/Tables/CDObjectsTable.h @@ -3,52 +3,31 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDObjectsTable.hpp - \brief Contains data for the Objects table - */ - -//! RebuildComponent Struct struct CDObjects { - unsigned int id; //!< The LOT of the object - std::string name; //!< The internal name of the object - UNUSED(unsigned int placeable); //!< Whether or not the object is placable - std::string type; //!< The object type - UNUSED(std::string description); //!< An internal description of the object - UNUSED(unsigned int localize); //!< Whether or not the object should localize - UNUSED(unsigned int npcTemplateID); //!< Something related to NPCs... - UNUSED(std::string displayName); //!< The display name of the object - float interactionDistance; //!< The interaction distance of the object - UNUSED(unsigned int nametag); //!< ??? - UNUSED(std::string _internalNotes); //!< Some internal notes (rarely used) - UNUSED(unsigned int locStatus); //!< ??? - UNUSED(std::string gate_version); //!< The gate version for the object - UNUSED(unsigned int HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com + unsigned int id; //!< The LOT of the object + std::string name; //!< The internal name of the object + UNUSED(unsigned int placeable); //!< Whether or not the object is placable + std::string type; //!< The object type + UNUSED(std::string description); //!< An internal description of the object + UNUSED(unsigned int localize); //!< Whether or not the object should localize + UNUSED(unsigned int npcTemplateID); //!< Something related to NPCs... + UNUSED(std::string displayName); //!< The display name of the object + float interactionDistance; //!< The interaction distance of the object + UNUSED(unsigned int nametag); //!< ??? + UNUSED(std::string _internalNotes); //!< Some internal notes (rarely used) + UNUSED(unsigned int locStatus); //!< ??? + UNUSED(std::string gate_version); //!< The gate version for the object + UNUSED(unsigned int HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com }; -//! ObjectSkills table -class CDObjectsTable : public CDTable { +class CDObjectsTable : public CDTable { private: - //std::vector entries; std::map entries; CDObjects m_default; - -public: - - //! Constructor - CDObjectsTable(void); - - //! Destructor - ~CDObjectsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Gets an entry by ID - const CDObjects& GetByID(unsigned int LOT); +public: + CDObjectsTable(); + // Gets an entry by ID + const CDObjects& GetByID(unsigned int LOT); }; diff --git a/dDatabase/Tables/CDPackageComponentTable.cpp b/dDatabase/Tables/CDPackageComponentTable.cpp index 23af5e38..efb85eeb 100644 --- a/dDatabase/Tables/CDPackageComponentTable.cpp +++ b/dDatabase/Tables/CDPackageComponentTable.cpp @@ -11,9 +11,9 @@ CDPackageComponentTable::CDPackageComponentTable(void) { tableSize.nextRow(); } - + tableSize.finalize(); - + // Reserve the size this->entries.reserve(size); @@ -21,9 +21,9 @@ CDPackageComponentTable::CDPackageComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PackageComponent"); while (!tableData.eof()) { CDPackageComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.LootMatrixIndex = tableData.getIntField(1, -1); - entry.packageType = tableData.getIntField(2, -1); + entry.id = tableData.getIntField("id", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.packageType = tableData.getIntField("packageType", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -32,14 +32,6 @@ CDPackageComponentTable::CDPackageComponentTable(void) { tableData.finalize(); } -//! Destructor -CDPackageComponentTable::~CDPackageComponentTable(void) { } - -//! Returns the table's name -std::string CDPackageComponentTable::GetName(void) const { - return "PackageComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDPackageComponentTable::Query(std::function predicate) { @@ -53,4 +45,5 @@ std::vector CDPackageComponentTable::Query(std::function CDPackageComponentTable::GetEntries(void) const { return this->entries; -} \ No newline at end of file +} + diff --git a/dDatabase/Tables/CDPackageComponentTable.h b/dDatabase/Tables/CDPackageComponentTable.h index 763acf8c..6c11ab39 100644 --- a/dDatabase/Tables/CDPackageComponentTable.h +++ b/dDatabase/Tables/CDPackageComponentTable.h @@ -3,48 +3,20 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDPackageComponentTable.hpp - \brief Contains data for the PackageComponent table - */ - - //! PackageComponent Entry Struct struct CDPackageComponent { unsigned int id; unsigned int LootMatrixIndex; unsigned int packageType; }; - -//! PackageComponent table -class CDPackageComponentTable : public CDTable { +class CDPackageComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor CDPackageComponentTable(void); - - //! Destructor - ~CDPackageComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDPhysicsComponentTable.cpp b/dDatabase/Tables/CDPhysicsComponentTable.cpp index b4b836ae..bb21ed7f 100644 --- a/dDatabase/Tables/CDPhysicsComponentTable.cpp +++ b/dDatabase/Tables/CDPhysicsComponentTable.cpp @@ -1,49 +1,46 @@ #include "CDPhysicsComponentTable.h" CDPhysicsComponentTable::CDPhysicsComponentTable(void) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent"); - while (!tableData.eof()) { + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent"); + while (!tableData.eof()) { CDPhysicsComponent* entry = new CDPhysicsComponent(); - entry->id = tableData.getIntField(0, -1); - entry->bStatic = tableData.getIntField(1, -1) != 0; - entry->physicsAsset = tableData.getStringField(2, ""); - UNUSED(entry->jump = tableData.getIntField(3, -1) != 0); - UNUSED(entry->doublejump = tableData.getIntField(4, -1) != 0); - entry->speed = tableData.getFloatField(5, -1); - UNUSED(entry->rotSpeed = tableData.getFloatField(6, -1)); - entry->playerHeight = tableData.getFloatField(7); - entry->playerRadius = tableData.getFloatField(8); - entry->pcShapeType = tableData.getIntField(9); - entry->collisionGroup = tableData.getIntField(10); - UNUSED(entry->airSpeed = tableData.getFloatField(11)); - UNUSED(entry->boundaryAsset = tableData.getStringField(12)); - UNUSED(entry->jumpAirSpeed = tableData.getFloatField(13)); - UNUSED(entry->friction = tableData.getFloatField(14)); - UNUSED(entry->gravityVolumeAsset = tableData.getStringField(15)); + entry->id = tableData.getIntField("id", -1); + entry->bStatic = tableData.getIntField("static", -1) != 0; + entry->physicsAsset = tableData.getStringField("physics_asset", ""); + UNUSED(entry->jump = tableData.getIntField("jump", -1) != 0); + UNUSED(entry->doublejump = tableData.getIntField("doublejump", -1) != 0); + entry->speed = tableData.getFloatField("speed", -1); + UNUSED(entry->rotSpeed = tableData.getFloatField("rotSpeed", -1)); + entry->playerHeight = tableData.getFloatField("playerHeight"); + entry->playerRadius = tableData.getFloatField("playerRadius"); + entry->pcShapeType = tableData.getIntField("pcShapeType"); + entry->collisionGroup = tableData.getIntField("collisionGroup"); + UNUSED(entry->airSpeed = tableData.getFloatField("airSpeed")); + UNUSED(entry->boundaryAsset = tableData.getStringField("boundaryAsset")); + UNUSED(entry->jumpAirSpeed = tableData.getFloatField("jumpAirSpeed")); + UNUSED(entry->friction = tableData.getFloatField("friction")); + UNUSED(entry->gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset")); m_entries.insert(std::make_pair(entry->id, entry)); - tableData.nextRow(); - } + tableData.nextRow(); + } tableData.finalize(); } -CDPhysicsComponentTable::~CDPhysicsComponentTable(void) { - for (auto e : m_entries) { - if (e.second) delete e.second; - } - - m_entries.clear(); -} +CDPhysicsComponentTable::~CDPhysicsComponentTable() { + for (auto e : m_entries) { + if (e.second) delete e.second; + } -std::string CDPhysicsComponentTable::GetName(void) const { - return "PhysicsComponent"; + m_entries.clear(); } CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) { - for (auto e : m_entries) { + for (auto e : m_entries) { if (e.first == componentID) return e.second; - } - - return nullptr; + } + + return nullptr; } + diff --git a/dDatabase/Tables/CDPhysicsComponentTable.h b/dDatabase/Tables/CDPhysicsComponentTable.h index aa19757f..e63d337d 100644 --- a/dDatabase/Tables/CDPhysicsComponentTable.h +++ b/dDatabase/Tables/CDPhysicsComponentTable.h @@ -21,14 +21,14 @@ struct CDPhysicsComponent { UNUSED(std::string gravityVolumeAsset); }; -class CDPhysicsComponentTable : public CDTable { +class CDPhysicsComponentTable : public CDTable { public: - CDPhysicsComponentTable(void); - ~CDPhysicsComponentTable(void); - - std::string GetName(void) const override; + CDPhysicsComponentTable(); + ~CDPhysicsComponentTable(); + + static const std::string GetTableName() { return "PhysicsComponent"; }; CDPhysicsComponent* GetByID(unsigned int componentID); private: std::map m_entries; -}; \ No newline at end of file +}; diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp b/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp index 500ef659..1fead45e 100644 --- a/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp +++ b/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp @@ -3,46 +3,41 @@ CDPropertyEntranceComponentTable::CDPropertyEntranceComponentTable() { - // First, get the size of the table - size_t size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM PropertyEntranceComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - tableSize.nextRow(); - } - + // First, get the size of the table + size_t size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM PropertyEntranceComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + tableSize.nextRow(); + } + tableSize.finalize(); - - this->entries.reserve(size); - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyEntranceComponent;"); - while (!tableData.eof()) { - auto entry = CDPropertyEntranceComponent { - static_cast(tableData.getIntField(0, -1)), - static_cast(tableData.getIntField(1, -1)), - tableData.getStringField(2, ""), - static_cast(tableData.getIntField(3, false)), - tableData.getStringField(4, "") - }; + this->entries.reserve(size); - this->entries.push_back(entry); - tableData.nextRow(); - } + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyEntranceComponent;"); + while (!tableData.eof()) { + auto entry = CDPropertyEntranceComponent{ + static_cast(tableData.getIntField("id", -1)), + static_cast(tableData.getIntField("mapID", -1)), + tableData.getStringField("propertyName", ""), + static_cast(tableData.getIntField("isOnProperty", false)), + tableData.getStringField("groupType", "") + }; + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -CDPropertyEntranceComponentTable::~CDPropertyEntranceComponentTable(void) = default; - -std::string CDPropertyEntranceComponentTable::GetName() const { - return "PropertyEntranceComponent"; -} - CDPropertyEntranceComponent CDPropertyEntranceComponentTable::GetByID(uint32_t id) { - for (const auto& entry : entries) { - if (entry.id == id) - return entry; - } + for (const auto& entry : entries) { + if (entry.id == id) + return entry; + } - return defaultEntry; + return defaultEntry; } + diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.h b/dDatabase/Tables/CDPropertyEntranceComponentTable.h index 8cecd941..925fd1be 100644 --- a/dDatabase/Tables/CDPropertyEntranceComponentTable.h +++ b/dDatabase/Tables/CDPropertyEntranceComponentTable.h @@ -2,40 +2,22 @@ #include "CDTable.h" struct CDPropertyEntranceComponent { - uint32_t id; - uint32_t mapID; - std::string propertyName; - bool isOnProperty; - std::string groupType; + uint32_t id; + uint32_t mapID; + std::string propertyName; + bool isOnProperty; + std::string groupType; }; -class CDPropertyEntranceComponentTable : public CDTable { +class CDPropertyEntranceComponentTable : public CDTable { public: - //! Constructor - CDPropertyEntranceComponentTable(); + CDPropertyEntranceComponentTable(); + // Queries the table with a custom "where" clause + CDPropertyEntranceComponent GetByID(uint32_t id); - //! Destructor - ~CDPropertyEntranceComponentTable(); - - //! Returns the table's name - /*! - \return The table name - */ - [[nodiscard]] std::string GetName() const override; - - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - CDPropertyEntranceComponent GetByID(uint32_t id); - - //! Gets all the entries in the table - /*! - \return The entries - */ - [[nodiscard]] std::vector GetEntries() const { return entries; } + // Gets all the entries in the table + [[nodiscard]] std::vector GetEntries() const { return entries; } private: - std::vector entries {}; - CDPropertyEntranceComponent defaultEntry {}; + std::vector entries{}; + CDPropertyEntranceComponent defaultEntry{}; }; diff --git a/dDatabase/Tables/CDPropertyTemplateTable.cpp b/dDatabase/Tables/CDPropertyTemplateTable.cpp index 11ba9378..4caa6dc5 100644 --- a/dDatabase/Tables/CDPropertyTemplateTable.cpp +++ b/dDatabase/Tables/CDPropertyTemplateTable.cpp @@ -2,45 +2,40 @@ CDPropertyTemplateTable::CDPropertyTemplateTable() { - // First, get the size of the table - size_t size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM PropertyTemplate;"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - tableSize.nextRow(); - } - + // First, get the size of the table + size_t size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM PropertyTemplate;"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + tableSize.nextRow(); + } + tableSize.finalize(); - - this->entries.reserve(size); - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyTemplate;"); - while (!tableData.eof()) { - auto entry = CDPropertyTemplate { - static_cast(tableData.getIntField(0, -1)), - static_cast(tableData.getIntField(1, -1)), - static_cast(tableData.getIntField(2, -1)), - tableData.getStringField(3, "") - }; + this->entries.reserve(size); - this->entries.push_back(entry); - tableData.nextRow(); - } + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyTemplate;"); + while (!tableData.eof()) { + auto entry = CDPropertyTemplate{ + static_cast(tableData.getIntField("id", -1)), + static_cast(tableData.getIntField("mapID", -1)), + static_cast(tableData.getIntField("vendorMapID", -1)), + tableData.getStringField("spawnName", "") + }; + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -CDPropertyTemplateTable::~CDPropertyTemplateTable() = default; - -std::string CDPropertyTemplateTable::GetName() const { - return "PropertyTemplate"; -} - CDPropertyTemplate CDPropertyTemplateTable::GetByMapID(uint32_t mapID) { - for (const auto& entry : entries) { - if (entry.mapID == mapID) - return entry; - } + for (const auto& entry : entries) { + if (entry.mapID == mapID) + return entry; + } - return defaultEntry; + return defaultEntry; } + diff --git a/dDatabase/Tables/CDPropertyTemplateTable.h b/dDatabase/Tables/CDPropertyTemplateTable.h index 24e6a739..cb075dbf 100644 --- a/dDatabase/Tables/CDPropertyTemplateTable.h +++ b/dDatabase/Tables/CDPropertyTemplateTable.h @@ -2,20 +2,19 @@ #include "CDTable.h" struct CDPropertyTemplate { - uint32_t id; - uint32_t mapID; - uint32_t vendorMapID; - std::string spawnName; + uint32_t id; + uint32_t mapID; + uint32_t vendorMapID; + std::string spawnName; }; -class CDPropertyTemplateTable : public CDTable { +class CDPropertyTemplateTable : public CDTable { public: - CDPropertyTemplateTable(); - ~CDPropertyTemplateTable(); + CDPropertyTemplateTable(); - [[nodiscard]] std::string GetName() const override; - CDPropertyTemplate GetByMapID(uint32_t mapID); + static const std::string GetTableName() { return "PropertyTemplate"; }; + CDPropertyTemplate GetByMapID(uint32_t mapID); private: - std::vector entries {}; - CDPropertyTemplate defaultEntry {}; -}; \ No newline at end of file + std::vector entries{}; + CDPropertyTemplate defaultEntry{}; +}; diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.cpp b/dDatabase/Tables/CDProximityMonitorComponentTable.cpp index d4195f0c..688de056 100644 --- a/dDatabase/Tables/CDProximityMonitorComponentTable.cpp +++ b/dDatabase/Tables/CDProximityMonitorComponentTable.cpp @@ -11,9 +11,9 @@ CDProximityMonitorComponentTable::CDProximityMonitorComponentTable(void) { tableSize.nextRow(); } - + tableSize.finalize(); - + // Reserve the size this->entries.reserve(size); @@ -21,10 +21,10 @@ CDProximityMonitorComponentTable::CDProximityMonitorComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ProximityMonitorComponent"); while (!tableData.eof()) { CDProximityMonitorComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.Proximities = tableData.getStringField(1, ""); - entry.LoadOnClient = tableData.getIntField(2, -1); - entry.LoadOnServer = tableData.getIntField(3, -1); + entry.id = tableData.getIntField("id", -1); + entry.Proximities = tableData.getStringField("Proximities", ""); + entry.LoadOnClient = tableData.getIntField("LoadOnClient", -1); + entry.LoadOnServer = tableData.getIntField("LoadOnServer", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -33,14 +33,6 @@ CDProximityMonitorComponentTable::CDProximityMonitorComponentTable(void) { tableData.finalize(); } -//! Destructor -CDProximityMonitorComponentTable::~CDProximityMonitorComponentTable(void) { } - -//! Returns the table's name -std::string CDProximityMonitorComponentTable::GetName(void) const { - return "ProximityMonitorComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDProximityMonitorComponentTable::Query(std::function predicate) { @@ -55,3 +47,4 @@ std::vector CDProximityMonitorComponentTable::Query std::vector CDProximityMonitorComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.h b/dDatabase/Tables/CDProximityMonitorComponentTable.h index 007bb916..38b7d43b 100644 --- a/dDatabase/Tables/CDProximityMonitorComponentTable.h +++ b/dDatabase/Tables/CDProximityMonitorComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDProximityMonitorComponentTable.hpp - \brief Contains data for the ProximityMonitorComponent table - */ - - //! ProximityMonitorComponent Entry Struct struct CDProximityMonitorComponent { unsigned int id; std::string Proximities; @@ -16,36 +10,14 @@ struct CDProximityMonitorComponent { bool LoadOnServer; }; - -//! ProximityMonitorComponent table -class CDProximityMonitorComponentTable : public CDTable { +class CDProximityMonitorComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor CDProximityMonitorComponentTable(void); - - //! Destructor - ~CDProximityMonitorComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDRailActivatorComponent.cpp b/dDatabase/Tables/CDRailActivatorComponent.cpp index e3a2f8b8..2ff8990d 100644 --- a/dDatabase/Tables/CDRailActivatorComponent.cpp +++ b/dDatabase/Tables/CDRailActivatorComponent.cpp @@ -2,82 +2,66 @@ #include "GeneralUtils.h" CDRailActivatorComponentTable::CDRailActivatorComponentTable() { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RailActivatorComponent;"); - while (!tableData.eof()) { - CDRailActivatorComponent entry; + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RailActivatorComponent;"); + while (!tableData.eof()) { + CDRailActivatorComponent entry; - entry.id = tableData.getIntField(0); + entry.id = tableData.getIntField("id", 0); - std::string startAnimation(tableData.getStringField(1, "")); - entry.startAnimation = GeneralUtils::ASCIIToUTF16(startAnimation); + entry.startAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("startAnim", "")); + entry.loopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("loopAnim", "")); + entry.stopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("stopAnim", "")); + entry.startSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("startSound", "")); + entry.loopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("loopSound", "")); + entry.stopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("stopSound", "")); - std::string loopAnimation(tableData.getStringField(2, "")); - entry.loopAnimation = GeneralUtils::ASCIIToUTF16(loopAnimation); + std::string loopEffectString(tableData.getStringField("effectIDs", "")); + entry.loopEffectID = EffectPairFromString(loopEffectString); - std::string stopAnimation(tableData.getStringField(3, "")); - entry.stopAnimation = GeneralUtils::ASCIIToUTF16(stopAnimation); + entry.preconditions = tableData.getStringField("preconditions", "-1"); - std::string startSound(tableData.getStringField(4, "")); - entry.startSound = GeneralUtils::ASCIIToUTF16(startSound); + entry.playerCollision = tableData.getIntField("playerCollision", 0); - std::string loopSound(tableData.getStringField(5, "")); - entry.loopSound = GeneralUtils::ASCIIToUTF16(loopSound); + entry.cameraLocked = tableData.getIntField("cameraLocked", 0); - std::string stopSound(tableData.getStringField(6, "")); - entry.stopSound = GeneralUtils::ASCIIToUTF16(stopSound); + std::string startEffectString(tableData.getStringField("StartEffectID", "")); + entry.startEffectID = EffectPairFromString(startEffectString); - std::string loopEffectString(tableData.getStringField(7, "")); - entry.loopEffectID = EffectPairFromString(loopEffectString); + std::string stopEffectString(tableData.getStringField("StopEffectID", "")); + entry.stopEffectID = EffectPairFromString(stopEffectString); - entry.preconditions = tableData.getStringField(8, "-1"); + entry.damageImmune = tableData.getIntField("DamageImmune", 0); - entry.playerCollision = tableData.getIntField(9, 0); + entry.noAggro = tableData.getIntField("NoAggro", 0); - entry.cameraLocked = tableData.getIntField(10, 0); + entry.showNameBillboard = tableData.getIntField("ShowNameBillboard", 0); - std::string startEffectString(tableData.getStringField(11, "")); - entry.startEffectID = EffectPairFromString(startEffectString); + m_Entries.push_back(entry); + tableData.nextRow(); + } - std::string stopEffectString(tableData.getStringField(12, "")); - entry.stopEffectID = EffectPairFromString(stopEffectString); - - entry.damageImmune = tableData.getIntField(13, 0); - - entry.noAggro = tableData.getIntField(14, 0); - - entry.showNameBillboard = tableData.getIntField(15, 0); - - m_Entries.push_back(entry); - tableData.nextRow(); - } - - tableData.finalize(); -} - -CDRailActivatorComponentTable::~CDRailActivatorComponentTable() = default; - -std::string CDRailActivatorComponentTable::GetName() const { - return "RailActivatorComponent"; + tableData.finalize(); } CDRailActivatorComponent CDRailActivatorComponentTable::GetEntryByID(int32_t id) const { - for (const auto& entry : m_Entries) { - if (entry.id == id) - return entry; - } + for (const auto& entry : m_Entries) { + if (entry.id == id) + return entry; + } - return {}; + return {}; } std::vector CDRailActivatorComponentTable::GetEntries() const { - return m_Entries; + return m_Entries; } -std::pair CDRailActivatorComponentTable::EffectPairFromString(std::string &str) { - const auto split = GeneralUtils::SplitString(str, ':'); - if (split.size() == 2) { - return { std::stoi(split.at(0)), GeneralUtils::ASCIIToUTF16(split.at(1)) }; - } +std::pair CDRailActivatorComponentTable::EffectPairFromString(std::string& str) { + const auto split = GeneralUtils::SplitString(str, ':'); + if (split.size() == 2) { + return { std::stoi(split.at(0)), GeneralUtils::ASCIIToUTF16(split.at(1)) }; + } - return {}; + return {}; } + diff --git a/dDatabase/Tables/CDRailActivatorComponent.h b/dDatabase/Tables/CDRailActivatorComponent.h index 4f06ff5f..03dd0525 100644 --- a/dDatabase/Tables/CDRailActivatorComponent.h +++ b/dDatabase/Tables/CDRailActivatorComponent.h @@ -2,33 +2,31 @@ #include "CDTable.h" struct CDRailActivatorComponent { - int32_t id; - std::u16string startAnimation; - std::u16string loopAnimation; - std::u16string stopAnimation; - std::u16string startSound; - std::u16string loopSound; - std::u16string stopSound; - std::pair startEffectID; - std::pair loopEffectID; - std::pair stopEffectID; - std::string preconditions; - bool playerCollision; - bool cameraLocked; - bool damageImmune; - bool noAggro; - bool showNameBillboard; + int32_t id; + std::u16string startAnimation; + std::u16string loopAnimation; + std::u16string stopAnimation; + std::u16string startSound; + std::u16string loopSound; + std::u16string stopSound; + std::pair startEffectID; + std::pair loopEffectID; + std::pair stopEffectID; + std::string preconditions; + bool playerCollision; + bool cameraLocked; + bool damageImmune; + bool noAggro; + bool showNameBillboard; }; -class CDRailActivatorComponentTable : public CDTable { +class CDRailActivatorComponentTable : public CDTable { public: - CDRailActivatorComponentTable(); - ~CDRailActivatorComponentTable(); - - std::string GetName() const override; - [[nodiscard]] CDRailActivatorComponent GetEntryByID(int32_t id) const; - [[nodiscard]] std::vector GetEntries() const; + CDRailActivatorComponentTable(); + static const std::string GetTableName() { return "RailActivatorComponent"; }; + [[nodiscard]] CDRailActivatorComponent GetEntryByID(int32_t id) const; + [[nodiscard]] std::vector GetEntries() const; private: - static std::pair EffectPairFromString(std::string& str); - std::vector m_Entries {}; + static std::pair EffectPairFromString(std::string& str); + std::vector m_Entries{}; }; diff --git a/dDatabase/Tables/CDRarityTableTable.cpp b/dDatabase/Tables/CDRarityTableTable.cpp index da41e3f3..0b1212c0 100644 --- a/dDatabase/Tables/CDRarityTableTable.cpp +++ b/dDatabase/Tables/CDRarityTableTable.cpp @@ -3,55 +3,48 @@ //! Constructor CDRarityTableTable::CDRarityTableTable(void) { - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RarityTable"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RarityTable"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } - tableSize.nextRow(); - } - tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RarityTable"); - while (!tableData.eof()) { - CDRarityTable entry; - entry.id = tableData.getIntField(0, -1); - entry.randmax = tableData.getFloatField(1, -1); - entry.rarity = tableData.getIntField(2, -1); - entry.RarityTableIndex = tableData.getIntField(3, -1); + // Reserve the size + this->entries.reserve(size); - this->entries.push_back(entry); - tableData.nextRow(); - } + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RarityTable"); + while (!tableData.eof()) { + CDRarityTable entry; + entry.id = tableData.getIntField("id", -1); + entry.randmax = tableData.getFloatField("randmax", -1); + entry.rarity = tableData.getIntField("rarity", -1); + entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDRarityTableTable::~CDRarityTableTable(void) { } - -//! Returns the table's name -std::string CDRarityTableTable::GetName(void) const { - return "RarityTable"; -} - //! Queries the table with a custom "where" clause std::vector CDRarityTableTable::Query(std::function predicate) { - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); - return data; + return data; } //! Gets all the entries in the table const std::vector& CDRarityTableTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDRarityTableTable.h b/dDatabase/Tables/CDRarityTableTable.h index 0a57e903..592346ed 100644 --- a/dDatabase/Tables/CDRarityTableTable.h +++ b/dDatabase/Tables/CDRarityTableTable.h @@ -3,70 +3,38 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDRarityTableTable.hpp - \brief Contains data for the RarityTable table - */ - - //! RarityTable Entry Struct struct CDRarityTable { - unsigned int id; - float randmax; - unsigned int rarity; - unsigned int RarityTableIndex; + unsigned int id; + float randmax; + unsigned int rarity; + unsigned int RarityTableIndex; - friend bool operator> (const CDRarityTable& c1, const CDRarityTable& c2) - { - return c1.rarity > c2.rarity; - } + friend bool operator> (const CDRarityTable& c1, const CDRarityTable& c2) { + return c1.rarity > c2.rarity; + } - friend bool operator>= (const CDRarityTable& c1, const CDRarityTable& c2) - { - return c1.rarity >= c2.rarity; - } + friend bool operator>= (const CDRarityTable& c1, const CDRarityTable& c2) { + return c1.rarity >= c2.rarity; + } - friend bool operator< (const CDRarityTable& c1, const CDRarityTable& c2) - { - return c1.rarity < c2.rarity; - } + friend bool operator< (const CDRarityTable& c1, const CDRarityTable& c2) { + return c1.rarity < c2.rarity; + } - friend bool operator<= (const CDRarityTable& c1, const CDRarityTable& c2) - { - return c1.rarity <= c2.rarity; - } + friend bool operator<= (const CDRarityTable& c1, const CDRarityTable& c2) { + return c1.rarity <= c2.rarity; + } }; - -//! RarityTable table -class CDRarityTableTable : public CDTable { +class CDRarityTableTable : public CDTable { private: - std::vector entries; + std::vector entries; public: + CDRarityTableTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); - //! Constructor - CDRarityTableTable(void); - - //! Destructor - ~CDRarityTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; - + const std::vector& GetEntries() const; }; diff --git a/dDatabase/Tables/CDRebuildComponentTable.cpp b/dDatabase/Tables/CDRebuildComponentTable.cpp index a1b5646c..d5c386d1 100644 --- a/dDatabase/Tables/CDRebuildComponentTable.cpp +++ b/dDatabase/Tables/CDRebuildComponentTable.cpp @@ -2,62 +2,55 @@ //! Constructor CDRebuildComponentTable::CDRebuildComponentTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RebuildComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RebuildComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Reserve the size - this->entries.reserve(size); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RebuildComponent"); - while (!tableData.eof()) { - CDRebuildComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.reset_time = tableData.getFloatField(1, -1.0f); - entry.complete_time = tableData.getFloatField(2, -1.0f); - entry.take_imagination = tableData.getIntField(3, -1); - entry.interruptible = tableData.getIntField(4, -1) == 1 ? true : false; - entry.self_activator = tableData.getIntField(5, -1) == 1 ? true : false; - entry.custom_modules = tableData.getStringField(6, ""); - entry.activityID = tableData.getIntField(7, -1); - entry.post_imagination_cost = tableData.getIntField(8, -1); - entry.time_before_smash = tableData.getFloatField(9, -1.0f); - - this->entries.push_back(entry); - tableData.nextRow(); - } + + // Reserve the size + this->entries.reserve(size); + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RebuildComponent"); + while (!tableData.eof()) { + CDRebuildComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.reset_time = tableData.getFloatField("reset_time", -1.0f); + entry.complete_time = tableData.getFloatField("complete_time", -1.0f); + entry.take_imagination = tableData.getIntField("take_imagination", -1); + entry.interruptible = tableData.getIntField("interruptible", -1) == 1 ? true : false; + entry.self_activator = tableData.getIntField("self_activator", -1) == 1 ? true : false; + entry.custom_modules = tableData.getStringField("custom_modules", ""); + entry.activityID = tableData.getIntField("activityID", -1); + entry.post_imagination_cost = tableData.getIntField("post_imagination_cost", -1); + entry.time_before_smash = tableData.getFloatField("time_before_smash", -1.0f); + + this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDRebuildComponentTable::~CDRebuildComponentTable(void) { } - -//! Returns the table's name -std::string CDRebuildComponentTable::GetName(void) const { - return "RebuildComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDRebuildComponentTable::Query(std::function predicate) { - - std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data; + + std::vector data = cpplinq::from(this->entries) + >> cpplinq::where(predicate) + >> cpplinq::to_vector(); + + return data; } //! Gets all the entries in the table std::vector CDRebuildComponentTable::GetEntries(void) const { - return this->entries; + return this->entries; } + diff --git a/dDatabase/Tables/CDRebuildComponentTable.h b/dDatabase/Tables/CDRebuildComponentTable.h index 49d2e44f..db70a47d 100644 --- a/dDatabase/Tables/CDRebuildComponentTable.h +++ b/dDatabase/Tables/CDRebuildComponentTable.h @@ -3,55 +3,28 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDRebuildComponentTable.hpp - \brief Contains data for the RebuildComponent table - */ - -//! RebuildComponent Struct struct CDRebuildComponent { - unsigned int id; //!< The component Id - float reset_time; //!< The reset time - float complete_time; //!< The complete time - unsigned int take_imagination; //!< The amount of imagination it costs - bool interruptible; //!< Whether or not the rebuild is interruptible - bool self_activator; //!< Whether or not the rebuild is a rebuild activator itself - std::string custom_modules; //!< The custom modules - unsigned int activityID; //!< The activity ID - unsigned int post_imagination_cost; //!< The post imagination cost - float time_before_smash; //!< The time before smash + unsigned int id; //!< The component Id + float reset_time; //!< The reset time + float complete_time; //!< The complete time + unsigned int take_imagination; //!< The amount of imagination it costs + bool interruptible; //!< Whether or not the rebuild is interruptible + bool self_activator; //!< Whether or not the rebuild is a rebuild activator itself + std::string custom_modules; //!< The custom modules + unsigned int activityID; //!< The activity ID + unsigned int post_imagination_cost; //!< The post imagination cost + float time_before_smash; //!< The time before smash }; -//! ObjectSkills table -class CDRebuildComponentTable : public CDTable { +class CDRebuildComponentTable : public CDTable { private: - std::vector entries; - + std::vector entries; + public: - - //! Constructor - CDRebuildComponentTable(void); - - //! Destructor - ~CDRebuildComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + CDRebuildComponentTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); + + std::vector GetEntries() const; }; diff --git a/dDatabase/Tables/CDRewardsTable.cpp b/dDatabase/Tables/CDRewardsTable.cpp index 2f7d1778..55672add 100644 --- a/dDatabase/Tables/CDRewardsTable.cpp +++ b/dDatabase/Tables/CDRewardsTable.cpp @@ -1,40 +1,37 @@ #include "CDRewardsTable.h" CDRewardsTable::CDRewardsTable(void) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Rewards"); - while (!tableData.eof()) { + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Rewards"); + while (!tableData.eof()) { CDRewards* entry = new CDRewards(); - entry->id = tableData.getIntField(0, -1); - entry->levelID = tableData.getIntField(1, -1); - entry->missionID = tableData.getIntField(2, -1); - entry->rewardType = tableData.getIntField(3, -1); - entry->value = tableData.getIntField(4, -1); - entry->count = tableData.getIntField(5, -1); + entry->id = tableData.getIntField("id", -1); + entry->levelID = tableData.getIntField("LevelID", -1); + entry->missionID = tableData.getIntField("MissionID", -1); + entry->rewardType = tableData.getIntField("RewardType", -1); + entry->value = tableData.getIntField("value", -1); + entry->count = tableData.getIntField("count", -1); m_entries.insert(std::make_pair(entry->id, entry)); - tableData.nextRow(); - } + tableData.nextRow(); + } tableData.finalize(); } CDRewardsTable::~CDRewardsTable(void) { - for (auto e : m_entries) { - if (e.second) delete e.second; - } - - m_entries.clear(); -} + for (auto e : m_entries) { + if (e.second) delete e.second; + } -std::string CDRewardsTable::GetName(void) const { - return "Rewards"; + m_entries.clear(); } std::vector CDRewardsTable::GetByLevelID(uint32_t levelID) { - std::vector result {}; - for (const auto& e : m_entries) { + std::vector result{}; + for (const auto& e : m_entries) { if (e.second->levelID == levelID) result.push_back(e.second); - } - - return result; + } + + return result; } + diff --git a/dDatabase/Tables/CDRewardsTable.h b/dDatabase/Tables/CDRewardsTable.h index c4f9fb70..2e079a83 100644 --- a/dDatabase/Tables/CDRewardsTable.h +++ b/dDatabase/Tables/CDRewardsTable.h @@ -11,14 +11,14 @@ struct CDRewards { int32_t count; }; -class CDRewardsTable : public CDTable { +class CDRewardsTable : public CDTable { public: - CDRewardsTable(void); - ~CDRewardsTable(void); - - std::string GetName(void) const override; + CDRewardsTable(); + ~CDRewardsTable(); + + static const std::string GetTableName() { return "Rewards"; }; std::vector GetByLevelID(uint32_t levelID); private: std::map m_entries; -}; \ No newline at end of file +}; diff --git a/dDatabase/Tables/CDScriptComponentTable.cpp b/dDatabase/Tables/CDScriptComponentTable.cpp index 11ab75ee..8050c139 100644 --- a/dDatabase/Tables/CDScriptComponentTable.cpp +++ b/dDatabase/Tables/CDScriptComponentTable.cpp @@ -2,41 +2,33 @@ //! Constructor CDScriptComponentTable::CDScriptComponentTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ScriptComponent"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ScriptComponent"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ScriptComponent"); - while (!tableData.eof()) { - CDScriptComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.script_name = tableData.getStringField(1, ""); - entry.client_script_name = tableData.getStringField(2, ""); - + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ScriptComponent"); + while (!tableData.eof()) { + CDScriptComponent entry; + entry.id = tableData.getIntField("id", -1); + entry.script_name = tableData.getStringField("script_name", ""); + entry.client_script_name = tableData.getStringField("client_script_name", ""); + this->entries.insert(std::make_pair(entry.id, entry)); - tableData.nextRow(); - } + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDScriptComponentTable::~CDScriptComponentTable(void) { } - -//! Returns the table's name -std::string CDScriptComponentTable::GetName(void) const { - return "ScriptComponent"; -} - const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) { std::map::iterator it = this->entries.find(id); if (it != this->entries.end()) { @@ -44,4 +36,5 @@ const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) { } return m_ToReturnWhenNoneFound; -} \ No newline at end of file +} + diff --git a/dDatabase/Tables/CDScriptComponentTable.h b/dDatabase/Tables/CDScriptComponentTable.h index 7fc802fa..77453939 100644 --- a/dDatabase/Tables/CDScriptComponentTable.h +++ b/dDatabase/Tables/CDScriptComponentTable.h @@ -3,44 +3,20 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDScriptComponentTable.hpp - \brief Contains data for the ScriptComponent table - */ - -//! ScriptComponent Struct struct CDScriptComponent { - unsigned int id; //!< The component ID - std::string script_name; //!< The script name - std::string client_script_name; //!< The client script name + unsigned int id; //!< The component ID + std::string script_name; //!< The script name + std::string client_script_name; //!< The client script name }; -//! ObjectSkills table -class CDScriptComponentTable : public CDTable { +class CDScriptComponentTable : public CDTable { private: - std::map entries; + std::map entries; CDScriptComponent m_ToReturnWhenNoneFound; - + public: - //! Gets an entry by ID + CDScriptComponentTable(); + // Gets an entry by scriptID const CDScriptComponent& GetByID(unsigned int id); - - //! Constructor - CDScriptComponentTable(void); - - //! Destructor - ~CDScriptComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - }; diff --git a/dDatabase/Tables/CDSkillBehaviorTable.cpp b/dDatabase/Tables/CDSkillBehaviorTable.cpp index ad79997d..c5df78ef 100644 --- a/dDatabase/Tables/CDSkillBehaviorTable.cpp +++ b/dDatabase/Tables/CDSkillBehaviorTable.cpp @@ -3,82 +3,67 @@ //! Constructor CDSkillBehaviorTable::CDSkillBehaviorTable(void) { - m_empty = CDSkillBehavior(); + m_empty = CDSkillBehavior(); - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM SkillBehavior"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM SkillBehavior"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } - tableSize.nextRow(); - } - tableSize.finalize(); - - // Reserve the size - //this->entries.reserve(size); - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM SkillBehavior"); - while (!tableData.eof()) { - CDSkillBehavior entry; - entry.skillID = tableData.getIntField(0, -1); - UNUSED(entry.locStatus = tableData.getIntField(1, -1)); - entry.behaviorID = tableData.getIntField(2, -1); - entry.imaginationcost = tableData.getIntField(3, -1); - entry.cooldowngroup = tableData.getIntField(4, -1); - entry.cooldown = tableData.getFloatField(5, -1.0f); - UNUSED(entry.isNpcEditor = tableData.getIntField(6, -1) == 1 ? true : false); - UNUSED(entry.skillIcon = tableData.getIntField(7, -1)); - UNUSED(entry.oomSkillID = tableData.getStringField(8, "")); - UNUSED(entry.oomBehaviorEffectID = tableData.getIntField(9, -1)); - UNUSED(entry.castTypeDesc = tableData.getIntField(10, -1)); - UNUSED(entry.imBonusUI = tableData.getIntField(11, -1)); - UNUSED(entry.lifeBonusUI = tableData.getIntField(12, -1)); - UNUSED(entry.armorBonusUI = tableData.getIntField(13, -1)); - UNUSED(entry.damageUI = tableData.getIntField(14, -1)); - UNUSED(entry.hideIcon = tableData.getIntField(15, -1) == 1 ? true : false); - UNUSED(entry.localize = tableData.getIntField(16, -1) == 1 ? true : false); - UNUSED(entry.gate_version = tableData.getStringField(17, "")); - UNUSED(entry.cancelType = tableData.getIntField(18, -1)); + // Reserve the size + //this->entries.reserve(size); - this->entries.insert(std::make_pair(entry.skillID, entry)); - //this->entries.push_back(entry); - tableData.nextRow(); - } + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM SkillBehavior"); + while (!tableData.eof()) { + CDSkillBehavior entry; + entry.skillID = tableData.getIntField("skillID", -1); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.behaviorID = tableData.getIntField("behaviorID", -1); + entry.imaginationcost = tableData.getIntField("imaginationcost", -1); + entry.cooldowngroup = tableData.getIntField("cooldowngroup", -1); + entry.cooldown = tableData.getFloatField("cooldown", -1.0f); + UNUSED(entry.isNpcEditor = tableData.getIntField("isNpcEditor", -1) == 1 ? true : false); + UNUSED(entry.skillIcon = tableData.getIntField("skillIcon", -1)); + UNUSED(entry.oomSkillID = tableData.getStringField("oomSkillID", "")); + UNUSED(entry.oomBehaviorEffectID = tableData.getIntField("oomBehaviorEffectID", -1)); + UNUSED(entry.castTypeDesc = tableData.getIntField("castTypeDesc", -1)); + UNUSED(entry.imBonusUI = tableData.getIntField("imBonusUI", -1)); + UNUSED(entry.lifeBonusUI = tableData.getIntField("lifeBonusUI", -1)); + UNUSED(entry.armorBonusUI = tableData.getIntField("armorBonusUI", -1)); + UNUSED(entry.damageUI = tableData.getIntField("damageUI", -1)); + UNUSED(entry.hideIcon = tableData.getIntField("hideIcon", -1) == 1 ? true : false); + UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.cancelType = tableData.getIntField("cancelType", -1)); + + this->entries.insert(std::make_pair(entry.skillID, entry)); + //this->entries.push_back(entry); + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDSkillBehaviorTable::~CDSkillBehaviorTable(void) { } - -//! Returns the table's name -std::string CDSkillBehaviorTable::GetName(void) const { - return "SkillBehavior"; -} - //! Queries the table with a custom "where" clause std::vector CDSkillBehaviorTable::Query(std::function predicate) { - - /*std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data;*/ - - //Logger::LogDebug("CDSkillBehaviorTable", "The 'Query' function is no longer working! Please use GetSkillByID instead!\n"); std::vector data; //So MSVC shuts up return data; } //! Gets an entry by ID const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(unsigned int skillID) { - std::map::iterator it = this->entries.find(skillID); - if (it != this->entries.end()) { - return it->second; - } + std::map::iterator it = this->entries.find(skillID); + if (it != this->entries.end()) { + return it->second; + } - return m_empty; + return m_empty; } + diff --git a/dDatabase/Tables/CDSkillBehaviorTable.h b/dDatabase/Tables/CDSkillBehaviorTable.h index d70dca56..eb3094e0 100644 --- a/dDatabase/Tables/CDSkillBehaviorTable.h +++ b/dDatabase/Tables/CDSkillBehaviorTable.h @@ -3,61 +3,39 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDSkillBehaviorTable.hpp - \brief Contains data for the SkillBehavior table - */ - -//! ZoneTable Struct struct CDSkillBehavior { - unsigned int skillID; //!< The Skill ID of the skill - UNUSED(unsigned int locStatus); //!< ?? - unsigned int behaviorID; //!< The Behavior ID of the skill - unsigned int imaginationcost; //!< The imagination cost of the skill - unsigned int cooldowngroup; //!< The cooldown group ID of the skill - float cooldown; //!< The cooldown time of the skill - UNUSED(bool isNpcEditor); //!< ??? - UNUSED(unsigned int skillIcon); //!< The Skill Icon ID - UNUSED(std::string oomSkillID); //!< ??? - UNUSED(unsigned int oomBehaviorEffectID); //!< ??? - UNUSED(unsigned int castTypeDesc); //!< The cast type description(?) - UNUSED(unsigned int imBonusUI); //!< The imagination bonus of the skill - UNUSED(nsigned int lifeBonusUI); //!< The life bonus of the skill - UNUSED(unsigned int armorBonusUI); //!< The armor bonus of the skill - UNUSED(unsigned int damageUI); //!< ??? - UNUSED(bool hideIcon); //!< Whether or not to show the icon - UNUSED(bool localize); //!< ??? - UNUSED(std::string gate_version); //!< ??? - UNUSED(unsigned int cancelType); //!< The cancel type (?) + unsigned int skillID; //!< The Skill ID of the skill + UNUSED(unsigned int locStatus); //!< ?? + unsigned int behaviorID; //!< The Behavior ID of the skill + unsigned int imaginationcost; //!< The imagination cost of the skill + unsigned int cooldowngroup; //!< The cooldown group ID of the skill + float cooldown; //!< The cooldown time of the skill + UNUSED(bool isNpcEditor); //!< ??? + UNUSED(unsigned int skillIcon); //!< The Skill Icon ID + UNUSED(std::string oomSkillID); //!< ??? + UNUSED(unsigned int oomBehaviorEffectID); //!< ??? + UNUSED(unsigned int castTypeDesc); //!< The cast type description(?) + UNUSED(unsigned int imBonusUI); //!< The imagination bonus of the skill + UNUSED(nsigned int lifeBonusUI); //!< The life bonus of the skill + UNUSED(unsigned int armorBonusUI); //!< The armor bonus of the skill + UNUSED(unsigned int damageUI); //!< ??? + UNUSED(bool hideIcon); //!< Whether or not to show the icon + UNUSED(bool localize); //!< ??? + UNUSED(std::string gate_version); //!< ??? + UNUSED(unsigned int cancelType); //!< The cancel type (?) }; -//! SkillBehavior table -class CDSkillBehaviorTable : public CDTable { +class CDSkillBehaviorTable : public CDTable { private: - std::map entries; - CDSkillBehavior m_empty; + std::map entries; + CDSkillBehavior m_empty; public: + CDSkillBehaviorTable(); + // Queries the table with a custom "where" clause + std::vector Query(std::function predicate); - //! Constructor - CDSkillBehaviorTable(void); - - //! Destructor - ~CDSkillBehaviorTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - std::vector Query(std::function predicate); - - //! Gets an entry by ID - const CDSkillBehavior& GetSkillByID(unsigned int skillID); + // Gets an entry by skillID + const CDSkillBehavior& GetSkillByID(unsigned int skillID); }; diff --git a/dDatabase/Tables/CDTable.h b/dDatabase/Tables/CDTable.h index ec056e8e..fca16eb8 100644 --- a/dDatabase/Tables/CDTable.h +++ b/dDatabase/Tables/CDTable.h @@ -1,9 +1,8 @@ #pragma once -// Custom Classes -#include "../CDClientDatabase.h" +#include "CDClientDatabase.h" +#include "Singleton.h" -// C++ #include #include #include @@ -13,29 +12,14 @@ #ifdef _WIN32 #define NOMINMAX // windows.h has min and max macros that breaks cpplinq -#endif +#endif #include "cpplinq.hpp" #pragma warning (disable : 4244) //Disable double to float conversion warnings #pragma warning (disable : 4715) //Disable "not all control paths return a value" -#if defined(__unix) || defined(__APPLE__) -//For Linux: -typedef __int64_t __int64; -#endif - -/*! - \file CDTable.hpp - \brief A virtual class for CDClient Tables - */ - -//! The base class for all CD tables -class CDTable { -public: - - //! Returns the table's name - /*! - \return The table name - */ - virtual std::string GetName() const = 0; +template +class CDTable : public Singleton { +protected: + virtual ~CDTable() = default; }; diff --git a/dDatabase/Tables/CDVendorComponentTable.cpp b/dDatabase/Tables/CDVendorComponentTable.cpp index e096e85a..dfff2e20 100644 --- a/dDatabase/Tables/CDVendorComponentTable.cpp +++ b/dDatabase/Tables/CDVendorComponentTable.cpp @@ -11,9 +11,9 @@ CDVendorComponentTable::CDVendorComponentTable(void) { tableSize.nextRow(); } - + tableSize.finalize(); - + // Reserve the size this->entries.reserve(size); @@ -21,11 +21,11 @@ CDVendorComponentTable::CDVendorComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM VendorComponent"); while (!tableData.eof()) { CDVendorComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.buyScalar = tableData.getFloatField(1, -1.0f); - entry.sellScalar = tableData.getFloatField(2, -1.0f); - entry.refreshTimeSeconds = tableData.getFloatField(3, -1.0f); - entry.LootMatrixIndex = tableData.getIntField(4, -1); + entry.id = tableData.getIntField("id", -1); + entry.buyScalar = tableData.getFloatField("buyScalar", -1.0f); + entry.sellScalar = tableData.getFloatField("sellScalar", -1.0f); + entry.refreshTimeSeconds = tableData.getFloatField("refreshTimeSeconds", -1.0f); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -34,14 +34,6 @@ CDVendorComponentTable::CDVendorComponentTable(void) { tableData.finalize(); } -//! Destructor -CDVendorComponentTable::~CDVendorComponentTable(void) { } - -//! Returns the table's name -std::string CDVendorComponentTable::GetName(void) const { - return "VendorComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDVendorComponentTable::Query(std::function predicate) { @@ -56,3 +48,4 @@ std::vector CDVendorComponentTable::Query(std::function CDVendorComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDVendorComponentTable.h b/dDatabase/Tables/CDVendorComponentTable.h index 2e0fb9e4..f2666d7e 100644 --- a/dDatabase/Tables/CDVendorComponentTable.h +++ b/dDatabase/Tables/CDVendorComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDVendorComponentTable.hpp - \brief Contains data for the VendorComponent table - */ - - //! VendorComponent Struct struct CDVendorComponent { unsigned int id; //!< The Component ID float buyScalar; //!< Buy Scalar (what does that mean?) @@ -17,36 +11,15 @@ struct CDVendorComponent { unsigned int LootMatrixIndex; //!< LootMatrixIndex of the vendor's items }; -//! VendorComponent table -class CDVendorComponentTable : public CDTable { +class CDVendorComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDVendorComponentTable(void); - - //! Destructor - ~CDVendorComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDVendorComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDZoneTableTable.cpp b/dDatabase/Tables/CDZoneTableTable.cpp index 7cd8d0d8..bafbf8fe 100644 --- a/dDatabase/Tables/CDZoneTableTable.cpp +++ b/dDatabase/Tables/CDZoneTableTable.cpp @@ -2,73 +2,65 @@ //! Constructor CDZoneTableTable::CDZoneTableTable(void) { - - // First, get the size of the table - unsigned int size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ZoneTable"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); - - tableSize.nextRow(); - } - + + // First, get the size of the table + unsigned int size = 0; + auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ZoneTable"); + while (!tableSize.eof()) { + size = tableSize.getIntField(0, 0); + + tableSize.nextRow(); + } + tableSize.finalize(); - - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable"); - while (!tableData.eof()) { - CDZoneTable entry; - entry.zoneID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.zoneName = tableData.getStringField(2, ""); - entry.scriptID = tableData.getIntField(3, -1); - entry.ghostdistance_min = tableData.getFloatField(4, -1.0f); - entry.ghostdistance = tableData.getFloatField(5, -1.0f); - entry.population_soft_cap = tableData.getIntField(6, -1); - entry.population_hard_cap = tableData.getIntField(7, -1); - UNUSED(entry.DisplayDescription = tableData.getStringField(8, "")); - UNUSED(entry.mapFolder = tableData.getStringField(9, "")); - entry.smashableMinDistance = tableData.getFloatField(10, -1.0f); - entry.smashableMaxDistance = tableData.getFloatField(11, -1.0f); - UNUSED(entry.mixerProgram = tableData.getStringField(12, "")); - UNUSED(entry.clientPhysicsFramerate = tableData.getStringField(13, "")); - UNUSED(entry.serverPhysicsFramerate = tableData.getStringField(14, "")); - entry.zoneControlTemplate = tableData.getIntField(15, -1); - entry.widthInChunks = tableData.getIntField(16, -1); - entry.heightInChunks = tableData.getIntField(17, -1); - entry.petsAllowed = tableData.getIntField(18, -1) == 1 ? true : false; - entry.localize = tableData.getIntField(19, -1) == 1 ? true : false; - entry.fZoneWeight = tableData.getFloatField(20, -1.0f); - UNUSED(entry.thumbnail = tableData.getStringField(21, "")); - entry.PlayerLoseCoinsOnDeath = tableData.getIntField(22, -1) == 1 ? true : false; - UNUSED(entry.disableSaveLoc = tableData.getIntField(23, -1) == 1 ? true : false); - entry.teamRadius = tableData.getFloatField(24, -1.0f); - UNUSED(entry.gate_version = tableData.getStringField(25, "")); - UNUSED(entry.mountsAllowed = tableData.getIntField(26, -1) == 1 ? true : false); - + + // Now get the data + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable"); + while (!tableData.eof()) { + CDZoneTable entry; + entry.zoneID = tableData.getIntField("zoneID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.zoneName = tableData.getStringField("zoneName", ""); + entry.scriptID = tableData.getIntField("scriptID", -1); + entry.ghostdistance_min = tableData.getFloatField("ghostdistance_min", -1.0f); + entry.ghostdistance = tableData.getFloatField("ghostdistance", -1.0f); + entry.population_soft_cap = tableData.getIntField("population_soft_cap", -1); + entry.population_hard_cap = tableData.getIntField("population_hard_cap", -1); + UNUSED(entry.DisplayDescription = tableData.getStringField("DisplayDescription", "")); + UNUSED(entry.mapFolder = tableData.getStringField("mapFolder", "")); + entry.smashableMinDistance = tableData.getFloatField("smashableMinDistance", -1.0f); + entry.smashableMaxDistance = tableData.getFloatField("smashableMaxDistance", -1.0f); + UNUSED(entry.mixerProgram = tableData.getStringField("mixerProgram", "")); + UNUSED(entry.clientPhysicsFramerate = tableData.getStringField("clientPhysicsFramerate", "")); + UNUSED(entry.serverPhysicsFramerate = tableData.getStringField("serverPhysicsFramerate", "")); + entry.zoneControlTemplate = tableData.getIntField("zoneControlTemplate", -1); + entry.widthInChunks = tableData.getIntField("widthInChunks", -1); + entry.heightInChunks = tableData.getIntField("heightInChunks", -1); + entry.petsAllowed = tableData.getIntField("petsAllowed", -1) == 1 ? true : false; + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.fZoneWeight = tableData.getFloatField("fZoneWeight", -1.0f); + UNUSED(entry.thumbnail = tableData.getStringField("thumbnail", "")); + entry.PlayerLoseCoinsOnDeath = tableData.getIntField("PlayerLoseCoinsOnDeath", -1) == 1 ? true : false; + UNUSED(entry.disableSaveLoc = tableData.getIntField("disableSaveLoc", -1) == 1 ? true : false); + entry.teamRadius = tableData.getFloatField("teamRadius", -1.0f); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.mountsAllowed = tableData.getIntField("mountsAllowed", -1) == 1 ? true : false); + this->m_Entries.insert(std::make_pair(entry.zoneID, entry)); - tableData.nextRow(); - } + tableData.nextRow(); + } tableData.finalize(); } -//! Destructor -CDZoneTableTable::~CDZoneTableTable(void) { } - -//! Returns the table's name -std::string CDZoneTableTable::GetName(void) const { - return "ZoneTable"; -} - //! Queries the table with a zoneID to find. const CDZoneTable* CDZoneTableTable::Query(unsigned int zoneID) { - const auto& iter = m_Entries.find(zoneID); + const auto& iter = m_Entries.find(zoneID); - if (iter != m_Entries.end()) - { - return &iter->second; - } + if (iter != m_Entries.end()) { + return &iter->second; + } return nullptr; -} \ No newline at end of file +} + diff --git a/dDatabase/Tables/CDZoneTableTable.h b/dDatabase/Tables/CDZoneTableTable.h index f99febc8..f844fd25 100644 --- a/dDatabase/Tables/CDZoneTableTable.h +++ b/dDatabase/Tables/CDZoneTableTable.h @@ -3,64 +3,43 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDZoneTableTable.hpp - \brief Contains data for the ZoneTable table - */ - -//! ZoneTable Struct struct CDZoneTable { - unsigned int zoneID; //!< The Zone ID of the object - unsigned int locStatus; //!< The Locale Status(?) - std::string zoneName; //!< The name of the zone - unsigned int scriptID; //!< The Script ID of the zone (ScriptsTable) - float ghostdistance_min; //!< The minimum ghosting distance - float ghostdistance; //!< The ghosting distance - unsigned int population_soft_cap; //!< The "soft cap" on the world population - unsigned int population_hard_cap; //!< The "hard cap" on the world population - UNUSED(std::string DisplayDescription); //!< The display description of the world - UNUSED(std::string mapFolder); //!< ??? - float smashableMinDistance; //!< The minimum smashable distance? - float smashableMaxDistance; //!< The maximum smashable distance? - UNUSED(std::string mixerProgram); //!< ??? - UNUSED(std::string clientPhysicsFramerate); //!< The client physics framerate - UNUSED(std::string serverPhysicsFramerate); //!< The server physics framerate - unsigned int zoneControlTemplate; //!< The Zone Control template - unsigned int widthInChunks; //!< The width of the world in chunks - unsigned int heightInChunks; //!< The height of the world in chunks - bool petsAllowed; //!< Whether or not pets are allowed in the world + unsigned int zoneID; //!< The Zone ID of the object + unsigned int locStatus; //!< The Locale Status(?) + std::string zoneName; //!< The name of the zone + unsigned int scriptID; //!< The Script ID of the zone (ScriptsTable) + float ghostdistance_min; //!< The minimum ghosting distance + float ghostdistance; //!< The ghosting distance + unsigned int population_soft_cap; //!< The "soft cap" on the world population + unsigned int population_hard_cap; //!< The "hard cap" on the world population + UNUSED(std::string DisplayDescription); //!< The display description of the world + UNUSED(std::string mapFolder); //!< ??? + float smashableMinDistance; //!< The minimum smashable distance? + float smashableMaxDistance; //!< The maximum smashable distance? + UNUSED(std::string mixerProgram); //!< ??? + UNUSED(std::string clientPhysicsFramerate); //!< The client physics framerate + UNUSED(std::string serverPhysicsFramerate); //!< The server physics framerate + unsigned int zoneControlTemplate; //!< The Zone Control template + unsigned int widthInChunks; //!< The width of the world in chunks + unsigned int heightInChunks; //!< The height of the world in chunks + bool petsAllowed; //!< Whether or not pets are allowed in the world bool localize; //!< Whether or not the world should be localized - float fZoneWeight; //!< ??? - UNUSED(std::string thumbnail); //!< The thumbnail of the world - bool PlayerLoseCoinsOnDeath; //!< Whether or not the user loses coins on death - UNUSED(bool disableSaveLoc); //!< Disables the saving location? + float fZoneWeight; //!< ??? + UNUSED(std::string thumbnail); //!< The thumbnail of the world + bool PlayerLoseCoinsOnDeath; //!< Whether or not the user loses coins on death + UNUSED(bool disableSaveLoc); //!< Disables the saving location? float teamRadius; //!< ??? - UNUSED(std::string gate_version); //!< The gate version - UNUSED(bool mountsAllowed); //!< Whether or not mounts are allowed + UNUSED(std::string gate_version); //!< The gate version + UNUSED(bool mountsAllowed); //!< Whether or not mounts are allowed }; -//! ZoneTable table -class CDZoneTableTable : public CDTable { +class CDZoneTableTable : public CDTable { private: std::map m_Entries; - + public: - - //! Constructor - CDZoneTableTable(void); - - //! Destructor - ~CDZoneTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a zoneID to find. - /*! - \param id The zoneID - */ - const CDZoneTable* Query(unsigned int zoneID); -}; \ No newline at end of file + CDZoneTableTable(); + + // Queries the table with a zoneID to find. + const CDZoneTable* Query(unsigned int zoneID); +}; diff --git a/dDatabase/Tables/CMakeLists.txt b/dDatabase/Tables/CMakeLists.txt new file mode 100644 index 00000000..b6a02b02 --- /dev/null +++ b/dDatabase/Tables/CMakeLists.txt @@ -0,0 +1,38 @@ +set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp" + "CDActivityRewardsTable.cpp" + "CDAnimationsTable.cpp" + "CDBehaviorParameterTable.cpp" + "CDBehaviorTemplateTable.cpp" + "CDBrickIDTableTable.cpp" + "CDComponentsRegistryTable.cpp" + "CDCurrencyTableTable.cpp" + "CDDestructibleComponentTable.cpp" + "CDEmoteTable.cpp" + "CDFeatureGatingTable.cpp" + "CDInventoryComponentTable.cpp" + "CDItemComponentTable.cpp" + "CDItemSetSkillsTable.cpp" + "CDItemSetsTable.cpp" + "CDLevelProgressionLookupTable.cpp" + "CDLootMatrixTable.cpp" + "CDLootTableTable.cpp" + "CDMissionEmailTable.cpp" + "CDMissionNPCComponentTable.cpp" + "CDMissionsTable.cpp" + "CDMissionTasksTable.cpp" + "CDMovementAIComponentTable.cpp" + "CDObjectSkillsTable.cpp" + "CDObjectsTable.cpp" + "CDPackageComponentTable.cpp" + "CDPhysicsComponentTable.cpp" + "CDPropertyEntranceComponentTable.cpp" + "CDPropertyTemplateTable.cpp" + "CDProximityMonitorComponentTable.cpp" + "CDRailActivatorComponent.cpp" + "CDRarityTableTable.cpp" + "CDRebuildComponentTable.cpp" + "CDRewardsTable.cpp" + "CDScriptComponentTable.cpp" + "CDSkillBehaviorTable.cpp" + "CDVendorComponentTable.cpp" + "CDZoneTableTable.cpp" PARENT_SCOPE) diff --git a/dGame/CMakeLists.txt b/dGame/CMakeLists.txt new file mode 100644 index 00000000..80f16042 --- /dev/null +++ b/dGame/CMakeLists.txt @@ -0,0 +1,65 @@ +set(DGAME_SOURCES "Character.cpp" + "Entity.cpp" + "EntityManager.cpp" + "LeaderboardManager.cpp" + "Player.cpp" + "TeamManager.cpp" + "TradingManager.cpp" + "User.cpp" + "UserManager.cpp") + +add_subdirectory(dBehaviors) + +foreach(file ${DGAME_DBEHAVIORS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dBehaviors/${file}") +endforeach() + +add_subdirectory(dComponents) + +foreach(file ${DGAME_DCOMPONENTS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dComponents/${file}") +endforeach() + +add_subdirectory(dEntity) + +foreach(file ${DGAME_DENTITY_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dEntity/${file}") +endforeach() + +add_subdirectory(dGameMessages) + +foreach(file ${DGAME_DGAMEMESSAGES_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dGameMessages/${file}") +endforeach() + +add_subdirectory(dInventory) + +foreach(file ${DGAME_DINVENTORY_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dInventory/${file}") +endforeach() + +add_subdirectory(dMission) + +foreach(file ${DGAME_DMISSION_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dMission/${file}") +endforeach() + +add_subdirectory(dPropertyBehaviors) + +foreach(file ${DGAME_DPROPERTYBEHAVIORS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dPropertyBehaviors/${file}") +endforeach() + +add_subdirectory(dUtilities) + +foreach(file ${DGAME_DUTILITIES_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dUtilities/${file}") +endforeach() + +foreach(file ${DSCRIPTS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "${PROJECT_SOURCE_DIR}/dScripts/${file}") +endforeach() + +add_library(dGame STATIC ${DGAME_SOURCES}) + +target_link_libraries(dGame dDatabase Recast Detour) diff --git a/dGame/Character.cpp b/dGame/Character.cpp index ce61ae70..319b9376 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -15,45 +15,51 @@ #include "Zone.h" #include "ChatPackets.h" #include "Inventory.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" +#include "ePlayerFlag.h" Character::Character(uint32_t id, User* parentUser) { //First load the name, etc: - m_ID = id; + m_ID = id; sql::PreparedStatement* stmt = Database::CreatePreppedStmt( "SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;" ); stmt->setInt64(1, id); - + sql::ResultSet* res = stmt->executeQuery(); - + while (res->next()) { m_Name = res->getString(1).c_str(); m_UnapprovedName = res->getString(2).c_str(); m_NameRejected = res->getBoolean(3); m_PropertyCloneID = res->getUInt(4); - m_PermissionMap = static_cast(res->getUInt64(5)); + m_PermissionMap = static_cast(res->getUInt64(5)); } - + delete res; delete stmt; - + //Load the xmlData now: sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt( "SELECT xml_data FROM charxml WHERE id=? LIMIT 1;" ); xmlStmt->setInt64(1, id); - + sql::ResultSet* xmlRes = xmlStmt->executeQuery(); while (xmlRes->next()) { m_XMLData = xmlRes->getString(1).c_str(); } - + delete xmlRes; delete xmlStmt; - + m_ZoneID = 0; //TEMP! Set back to 0 when done. This is so we can see loading screen progress for testing. m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused. m_ZoneCloneID = 0; @@ -62,57 +68,56 @@ Character::Character(uint32_t id, User* parentUser) { //Quickly and dirtly parse the xmlData to get the info we need: DoQuickXMLDataParse(); - + //Set our objectID: m_ObjectID = m_ID; - m_ObjectID = GeneralUtils::SetBit(m_ObjectID, OBJECT_BIT_CHARACTER); - m_ObjectID = GeneralUtils::SetBit(m_ObjectID, OBJECT_BIT_PERSISTENT); - - m_ParentUser = parentUser; + GeneralUtils::SetBit(m_ObjectID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(m_ObjectID, eObjectBits::PERSISTENT); + + m_ParentUser = parentUser; m_OurEntity = nullptr; m_BuildMode = false; } Character::~Character() { delete m_Doc; - m_Doc = nullptr; + m_Doc = nullptr; } -void Character::UpdateFromDatabase() -{ +void Character::UpdateFromDatabase() { sql::PreparedStatement* stmt = Database::CreatePreppedStmt( "SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;" ); stmt->setInt64(1, m_ID); - + sql::ResultSet* res = stmt->executeQuery(); - + while (res->next()) { m_Name = res->getString(1).c_str(); m_UnapprovedName = res->getString(2).c_str(); m_NameRejected = res->getBoolean(3); m_PropertyCloneID = res->getUInt(4); - m_PermissionMap = static_cast(res->getUInt64(5)); + m_PermissionMap = static_cast(res->getUInt64(5)); } - + delete res; delete stmt; - + //Load the xmlData now: sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt( "SELECT xml_data FROM charxml WHERE id=? LIMIT 1;" ); xmlStmt->setInt64(1, m_ID); - + sql::ResultSet* xmlRes = xmlStmt->executeQuery(); while (xmlRes->next()) { m_XMLData = xmlRes->getString(1).c_str(); } - + delete xmlRes; delete xmlStmt; - + m_ZoneID = 0; //TEMP! Set back to 0 when done. This is so we can see loading screen progress for testing. m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused. m_ZoneCloneID = 0; @@ -122,67 +127,66 @@ void Character::UpdateFromDatabase() //Quickly and dirtly parse the xmlData to get the info we need: DoQuickXMLDataParse(); - + //Set our objectID: m_ObjectID = m_ID; - m_ObjectID = GeneralUtils::SetBit(m_ObjectID, OBJECT_BIT_CHARACTER); - m_ObjectID = GeneralUtils::SetBit(m_ObjectID, OBJECT_BIT_PERSISTENT); - + GeneralUtils::SetBit(m_ObjectID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(m_ObjectID, eObjectBits::PERSISTENT); + m_OurEntity = nullptr; m_BuildMode = false; } void Character::DoQuickXMLDataParse() { if (m_XMLData.size() == 0) return; - + delete m_Doc; - m_Doc = new tinyxml2::XMLDocument(); - if (!m_Doc) return; - + m_Doc = new tinyxml2::XMLDocument(); + if (!m_Doc) return; + if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) { - Game::logger->Log("Character", "Loaded xmlData for character %s (%i)!\n", m_Name.c_str(), m_ID); + Game::logger->Log("Character", "Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID); } else { - Game::logger->Log("Character", "Failed to load xmlData!\n"); - //Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true); + Game::logger->Log("Character", "Failed to load xmlData!"); + //Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true); return; } - + tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf"); if (!mf) { - Game::logger->Log("Character", "Failed to find mf tag!\n"); + Game::logger->Log("Character", "Failed to find mf tag!"); return; } - + mf->QueryAttribute("hc", &m_HairColor); mf->QueryAttribute("hs", &m_HairStyle); - + mf->QueryAttribute("t", &m_ShirtColor); mf->QueryAttribute("l", &m_PantsColor); - + mf->QueryAttribute("lh", &m_LeftHand); mf->QueryAttribute("rh", &m_RightHand); - + mf->QueryAttribute("es", &m_Eyebrows); mf->QueryAttribute("ess", &m_Eyes); mf->QueryAttribute("ms", &m_Mouth); - + tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv"); if (!inv) { - Game::logger->Log("Character", "Char has no inv!\n"); + Game::logger->Log("Character", "Char has no inv!"); return; } - + tinyxml2::XMLElement* bag = inv->FirstChildElement("items")->FirstChildElement("in"); if (!bag) { - Game::logger->Log("Character", "Couldn't find bag0!\n"); + Game::logger->Log("Character", "Couldn't find bag0!"); return; } - - while (bag != nullptr) - { + + while (bag != nullptr) { auto* sib = bag->FirstChildElement(); - + while (sib != nullptr) { bool eq = false; sib->QueryAttribute("eq", &eq); @@ -198,12 +202,14 @@ void Character::DoQuickXMLDataParse() { bag = bag->NextSiblingElement(); } - - + + tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); - if (character) { + if (character) { character->QueryAttribute("cc", &m_Coins); - character->QueryAttribute("gm", &m_GMLevel); + int32_t gm_level = 0; + character->QueryAttribute("gm", &gm_level); + m_GMLevel = static_cast(gm_level); uint64_t lzidConcat = 0; if (character->FindAttribute("lzid")) { @@ -221,9 +227,9 @@ void Character::DoQuickXMLDataParse() { } if (character->FindAttribute("lnzid")) { - uint32_t lastNonInstanceZoneID = 0; - character->QueryAttribute("lnzid", &lastNonInstanceZoneID); - m_LastNonInstanceZoneID = lastNonInstanceZoneID; + uint32_t lastNonInstanceZoneID = 0; + character->QueryAttribute("lnzid", &lastNonInstanceZoneID); + m_LastNonInstanceZoneID = lastNonInstanceZoneID; } if (character->FindAttribute("tscene")) { @@ -260,33 +266,34 @@ void Character::DoQuickXMLDataParse() { character->QueryAttribute("lzry", &m_OriginalRotation.y); character->QueryAttribute("lzrz", &m_OriginalRotation.z); character->QueryAttribute("lzrw", &m_OriginalRotation.w); - } - - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); - if (flags) { - auto* currentChild = flags->FirstChildElement(); - while (currentChild) { - uint32_t index = 0; - uint64_t value = 0; - const auto* temp = currentChild->Attribute("v"); - - index = std::stoul(currentChild->Attribute("id")); - value = std::stoull(temp); - - m_PlayerFlags.insert(std::make_pair(index, value)); - currentChild = currentChild->NextSiblingElement(); - } - } + } + + auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + if (flags) { + auto* currentChild = flags->FirstChildElement(); + while (currentChild) { + const auto* temp = currentChild->Attribute("v"); + const auto* id = currentChild->Attribute("id"); + if (temp && id) { + uint32_t index = 0; + uint64_t value = 0; + + index = std::stoul(id); + value = std::stoull(temp); + + m_PlayerFlags.insert(std::make_pair(index, value)); + } + currentChild = currentChild->NextSiblingElement(); + } + } } -void Character::UnlockEmote(int emoteID) -{ +void Character::UnlockEmote(int emoteID) { m_UnlockedEmotes.push_back(emoteID); GameMessages::SendSetEmoteLockState(EntityManager::Instance()->GetEntity(m_ObjectID), false, emoteID); } -void Character::SetBuildMode(bool buildMode) -{ +void Character::SetBuildMode(bool buildMode) { m_BuildMode = buildMode; auto* controller = dZoneManager::Instance()->GetZoneControlObject(); @@ -295,19 +302,19 @@ void Character::SetBuildMode(bool buildMode) } void Character::SaveXMLToDatabase() { - if (!m_Doc) return; - - //For metrics, we'll record the time it took to save: - auto start = std::chrono::system_clock::now(); - - tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); - if (character) { - character->SetAttribute("gm", m_GMLevel); + if (!m_Doc) return; + + //For metrics, we'll record the time it took to save: + auto start = std::chrono::system_clock::now(); + + tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); + if (character) { + character->SetAttribute("gm", static_cast(m_GMLevel)); character->SetAttribute("cc", m_Coins); + auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); // lzid garbage, binary concat of zoneID, zoneInstance and zoneClone - if (Game::server->GetZoneID() != 0) { - auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); + if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) { uint64_t lzidConcat = zoneInfo.GetCloneID(); lzidConcat = (lzidConcat << 16) | uint16_t(zoneInfo.GetInstanceID()); lzidConcat = (lzidConcat << 16) | uint16_t(zoneInfo.GetMapID()); @@ -323,7 +330,7 @@ void Character::SaveXMLToDatabase() { auto emotes = character->FirstChildElement("ue"); if (!emotes) emotes = m_Doc->NewElement("ue"); - + emotes->DeleteChildren(); for (int emoteID : m_UnlockedEmotes) { auto emote = m_Doc->NewElement("e"); @@ -333,110 +340,132 @@ void Character::SaveXMLToDatabase() { } character->LinkEndChild(emotes); - } - - //Export our flags: - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + } + + //Export our flags: + auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); if (!flags) { flags = m_Doc->NewElement("flag"); //Create a flags tag if we don't have one m_Doc->FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time } - - flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes - for (std::pair flag : m_PlayerFlags) { - auto* f = m_Doc->NewElement("f"); - f->SetAttribute("id", flag.first); - - //Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute. - //Only signed 64-bits ints would work. - std::string v = std::to_string(flag.second); - f->SetAttribute("v", v.c_str()); - + + flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes + for (std::pair flag : m_PlayerFlags) { + auto* f = m_Doc->NewElement("f"); + f->SetAttribute("id", flag.first); + + //Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute. + //Only signed 64-bits ints would work. + std::string v = std::to_string(flag.second); + f->SetAttribute("v", v.c_str()); + flags->LinkEndChild(f); } + // Prevents the news feed from showing up on world transfers + if (GetPlayerFlag(ePlayerFlag::IS_NEWS_SCREEN_VISIBLE)) { + auto* s = m_Doc->NewElement("s"); + s->SetAttribute("si", ePlayerFlag::IS_NEWS_SCREEN_VISIBLE); + flags->LinkEndChild(s); + } + SaveXmlRespawnCheckpoints(); - //Call upon the entity to update our xmlDoc: + //Call upon the entity to update our xmlDoc: if (!m_OurEntity) { - Game::logger->Log("Character", "We didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!\n"); + Game::logger->Log("Character", "%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str()); return; } - - m_OurEntity->UpdateXMLDoc(m_Doc); - - //Dump our xml into m_XMLData: - auto* printer = new tinyxml2::XMLPrinter(0, true, 0); - m_Doc->Print(printer); - m_XMLData = printer->CStr(); - - //Finally, save to db: - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charxml SET xml_data=? WHERE id=?"); - stmt->setString(1, m_XMLData.c_str()); - stmt->setUInt(2, m_ID); - stmt->execute(); - delete stmt; - - //For metrics, log the time it took to save: - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed = end - start; - Game::logger->Log("Character", "Saved character to Database in: %fs\n", elapsed.count()); + m_OurEntity->UpdateXMLDoc(m_Doc); + + WriteToDatabase(); + + //For metrics, log the time it took to save: + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed = end - start; + Game::logger->Log("Character", "%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count()); +} + +void Character::SetIsNewLogin() { + // If we dont have a flag element, then we cannot have a s element as a child of flag. + auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + if (!flags) return; + + auto* currentChild = flags->FirstChildElement(); + while (currentChild) { + if (currentChild->Attribute("si")) { + flags->DeleteChild(currentChild); + Game::logger->Log("Character", "Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str()); + WriteToDatabase(); + } + currentChild = currentChild->NextSiblingElement(); + } +} + +void Character::WriteToDatabase() { + //Dump our xml into m_XMLData: + auto* printer = new tinyxml2::XMLPrinter(0, true, 0); + m_Doc->Print(printer); + m_XMLData = printer->CStr(); + + //Finally, save to db: + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charxml SET xml_data=? WHERE id=?"); + stmt->setString(1, m_XMLData.c_str()); + stmt->setUInt(2, m_ID); + stmt->execute(); + delete stmt; delete printer; } -void Character::SetPlayerFlag(const uint32_t flagId, const bool value) { +void Character::SetPlayerFlag(const int32_t flagId, const bool value) { // If the flag is already set, we don't have to recalculate it if (GetPlayerFlag(flagId) == value) return; - if (value) - { + if (value) { // Update the mission component: auto* player = EntityManager::Instance()->GetEntity(m_ObjectID); - if (player != nullptr) - { + if (player != nullptr) { auto* missionComponent = player->GetComponent(); - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG, flagId); + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::PLAYER_FLAG, flagId); } } } - - // Calculate the index first - auto flagIndex = uint32_t(std::floor(flagId / 64)); - const auto shiftedValue = 1ULL << flagId % 64; + // Calculate the index first + auto flagIndex = uint32_t(std::floor(flagId / 64)); - auto it = m_PlayerFlags.find(flagIndex); + const auto shiftedValue = 1ULL << flagId % 64; + + auto it = m_PlayerFlags.find(flagIndex); // Check if flag index exists - if (it != m_PlayerFlags.end()) - { - // Update the value - if (value) { - it->second |= shiftedValue; - } else { - it->second &= ~shiftedValue; - } - } else { - if (value) { - // Otherwise, insert the value - uint64_t flagValue = 0; - - flagValue |= shiftedValue; - - m_PlayerFlags.insert(std::make_pair(flagIndex, flagValue)); - } - } + if (it != m_PlayerFlags.end()) { + // Update the value + if (value) { + it->second |= shiftedValue; + } else { + it->second &= ~shiftedValue; + } + } else { + if (value) { + // Otherwise, insert the value + uint64_t flagValue = 0; - // Notify the client that a flag has changed server-side - GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress()); + flagValue |= shiftedValue; + + m_PlayerFlags.insert(std::make_pair(flagIndex, flagValue)); + } + } + + // Notify the client that a flag has changed server-side + GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress()); } -bool Character::GetPlayerFlag(const uint32_t flagId) const { +bool Character::GetPlayerFlag(const int32_t flagId) const { // Calculate the index first const auto flagIndex = uint32_t(std::floor(flagId / 64)); @@ -453,45 +482,42 @@ bool Character::GetPlayerFlag(const uint32_t flagId) const { void Character::SetRetroactiveFlags() { // Retroactive check for if player has joined a faction to set their 'joined a faction' flag to true. - if (GetPlayerFlag(ePlayerFlags::VENTURE_FACTION) || GetPlayerFlag(ePlayerFlags::ASSEMBLY_FACTION) || GetPlayerFlag(ePlayerFlags::PARADOX_FACTION) || GetPlayerFlag(ePlayerFlags::SENTINEL_FACTION)) { - SetPlayerFlag(ePlayerFlags::JOINED_A_FACTION, true); + if (GetPlayerFlag(ePlayerFlag::VENTURE_FACTION) || GetPlayerFlag(ePlayerFlag::ASSEMBLY_FACTION) || GetPlayerFlag(ePlayerFlag::PARADOX_FACTION) || GetPlayerFlag(ePlayerFlag::SENTINEL_FACTION)) { + SetPlayerFlag(ePlayerFlag::JOINED_A_FACTION, true); } } -void Character::SaveXmlRespawnCheckpoints() -{ - //Export our respawn points: - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); +void Character::SaveXmlRespawnCheckpoints() { + //Export our respawn points: + auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); if (!points) { points = m_Doc->NewElement("res"); m_Doc->FirstChildElement("obj")->LinkEndChild(points); } - - points->DeleteChildren(); - for (const auto& point : m_WorldRespawnCheckpoints) { - auto* r = m_Doc->NewElement("r"); - r->SetAttribute("w", point.first); - - r->SetAttribute("x", point.second.x); - r->SetAttribute("y", point.second.y); - r->SetAttribute("z", point.second.z); - + + points->DeleteChildren(); + for (const auto& point : m_WorldRespawnCheckpoints) { + auto* r = m_Doc->NewElement("r"); + r->SetAttribute("w", point.first); + + r->SetAttribute("x", point.second.x); + r->SetAttribute("y", point.second.y); + r->SetAttribute("z", point.second.z); + points->LinkEndChild(r); } } -void Character::LoadXmlRespawnCheckpoints() -{ +void Character::LoadXmlRespawnCheckpoints() { m_WorldRespawnCheckpoints.clear(); - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); + auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); if (!points) { return; } auto* r = points->FirstChildElement("r"); - while (r != nullptr) - { + while (r != nullptr) { int32_t map = 0; NiPoint3 point = NiPoint3::ZERO; @@ -504,11 +530,10 @@ void Character::LoadXmlRespawnCheckpoints() m_WorldRespawnCheckpoints[map] = point; } - + } -void Character::OnZoneLoad() -{ +void Character::OnZoneLoad() { if (m_OurEntity == nullptr) { return; } @@ -517,24 +542,24 @@ void Character::OnZoneLoad() if (missionComponent != nullptr) { // Fix the monument race flag - if (missionComponent->GetMissionState(319) >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { - SetPlayerFlag(33, true); + if (missionComponent->GetMissionState(319) >= eMissionState::READY_TO_COMPLETE) { + SetPlayerFlag(ePlayerFlag::AG_FINISH_LINE_BUILT, true); } } const auto maxGMLevel = m_ParentUser->GetMaxGMLevel(); // This does not apply to the GMs - if (maxGMLevel > GAME_MASTER_LEVEL_CIVILIAN) { + if (maxGMLevel > eGameMasterLevel::CIVILIAN) { return; } /** - * Restrict old character to 1 million coins - */ - if (HasPermission(PermissionMap::Old)) { + * Restrict old character to 1 million coins + */ + if (HasPermission(ePermissionMap::Old)) { if (GetCoins() > 1000000) { - SetCoins(1000000, eLootSourceType::LOOT_SOURCE_NONE); + SetCoins(1000000, eLootSourceType::NONE); } } @@ -550,23 +575,19 @@ void Character::OnZoneLoad() } } -PermissionMap Character::GetPermissionMap() const -{ +ePermissionMap Character::GetPermissionMap() const { return m_PermissionMap; } -bool Character::HasPermission(PermissionMap permission) const -{ +bool Character::HasPermission(ePermissionMap permission) const { return (static_cast(m_PermissionMap) & static_cast(permission)) != 0; } -void Character::SetRespawnPoint(LWOMAPID map, const NiPoint3& point) -{ +void Character::SetRespawnPoint(LWOMAPID map, const NiPoint3& point) { m_WorldRespawnCheckpoints[map] = point; } -const NiPoint3& Character::GetRespawnPoint(LWOMAPID map) const -{ +const NiPoint3& Character::GetRespawnPoint(LWOMAPID map) const { const auto& pair = m_WorldRespawnCheckpoints.find(map); if (pair == m_WorldRespawnCheckpoints.end()) return NiPoint3::ZERO; @@ -575,8 +596,7 @@ const NiPoint3& Character::GetRespawnPoint(LWOMAPID map) const } void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) { - if (newCoins < 0) - { + if (newCoins < 0) { newCoins = 0; } @@ -585,27 +605,42 @@ void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) { GameMessages::SendSetCurrency(EntityManager::Instance()->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource); } -bool Character::HasBeenToWorld(LWOMAPID mapID) const -{ +bool Character::HasBeenToWorld(LWOMAPID mapID) const { return m_WorldRespawnCheckpoints.find(mapID) != m_WorldRespawnCheckpoints.end(); } -void Character::SendMuteNotice() const -{ +void Character::SendMuteNotice() const { if (!m_ParentUser->GetIsMuted()) return; time_t expire = m_ParentUser->GetMuteExpire(); char buffer[32] = "brought up for review.\0"; - if (expire != 1) - { - std::tm * ptm = std::localtime(&expire); + if (expire != 1) { + std::tm* ptm = std::localtime(&expire); // Format: Mo, 15.06.2009 20:20:00 std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); } - + const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); ChatPackets::SendSystemMessage(GetEntity()->GetSystemAddress(), u"You are muted until " + timeStr); } + +void Character::SetBillboardVisible(bool visible) { + if (m_BillboardVisible == visible) return; + m_BillboardVisible = visible; + + GameMessages::SendSetNamebillboardState(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + if (!visible) return; + + // The GameMessage we send for turning the nameplate off just deletes the BillboardSubcomponent from the parent component. + // Because that same message does not allow for custom parameters, we need to create the BillboardSubcomponent a different way + // This workaround involves sending an unrelated GameMessage that does not apply to player entites, + // but forces the client to create the necessary SubComponent that controls the billboard. + GameMessages::SendShowBillboardInteractIcon(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + // Now turn off the billboard for the owner. + GameMessages::SendSetNamebillboardState(m_OurEntity->GetSystemAddress(), m_OurEntity->GetObjectID()); +} diff --git a/dGame/Character.h b/dGame/Character.h index 9678eb3d..3759f206 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -9,11 +9,14 @@ #include "NiPoint3.h" #include "NiQuaternion.h" -#include "PermissionMap.h" +#include "ePermissionMap.h" class User; struct Packet; class Entity; +enum class ePermissionMap : uint64_t; +enum class eGameMasterLevel : uint8_t; +enum class eLootSourceType : uint32_t; /** * Meta information about a character, like their name and style @@ -23,344 +26,357 @@ public: Character(uint32_t id, User* parentUser); ~Character(); - void SaveXMLToDatabase(); - void UpdateFromDatabase(); + /** + * Write the current m_Doc to the database for saving. + */ + void WriteToDatabase(); + void SaveXMLToDatabase(); + void UpdateFromDatabase(); - void SaveXmlRespawnCheckpoints(); - void LoadXmlRespawnCheckpoints(); + void SaveXmlRespawnCheckpoints(); + void LoadXmlRespawnCheckpoints(); - const std::string& GetXMLData() const { return m_XMLData; } - tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; } + const std::string& GetXMLData() const { return m_XMLData; } + tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; } - /** - * Gets the database ID of the character - * @return the database ID of the character - */ + /** + * Out of abundance of safety and clarity of what this saves, this is its own function. + * + * Clears the s element from the flag element and saves the xml to the database. Used to prevent the news + * feed from showing up on world transfers. + * + */ + void SetIsNewLogin(); + + /** + * Gets the database ID of the character + * @return the database ID of the character + */ uint32_t GetID() const { return m_ID; } - /** - * Gets the (custom) name of the character - * @return the name of the character - */ + /** + * Gets the (custom) name of the character + * @return the name of the character + */ const std::string& GetName() const { return m_Name; } - /** - * Gets the generated name of the character - * @return the generated name - */ + /** + * Gets the generated name of the character + * @return the generated name + */ const std::string& GetUnapprovedName() const { return m_UnapprovedName; } - /** - * Gets whether or not the custom name for this character was rejected - * @return whether the custom name for this character was rejected - */ + /** + * Gets whether or not the custom name for this character was rejected + * @return whether the custom name for this character was rejected + */ bool GetNameRejected() const { return m_NameRejected; } - /** - * Gets the object ID of the entity this character belongs to - * @return the object ID of the entity this character belongs to - */ + /** + * Gets the object ID of the entity this character belongs to + * @return the object ID of the entity this character belongs to + */ LWOOBJID GetObjectID() const { return m_ObjectID; } - /** - * Gets the identifier for the properties of this character - * @return The identifier for the properties of this character - */ + /** + * Gets the identifier for the properties of this character + * @return The identifier for the properties of this character + */ uint32_t GetPropertyCloneID() const { return m_PropertyCloneID; } - /** - * Gets the last login of this character in MS - * @return the last login of this character - */ + /** + * Gets the last login of this character in MS + * @return the last login of this character + */ uint64_t GetLastLogin() const { return m_LastLogin; } - - /** - * Gets the default shirt color for this character - * @return the default shirt color ID - */ - uint32_t GetShirtColor() const { return m_ShirtColor; } - /** - * Gets the default hair style for this character - * @return the default hair style ID - */ - uint32_t GetShirtStyle() const { return m_ShirtStyle; } + /** + * Gets the default shirt color for this character + * @return the default shirt color ID + */ + uint32_t GetShirtColor() const { return m_ShirtColor; } - /** - * Gets the default pants color for this character - * @return the default pants color ID - */ - uint32_t GetPantsColor() const { return m_PantsColor; } + /** + * Gets the default hair style for this character + * @return the default hair style ID + */ + uint32_t GetShirtStyle() const { return m_ShirtStyle; } - /** - * Gets the default hair color for this character - * @return the default hair color ID - */ - uint32_t GetHairColor() const { return m_HairColor; } + /** + * Gets the default pants color for this character + * @return the default pants color ID + */ + uint32_t GetPantsColor() const { return m_PantsColor; } - /** - * Gets the default hair style of this character - * @return the default hair style ID - */ - uint32_t GetHairStyle() const { return m_HairStyle; } + /** + * Gets the default hair color for this character + * @return the default hair color ID + */ + uint32_t GetHairColor() const { return m_HairColor; } - /** - * Gets the eyes config for this character - * @return the eyes config ID - */ - uint32_t GetEyes() const { return m_Eyes; } + /** + * Gets the default hair style of this character + * @return the default hair style ID + */ + uint32_t GetHairStyle() const { return m_HairStyle; } - /** - * Gets the eyebrows config for this character - * @return the eyebrow config ID - */ - uint32_t GetEyebrows() const { return m_Eyebrows; } + /** + * Gets the eyes config for this character + * @return the eyes config ID + */ + uint32_t GetEyes() const { return m_Eyes; } - /** - * Get the mouth of this character - * @return the mouth ID - */ - uint32_t GetMouth() const { return m_Mouth; } + /** + * Gets the eyebrows config for this character + * @return the eyebrow config ID + */ + uint32_t GetEyebrows() const { return m_Eyebrows; } - /** - * Gets the left hand color of this character - * @return the left hand color ID - */ - uint32_t GetLeftHand() const { return m_LeftHand; } + /** + * Get the mouth of this character + * @return the mouth ID + */ + uint32_t GetMouth() const { return m_Mouth; } - /** - * Gets the right hand color of this character - * @return the right hand color ID - */ - uint32_t GetRightHand() const { return m_RightHand; } + /** + * Gets the left hand color of this character + * @return the left hand color ID + */ + uint32_t GetLeftHand() const { return m_LeftHand; } - /** - * Sets the default shirt color for this character - * @param color the shirt color ID to set - */ - void SetShirtColor(uint32_t color) { m_ShirtColor = color; } + /** + * Gets the right hand color of this character + * @return the right hand color ID + */ + uint32_t GetRightHand() const { return m_RightHand; } - /** - * Sets the default shirt style for this character - * @param style the shirt style ID to set - */ - void SetShirtStyle(uint32_t style) { m_ShirtStyle = style; } + /** + * Sets the default shirt color for this character + * @param color the shirt color ID to set + */ + void SetShirtColor(uint32_t color) { m_ShirtColor = color; } - /** - * Sets the default pants color for this character - * @param color the pants color ID to set - */ - void SetPantsColor(uint32_t color) { m_PantsColor = color; } + /** + * Sets the default shirt style for this character + * @param style the shirt style ID to set + */ + void SetShirtStyle(uint32_t style) { m_ShirtStyle = style; } - /** - * Sets the default hair color for this character - * @param color the hair color ID to set - */ - void SetHairColor(uint32_t color) { m_HairColor = color; } + /** + * Sets the default pants color for this character + * @param color the pants color ID to set + */ + void SetPantsColor(uint32_t color) { m_PantsColor = color; } - /** - * Sets the default hair style for this character - * @param style the hair style ID to set - */ - void SetHairStyle(uint32_t style) { m_HairStyle = style; } + /** + * Sets the default hair color for this character + * @param color the hair color ID to set + */ + void SetHairColor(uint32_t color) { m_HairColor = color; } - /** - * Sets the eyes config for this character - * @param eyes the eyes config ID to set - */ - void SetEyes(uint32_t eyes) { m_Eyes = eyes; } + /** + * Sets the default hair style for this character + * @param style the hair style ID to set + */ + void SetHairStyle(uint32_t style) { m_HairStyle = style; } - /** - * Sets the eyebrows config for this character - * @param eyebrows the eyebrows config ID to set - */ - void SetEyebrows(uint32_t eyebrows) { m_Eyebrows = eyebrows; } + /** + * Sets the eyes config for this character + * @param eyes the eyes config ID to set + */ + void SetEyes(uint32_t eyes) { m_Eyes = eyes; } - /** - * Sets the mouth config for this character - * @param mouth the mouth config ID to set - */ - void SetMouth(uint32_t mouth) { m_Mouth = mouth; } + /** + * Sets the eyebrows config for this character + * @param eyebrows the eyebrows config ID to set + */ + void SetEyebrows(uint32_t eyebrows) { m_Eyebrows = eyebrows; } - /** - * Sets the left hand color for this character - * @param color the left hand color ID to set - */ - void SetLeftHand(uint32_t leftHand) { m_LeftHand = leftHand; } + /** + * Sets the mouth config for this character + * @param mouth the mouth config ID to set + */ + void SetMouth(uint32_t mouth) { m_Mouth = mouth; } - /** - * Sets the right hand color for this character - * @param color the right hand color ID to set - */ - void SetRightHand(uint32_t rightHand) { m_RightHand = rightHand; } + /** + * Sets the left hand color for this character + * @param color the left hand color ID to set + */ + void SetLeftHand(uint32_t leftHand) { m_LeftHand = leftHand; } + + /** + * Sets the right hand color for this character + * @param color the right hand color ID to set + */ + void SetRightHand(uint32_t rightHand) { m_RightHand = rightHand; } - /** - * Whether this character has visited a certain zone - * @param mapID the ID of the zone to check for - * @return Whether the character has visited the provided zone - */ + /** + * Whether this character has visited a certain zone + * @param mapID the ID of the zone to check for + * @return Whether the character has visited the provided zone + */ bool HasBeenToWorld(LWOMAPID mapID) const; - /** - * Gets the zone ID the character is currently in - * @return the zone ID the character is currently in - */ + /** + * Gets the zone ID the character is currently in + * @return the zone ID the character is currently in + */ uint32_t GetZoneID() const { return m_ZoneID; } - /** - * Sets the zone ID the character is currently in - * @param id the zone ID to set - */ - void SetZoneID(uint32_t id) { m_ZoneID = id; } + /** + * Sets the zone ID the character is currently in + * @param id the zone ID to set + */ + void SetZoneID(uint32_t id) { m_ZoneID = id; } - /** - * Gets the instance ID of the zone the character is currently in, for boss battles - * @return the instance ID of the zone the character is in - */ + /** + * Gets the instance ID of the zone the character is currently in, for boss battles + * @return the instance ID of the zone the character is in + */ uint32_t GetZoneInstance() const { return m_ZoneInstanceID; } - /** - * Sets the zone instance ID the character is currently in - * @param instance the instance ID of the zone - */ - void SetZoneInstance(uint32_t instance) { m_ZoneInstanceID = instance; } + /** + * Sets the zone instance ID the character is currently in + * @param instance the instance ID of the zone + */ + void SetZoneInstance(uint32_t instance) { m_ZoneInstanceID = instance; } - /** - * Gets the clone ID of the zone the character is currently in, for properties - * @return the clone ID of the zone the character is in - */ + /** + * Gets the clone ID of the zone the character is currently in, for properties + * @return the clone ID of the zone the character is in + */ uint32_t GetZoneClone() const { return m_ZoneCloneID; } - /** - * Sets the clone ID of the zone the character is currently in - * @param clone the clone ID of the zone - */ - void SetZoneClone(uint32_t clone) { m_ZoneCloneID = clone; } + /** + * Sets the clone ID of the zone the character is currently in + * @param clone the clone ID of the zone + */ + void SetZoneClone(uint32_t clone) { m_ZoneCloneID = clone; } - /** - * Gets the last zone the character was in, that was not an instance (=boss battle), to be able to send them back - * @return the zone ID of the last non-instance zone this character was in - */ + /** + * Gets the last zone the character was in, that was not an instance (=boss battle), to be able to send them back + * @return the zone ID of the last non-instance zone this character was in + */ uint32_t GetLastNonInstanceZoneID() const { return m_LastNonInstanceZoneID; } - /** - * Sets the last non instance zone ID for the character - * @param id the zone ID - */ - void SetLastNonInstanceZoneID(uint32_t id) { m_LastNonInstanceZoneID = id; } + /** + * Sets the last non instance zone ID for the character + * @param id the zone ID + */ + void SetLastNonInstanceZoneID(uint32_t id) { m_LastNonInstanceZoneID = id; } - /** - * Gets the name of the scene that will play when the character lands in the next zone - * @return the name of the landing scene - */ + /** + * Gets the name of the scene that will play when the character lands in the next zone + * @return the name of the landing scene + */ const std::string& GetTargetScene() const { return m_TargetScene; } - /** - * Sets the name of the landing scene that will play when the player lands in the new zone - * NOTE: Generally set by launch pads before heading off to the next zone - * @param value the name of the landing scene to set - */ - void SetTargetScene(const std::string& value) { m_TargetScene = value; } + /** + * Sets the name of the landing scene that will play when the player lands in the new zone + * NOTE: Generally set by launch pads before heading off to the next zone + * @param value the name of the landing scene to set + */ + void SetTargetScene(const std::string& value) { m_TargetScene = value; } - /** - * Gets the starting position of the character (at spawn) - * @return the starting position of the character - */ + /** + * Gets the starting position of the character (at spawn) + * @return the starting position of the character + */ const NiPoint3& GetOriginalPos() const { return m_OriginalPosition; } - /** - * Gets the starting rotation of the character (at spawn) - * @return the starting rotation of the character - */ + /** + * Gets the starting rotation of the character (at spawn) + * @return the starting rotation of the character + */ const NiQuaternion& GetOriginalRot() const { return m_OriginalRotation; } - /** - * Gets the respawn point of the the character for a certain map - * @param map the map ID to get the respawn point for - * @return the respawn point of the character on the given map - */ - const NiPoint3& GetRespawnPoint(LWOMAPID map) const; + /** + * Gets the respawn point of the the character for a certain map + * @param map the map ID to get the respawn point for + * @return the respawn point of the character on the given map + */ + const NiPoint3& GetRespawnPoint(LWOMAPID map) const; - /** - * Sets the respawn point of this character for a given map - * @param map the map to set the respawn point for - * @param point the point to set as respawn point on the given map - */ + /** + * Sets the respawn point of this character for a given map + * @param map the map to set the respawn point for + * @param point the point to set as respawn point on the given map + */ void SetRespawnPoint(LWOMAPID map, const NiPoint3& point); - /** - * Gets the GM level of the character - * @return the GM level - */ - int32_t GetGMLevel() const { return m_GMLevel; } + /** + * Gets the GM level of the character + * @return the GM level + */ + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } - /** - * Sets the GM level of the character - * @param value the GM level to set - */ - void SetGMLevel(uint8_t value) { m_GMLevel = value; } + /** + * Sets the GM level of the character + * @param value the GM level to set + */ + void SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; } - /** - * Gets the current amount of coins of the character - * @return the current amount of coins - */ + /** + * Gets the current amount of coins of the character + * @return the current amount of coins + */ const int64_t GetCoins() const { return m_Coins; } - /** - * Updates the current amount of coins of the character by a specified amount - * @param newCoins the amount of coins to update by - * @param coinSource The source of the loot - */ - void SetCoins(int64_t newCoins, eLootSourceType coinSource); + /** + * Updates the current amount of coins of the character by a specified amount + * @param newCoins the amount of coins to update by + * @param coinSource The source of the loot + */ + void SetCoins(int64_t newCoins, eLootSourceType coinSource); - /** - * Get the entity this character belongs to - * @return the entity this character belongs to - */ + /** + * Get the entity this character belongs to + * @return the entity this character belongs to + */ Entity* GetEntity() const { return m_OurEntity; } - /** - * Sets the entity this character belongs to - * @param entity the entity this character belongs to - */ + /** + * Sets the entity this character belongs to + * @param entity the entity this character belongs to + */ void SetEntity(Entity* entity) { m_OurEntity = entity; } - /** - * Gets the current build mode of the character (on or off) - * @return the current build mode of the character - */ + /** + * Gets the current build mode of the character (on or off) + * @return the current build mode of the character + */ bool GetBuildMode() const { return m_BuildMode; } - /** - * Sets the current build mode for the character (either on or off) - * @param buildMode the build mode to set - */ + /** + * Sets the current build mode for the character (either on or off) + * @param buildMode the build mode to set + */ void SetBuildMode(bool buildMode); - /** - * Gets the title of an announcement that a character made (reserved for GMs) - * @return the title of the announcement a character made - */ + /** + * Gets the title of an announcement that a character made (reserved for GMs) + * @return the title of the announcement a character made + */ const std::string& GetAnnouncementTitle() const { return m_AnnouncementTitle; } - /** - * Sets the title of an announcement a character will make (reserved for GMs) - * @param value the title to set - */ + /** + * Sets the title of an announcement a character will make (reserved for GMs) + * @param value the title to set + */ void SetAnnouncementTitle(const std::string& value) { m_AnnouncementTitle = value; } - /** - * Gets the body of an announcement a character made (reserved for GMs) - * @return the body of the announcement - */ + /** + * Gets the body of an announcement a character made (reserved for GMs) + * @return the body of the announcement + */ const std::string& GetAnnouncementMessage() const { return m_AnnouncementMessage; } - /** - * Sets the body of an annoucement to make (reserved for GMs) - * @param value the body of the announcement - */ + /** + * Sets the body of an annoucement to make (reserved for GMs) + * @param value the body of the announcement + */ void SetAnnouncementMessage(const std::string& value) { m_AnnouncementMessage = value; } /** @@ -368,29 +384,29 @@ public: */ void OnZoneLoad(); - /** - * Gets the permissions of the character, determining what actions a character may do - * @return the permissions for this character - */ - PermissionMap GetPermissionMap() const; + /** + * Gets the permissions of the character, determining what actions a character may do + * @return the permissions for this character + */ + ePermissionMap GetPermissionMap() const; - /** - * Check if this character has a certain permission - * @param permission the ID of the permission to check for - * @return whether the character has the specified permission - */ - bool HasPermission(PermissionMap permission) const; + /** + * Check if this character has a certain permission + * @param permission the ID of the permission to check for + * @return whether the character has the specified permission + */ + bool HasPermission(ePermissionMap permission) const; - /** - * Gets all the emotes this character has unlocked so far - * @return the emotes this character has unlocked - */ + /** + * Gets all the emotes this character has unlocked so far + * @return the emotes this character has unlocked + */ const std::vector& GetUnlockedEmotes() const { return m_UnlockedEmotes; } - /** - * Unlocks an emote, adding it to the unlocked list, also updates the state for the client - * @param emoteID the ID of the emote to unlock - */ + /** + * Unlocks an emote, adding it to the unlocked list, also updates the state for the client + * @param emoteID the ID of the emote to unlock + */ void UnlockEmote(int emoteID); /** @@ -399,32 +415,48 @@ public: * @param flagId the ID of the flag to set * @param value the value to set for the flag */ - void SetPlayerFlag(uint32_t flagId, bool value); + void SetPlayerFlag(int32_t flagId, bool value); - /** - * Gets the value for a certain character flag - * @param flagId the ID of the flag to get a value for - * @return the value of the flag given the ID (the default is false, obviously) - */ - bool GetPlayerFlag(uint32_t flagId) const; + /** + * Gets the value for a certain character flag + * @param flagId the ID of the flag to get a value for + * @return the value of the flag given the ID (the default is false, obviously) + */ + bool GetPlayerFlag(int32_t flagId) const; /** * Notifies the character that they're now muted */ void SendMuteNotice() const; - /** - * Sets any flags that are meant to have been set that may not have been set due to them being - * missing in a previous patch. - */ - void SetRetroactiveFlags(); - - /** - * Get the equipped items for this character, only used for character creation - * @return the equipped items for this character on world load - */ + /** + * Sets any flags that are meant to have been set that may not have been set due to them being + * missing in a previous patch. + */ + void SetRetroactiveFlags(); + + /** + * Get the equipped items for this character, only used for character creation + * @return the equipped items for this character on world load + */ const std::vector& GetEquippedItems() const { return m_EquippedItems; } - + + /** + * @brief Get the flying state + * @return value of the flying state + */ + bool GetIsFlying() { return m_IsFlying; } + + /** + * @brief Set the value of the flying state + * @param isFlying the flying state + */ + void SetIsFlying(bool isFlying) { m_IsFlying = isFlying; } + + bool GetBillboardVisible() { return m_BillboardVisible; } + + void SetBillboardVisible(bool visible); + private: /** * The ID of this character. First 32 bits of the ObjectID. @@ -448,44 +480,44 @@ private: /** * 0-9, the Game Master level of this character. - * + * * @see eGameMasterLevel */ - int32_t m_GMLevel; + eGameMasterLevel m_GMLevel; /** * Bitmap of permission attributes this character has. */ - PermissionMap m_PermissionMap; + ePermissionMap m_PermissionMap; - /** - * The default name of this character - */ + /** + * The default name of this character + */ std::string m_Name; - /** - * The custom name of the character - */ + /** + * The custom name of the character + */ std::string m_UnapprovedName; - /** - * Whether the custom name of this character is rejected - */ + /** + * Whether the custom name of this character is rejected + */ bool m_NameRejected; - /** - * The current amount of coins of this character - */ + /** + * The current amount of coins of this character + */ int64_t m_Coins; - /** - * Whether the character is building - */ + /** + * Whether the character is building + */ bool m_BuildMode; - /** - * The items equipped by the character on world load - */ + /** + * The items equipped by the character on world load + */ std::vector m_EquippedItems; /** @@ -493,126 +525,126 @@ private: */ uint32_t m_ShirtColor = 0; - /** - * The default shirt style of the character - */ + /** + * The default shirt style of the character + */ uint32_t m_ShirtStyle = 0; - /** - * The default pants color of the character - */ + /** + * The default pants color of the character + */ uint32_t m_PantsColor = 1; - /** - * The default hair color of the character - */ + /** + * The default hair color of the character + */ uint32_t m_HairColor = 0; - /** - * The default hair style of the character - */ + /** + * The default hair style of the character + */ uint32_t m_HairStyle = 0; - /** - * The eyes style of the character - */ + /** + * The eyes style of the character + */ uint32_t m_Eyes = 1; - /** - * The eyebrow style of the character - */ + /** + * The eyebrow style of the character + */ uint32_t m_Eyebrows = 33; - /** - * The mouth style of the character - */ + /** + * The mouth style of the character + */ uint32_t m_Mouth = 8; - /* - * The left hand ID of the character - * NOTE: This might just be client stack garbage. - */ + /* + * The left hand ID of the character + * NOTE: This might just be client stack garbage. + */ uint32_t m_LeftHand = 23571472; - /** - * The right hand ID of the character - * NOTE: This might just be client stack garbage. - */ + /** + * The right hand ID of the character + * NOTE: This might just be client stack garbage. + */ uint32_t m_RightHand = 23124164; - /** - * The emotes unlocked by this character - */ + /** + * The emotes unlocked by this character + */ std::vector m_UnlockedEmotes; - /** - * The ID of the properties of this character - */ + /** + * The ID of the properties of this character + */ uint32_t m_PropertyCloneID; - /** - * The XML data for this character, stored as string - */ + /** + * The XML data for this character, stored as string + */ std::string m_XMLData; - /** - * The last zone visited by the character that was not an instance zone - */ + /** + * The last zone visited by the character that was not an instance zone + */ uint32_t m_LastNonInstanceZoneID = 0; - /** - * The ID of the zone the character is currently in - */ + /** + * The ID of the zone the character is currently in + */ uint32_t m_ZoneID = 0; - /** - * The instance ID of the zone the character is currently in (for boss battles) - */ + /** + * The instance ID of the zone the character is currently in (for boss battles) + */ uint32_t m_ZoneInstanceID = 0; - /** - * The clone ID of the zone the character is currently in (for properties) - */ + /** + * The clone ID of the zone the character is currently in (for properties) + */ uint32_t m_ZoneCloneID = 0; - /** - * The last time this character logged in - */ + /** + * The last time this character logged in + */ uint64_t m_LastLogin; - /** - * The gameplay flags this character has (not just true values) - */ - std::unordered_map m_PlayerFlags; + /** + * The gameplay flags this character has (not just true values) + */ + std::unordered_map m_PlayerFlags; - /** - * The character XML belonging to this character - */ - tinyxml2::XMLDocument* m_Doc; + /** + * The character XML belonging to this character + */ + tinyxml2::XMLDocument* m_Doc; - /** - * Title of an announcement this character made (reserved for GMs) - */ + /** + * Title of an announcement this character made (reserved for GMs) + */ std::string m_AnnouncementTitle; - /** - * The body of an announcement this character made (reserved for GMs) - */ + /** + * The body of an announcement this character made (reserved for GMs) + */ std::string m_AnnouncementMessage; - /** - * The spawn position of this character when loading in - */ + /** + * The spawn position of this character when loading in + */ NiPoint3 m_OriginalPosition; - /** - * The spawn rotation of this character when loading in - */ + /** + * The spawn rotation of this character when loading in + */ NiQuaternion m_OriginalRotation; - /** - * The respawn points of this character, per world - */ + /** + * The respawn points of this character, per world + */ std::map m_WorldRespawnCheckpoints; /** @@ -620,7 +652,17 @@ private: * Set by the launchpad the player used to get to the current world. */ std::string m_TargetScene; - + + /** + * Bool that tracks the flying state of the user. + */ + bool m_IsFlying = false; + + /** + * True if billboard (referred to as nameplate for end users) is visible, false otherwise + */ + bool m_BillboardVisible = true; + /** * Queries the character XML and updates all the fields of this object * NOTE: quick as there's no DB lookups diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index bb7e0335..b9fc79fb 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -17,6 +17,14 @@ #include "UserManager.h" #include "dpWorld.h" #include "Player.h" +#include "LUTriggers.h" +#include "User.h" +#include "EntityTimer.h" +#include "EntityCallbackTimer.h" +#include "Loot.h" +#include "eMissionTaskType.h" +#include "eTriggerEventType.h" +#include "eObjectBits.h" //Component includes: #include "Component.h" @@ -28,6 +36,8 @@ #include "BuffComponent.h" #include "BouncerComponent.h" #include "InventoryComponent.h" +#include "LevelProgressionComponent.h" +#include "PlayerForcedMovementComponent.h" #include "ScriptComponent.h" #include "SkillComponent.h" #include "SimplePhysicsComponent.h" @@ -60,15 +70,30 @@ #include "ShootingGalleryComponent.h" #include "RailActivatorComponent.h" #include "LUPExhibitComponent.h" +#include "TriggerComponent.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" +#include "eReplicaPacketType.h" + +// Table includes +#include "CDComponentsRegistryTable.h" +#include "CDCurrencyTableTable.h" +#include "CDMovementAIComponentTable.h" +#include "CDProximityMonitorComponentTable.h" +#include "CDRebuildComponentTable.h" +#include "CDObjectSkillsTable.h" +#include "CDObjectsTable.h" +#include "CDScriptComponentTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDZoneTableTable.h" Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) { m_ObjectID = objectID; m_TemplateID = info.lot; m_ParentEntity = parentEntity; m_Character = nullptr; - m_GMLevel = 0; + m_GMLevel = eGameMasterLevel::CIVILIAN; m_CollectibleID = 0; - m_Trigger = nullptr; //new LUTriggers::Trigger(); m_NetworkID = 0; m_Groups = {}; m_OwnerOverride = LWOOBJID_EMPTY; @@ -88,8 +113,8 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) m_Scale = info.scale; m_Spawner = info.spawner; m_SpawnerID = info.spawnerID; - m_HasSpawnerNodeID = info.hasSpawnerNodeID; - m_SpawnerNodeID = info.spawnerNodeID; + m_HasSpawnerNodeID = info.hasSpawnerNodeID; + m_SpawnerNodeID = info.spawnerNodeID; if (info.lot != 1) m_PlayerIsReadyForUpdates = true; } @@ -103,47 +128,30 @@ Entity::~Entity() { CancelCallbackTimers(); const auto components = m_Components; - + for (const auto& pair : components) { delete pair.second; m_Components.erase(pair.first); } + + for (auto child : m_ChildEntities) { + if (child) child->RemoveParent(); + } + if (m_ParentEntity) { m_ParentEntity->RemoveChild(this); } } -void Entity::Initialize() -{ +void Entity::Initialize() { /** * Setup trigger */ - const auto triggerName = GetVarAsString(u"trigger_id"); + const auto triggerInfo = GetVarAsString(u"trigger_id"); - if (!triggerName.empty()) { - std::stringstream ss(triggerName); - std::vector tokens; - std::string token; - while (std::getline(ss, token, ':')) { - tokens.push_back(token); - } - - uint32_t sceneID = std::stoi(tokens[0]); - uint32_t triggerID = std::stoi(tokens[1]); - - if (m_Trigger != nullptr) { - delete m_Trigger; - m_Trigger = nullptr; - } - - m_Trigger = dZoneManager::Instance()->GetZone()->GetTrigger(sceneID, triggerID); - - if (m_Trigger == nullptr) { - m_Trigger = new LUTriggers::Trigger(); - } - } + if (!triggerInfo.empty()) m_Components.emplace(eReplicaComponentType::TRIGGER, new TriggerComponent(this, triggerInfo)); /** * Setup groups @@ -165,85 +173,87 @@ void Entity::Initialize() } // Get the registry table - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); /** * Special case for BBB models. They have components not corresponding to the registry. */ if (m_TemplateID == 14) { - const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SIMPLE_PHYSICS); + const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS); SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SIMPLE_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp)); - ModelComponent* modelcomp = new ModelComponent(0, this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MODEL, modelcomp)); + ModelComponent* modelcomp = new ModelComponent(this); + m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, modelcomp)); RenderComponent* render = new RenderComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render)); + m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render)); + auto destroyableComponent = new DestroyableComponent(this); + destroyableComponent->SetHealth(1); + destroyableComponent->SetMaxHealth(1.0f); + destroyableComponent->SetFaction(-1, true); + destroyableComponent->SetIsSmashable(true); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent)); // We have all our components. - return; + return; } /** * Go through all the components and check if this entity has them. - * + * * Not all components are implemented. Some are represented by a nullptr, as they hold no data. */ if (GetParentUser()) { auto missions = new MissionComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MISSION, missions)); + m_Components.insert(std::make_pair(eReplicaComponentType::MISSION, missions)); missions->LoadFromXml(m_Character->GetXMLDoc()); } - uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PET); + uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET); if (petComponentId > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PET, new PetComponent(this, petComponentId))); + m_Components.insert(std::make_pair(eReplicaComponentType::PET, new PetComponent(this, petComponentId))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ZONE_CONTROL) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ZONE_CONTROL, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::ZONE_CONTROL, nullptr)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSABLE, new PossessableComponent(this))); + uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE); + if (possessableComponentId > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSABLE, new PossessableComponent(this, possessableComponentId))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MODULE_ASSEMBLY) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_MODULE_ASSEMBLY, new ModuleAssemblyComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::MODULE_ASSEMBLY, new ModuleAssemblyComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RACING_STATS) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RACING_STATS, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::RACING_STATS, nullptr)); } - PetComponent* petComponent; - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ITEM) > 0 && !TryGetComponent(COMPONENT_TYPE_PET, petComponent)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ITEM, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1) >= 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::LUP_EXHIBIT, new LUPExhibitComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_EXHIBIT, -1) >= 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_EXHIBIT, new LUPExhibitComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::RACING_CONTROL, new RacingControlComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RACING_CONTROL) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RACING_CONTROL, new RacingControlComponent(this))); - } - - const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_ENTRANCE); + const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_ENTRANCE); if (propertyEntranceComponentID > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROPERTY_ENTRANCE, - new PropertyEntranceComponent(propertyEntranceComponentID, this))); + m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY_ENTRANCE, + new PropertyEntranceComponent(propertyEntranceComponentID, this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_CONTROLLABLE_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) { ControllablePhysicsComponent* controllablePhysics = new ControllablePhysicsComponent(this); if (m_Character) { - controllablePhysics->LoadFromXML(m_Character->GetXMLDoc()); + controllablePhysics->LoadFromXml(m_Character->GetXMLDoc()); const auto mapID = Game::server->GetZoneID(); @@ -258,110 +268,96 @@ void Entity::Initialize() if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) { pos = m_Character->GetRespawnPoint(mapID); rot = dZoneManager::Instance()->GetZone()->GetSpawnRot(); - } - else if (targetScene != nullptr) { + } else if (targetScene != nullptr) { pos = targetScene->GetPosition(); rot = targetScene->GetRotation(); - } - else { - pos = dZoneManager::Instance()->GetZone()->GetSpawnPos(); - rot = dZoneManager::Instance()->GetZone()->GetSpawnRot(); + } else { + pos = dZoneManager::Instance()->GetZone()->GetSpawnPos(); + rot = dZoneManager::Instance()->GetZone()->GetSpawnRot(); } controllablePhysics->SetPosition(pos); controllablePhysics->SetRotation(rot); } - } - else { + } else { controllablePhysics->SetPosition(m_DefaultPosition); controllablePhysics->SetRotation(m_DefaultRotation); } - m_Components.insert(std::make_pair(COMPONENT_TYPE_CONTROLLABLE_PHYSICS, controllablePhysics)); + m_Components.insert(std::make_pair(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysics)); } // If an entity is marked a phantom, simple physics is made into phantom phyics. bool markedAsPhantom = GetVar(u"markedAsPhantom"); - const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SIMPLE_PHYSICS); + const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS); if (!markedAsPhantom && simplePhysicsComponentID > 0) { SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SIMPLE_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) { RigidbodyPhantomPhysicsComponent* comp = new RigidbodyPhantomPhysicsComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, comp)); } - if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PHANTOM_PHYSICS) > 0) { + if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) { PhantomPhysicsComponent* phantomPhysics = new PhantomPhysicsComponent(this); phantomPhysics->SetPhysicsEffectActive(false); - m_Components.insert(std::make_pair(COMPONENT_TYPE_PHANTOM_PHYSICS, phantomPhysics)); + m_Components.insert(std::make_pair(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysics)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_VEHICLE_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) { VehiclePhysicsComponent* vehiclePhysicsComponent = new VehiclePhysicsComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_VEHICLE_PHYSICS, vehiclePhysicsComponent)); + m_Components.insert(std::make_pair(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)); vehiclePhysicsComponent->SetPosition(m_DefaultPosition); vehiclePhysicsComponent->SetRotation(m_DefaultRotation); } - - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SOUND_TRIGGER, -1) != -1) { - auto* comp = new SoundTriggerComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SOUND_TRIGGER, comp)); - } - //Check to see if we have a moving platform component: - //Which, for some reason didn't get added to the ComponentsRegistry so we have to check for a path manually here. - std::string attachedPath = GetVarAsString(u"attached_path"); - - if (!attachedPath.empty() || compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MOVING_PLATFORM, -1) != -1) { - MovingPlatformComponent* plat = new MovingPlatformComponent(this, attachedPath); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVING_PLATFORM, plat)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) { + auto* comp = new SoundTriggerComponent(this); + m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp)); } //Also check for the collectible id: m_CollectibleID = GetVarAs(u"collectible_id"); - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUFF) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF) > 0) { BuffComponent* comp = new BuffComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BUFF, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BUFF, comp)); } - int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_COLLECTIBLE); + int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE); - if (collectibleComponentID > 0){ - m_Components.insert(std::make_pair(COMPONENT_TYPE_COLLECTIBLE, nullptr)); + if (collectibleComponentID > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::COLLECTIBLE, nullptr)); } /** * Multiple components require the destructible component. */ - int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUFF); - int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_REBUILD); + int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF); + int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD); int componentID = 0; if (collectibleComponentID > 0) componentID = collectibleComponentID; if (rebuildComponentID > 0) componentID = rebuildComponentID; if (buffComponentID > 0) componentID = buffComponentID; - CDDestructibleComponentTable* destCompTable = CDClientManager::Instance()->GetTable("DestructibleComponent"); + CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable(); std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (buffComponentID > 0 || collectibleComponentID > 0) { DestroyableComponent* comp = new DestroyableComponent(this); if (m_Character) { - comp->LoadFromXML(m_Character->GetXMLDoc()); - } - else { + comp->LoadFromXml(m_Character->GetXMLDoc()); + } else { if (componentID > 0) { std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (destCompData.size() > 0) { - if (HasComponent(COMPONENT_TYPE_RACING_STATS)) - { + if (HasComponent(eReplicaComponentType::RACING_STATS)) { destCompData[0].imagination = 60; } @@ -381,7 +377,7 @@ void Entity::Initialize() uint32_t npcMinLevel = destCompData[0].level; uint32_t currencyIndex = destCompData[0].CurrencyIndex; - CDCurrencyTableTable* currencyTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + CDCurrencyTableTable* currencyTable = CDClientManager::Instance().GetTable(); std::vector currencyValues = currencyTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == currencyIndex && entry.npcminlevel == npcMinLevel); }); if (currencyValues.size() > 0) { @@ -393,8 +389,7 @@ void Entity::Initialize() // extraInfo overrides comp->SetIsSmashable(GetVarAs(u"is_smashable") != 0); } - } - else { + } else { comp->SetHealth(1); comp->SetArmor(0); @@ -406,8 +401,8 @@ void Entity::Initialize() comp->AddFaction(6); //Smashables // A race car has 60 imagination, other entities defaults to 0. - comp->SetImagination(HasComponent(COMPONENT_TYPE_RACING_STATS) ? 60 : 0); - comp->SetMaxImagination(HasComponent(COMPONENT_TYPE_RACING_STATS) ? 60 : 0); + comp->SetImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); + comp->SetMaxImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); } } @@ -425,40 +420,43 @@ void Entity::Initialize() } } - m_Components.insert(std::make_pair(COMPONENT_TYPE_DESTROYABLE, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp)); } - /*if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_DESTROYABLE) > 0 || m_Character) { - DestroyableComponent* comp = new DestroyableComponent(); - if (m_Character) comp->LoadFromXML(m_Character->GetXMLDoc()); - m_Components.push_back(std::make_pair(COMPONENT_TYPE_DESTROYABLE, comp)); - }*/ + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER) > 0 || m_Character) { + // Character Component always has a possessor, level, and forced movement components + m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSOR, new PossessorComponent(this))); - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_CHARACTER) > 0 || m_Character) { - // Character Component always has a possessor component - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSOR, new PossessorComponent(this))); - CharacterComponent* comp = new CharacterComponent(this, m_Character); - m_Components.insert(std::make_pair(COMPONENT_TYPE_CHARACTER, comp)); + // load in the xml for the level + auto* levelComp = new LevelProgressionComponent(this); + levelComp->LoadFromXml(m_Character->GetXMLDoc()); + m_Components.insert(std::make_pair(eReplicaComponentType::LEVEL_PROGRESSION, levelComp)); + + m_Components.insert(std::make_pair(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, new PlayerForcedMovementComponent(this))); + + CharacterComponent* charComp = new CharacterComponent(this, m_Character); + charComp->LoadFromXml(m_Character->GetXMLDoc()); + m_Components.insert(std::make_pair(eReplicaComponentType::CHARACTER, charComp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_INVENTORY) > 0 || m_Character) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) { InventoryComponent* comp = nullptr; if (m_Character) comp = new InventoryComponent(this, m_Character->GetXMLDoc()); else comp = new InventoryComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_INVENTORY, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::INVENTORY, comp)); } // if this component exists, then we initialize it. it's value is always 0 - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH_LUP, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH_LUP, -1) != -1) { auto comp = new RocketLaunchLupComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH_LUP, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH_LUP, comp)); } /** * This is a bit of a mess */ - CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable("ScriptComponent"); - int scriptComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SCRIPT); + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPT, -1); std::string scriptName = ""; bool client = false; @@ -468,18 +466,15 @@ void Entity::Initialize() CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); scriptName = scriptCompData.script_name; clientScriptName = scriptCompData.client_script_name; - } - else { + } else { scriptName = ""; } if (scriptName != "" || (scriptName == "" && m_Character)) { - - } - else if (clientScriptName != "") { + + } else if (clientScriptName != "") { client = true; - } - else if (!m_Character) { + } else if (!m_Character) { client = true; } } @@ -503,42 +498,41 @@ void Entity::Initialize() scriptName = customScriptServer; } - if (!scriptName.empty() || client || m_Character) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty()))); + if (!scriptName.empty() || client || m_Character || scriptComponentID >= 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty()))); } // ZoneControl script if (m_TemplateID == 2365) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable(); const auto zoneID = dZoneManager::Instance()->GetZoneID(); const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID()); - if (zoneData != nullptr) - { + if (zoneData != nullptr) { int zoneScriptID = zoneData->scriptID; CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID); ScriptComponent* comp = new ScriptComponent(this, zoneScriptData.script_name, true); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPT, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp)); } } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SKILL, -1) != -1 || m_Character) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1) != -1 || m_Character) { SkillComponent* comp = new SkillComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SKILL, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SKILL, comp)); } - const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BASE_COMBAT_AI); + const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI); if (combatAiId > 0) { BaseCombatAIComponent* comp = new BaseCombatAIComponent(this, combatAiId); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BASE_COMBAT_AI, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BASE_COMBAT_AI, comp)); } - if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_REBUILD) > 0) { + if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) { RebuildComponent* comp = new RebuildComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_REBUILD, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::QUICK_BUILD, comp)); - CDRebuildComponentTable* rebCompTable = CDClientManager::Instance()->GetTable("RebuildComponent"); + CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable(); std::vector rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); }); if (rebCompData.size() > 0) { @@ -576,74 +570,89 @@ void Entity::Initialize() } } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SWITCH, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1) != -1) { SwitchComponent* comp = new SwitchComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SWITCH, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SWITCH, comp)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_VENDOR) > 0)) { + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) { VendorComponent* comp = new VendorComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_VENDOR, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_VENDOR, -1) != -1) - { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) { auto* component = new PropertyVendorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROPERTY_VENDOR, component); + m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_VENDOR, component); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_MANAGEMENT, -1) != -1) - { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1) != -1) { auto* component = new PropertyManagementComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROPERTY_MANAGEMENT, component); + m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_MANAGEMENT, component); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0 + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0 BouncerComponent* comp = new BouncerComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BOUNCER, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RENDER) > 0 && m_TemplateID != 2365) || m_Character) { + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER) > 0 && m_TemplateID != 2365) || m_Character) { RenderComponent* render = new RenderComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render)); + m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MISSION_OFFER) > 0) || m_Character) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID))); + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER) > 0) || m_Character) { + m_Components.insert(std::make_pair(eReplicaComponentType::MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUILD_BORDER, -1) != -1) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_BUILD_BORDER, new BuildBorderComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1) != -1) { + m_Components.insert(std::make_pair(eReplicaComponentType::BUILD_BORDER, new BuildBorderComponent(this))); } // Scripted activity component - int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SCRIPTED_ACTIVITY); + int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY); if ((scriptedActivityID > 0)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID))); + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID))); + } + + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent()) { + m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, new ModelComponent(this))); + if (m_Components.find(eReplicaComponentType::DESTROYABLE) == m_Components.end()) { + auto destroyableComponent = new DestroyableComponent(this); + destroyableComponent->SetHealth(1); + destroyableComponent->SetMaxHealth(1.0f); + destroyableComponent->SetFaction(-1, true); + destroyableComponent->SetIsSmashable(true); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent)); + } + } + + PetComponent* petComponent; + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) { + m_Components.insert(std::make_pair(eReplicaComponentType::ITEM, nullptr)); } // Shooting gallery component - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SHOOTING_GALLERY) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SHOOTING_GALLERY, new ShootingGalleryComponent(this))); - } - - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY, -1) != -1) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROPERTY, new PropertyComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::SHOOTING_GALLERY, new ShootingGalleryComponent(this))); } - const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) { + m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY, new PropertyComponent(this))); + } + + const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH); if ((rocketId > 0)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId))); + m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId))); } - const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RAIL_ACTIVATOR); + const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR); if (railComponentID > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID))); + m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID))); } - int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MOVEMENT_AI); + int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI); if (movementAIID > 0) { - CDMovementAIComponentTable* moveAITable = CDClientManager::Instance()->GetTable("MovementAIComponent"); + CDMovementAIComponentTable* moveAITable = CDClientManager::Instance().GetTable(); std::vector moveAIComp = moveAITable->Query([=](CDMovementAIComponent entry) {return (entry.id == movementAIID); }); if (moveAIComp.size() > 0) { @@ -666,11 +675,9 @@ void Entity::Initialize() } } - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); } - } - else if (petComponentId > 0 || combatAiId > 0 && GetComponent()->GetTetherSpeed() > 0) - { + } else if (petComponentId > 0 || combatAiId > 0 && GetComponent()->GetTetherSpeed() > 0) { MovementAIInfo moveInfo = MovementAIInfo(); moveInfo.movementType = ""; moveInfo.wanderChance = 0; @@ -679,17 +686,37 @@ void Entity::Initialize() moveInfo.wanderDelayMax = 5; moveInfo.wanderDelayMin = 2; - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); } - int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROXIMITY_MONITOR); + std::string pathName = GetVarAsString(u"attached_path"); + const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName); + + //Check to see if we have an attached path and add the appropiate component to handle it: + if (path){ + // if we have a moving platform path, then we need a moving platform component + if (path->pathType == PathType::MovingPlatform) { + MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat)); + // else if we are a movement path + } /*else if (path->pathType == PathType::Movement) { + auto movementAIcomp = GetComponent(); + if (movementAIcomp){ + // TODO: set path in existing movementAIComp + } else { + // TODO: create movementAIcomp and set path + } + }*/ + } + + int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR); if (proximityMonitorID > 0) { - CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance()->GetTable("ProximityMonitorComponent"); + CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance().GetTable(); std::vector proxCompData = proxCompTable->Query([=](CDProximityMonitorComponent entry) { return (entry.id == proximityMonitorID); }); if (proxCompData.size() > 0) { std::vector proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ','); ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1])); - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROXIMITY_MONITOR, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp)); } } @@ -698,59 +725,54 @@ void Entity::Initialize() for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnStartup(this); } - }); + }); - if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) - { + if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) { // Don't ghost what is likely large scene elements - if (m_Components.size() == 2 && HasComponent(COMPONENT_TYPE_SIMPLE_PHYSICS) && HasComponent(COMPONENT_TYPE_RENDER)) - { + if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) { goto no_ghosting; } /* Filter for ghosting candidates. - * + * * Don't ghost moving platforms, until we've got proper syncing for those. * Don't ghost big phantom physics triggers, as putting those to sleep might prevent interactions. * Don't ghost property related objects, as the client expects those to always be loaded. */ if ( !EntityManager::IsExcludedFromGhosting(GetLOT()) && - !HasComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY) && - !HasComponent(COMPONENT_TYPE_MOVING_PLATFORM) && - !HasComponent(COMPONENT_TYPE_PHANTOM_PHYSICS) && - !HasComponent(COMPONENT_TYPE_PROPERTY) && - !HasComponent(COMPONENT_TYPE_RACING_CONTROL) && - !HasComponent(COMPONENT_TYPE_VEHICLE_PHYSICS) - ) - //if (HasComponent(COMPONENT_TYPE_BASE_COMBAT_AI)) + !HasComponent(eReplicaComponentType::SCRIPTED_ACTIVITY) && + !HasComponent(eReplicaComponentType::MOVING_PLATFORM) && + !HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && + !HasComponent(eReplicaComponentType::PROPERTY) && + !HasComponent(eReplicaComponentType::RACING_CONTROL) && + !HasComponent(eReplicaComponentType::VEHICLE_PHYSICS) + ) + //if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI)) { m_IsGhostingCandidate = true; } - if (GetLOT() == 6368) - { + if (GetLOT() == 6368) { m_IsGhostingCandidate = true; } // Special case for collectibles in Ninjago - if (HasComponent(COMPONENT_TYPE_COLLECTIBLE) && Game::server->GetZoneID() == 2000) - { + if (HasComponent(eReplicaComponentType::COLLECTIBLE) && Game::server->GetZoneID() == 2000) { m_IsGhostingCandidate = true; } } - no_ghosting: +no_ghosting: - TriggerEvent("OnCreate"); + TriggerEvent(eTriggerEventType::CREATE, this); if (m_Character) { auto* controllablePhysicsComponent = GetComponent(); - auto* characterComponent = GetComponent(); + auto* levelComponent = GetComponent(); - if (controllablePhysicsComponent != nullptr && characterComponent->GetLevel() >= 20) - { - controllablePhysicsComponent->SetSpeedMultiplier(525.0f / 500.0f); + if (controllablePhysicsComponent && levelComponent) { + controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f); } } } @@ -763,36 +785,30 @@ bool Entity::operator!=(const Entity& other) const { return other.m_ObjectID != m_ObjectID; } -User* Entity::GetParentUser() const -{ - if (!IsPlayer()) - { +User* Entity::GetParentUser() const { + if (!IsPlayer()) { return nullptr; } return static_cast(this)->GetParentUser(); } -Component* Entity::GetComponent(int32_t componentID) const { +Component* Entity::GetComponent(eReplicaComponentType componentID) const { const auto& index = m_Components.find(componentID); - if (index == m_Components.end()) - { + if (index == m_Components.end()) { return nullptr; } - + return index->second; } -bool Entity::HasComponent(const int32_t componentId) const -{ +bool Entity::HasComponent(const eReplicaComponentType componentId) const { return m_Components.find(componentId) != m_Components.end(); } -void Entity::AddComponent(const int32_t componentId, Component* component) -{ - if (HasComponent(componentId)) - { +void Entity::AddComponent(const eReplicaComponentType componentId, Component* component) { + if (HasComponent(componentId)) { return; } @@ -801,20 +817,36 @@ void Entity::AddComponent(const int32_t componentId, Component* component) std::vector Entity::GetScriptComponents() { std::vector comps; - for (std::pair p : m_Components) { - if (p.first == COMPONENT_TYPE_SCRIPT) { + for (std::pair p : m_Components) { + if (p.first == eReplicaComponentType::SCRIPT) { comps.push_back(static_cast(p.second)); } } - + return comps; } +void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Subscribe(scriptObjId, scriptToAdd); + } +} + +void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Unsubscribe(scriptObjId); + } +} + void Entity::SetProximityRadius(float proxRadius, std::string name) { ProximityMonitorComponent* proxMon = GetComponent(); if (!proxMon) { proxMon = new ProximityMonitorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROXIMITY_MONITOR, proxMon); + m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon); } proxMon->SetProximityRadius(proxRadius, name); } @@ -823,12 +855,12 @@ void Entity::SetProximityRadius(dpEntity* entity, std::string name) { ProximityMonitorComponent* proxMon = GetComponent(); if (!proxMon) { proxMon = new ProximityMonitorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROXIMITY_MONITOR, proxMon); + m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon); } proxMon->SetProximityRadius(entity, name); } -void Entity::SetGMLevel(uint8_t value) { +void Entity::SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; if (GetParentUser()) { Character* character = GetParentUser()->GetLastUsedChar(); @@ -845,7 +877,7 @@ void Entity::SetGMLevel(uint8_t value) { } void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType) { - if (packetType == PACKET_TYPE_CONSTRUCTION) { + if (packetType == eReplicaPacketType::CONSTRUCTION) { outBitStream->Write(m_ObjectID); outBitStream->Write(m_TemplateID); @@ -856,8 +888,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke for (size_t i = 0; i < name.size(); ++i) { outBitStream->Write(name[i]); } - } - else { + } else { const auto& name = GetVar(u"npcName"); outBitStream->Write(uint8_t(name.size())); @@ -870,10 +901,10 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke const auto& syncLDF = GetVar>(u"syncLDF"); - //limiting it to lot 14 right now - if (m_Settings.size() > 0 && m_TemplateID == 14) { + // Only sync for models. + if (m_Settings.size() > 0 && (GetComponent() && !GetComponent())) { outBitStream->Write1(); //ldf data - + RakNet::BitStream settingStream; settingStream.Write(m_Settings.size()); @@ -886,8 +917,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write(settingStream.GetNumberOfBytesUsed() + 1); outBitStream->Write(0); //no compression used outBitStream->Write(settingStream); - } - else if (!syncLDF.empty()) { + } else if (!syncLDF.empty()) { std::vector ldfData; for (const auto& data : syncLDF) { @@ -908,25 +938,26 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write(settingStream.GetNumberOfBytesUsed() + 1); outBitStream->Write(0); //no compression used outBitStream->Write(settingStream); - } - else { - outBitStream->Write0(); //No ldf data + } else { + outBitStream->Write0(); //No ldf data } - if (m_Trigger != nullptr && m_Trigger->events.size() > 0) { - outBitStream->Write1(); - } - else { + TriggerComponent* triggerComponent; + if (TryGetComponent(eReplicaComponentType::TRIGGER, triggerComponent)) { + // has trigger component, check to see if we have events to handle + auto* trigger = triggerComponent->GetTrigger(); + outBitStream->Write(trigger && trigger->events.size() > 0); + } else { // no trigger componenet, so definitely no triggers outBitStream->Write0(); } + if (m_ParentEntity != nullptr || m_SpawnerID != 0) { outBitStream->Write1(); - if (m_ParentEntity != nullptr) outBitStream->Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), OBJECT_BIT_CLIENT)); + if (m_ParentEntity != nullptr) outBitStream->Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), static_cast(eObjectBits::CLIENT))); else if (m_Spawner != nullptr && m_Spawner->m_Info.isNetwork) outBitStream->Write(m_SpawnerID); - else outBitStream->Write(GeneralUtils::SetBit(m_SpawnerID, OBJECT_BIT_CLIENT)); - } - else outBitStream->Write0(); + else outBitStream->Write(GeneralUtils::SetBit(m_SpawnerID, static_cast(eObjectBits::CLIENT))); + } else outBitStream->Write0(); outBitStream->Write(m_HasSpawnerNodeID); if (m_HasSpawnerNodeID) outBitStream->Write(m_SpawnerNodeID); @@ -941,16 +972,15 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write0(); //ObjectWorldState - if (m_GMLevel != 0) { + if (m_GMLevel != eGameMasterLevel::CIVILIAN) { outBitStream->Write1(); outBitStream->Write(m_GMLevel); - } - else outBitStream->Write0(); //No GM Level + } else outBitStream->Write0(); //No GM Level } - + // Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity. - outBitStream->Write(m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION); - if (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION) { + outBitStream->Write(m_IsParentChildDirty || packetType == eReplicaPacketType::CONSTRUCTION); + if (m_IsParentChildDirty || packetType == eReplicaPacketType::CONSTRUCTION) { m_IsParentChildDirty = false; outBitStream->Write(m_ParentEntity != nullptr); if (m_ParentEntity) { @@ -975,73 +1005,63 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType bool destroyableSerialized = false; bool bIsInitialUpdate = false; - if (packetType == PACKET_TYPE_CONSTRUCTION) bIsInitialUpdate = true; + if (packetType == eReplicaPacketType::CONSTRUCTION) bIsInitialUpdate = true; unsigned int flags = 0; PossessableComponent* possessableComponent; - if (TryGetComponent(COMPONENT_TYPE_POSSESSABLE, possessableComponent)) - { + if (TryGetComponent(eReplicaComponentType::POSSESSABLE, possessableComponent)) { possessableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ModuleAssemblyComponent* moduleAssemblyComponent; - if (TryGetComponent(COMPONENT_TYPE_MODULE_ASSEMBLY, moduleAssemblyComponent)) - { + if (TryGetComponent(eReplicaComponentType::MODULE_ASSEMBLY, moduleAssemblyComponent)) { moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } - + ControllablePhysicsComponent* controllablePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) - { + if (TryGetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) { controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SimplePhysicsComponent* simplePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_SIMPLE_PHYSICS, simplePhysicsComponent)) - { + if (TryGetComponent(eReplicaComponentType::SIMPLE_PHYSICS, simplePhysicsComponent)) { simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RigidbodyPhantomPhysicsComponent* rigidbodyPhantomPhysics; - if (TryGetComponent(COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) - { + if (TryGetComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) { rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate, flags); } VehiclePhysicsComponent* vehiclePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_VEHICLE_PHYSICS, vehiclePhysicsComponent)) - { + if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) { vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } PhantomPhysicsComponent* phantomPhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS, phantomPhysicsComponent)) - { + if (TryGetComponent(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysicsComponent)) { phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SoundTriggerComponent* soundTriggerComponent; - if (TryGetComponent(COMPONENT_TYPE_SOUND_TRIGGER, soundTriggerComponent)) { - soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + if (TryGetComponent(eReplicaComponentType::SOUND_TRIGGER, soundTriggerComponent)) { + soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BuffComponent* buffComponent; - if (TryGetComponent(COMPONENT_TYPE_BUFF, buffComponent)) - { + if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) { buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags); DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) - { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; } - if (HasComponent(COMPONENT_TYPE_COLLECTIBLE)) { + if (HasComponent(eReplicaComponentType::COLLECTIBLE)) { DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent) && !destroyableSerialized) - { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; @@ -1049,59 +1069,68 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } PetComponent* petComponent; - if (TryGetComponent(COMPONENT_TYPE_PET, petComponent)) - { + if (TryGetComponent(eReplicaComponentType::PET, petComponent)) { petComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } CharacterComponent* characterComponent; - if (TryGetComponent(COMPONENT_TYPE_CHARACTER, characterComponent)) { + if (TryGetComponent(eReplicaComponentType::CHARACTER, characterComponent)) { PossessorComponent* possessorComponent; - if (TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { + if (TryGetComponent(eReplicaComponentType::POSSESSOR, possessorComponent)) { possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } else { // Should never happen, but just to be safe outBitStream->Write0(); } + + LevelProgressionComponent* levelProgressionComponent; + if (TryGetComponent(eReplicaComponentType::LEVEL_PROGRESSION, levelProgressionComponent)) { + levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + } else { + // Should never happen, but just to be safe + outBitStream->Write0(); + } + + PlayerForcedMovementComponent* playerForcedMovementComponent; + if (TryGetComponent(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, playerForcedMovementComponent)) { + playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + } else { + // Should never happen, but just to be safe + outBitStream->Write0(); + } + characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } - if (HasComponent(COMPONENT_TYPE_ITEM)) - { + if (HasComponent(eReplicaComponentType::ITEM)) { outBitStream->Write0(); } InventoryComponent* inventoryComponent; - if (TryGetComponent(COMPONENT_TYPE_INVENTORY, inventoryComponent)) - { + if (TryGetComponent(eReplicaComponentType::INVENTORY, inventoryComponent)) { inventoryComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ScriptComponent* scriptComponent; - if (TryGetComponent(COMPONENT_TYPE_SCRIPT, scriptComponent)) - { + if (TryGetComponent(eReplicaComponentType::SCRIPT, scriptComponent)) { scriptComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SkillComponent* skillComponent; - if (TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) - { + if (TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) { skillComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BaseCombatAIComponent* baseCombatAiComponent; - if (TryGetComponent(COMPONENT_TYPE_BASE_COMBAT_AI, baseCombatAiComponent)) - { + if (TryGetComponent(eReplicaComponentType::BASE_COMBAT_AI, baseCombatAiComponent)) { baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RebuildComponent* rebuildComponent; - if (TryGetComponent(COMPONENT_TYPE_REBUILD, rebuildComponent)) - { + if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, rebuildComponent)) { DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent) && !destroyableSerialized) - { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; @@ -1109,78 +1138,71 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } MovingPlatformComponent* movingPlatformComponent; - if (TryGetComponent(COMPONENT_TYPE_MOVING_PLATFORM, movingPlatformComponent)) - { + if (TryGetComponent(eReplicaComponentType::MOVING_PLATFORM, movingPlatformComponent)) { movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SwitchComponent* switchComponent; - if (TryGetComponent(COMPONENT_TYPE_SWITCH, switchComponent)) { + if (TryGetComponent(eReplicaComponentType::SWITCH, switchComponent)) { switchComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } VendorComponent* vendorComponent; - if (TryGetComponent(COMPONENT_TYPE_VENDOR, vendorComponent)) - { + if (TryGetComponent(eReplicaComponentType::VENDOR, vendorComponent)) { vendorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BouncerComponent* bouncerComponent; - if (TryGetComponent(COMPONENT_TYPE_BOUNCER, bouncerComponent)) - { + if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) { bouncerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ScriptedActivityComponent* scriptedActivityComponent; - if (TryGetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY, scriptedActivityComponent)) { + if (TryGetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY, scriptedActivityComponent)) { scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } - ShootingGalleryComponent* shootingGalleryComponent; - if (TryGetComponent(COMPONENT_TYPE_SHOOTING_GALLERY, shootingGalleryComponent)) { - shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate, flags); - } + ShootingGalleryComponent* shootingGalleryComponent; + if (TryGetComponent(eReplicaComponentType::SHOOTING_GALLERY, shootingGalleryComponent)) { + shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + } RacingControlComponent* racingControlComponent; - if (TryGetComponent(COMPONENT_TYPE_RACING_CONTROL, racingControlComponent)) - { + if (TryGetComponent(eReplicaComponentType::RACING_CONTROL, racingControlComponent)) { racingControlComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } LUPExhibitComponent* lupExhibitComponent; - if (TryGetComponent(COMPONENT_TYPE_EXHIBIT, lupExhibitComponent)) - { + if (TryGetComponent(eReplicaComponentType::LUP_EXHIBIT, lupExhibitComponent)) { lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ModelComponent* modelComponent; - if (TryGetComponent(COMPONENT_TYPE_MODEL, modelComponent)) { + if (TryGetComponent(eReplicaComponentType::MODEL, modelComponent)) { modelComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RenderComponent* renderComponent; - if (TryGetComponent(COMPONENT_TYPE_RENDER, renderComponent)) - { + if (TryGetComponent(eReplicaComponentType::RENDER, renderComponent)) { renderComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } - if (HasComponent(COMPONENT_TYPE_ZONE_CONTROL)) - { + if (modelComponent) { + DestroyableComponent* destroyableComponent; + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { + destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + destroyableSerialized = true; + } + } + + if (HasComponent(eReplicaComponentType::ZONE_CONTROL)) { outBitStream->Write(0x40000000); } // BBB Component, unused currently - // Need to to write0 so that is serlaizese correctly + // Need to to write0 so that is serialized correctly // TODO: Implement BBB Component outBitStream->Write0(); - - /* - if (m_Trigger != nullptr) - { - outBitStream->Write1(); - outBitStream->Write(m_Trigger->id); - } - */ } void Entity::ResetFlags() { @@ -1191,8 +1213,7 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) { //This function should only ever be called from within Character, meaning doc should always exist when this is called. //Naturally, we don't include any non-player components in this update function. - for (const auto& pair : m_Components) - { + for (const auto& pair : m_Components) { if (pair.second == nullptr) continue; pair.second->UpdateXml(doc); @@ -1200,17 +1221,22 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) { } void Entity::Update(const float deltaTime) { - for (int i = 0; i < m_Timers.size(); i++) { - m_Timers[i]->Update(deltaTime); - if (m_Timers[i]->GetTime() <= 0) { - const auto timerName = m_Timers[i]->GetName(); + uint32_t timerPosition; + timerPosition = 0; + while (timerPosition < m_Timers.size()) { + m_Timers[timerPosition]->Update(deltaTime); + if (m_Timers[timerPosition]->GetTime() <= 0) { + const auto timerName = m_Timers[timerPosition]->GetName(); - delete m_Timers[i]; - m_Timers.erase(m_Timers.begin() + i); + delete m_Timers[timerPosition]; + m_Timers.erase(m_Timers.begin() + timerPosition); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnTimerDone(this, timerName); } + TriggerEvent(eTriggerEventType::TIMER_DONE, this); + } else { + timerPosition++; } } @@ -1223,14 +1249,19 @@ void Entity::Update(const float deltaTime) { } } - if (IsSleeping()) - { + // Add pending timers to the list of timers so they start next tick. + if (m_PendingTimers.size() > 0) { + for (auto namedTimer : m_PendingTimers) { + m_Timers.push_back(namedTimer); + } + m_PendingTimers.clear(); + } + + if (IsSleeping()) { Sleep(); return; - } - else - { + } else { Wake(); } @@ -1238,8 +1269,7 @@ void Entity::Update(const float deltaTime) { script->OnUpdate(this); } - for (const auto& pair : m_Components) - { + for (const auto& pair : m_Components) { if (pair.second == nullptr) continue; pair.second->Update(deltaTime); @@ -1272,8 +1302,8 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { script->OnCollisionPhantom(this, other); } - for (const auto& callback: m_PhantomCollisionCallbacks) { - callback(other); + for (const auto& callback : m_PhantomCollisionCallbacks) { + callback(other); } SwitchComponent* switchComp = GetComponent(); @@ -1281,26 +1311,23 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { switchComp->EntityEnter(other); } - TriggerEvent("OnEnter", other); + TriggerEvent(eTriggerEventType::ENTER, other); // POI system const auto& poi = GetVar(u"POI"); if (!poi.empty()) { auto* missionComponent = other->GetComponent(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_LOCATION, 0, 0, GeneralUtils::UTF16ToWTF8(poi)); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, GeneralUtils::UTF16ToWTF8(poi)); } } - if (!other->GetIsDead()) - { + if (!other->GetIsDead()) { auto* combat = GetComponent(); - - if (combat != nullptr) - { + + if (combat != nullptr) { const auto index = std::find(m_TargetsInPhantom.begin(), m_TargetsInPhantom.end(), otherEntity); if (index != m_TargetsInPhantom.end()) return; @@ -1314,12 +1341,15 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { } } -void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) -{ +void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { auto* other = EntityManager::Instance()->GetEntity(otherEntity); if (!other) return; - TriggerEvent("OnLeave", other); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnOffCollisionPhantom(this, other); + } + + TriggerEvent(eTriggerEventType::EXIT, other); SwitchComponent* switchComp = GetComponent(); if (switchComp) { @@ -1327,59 +1357,55 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) } const auto index = std::find(m_TargetsInPhantom.begin(), m_TargetsInPhantom.end(), otherEntity); - + if (index == m_TargetsInPhantom.end()) return; m_TargetsInPhantom.erase(index); } void Entity::OnFireEventServerSide(Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnFireEventServerSide(this, sender, args, param1, param2, param3); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnFireEventServerSide(this, sender, args, param1, param2, param3); } } void Entity::OnActivityStateChangeRequest(LWOOBJID senderID, int32_t value1, int32_t value2, const std::u16string& stringValue) { - for (CppScripts::Script *script : CppScripts::GetEntityScripts(this)) { - script->OnActivityStateChangeRequest(this, senderID, value1, value2, stringValue); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnActivityStateChangeRequest(this, senderID, value1, value2, stringValue); } } -void Entity::OnCinematicUpdate(Entity *self, Entity *sender, eCinematicEvent event, const std::u16string &pathName, - float_t pathTime, float_t totalTime, int32_t waypoint) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnCinematicUpdate(self, sender, event, pathName, pathTime, totalTime, waypoint); - } +void Entity::OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, + float_t pathTime, float_t totalTime, int32_t waypoint) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnCinematicUpdate(self, sender, event, pathName, pathTime, totalTime, waypoint); + } } -void Entity::NotifyObject(Entity* sender, const std::string& name, int32_t param1, int32_t param2) -{ +void Entity::NotifyObject(Entity* sender, const std::string& name, int32_t param1, int32_t param2) { GameMessages::SendNotifyObject(GetObjectID(), sender->GetObjectID(), GeneralUtils::ASCIIToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnNotifyObject(this, sender, name, param1, param2); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnNotifyObject(this, sender, name, param1, param2); } } -void Entity::OnEmoteReceived(const int32_t emote, Entity* target) -{ - for (auto* script : CppScripts::GetEntityScripts(this)) - { +void Entity::OnEmoteReceived(const int32_t emote, Entity* target) { + for (auto* script : CppScripts::GetEntityScripts(this)) { script->OnEmoteReceived(this, emote, target); } } void Entity::OnUse(Entity* originator) { - TriggerEvent("OnInteract"); + TriggerEvent(eTriggerEventType::INTERACT, originator); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnUse(this, originator); } // component base class when - - for (const auto& pair : m_Components) - { + + for (const auto& pair : m_Components) { if (pair.second == nullptr) continue; pair.second->OnUse(originator); @@ -1393,91 +1419,87 @@ void Entity::OnHitOrHealResult(Entity* attacker, int32_t damage) { } void Entity::OnHit(Entity* attacker) { + TriggerEvent(eTriggerEventType::HIT, attacker); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnHit(this, attacker); } } -void Entity::OnZonePropertyEditBegin() -{ +void Entity::OnZonePropertyEditBegin() { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyEditBegin(this); } } -void Entity::OnZonePropertyEditEnd() -{ +void Entity::OnZonePropertyEditEnd() { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyEditEnd(this); } } -void Entity::OnZonePropertyModelEquipped() -{ +void Entity::OnZonePropertyModelEquipped() { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelEquipped(this); } } -void Entity::OnZonePropertyModelPlaced(Entity* player) -{ +void Entity::OnZonePropertyModelPlaced(Entity* player) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelPlaced(this, player); } } -void Entity::OnZonePropertyModelPickedUp(Entity* player) -{ +void Entity::OnZonePropertyModelPickedUp(Entity* player) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelPickedUp(this, player); } } -void Entity::OnZonePropertyModelRemoved(Entity* player) -{ +void Entity::OnZonePropertyModelRemoved(Entity* player) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelRemoved(this, player); } } -void Entity::OnZonePropertyModelRemovedWhileEquipped(Entity* player) -{ +void Entity::OnZonePropertyModelRemovedWhileEquipped(Entity* player) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelRemovedWhileEquipped(this, player); } } -void Entity::OnZonePropertyModelRotated(Entity* player) -{ +void Entity::OnZonePropertyModelRotated(Entity* player) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnZonePropertyModelRotated(this, player); } } -void Entity::OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ +void Entity::OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnMessageBoxResponse(this, sender, button, identifier, userData); } } -void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ +void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier); } } -void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) -{ +void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) { if (!m_PlayerIsReadyForUpdates) return; auto* destroyableComponent = GetComponent(); - if (destroyableComponent == nullptr) - { + if (destroyableComponent == nullptr) { Kill(EntityManager::Instance()->GetEntity(source)); return; } + auto* possessorComponent = GetComponent(); + if (possessorComponent) { + if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) { + auto* mount = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + if (mount) possessorComponent->Dismount(mount, true); + } + } destroyableComponent->Smash(source, killType, deathType); } @@ -1493,62 +1515,53 @@ void Entity::Kill(Entity* murderer) { //OMAI WA MOU, SHINDERIU - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) - { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnDie(this, murderer); } - if (m_Spawner != nullptr) - { + if (m_Spawner != nullptr) { m_Spawner->NotifyOfEntityDeath(m_ObjectID); } - if (!IsPlayer()) - { + if (!IsPlayer()) { EntityManager::Instance()->DestroyEntity(this); } - + const auto& grpNameQBShowBricks = GetVar(u"grpNameQBShowBricks"); - if (!grpNameQBShowBricks.empty()) - { + if (!grpNameQBShowBricks.empty()) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(grpNameQBShowBricks); Spawner* spawner = nullptr; - if (!spawners.empty()) - { + if (!spawners.empty()) { spawner = spawners[0]; - } - else - { + } else { spawners = dZoneManager::Instance()->GetSpawnersInGroup(grpNameQBShowBricks); - if (!spawners.empty()) - { + if (!spawners.empty()) { spawner = spawners[0]; } } - if (spawner != nullptr) - { + if (spawner != nullptr) { spawner->Spawn(); } } - // Track a player being smashed - auto* characterComponent = GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(TimesSmashed); - } + // Track a player being smashed + auto* characterComponent = GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(TimesSmashed); + } - // Track a player smashing something else - if (murderer != nullptr) { - auto* murdererCharacterComponent = murderer->GetComponent(); - if (murdererCharacterComponent != nullptr) { - murdererCharacterComponent->UpdatePlayerStatistic(SmashablesSmashed); - } - } + // Track a player smashing something else + if (murderer != nullptr) { + auto* murdererCharacterComponent = murderer->GetComponent(); + if (murdererCharacterComponent != nullptr) { + murdererCharacterComponent->UpdatePlayerStatistic(SmashablesSmashed); + } + } } void Entity::AddDieCallback(const std::function& callback) { @@ -1556,14 +1569,14 @@ void Entity::AddDieCallback(const std::function& callback) { } void Entity::AddCollisionPhantomCallback(const std::function& callback) { - m_PhantomCollisionCallbacks.push_back(callback); + m_PhantomCollisionCallbacks.push_back(callback); } -void Entity::AddRebuildCompleteCallback(const std::function &callback) const { - auto* rebuildComponent = GetComponent(); - if (rebuildComponent != nullptr) { - rebuildComponent->AddRebuildCompleteCallback(callback); - } +void Entity::AddRebuildCompleteCallback(const std::function& callback) const { + auto* rebuildComponent = GetComponent(); + if (rebuildComponent != nullptr) { + rebuildComponent->AddRebuildCompleteCallback(callback); + } } bool Entity::GetIsDead() const { @@ -1584,37 +1597,35 @@ void Entity::PickupItem(const LWOOBJID& objectID) { InventoryComponent* inv = GetComponent(); if (!inv) return; - CDObjectsTable* objectsTable = CDClientManager::Instance()->GetTable("Objects"); - + CDObjectsTable* objectsTable = CDClientManager::Instance().GetTable(); + auto& droppedLoot = static_cast(this)->GetDroppedLoot(); for (const auto& p : droppedLoot) { if (p.first == objectID) { - auto* characterComponent = GetComponent(); - if (characterComponent != nullptr) { - characterComponent->TrackLOTCollection(p.second.lot); - } + auto* characterComponent = GetComponent(); + if (characterComponent != nullptr) { + characterComponent->TrackLOTCollection(p.second.lot); + } const CDObjects& object = objectsTable->GetByID(p.second.lot); if (object.id != 0 && object.type == "Powerup") { - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable(); std::vector skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); }); for (CDObjectSkills skill : skills) { - CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance().GetTable(); CDSkillBehavior behaviorData = skillBehTable->GetSkillByID(skill.skillID); SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID()); auto* missionComponent = GetComponent(); - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_POWERUP, skill.skillID); + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID); } } - } - else { - inv->AddItem(p.second.lot, p.second.count, eLootSourceType::LOOT_SOURCE_PICKUP, eInventoryType::INVALID, {}, LWOOBJID_EMPTY, true, false, LWOOBJID_EMPTY, eInventoryType::INVALID, 1); + } else { + inv->AddItem(p.second.lot, p.second.count, eLootSourceType::PICKUP, eInventoryType::INVALID, {}, LWOOBJID_EMPTY, true, false, LWOOBJID_EMPTY, eInventoryType::INVALID, 1); } } } @@ -1626,7 +1637,7 @@ bool Entity::CanPickupCoins(uint64_t count) { if (!IsPlayer()) return false; auto* player = static_cast(this); auto droppedCoins = player->GetDroppedCoins(); - if (count > droppedCoins) { + if (count > droppedCoins) { return false; } else { player->SetDroppedCoins(droppedCoins - count); @@ -1649,18 +1660,24 @@ void Entity::AddChild(Entity* child) { void Entity::RemoveChild(Entity* child) { if (!child) return; - for (auto entity = m_ChildEntities.begin(); entity != m_ChildEntities.end(); entity++) { - if (*entity && (*entity)->GetObjectID() == child->GetObjectID()) { + uint32_t entityPosition = 0; + while (entityPosition < m_ChildEntities.size()) { + if (!m_ChildEntities[entityPosition] || (m_ChildEntities[entityPosition])->GetObjectID() == child->GetObjectID()) { m_IsParentChildDirty = true; - m_ChildEntities.erase(entity); - return; + m_ChildEntities.erase(m_ChildEntities.begin() + entityPosition); + } else { + entityPosition++; } } } +void Entity::RemoveParent() { + this->m_ParentEntity = nullptr; +} + void Entity::AddTimer(std::string name, float time) { EntityTimer* timer = new EntityTimer(name, time); - m_Timers.push_back(timer); + m_PendingTimers.push_back(timer); } void Entity::AddCallbackTimer(float time, std::function callback) { @@ -1668,12 +1685,9 @@ void Entity::AddCallbackTimer(float time, std::function callback) { m_CallbackTimers.push_back(timer); } -bool Entity::HasTimer(const std::string& name) -{ - for (auto* timer : m_Timers) - { - if (timer->GetName() == name) - { +bool Entity::HasTimer(const std::string& name) { + for (auto* timer : m_Timers) { + if (timer->GetName() == name) { return true; } } @@ -1681,13 +1695,11 @@ bool Entity::HasTimer(const std::string& name) return false; } -void Entity::CancelCallbackTimers() -{ - for (auto* callback : m_CallbackTimers) - { +void Entity::CancelCallbackTimers() { + for (auto* callback : m_CallbackTimers) { delete callback; } - + m_CallbackTimers.clear(); } @@ -1699,13 +1711,13 @@ void Entity::ScheduleKillAfterUpdate(Entity* murderer) { } void Entity::CancelTimer(const std::string& name) { - for (int i = 0; i < m_Timers.size(); i++) { - if (m_Timers[i]->GetName() == name) { - delete m_Timers[i]; - m_Timers.erase(m_Timers.begin() + i); - return; - } - } + for (int i = 0; i < m_Timers.size(); i++) { + if (m_Timers[i]->GetName() == name) { + delete m_Timers[i]; + m_Timers.erase(m_Timers.begin() + i); + return; + } + } } void Entity::CancelAllTimers() { @@ -1713,8 +1725,7 @@ void Entity::CancelAllTimers() { if (timer) delete timer; }*/ - for (auto* timer : m_Timers) - { + for (auto* timer : m_Timers) { delete timer; } @@ -1731,106 +1742,16 @@ bool Entity::IsPlayer() const { return m_TemplateID == 1 && GetSystemAddress() != UNASSIGNED_SYSTEM_ADDRESS; } -void Entity::TriggerEvent(std::string eventID, Entity* optionalTarget) { - if (m_Trigger != nullptr && m_Trigger->enabled) { - for (LUTriggers::Event* triggerEvent : m_Trigger->events) { - if (triggerEvent->eventID == eventID) { - for (LUTriggers::Command* cmd : triggerEvent->commands) { - HandleTriggerCommand(cmd->id, cmd->target, cmd->targetName, cmd->args, optionalTarget); - } - } - } - } +void Entity::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) { + auto* triggerComponent = GetComponent(); + if (triggerComponent) triggerComponent->TriggerEvent(event, optionalTarget); } -// This should probably get it's own triggers class at some point... -void Entity::HandleTriggerCommand(std::string id, std::string target, std::string targetName, std::string args, Entity* optionalTarget) { - std::vector argArray; - // Parse args - std::stringstream ssData(args); - std::string token; - char deliminator = ','; - - while (std::getline(ssData, token, deliminator)) { - std::string lowerToken; - for (char character : token) { - lowerToken.push_back(std::tolower(character)); // make lowercase to ensure it works - } - argArray.push_back(lowerToken); - } - - std::vector targetEntities; - if (target == "self") targetEntities.push_back(this); - if (target == "objGroup") targetEntities = EntityManager::Instance()->GetEntitiesInGroup(targetName); - if (optionalTarget) targetEntities.push_back(optionalTarget); - if (targetEntities.size() == 0) return; - for (Entity* targetEntity : targetEntities) { - if (!targetEntity) continue; - - if (id == "SetPhysicsVolumeEffect") { - PhantomPhysicsComponent* phanPhys = GetComponent(); - if (!phanPhys) return; - - phanPhys->SetPhysicsEffectActive(true); - uint32_t effectType = 0; - if (argArray[0] == "push") effectType = 0; - else if (argArray[0] == "attract") effectType = 1; - else if (argArray[0] == "repulse") effectType = 2; - else if (argArray[0] == "gravity") effectType = 3; - else if (argArray[0] == "friction") effectType = 4; - - phanPhys->SetEffectType(effectType); - phanPhys->SetDirectionalMultiplier(std::stof(argArray[1])); - if (argArray.size() > 4) { - NiPoint3 direction = NiPoint3::ZERO; - GeneralUtils::TryParse(argArray[2], direction.x); - GeneralUtils::TryParse(argArray[3], direction.y); - GeneralUtils::TryParse(argArray[4], direction.z); - phanPhys->SetDirection(direction); - } - if (argArray.size() > 5) { - phanPhys->SetMin(std::stoi(argArray[6])); - phanPhys->SetMax(std::stoi(argArray[7])); - } - - if (target == "self") { - EntityManager::Instance()->ConstructEntity(this); - } - } - else if (id == "updateMission") { - CDMissionTasksTable* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - std::vector missionTasks = missionTasksTable->Query([=](CDMissionTasks entry) { - std::string lowerTargetGroup; - for (char character : entry.targetGroup) { - lowerTargetGroup.push_back(std::tolower(character)); // make lowercase to ensure it works - } - - return (lowerTargetGroup == argArray[4]); - }); - - for (const CDMissionTasks& task : missionTasks) { - MissionComponent* missionComponent = targetEntity->GetComponent(); - if (!missionComponent) continue; - - missionComponent->ForceProgress(task.id, task.uid, std::stoi(argArray[2])); - } - } - else if (id == "fireEvent") { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { - script->OnFireEventServerSide(targetEntity, this, args, 0, 0, 0); - } - } - } -} - -Entity* Entity::GetOwner() const -{ - if (m_OwnerOverride != LWOOBJID_EMPTY) - { +Entity* Entity::GetOwner() const { + if (m_OwnerOverride != LWOOBJID_EMPTY) { auto* other = EntityManager::Instance()->GetEntity(m_OwnerOverride); - if (other != nullptr) - { + if (other != nullptr) { return other->GetOwner(); } } @@ -1838,272 +1759,225 @@ Entity* Entity::GetOwner() const return const_cast(this); } -const NiPoint3& Entity::GetDefaultPosition() const -{ +const NiPoint3& Entity::GetDefaultPosition() const { return m_DefaultPosition; } -const NiQuaternion& Entity::GetDefaultRotation() const -{ +const NiQuaternion& Entity::GetDefaultRotation() const { return m_DefaultRotation; } -float Entity::GetDefaultScale() const -{ +float Entity::GetDefaultScale() const { return m_Scale; } -void Entity::SetOwnerOverride(const LWOOBJID value) -{ +void Entity::SetOwnerOverride(const LWOOBJID value) { m_OwnerOverride = value; } -bool Entity::GetIsGhostingCandidate() const -{ +bool Entity::GetIsGhostingCandidate() const { return m_IsGhostingCandidate; } -int8_t Entity::GetObservers() const -{ +int8_t Entity::GetObservers() const { return m_Observers; } -void Entity::SetObservers(int8_t value) -{ - if (value < 0) - { +void Entity::SetObservers(int8_t value) { + if (value < 0) { value = 0; } m_Observers = value; } -void Entity::Sleep() -{ +void Entity::Sleep() { auto* baseCombatAIComponent = GetComponent(); - - if (baseCombatAIComponent != nullptr) - { + + if (baseCombatAIComponent != nullptr) { baseCombatAIComponent->Sleep(); - } + } } -void Entity::Wake() -{ +void Entity::Wake() { auto* baseCombatAIComponent = GetComponent(); - - if (baseCombatAIComponent != nullptr) - { + + if (baseCombatAIComponent != nullptr) { baseCombatAIComponent->Wake(); } } -bool Entity::IsSleeping() const -{ +bool Entity::IsSleeping() const { return m_IsGhostingCandidate && m_Observers == 0; } -const NiPoint3& Entity::GetPosition() const -{ +const NiPoint3& Entity::GetPosition() const { if (!this) return NiPoint3::ZERO; auto* controllable = GetComponent(); - if (controllable != nullptr) - { + if (controllable != nullptr) { return controllable->GetPosition(); } auto* phantom = GetComponent(); - if (phantom != nullptr) - { + if (phantom != nullptr) { return phantom->GetPosition(); } auto* simple = GetComponent(); - if (simple != nullptr) - { + if (simple != nullptr) { return simple->GetPosition(); } auto* vehicel = GetComponent(); - if (vehicel != nullptr) - { + if (vehicel != nullptr) { return vehicel->GetPosition(); } return NiPoint3::ZERO; } -const NiQuaternion& Entity::GetRotation() const -{ +const NiQuaternion& Entity::GetRotation() const { auto* controllable = GetComponent(); - if (controllable != nullptr) - { + if (controllable != nullptr) { return controllable->GetRotation(); } auto* phantom = GetComponent(); - if (phantom != nullptr) - { + if (phantom != nullptr) { return phantom->GetRotation(); } auto* simple = GetComponent(); - if (simple != nullptr) - { + if (simple != nullptr) { return simple->GetRotation(); } - + auto* vehicel = GetComponent(); - if (vehicel != nullptr) - { + if (vehicel != nullptr) { return vehicel->GetRotation(); } return NiQuaternion::IDENTITY; } -void Entity::SetPosition(NiPoint3 position) -{ +void Entity::SetPosition(NiPoint3 position) { auto* controllable = GetComponent(); - if (controllable != nullptr) - { + if (controllable != nullptr) { controllable->SetPosition(position); } auto* phantom = GetComponent(); - if (phantom != nullptr) - { + if (phantom != nullptr) { phantom->SetPosition(position); } auto* simple = GetComponent(); - if (simple != nullptr) - { + if (simple != nullptr) { simple->SetPosition(position); } auto* vehicel = GetComponent(); - if (vehicel != nullptr) - { + if (vehicel != nullptr) { vehicel->SetPosition(position); } EntityManager::Instance()->SerializeEntity(this); } -void Entity::SetRotation(NiQuaternion rotation) -{ +void Entity::SetRotation(NiQuaternion rotation) { auto* controllable = GetComponent(); - if (controllable != nullptr) - { + if (controllable != nullptr) { controllable->SetRotation(rotation); } auto* phantom = GetComponent(); - if (phantom != nullptr) - { + if (phantom != nullptr) { phantom->SetRotation(rotation); } auto* simple = GetComponent(); - if (simple != nullptr) - { + if (simple != nullptr) { simple->SetRotation(rotation); } auto* vehicel = GetComponent(); - if (vehicel != nullptr) - { + if (vehicel != nullptr) { vehicel->SetRotation(rotation); } EntityManager::Instance()->SerializeEntity(this); } -bool Entity::GetBoolean(const std::u16string& name) const -{ +bool Entity::GetBoolean(const std::u16string& name) const { return GetVar(name); } -int32_t Entity::GetI32(const std::u16string& name) const -{ +int32_t Entity::GetI32(const std::u16string& name) const { return GetVar(name); } -int64_t Entity::GetI64(const std::u16string& name) const -{ +int64_t Entity::GetI64(const std::u16string& name) const { return GetVar(name); } -void Entity::SetBoolean(const std::u16string& name, const bool value) -{ +void Entity::SetBoolean(const std::u16string& name, const bool value) { SetVar(name, value); } -void Entity::SetI32(const std::u16string& name, const int32_t value) -{ +void Entity::SetI32(const std::u16string& name, const int32_t value) { SetVar(name, value); } -void Entity::SetI64(const std::u16string& name, const int64_t value) -{ +void Entity::SetI64(const std::u16string& name, const int64_t value) { SetVar(name, value); } -bool Entity::HasVar(const std::u16string& name) const -{ - for (auto* data : m_Settings) - { - if (data->GetKey() == name) - { +bool Entity::HasVar(const std::u16string& name) const { + for (auto* data : m_Settings) { + if (data->GetKey() == name) { return true; } } - + return false; } -uint16_t Entity::GetNetworkId() const -{ +uint16_t Entity::GetNetworkId() const { return m_NetworkID; } -void Entity::SetNetworkId(const uint16_t id) -{ +void Entity::SetNetworkId(const uint16_t id) { m_NetworkID = id; } -std::vector& Entity::GetTargetsInPhantom() -{ +std::vector& Entity::GetTargetsInPhantom() { std::vector valid; // Clean up invalid targets, like disconnected players - for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) - { + for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) { const auto id = m_TargetsInPhantom.at(i); auto* entity = EntityManager::Instance()->GetEntity(id); - if (entity == nullptr) - { + if (entity == nullptr) { continue; } @@ -2116,20 +1990,16 @@ std::vector& Entity::GetTargetsInPhantom() } void Entity::SendNetworkVar(const std::string& data, const SystemAddress& sysAddr) { - GameMessages::SendSetNetworkScriptVar(this, sysAddr, data); + GameMessages::SendSetNetworkScriptVar(this, sysAddr, data); } -LDFBaseData* Entity::GetVarData(const std::u16string& name) const -{ - for (auto* data : m_Settings) - { - if (data == nullptr) - { +LDFBaseData* Entity::GetVarData(const std::u16string& name) const { + for (auto* data : m_Settings) { + if (data == nullptr) { continue; } - if (data->GetKey() != name) - { + if (data->GetKey() != name) { continue; } @@ -2139,12 +2009,10 @@ LDFBaseData* Entity::GetVarData(const std::u16string& name) const return nullptr; } -std::string Entity::GetVarAsString(const std::u16string& name) const -{ +std::string Entity::GetVarAsString(const std::u16string& name) const { auto* data = GetVarData(name); - if (data == nullptr) - { + if (data == nullptr) { return ""; } @@ -2152,15 +2020,15 @@ std::string Entity::GetVarAsString(const std::u16string& name) const } void Entity::Resurrect() { - if (IsPlayer()) { - GameMessages::SendResurrect(this); - } + if (IsPlayer()) { + GameMessages::SendResurrect(this); + } } void Entity::AddToGroup(const std::string& group) { - if (std::find(m_Groups.begin(), m_Groups.end(), group) == m_Groups.end()) { - m_Groups.push_back(group); - } + if (std::find(m_Groups.begin(), m_Groups.end(), group) == m_Groups.end()) { + m_Groups.push_back(group); + } } void Entity::RetroactiveVaultSize() { diff --git a/dGame/Entity.h b/dGame/Entity.h index c804deaa..b980b179 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -4,65 +4,76 @@ #include #include #include +#include #include -#include "../thirdparty/raknet/Source/Replica.h" -#include "../thirdparty/raknet/Source/ReplicaManager.h" - -#include "dCommonVars.h" -#include "User.h" #include "NiPoint3.h" #include "NiQuaternion.h" #include "LDFFormat.h" -#include "Loot.h" -#include "Zone.h" +#include "eKillType.h" -#include "EntityTimer.h" -#include "EntityCallbackTimer.h" -#include "EntityInfo.h" +namespace Loot { + class Info; +}; + +namespace tinyxml2 { + class XMLDocument; +}; class Player; +class EntityInfo; +class User; class Spawner; class ScriptComponent; class dpEntity; +class EntityTimer; class Component; +class Item; class Character; +class EntityCallbackTimer; +enum class eTriggerEventType; +enum class eGameMasterLevel : uint8_t; +enum class eReplicaComponentType : uint32_t; +enum class eReplicaPacketType : uint8_t; +enum class eCinematicEvent : uint32_t; + +namespace CppScripts { + class Script; +}; /** * An entity in the world. Has multiple components. */ class Entity { public: - explicit Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity = nullptr); - virtual ~Entity(); + explicit Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity = nullptr); + virtual ~Entity(); virtual void Initialize(); - - bool operator==(const Entity& other) const; - bool operator!=(const Entity& other) const; + + bool operator==(const Entity& other) const; + bool operator!=(const Entity& other) const; /** * Getters */ - - const LWOOBJID& GetObjectID() const { return m_ObjectID; } - const LOT GetLOT() const { return m_TemplateID; } + const LWOOBJID& GetObjectID() const { return m_ObjectID; } - Character* GetCharacter() const { return m_Character; } + const LOT GetLOT() const { return m_TemplateID; } - uint8_t GetGMLevel() const { return m_GMLevel; } + Character* GetCharacter() const { return m_Character; } - uint8_t GetCollectibleID() const { return uint8_t(m_CollectibleID); } + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } + + uint8_t GetCollectibleID() const { return uint8_t(m_CollectibleID); } Entity* GetParentEntity() const { return m_ParentEntity; } - LUTriggers::Trigger* GetTrigger() const { return m_Trigger; } - std::vector& GetGroups() { return m_Groups; }; Spawner* GetSpawner() const { return m_Spawner; } - + LWOOBJID GetSpawnerID() const { return m_SpawnerID; } const std::vector& GetSettings() const { return m_Settings; } @@ -71,7 +82,7 @@ public: bool GetIsDead() const; - bool GetPlayerReadyForUpdates() const { return m_PlayerIsReadyForUpdates;} + bool GetPlayerReadyForUpdates() const { return m_PlayerIsReadyForUpdates; } bool GetIsGhostingCandidate() const; @@ -86,7 +97,7 @@ public: const NiQuaternion& GetDefaultRotation() const; float GetDefaultScale() const; - + const NiPoint3& GetPosition() const; const NiQuaternion& GetRotation() const; @@ -99,9 +110,9 @@ public: * Setters */ - void SetCharacter(Character* value) { m_Character = value; } - - void SetGMLevel(uint8_t value); + void SetCharacter(Character* value) { m_Character = value; } + + void SetGMLevel(eGameMasterLevel value); void SetOwnerOverride(LWOOBJID value); @@ -118,32 +129,36 @@ public: virtual void SetRespawnPos(NiPoint3 position) {} virtual void SetRespawnRot(NiQuaternion rotation) {} - + virtual void SetSystemAddress(const SystemAddress& value) {}; /** * Component management */ - Component* GetComponent(int32_t componentID) const; + Component* GetComponent(eReplicaComponentType componentID) const; template T* GetComponent() const; template - bool TryGetComponent(int32_t componentId, T*& component) const; + bool TryGetComponent(eReplicaComponentType componentId, T*& component) const; - bool HasComponent(int32_t componentId) const; + bool HasComponent(eReplicaComponentType componentId) const; - void AddComponent(int32_t componentId, Component* component); + void AddComponent(eReplicaComponentType componentId, Component* component); std::vector GetScriptComponents(); + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName); + void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName); + void SetProximityRadius(float proxRadius, std::string name); void SetProximityRadius(dpEntity* entity, std::string name); void AddChild(Entity* child); void RemoveChild(Entity* child); + void RemoveParent(); void AddTimer(std::string name, float time); void AddCallbackTimer(float time, std::function callback); bool HasTimer(const std::string& name); @@ -151,32 +166,32 @@ public: void CancelAllTimers(); void CancelTimer(const std::string& name); - void AddToGroup(const std::string& group); + void AddToGroup(const std::string& group); bool IsPlayer() const; - std::unordered_map& GetComponents() { return m_Components; } // TODO: Remove - + std::unordered_map& GetComponents() { return m_Components; } // TODO: Remove + void WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); void WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); - void ResetFlags(); - void UpdateXMLDoc(tinyxml2::XMLDocument* doc); + void ResetFlags(); + void UpdateXMLDoc(tinyxml2::XMLDocument* doc); void Update(float deltaTime); // Events void OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status); void OnCollisionPhantom(LWOOBJID otherEntity); - void OnCollisionLeavePhantom(LWOOBJID otherEntity); + void OnCollisionLeavePhantom(LWOOBJID otherEntity); - void OnFireEventServerSide(Entity* sender, std::string args, int32_t param1 = -1, int32_t param2 = -1, int32_t param3 = -1); - void OnActivityStateChangeRequest(const LWOOBJID senderID, const int32_t value1, const int32_t value2, - const std::u16string& stringValue); - void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, - float_t pathTime, float_t totalTime, int32_t waypoint); + void OnFireEventServerSide(Entity* sender, std::string args, int32_t param1 = -1, int32_t param2 = -1, int32_t param3 = -1); + void OnActivityStateChangeRequest(const LWOOBJID senderID, const int32_t value1, const int32_t value2, + const std::u16string& stringValue); + void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, + float_t pathTime, float_t totalTime, int32_t waypoint); void NotifyObject(Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0); void OnEmoteReceived(int32_t emote, Entity* target); - - void OnUse(Entity* originator); + + void OnUse(Entity* originator); void OnHitOrHealResult(Entity* attacker, int32_t damage); void OnHit(Entity* attacker); @@ -195,7 +210,7 @@ public: void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u""); void Kill(Entity* murderer = nullptr); - void AddRebuildCompleteCallback(const std::function& callback) const; + void AddRebuildCompleteCallback(const std::function& callback) const; void AddCollisionPhantomCallback(const std::function& callback); void AddDieCallback(const std::function& callback); void Resurrect(); @@ -207,9 +222,8 @@ public: void RegisterCoinDrop(uint64_t count); void ScheduleKillAfterUpdate(Entity* murderer = nullptr); - void TriggerEvent(std::string eveneventtID, Entity* optionalTarget = nullptr); + void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr); void ScheduleDestructionAfterUpdate() { m_ShouldDestroyAfterUpdate = true; } - void HandleTriggerCommand(std::string id, std::string target, std::string targetName, std::string args, Entity* optionalTarget); virtual NiPoint3 GetRespawnPosition() const { return NiPoint3::ZERO; } virtual NiQuaternion GetRespawnRotation() const { return NiQuaternion::IDENTITY; } @@ -221,15 +235,15 @@ public: /* * Utility */ - /** - * Retroactively corrects the model vault size due to incorrect initialization in a previous patch. - * - */ + /** + * Retroactively corrects the model vault size due to incorrect initialization in a previous patch. + * + */ void RetroactiveVaultSize(); bool GetBoolean(const std::u16string& name) const; int32_t GetI32(const std::u16string& name) const; int64_t GetI64(const std::u16string& name) const; - + void SetBoolean(const std::u16string& name, bool value); void SetI32(const std::u16string& name, int32_t value); void SetI64(const std::u16string& name, int64_t value); @@ -247,11 +261,11 @@ public: template void SetNetworkVar(const std::u16string& name, T value, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - template - void SetNetworkVar(const std::u16string& name, std::vector value, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); + template + void SetNetworkVar(const std::u16string& name, std::vector value, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - template - T GetNetworkVar(const std::u16string& name); + template + T GetNetworkVar(const std::u16string& name); /** * Get the LDF value and cast it as T. @@ -277,38 +291,37 @@ public: Entity* GetScheduledKiller() { return m_ScheduleKiller; } protected: - LWOOBJID m_ObjectID; - - LOT m_TemplateID; - - std::vector m_Settings; - std::vector m_NetworkSettings; + LWOOBJID m_ObjectID; - NiPoint3 m_DefaultPosition; - NiQuaternion m_DefaultRotation; + LOT m_TemplateID; + + std::vector m_Settings; + std::vector m_NetworkSettings; + + NiPoint3 m_DefaultPosition; + NiQuaternion m_DefaultRotation; float m_Scale; Spawner* m_Spawner; - LWOOBJID m_SpawnerID; - - bool m_HasSpawnerNodeID; - uint32_t m_SpawnerNodeID; - - LUTriggers::Trigger* m_Trigger; + LWOOBJID m_SpawnerID; + + bool m_HasSpawnerNodeID; + uint32_t m_SpawnerNodeID; Character* m_Character; - - Entity* m_ParentEntity; //For spawners and the like + + Entity* m_ParentEntity; //For spawners and the like std::vector m_ChildEntities; - uint8_t m_GMLevel; - uint16_t m_CollectibleID; + eGameMasterLevel m_GMLevel; + uint16_t m_CollectibleID; std::vector m_Groups; uint16_t m_NetworkID; std::vector> m_DieCallbacks; - std::vector> m_PhantomCollisionCallbacks; - - std::unordered_map m_Components; //The int is the ID of the component + std::vector> m_PhantomCollisionCallbacks; + + std::unordered_map m_Components; std::vector m_Timers; + std::vector m_PendingTimers; std::vector m_CallbackTimers; bool m_ShouldDestroyAfterUpdate = false; @@ -336,12 +349,10 @@ protected: */ template -bool Entity::TryGetComponent(const int32_t componentId, T*& component) const -{ +bool Entity::TryGetComponent(const eReplicaComponentType componentId, T*& component) const { const auto& index = m_Components.find(componentId); - if (index == m_Components.end()) - { + if (index == m_Components.end()) { component = nullptr; return false; @@ -353,26 +364,22 @@ bool Entity::TryGetComponent(const int32_t componentId, T*& component) const } template -T* Entity::GetComponent() const -{ +T* Entity::GetComponent() const { return dynamic_cast(GetComponent(T::ComponentType)); } template -const T& Entity::GetVar(const std::u16string& name) const -{ +const T& Entity::GetVar(const std::u16string& name) const { auto* data = GetVarData(name); - if (data == nullptr) - { + if (data == nullptr) { return LDFData::Default; } auto* typed = dynamic_cast*>(data); - if (typed == nullptr) - { + if (typed == nullptr) { return LDFData::Default; } @@ -380,14 +387,12 @@ const T& Entity::GetVar(const std::u16string& name) const } template -T Entity::GetVarAs(const std::u16string& name) const -{ +T Entity::GetVarAs(const std::u16string& name) const { const auto data = GetVarAsString(name); T value; - if (!GeneralUtils::TryParse(data, value)) - { + if (!GeneralUtils::TryParse(data, value)) { return LDFData::Default; } @@ -395,12 +400,10 @@ T Entity::GetVarAs(const std::u16string& name) const } template -void Entity::SetVar(const std::u16string& name, T value) -{ +void Entity::SetVar(const std::u16string& name, T value) { auto* data = GetVarData(name); - if (data == nullptr) - { + if (data == nullptr) { auto* data = new LDFData(name, value); m_Settings.push_back(data); @@ -410,8 +413,7 @@ void Entity::SetVar(const std::u16string& name, T value) auto* typed = dynamic_cast*>(data); - if (typed == nullptr) - { + if (typed == nullptr) { return; } @@ -420,81 +422,81 @@ void Entity::SetVar(const std::u16string& name, T value) template void Entity::SetNetworkVar(const std::u16string& name, T value, const SystemAddress& sysAddr) { - LDFData* newData = nullptr; + LDFData* newData = nullptr; - for (auto* data :m_NetworkSettings) { - if (data->GetKey() != name) - continue; + for (auto* data : m_NetworkSettings) { + if (data->GetKey() != name) + continue; - newData = dynamic_cast*>(data); - if (newData != nullptr) { - newData->SetValue(value); - } else { // If we're changing types - m_NetworkSettings.erase( + newData = dynamic_cast*>(data); + if (newData != nullptr) { + newData->SetValue(value); + } else { // If we're changing types + m_NetworkSettings.erase( std::remove(m_NetworkSettings.begin(), m_NetworkSettings.end(), data), m_NetworkSettings.end() ); - delete data; - } + delete data; + } - break; - } + break; + } - if (newData == nullptr) { - newData = new LDFData(name, value); - } + if (newData == nullptr) { + newData = new LDFData(name, value); + } - m_NetworkSettings.push_back(newData); - SendNetworkVar(newData->GetString(true), sysAddr); + m_NetworkSettings.push_back(newData); + SendNetworkVar(newData->GetString(true), sysAddr); } template void Entity::SetNetworkVar(const std::u16string& name, std::vector values, const SystemAddress& sysAddr) { - std::stringstream updates; - auto index = 1; + std::stringstream updates; + auto index = 1; - for (const auto& value : values) { - LDFData* newData = nullptr; - const auto& indexedName = name + u"." + GeneralUtils::to_u16string(index); + for (const auto& value : values) { + LDFData* newData = nullptr; + const auto& indexedName = name + u"." + GeneralUtils::to_u16string(index); - for (auto* data : m_NetworkSettings) { - if (data->GetKey() != indexedName) - continue; + for (auto* data : m_NetworkSettings) { + if (data->GetKey() != indexedName) + continue; - newData = dynamic_cast*>(data); - newData->SetValue(value); - break; - } + newData = dynamic_cast*>(data); + newData->SetValue(value); + break; + } - if (newData == nullptr) { - newData = new LDFData(indexedName, value); - } + if (newData == nullptr) { + newData = new LDFData(indexedName, value); + } - m_NetworkSettings.push_back(newData); + m_NetworkSettings.push_back(newData); - if (index == values.size()) { - updates << newData->GetString(true); - } else { - updates << newData->GetString(true) << "\n"; - } + if (index == values.size()) { + updates << newData->GetString(true); + } else { + updates << newData->GetString(true) << "\n"; + } - index++; - } + index++; + } - SendNetworkVar(updates.str(), sysAddr); + SendNetworkVar(updates.str(), sysAddr); } template T Entity::GetNetworkVar(const std::u16string& name) { - for (auto* data : m_NetworkSettings) { - if (data == nullptr || data->GetKey() != name) - continue; + for (auto* data : m_NetworkSettings) { + if (data == nullptr || data->GetKey() != name) + continue; - auto* typed = dynamic_cast*>(data); - if (typed == nullptr) - continue; + auto* typed = dynamic_cast*>(data); + if (typed == nullptr) + continue; - return typed->GetValue(); - } + return typed->GetValue(); + } - return LDFData::Default; + return LDFData::Default; } diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index db60a1d1..0fc859bd 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -17,6 +17,13 @@ #include "MissionComponent.h" #include "Game.h" #include "dLogger.h" +#include "MessageIdentifiers.h" +#include "dConfig.h" +#include "eTriggerEventType.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" +#include "eReplicaPacketType.h" EntityManager* EntityManager::m_Address = nullptr; @@ -57,6 +64,20 @@ void EntityManager::Initialize() { m_GhostingExcludedZones.end(), dZoneManager::Instance()->GetZoneID().GetMapID() ) == m_GhostingExcludedZones.end(); + + // grab hardcore mode settings and load them with sane defaults + auto hcmode = Game::config->GetValue("hardcore_mode"); + m_HardcoreMode = hcmode.empty() ? false : (hcmode == "1"); + auto hcUscorePercent = Game::config->GetValue("hardcore_lose_uscore_on_death_percent"); + m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : std::stoi(hcUscorePercent); + auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier"); + m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : std::stoi(hcUscoreMult); + auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death"); + m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1"); + + // If cloneID is not zero, then hardcore mode is disabled + // aka minigames and props + if (dZoneManager::Instance()->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false; } EntityManager::~EntityManager() { @@ -65,7 +86,7 @@ EntityManager::~EntityManager() { Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) { // Determine the objectID for the new entity - LWOOBJID id; + LWOOBJID id; // If an explicit ID was provided, use it if (explicitId != LWOOBJID_EMPTY) { @@ -74,50 +95,49 @@ Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentE // For non player entites, we'll generate a new ID or set the appropiate flags else if (user == nullptr || info.lot != 1) { - + // Entities with no ID already set, often spawned entities, we'll generate a new sequencial ID - if (info.id == 0) { + if (info.id == 0) { id = ObjectIDManager::Instance()->GenerateObjectID(); } // Entities with an ID already set, often level entities, we'll use that ID as a base - else { + else { id = info.id; } // Exclude the zone control object from any flags - if(!controller && info.lot != 14) { + if (!controller && info.lot != 14) { // The client flags means the client should render the entity - id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT); + GeneralUtils::SetBit(id, eObjectBits::CLIENT); // Spawned entities require the spawned flag to render if (info.spawnerID != 0) { - id = GeneralUtils::SetBit(id, OBJECT_BIT_SPAWNED); + GeneralUtils::SetBit(id, eObjectBits::SPAWNED); } } - } + } // For players, we'll use the persistent ID for that character else { id = user->GetLastUsedChar()->GetObjectID(); } - info.id = id; - + info.id = id; + Entity* entity; // Check if the entitty if a player, in case use the extended player entity class if (user != nullptr) { entity = new Player(id, info, user, parentEntity); - } - else { + } else { entity = new Entity(id, info, parentEntity); } // Initialize the entity entity->Initialize(); - + // Add the entity to the entity map m_Entities.insert_or_assign(id, entity); @@ -133,7 +153,7 @@ Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentE m_SpawnPoints.insert_or_assign(GeneralUtils::UTF16ToWTF8(spawnName), entity->GetObjectID()); } - return entity; + return entity; } void EntityManager::DestroyEntity(const LWOOBJID& objectID) { @@ -141,9 +161,9 @@ void EntityManager::DestroyEntity(const LWOOBJID& objectID) { } void EntityManager::DestroyEntity(Entity* entity) { - if (entity == nullptr) { - return; - } + if (!entity) return; + + entity->TriggerEvent(eTriggerEventType::DESTROY, entity); const auto id = entity->GetObjectID(); @@ -160,112 +180,92 @@ void EntityManager::DestroyEntity(Entity* entity) { ScheduleForDeletion(id); } -void EntityManager::UpdateEntities(const float deltaTime) { - for (const auto& e : m_Entities) { - e.second->Update(deltaTime); - } +void EntityManager::SerializeEntities() { + for (auto entry = m_EntitiesToSerialize.begin(); entry != m_EntitiesToSerialize.end(); entry++) { + auto* entity = GetEntity(*entry); - for (const auto entityId : m_EntitiesToSerialize) - { - auto* entity = GetEntity(entityId); - - if (entity == nullptr) continue; + if (!entity) continue; m_SerializationCounter++; RakNet::BitStream stream; - stream.Write(static_cast(ID_REPLICA_MANAGER_SERIALIZE)); stream.Write(static_cast(entity->GetNetworkId())); - entity->WriteBaseReplicaData(&stream, PACKET_TYPE_SERIALIZATION); - entity->WriteComponents(&stream, PACKET_TYPE_SERIALIZATION); + entity->WriteBaseReplicaData(&stream, eReplicaPacketType::SERIALIZATION); + entity->WriteComponents(&stream, eReplicaPacketType::SERIALIZATION); - if (entity->GetIsGhostingCandidate()) - { - for (auto* player : Player::GetAllPlayers()) - { - if (player->IsObserved(entityId)) - { + if (entity->GetIsGhostingCandidate()) { + for (auto* player : Player::GetAllPlayers()) { + if (player->IsObserved(*entry)) { Game::server->Send(&stream, player->GetSystemAddress(), false); } } - } - else - { + } else { Game::server->Send(&stream, UNASSIGNED_SYSTEM_ADDRESS, true); } } - m_EntitiesToSerialize.clear(); +} - for (const auto& entry : m_EntitiesToKill) - { - auto* entity = GetEntity(entry); +void EntityManager::KillEntities() { + for (auto entry = m_EntitiesToKill.begin(); entry != m_EntitiesToKill.end(); entry++) { + auto* entity = GetEntity(*entry); - if (!entity) continue; - - if (entity->GetScheduledKiller()) - { - entity->Smash(entity->GetScheduledKiller()->GetObjectID(), SILENT); + if (!entity) { + Game::logger->Log("EntityManager", "Attempting to kill null entity %llu", *entry); + continue; } - else - { - entity->Smash(LWOOBJID_EMPTY, SILENT); + + if (entity->GetScheduledKiller()) { + entity->Smash(entity->GetScheduledKiller()->GetObjectID(), eKillType::SILENT); + } else { + entity->Smash(LWOOBJID_EMPTY, eKillType::SILENT); } } - m_EntitiesToKill.clear(); +} - for (const auto entry : m_EntitiesToDelete) - { - // Get all this info first before we delete the player. - auto entityToDelete = GetEntity(entry); +void EntityManager::DeleteEntities() { + for (auto entry = m_EntitiesToDelete.begin(); entry != m_EntitiesToDelete.end(); entry++) { + auto entityToDelete = GetEntity(*entry); + if (entityToDelete) { + // Get all this info first before we delete the player. + auto networkIdToErase = entityToDelete->GetNetworkId(); + const auto& ghostingToDelete = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entityToDelete); - auto networkIdToErase = entityToDelete->GetNetworkId(); - - const auto& ghostingToDelete = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entityToDelete); - - if (entityToDelete) - { - // If we are a player run through the player destructor. - if (entityToDelete->IsPlayer()) - { - delete dynamic_cast(entityToDelete); - } - else - { - delete entityToDelete; - } + delete entityToDelete; entityToDelete = nullptr; - if (networkIdToErase != 0) - { - m_LostNetworkIds.push(networkIdToErase); - } - } + if (networkIdToErase != 0) m_LostNetworkIds.push(networkIdToErase); - if (ghostingToDelete != m_EntitiesToGhost.end()) - { - m_EntitiesToGhost.erase(ghostingToDelete); + if (ghostingToDelete != m_EntitiesToGhost.end()) m_EntitiesToGhost.erase(ghostingToDelete); + } else { + Game::logger->Log("EntityManager", "Attempted to delete non-existent entity %llu", *entry); } - - m_Entities.erase(entry); - + m_Entities.erase(*entry); } - m_EntitiesToDelete.clear(); } -Entity * EntityManager::GetEntity(const LWOOBJID& objectId) const { +void EntityManager::UpdateEntities(const float deltaTime) { + for (const auto& e : m_Entities) { + e.second->Update(deltaTime); + } + + SerializeEntities(); + KillEntities(); + DeleteEntities(); +} + +Entity* EntityManager::GetEntity(const LWOOBJID& objectId) const { const auto& index = m_Entities.find(objectId); - - if (index == m_Entities.end()) - { + + if (index == m_Entities.end()) { return nullptr; } - + return index->second; } @@ -282,39 +282,36 @@ std::vector EntityManager::GetEntitiesInGroup(const std::string& group) return entitiesInGroup; } -std::vector EntityManager::GetEntitiesByComponent(const int componentType) const { +std::vector EntityManager::GetEntitiesByComponent(const eReplicaComponentType componentType) const { std::vector withComp; for (const auto& entity : m_Entities) { - if (componentType != -1 && !entity.second->HasComponent(componentType)) continue; - + if (componentType != eReplicaComponentType::INVALID && !entity.second->HasComponent(componentType)) continue; + withComp.push_back(entity.second); } return withComp; } -std::vector EntityManager::GetEntitiesByLOT(const LOT &lot) const { - std::vector entities; +std::vector EntityManager::GetEntitiesByLOT(const LOT& lot) const { + std::vector entities; - for (const auto& entity : m_Entities) { - if (entity.second->GetLOT() == lot) - entities.push_back(entity.second); - } + for (const auto& entity : m_Entities) { + if (entity.second->GetLOT() == lot) + entities.push_back(entity.second); + } - return entities; + return entities; } -Entity* EntityManager::GetZoneControlEntity() const -{ +Entity* EntityManager::GetZoneControlEntity() const { return m_ZoneControlEntity; } -Entity* EntityManager::GetSpawnPointEntity(const std::string& spawnName) const -{ +Entity* EntityManager::GetSpawnPointEntity(const std::string& spawnName) const { // Lookup the spawn point entity in the map const auto& spawnPoint = m_SpawnPoints.find(spawnName); - if (spawnPoint == m_SpawnPoints.end()) - { + if (spawnPoint == m_SpawnPoints.end()) { return nullptr; } @@ -322,91 +319,76 @@ Entity* EntityManager::GetSpawnPointEntity(const std::string& spawnName) const return GetEntity(spawnPoint->second); } -const std::unordered_map& EntityManager::GetSpawnPointEntities() const -{ +const std::unordered_map& EntityManager::GetSpawnPointEntities() const { return m_SpawnPoints; } void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr, const bool skipChecks) { - if (entity->GetNetworkId() == 0) - { + if (!entity) { + Game::logger->Log("EntityManager", "Attempted to construct null entity"); + return; + } + + if (entity->GetNetworkId() == 0) { uint16_t networkId; - - if (!m_LostNetworkIds.empty()) - { + + if (!m_LostNetworkIds.empty()) { networkId = m_LostNetworkIds.top(); m_LostNetworkIds.pop(); - } - else - { + } else { networkId = ++m_NetworkIdCounter; } entity->SetNetworkId(networkId); } - + const auto checkGhosting = entity->GetIsGhostingCandidate(); - if (checkGhosting) - { + if (checkGhosting) { const auto& iter = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entity); - if (iter == m_EntitiesToGhost.end()) - { + if (iter == m_EntitiesToGhost.end()) { m_EntitiesToGhost.push_back(entity); } } - if (checkGhosting && sysAddr == UNASSIGNED_SYSTEM_ADDRESS) - { + if (checkGhosting && sysAddr == UNASSIGNED_SYSTEM_ADDRESS) { CheckGhosting(entity); return; } m_SerializationCounter++; - + RakNet::BitStream stream; stream.Write(static_cast(ID_REPLICA_MANAGER_CONSTRUCTION)); stream.Write(true); stream.Write(static_cast(entity->GetNetworkId())); - - entity->WriteBaseReplicaData(&stream, PACKET_TYPE_CONSTRUCTION); - entity->WriteComponents(&stream, PACKET_TYPE_CONSTRUCTION); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) - { - if (skipChecks) - { + entity->WriteBaseReplicaData(&stream, eReplicaPacketType::CONSTRUCTION); + entity->WriteComponents(&stream, eReplicaPacketType::CONSTRUCTION); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) { + if (skipChecks) { Game::server->Send(&stream, UNASSIGNED_SYSTEM_ADDRESS, true); - } - else - { - for (auto* player : Player::GetAllPlayers()) - { - if (player->GetPlayerReadyForUpdates()) - { + } else { + for (auto* player : Player::GetAllPlayers()) { + if (player->GetPlayerReadyForUpdates()) { Game::server->Send(&stream, player->GetSystemAddress(), false); - } - else - { + } else { player->AddLimboConstruction(entity->GetObjectID()); } } } - } - else - { + } else { Game::server->Send(&stream, sysAddr, false); } - PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); + // PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); - if (entity->IsPlayer()) - { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) - { + if (entity->IsPlayer()) { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, sysAddr); } } @@ -416,21 +398,18 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) { //ZoneControl is special: ConstructEntity(m_ZoneControlEntity, sysAddr); - for (const auto& e : m_Entities) { + for (const auto& e : m_Entities) { if (e.second && (e.second->GetSpawnerID() != 0 || e.second->GetLOT() == 1) && !e.second->GetIsGhostingCandidate()) { ConstructEntity(e.second, sysAddr); } - } + } UpdateGhosting(Player::GetPlayer(sysAddr)); } void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) { - if (entity->GetNetworkId() == 0) - { - return; - } - + if (!entity || entity->GetNetworkId() == 0) return; + RakNet::BitStream stream; stream.Write(static_cast(ID_REPLICA_MANAGER_DESTRUCTION)); @@ -438,23 +417,17 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) Game::server->Send(&stream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); - for (auto* player : Player::GetAllPlayers()) - { - if (!player->GetPlayerReadyForUpdates()) - { + for (auto* player : Player::GetAllPlayers()) { + if (!player->GetPlayerReadyForUpdates()) { player->RemoveLimboConstruction(entity->GetObjectID()); } } } void EntityManager::SerializeEntity(Entity* entity) { - if (entity->GetNetworkId() == 0) - { - return; - } + if (!entity || entity->GetNetworkId() == 0) return; - if (std::find(m_EntitiesToSerialize.begin(), m_EntitiesToSerialize.end(), entity->GetObjectID()) == m_EntitiesToSerialize.end()) - { + if (std::find(m_EntitiesToSerialize.begin(), m_EntitiesToSerialize.end(), entity->GetObjectID()) == m_EntitiesToSerialize.end()) { m_EntitiesToSerialize.push_back(entity->GetObjectID()); } @@ -462,49 +435,40 @@ void EntityManager::SerializeEntity(Entity* entity) { } void EntityManager::DestructAllEntities(const SystemAddress& sysAddr) { - for (const auto& e : m_Entities) { + for (const auto& e : m_Entities) { DestructEntity(e.second, sysAddr); - } + } } -void EntityManager::SetGhostDistanceMax(float value) -{ +void EntityManager::SetGhostDistanceMax(float value) { m_GhostDistanceMaxSquared = value * value; } -float EntityManager::GetGhostDistanceMax() const -{ +float EntityManager::GetGhostDistanceMax() const { return std::sqrt(m_GhostDistanceMaxSquared); } -void EntityManager::SetGhostDistanceMin(float value) -{ +void EntityManager::SetGhostDistanceMin(float value) { m_GhostDistanceMinSqaured = value * value; } -float EntityManager::GetGhostDistanceMin() const -{ +float EntityManager::GetGhostDistanceMin() const { return std::sqrt(m_GhostDistanceMinSqaured); } -void EntityManager::QueueGhostUpdate(LWOOBJID playerID) -{ +void EntityManager::QueueGhostUpdate(LWOOBJID playerID) { const auto& iter = std::find(m_PlayersToUpdateGhosting.begin(), m_PlayersToUpdateGhosting.end(), playerID); - if (iter == m_PlayersToUpdateGhosting.end()) - { + if (iter == m_PlayersToUpdateGhosting.end()) { m_PlayersToUpdateGhosting.push_back(playerID); } } -void EntityManager::UpdateGhosting() -{ - for (const auto playerID : m_PlayersToUpdateGhosting) - { +void EntityManager::UpdateGhosting() { + for (const auto playerID : m_PlayersToUpdateGhosting) { auto* player = Player::GetPlayer(playerID); - if (player == nullptr) - { + if (player == nullptr) { continue; } @@ -514,25 +478,21 @@ void EntityManager::UpdateGhosting() m_PlayersToUpdateGhosting.clear(); } -void EntityManager::UpdateGhosting(Player* player) -{ - if (player == nullptr) - { +void EntityManager::UpdateGhosting(Player* player) { + if (player == nullptr) { return; } auto* missionComponent = player->GetComponent(); - if (missionComponent == nullptr) - { + if (missionComponent == nullptr) { return; } const auto& referencePoint = player->GetGhostReferencePoint(); const auto isOverride = player->GetGhostOverride(); - for (auto* entity : m_EntitiesToGhost) - { + for (auto* entity : m_EntitiesToGhost) { const auto isAudioEmitter = entity->GetLOT() == 6368; const auto& entityPoint = entity->GetPosition(); @@ -546,59 +506,50 @@ void EntityManager::UpdateGhosting(Player* player) auto ghostingDistanceMax = m_GhostDistanceMaxSquared; auto ghostingDistanceMin = m_GhostDistanceMinSqaured; - if (isAudioEmitter) - { + if (isAudioEmitter) { ghostingDistanceMax = ghostingDistanceMin; } - if (observed && distance > ghostingDistanceMax && !isOverride) - { + if (observed && distance > ghostingDistanceMax && !isOverride) { player->GhostEntity(id); DestructEntity(entity, player->GetSystemAddress()); entity->SetObservers(entity->GetObservers() - 1); - } - else if (!observed && ghostingDistanceMin > distance) - { + } else if (!observed && ghostingDistanceMin > distance) { // Check collectables, don't construct if it has been collected uint32_t collectionId = entity->GetCollectibleID(); - if (collectionId != 0) - { + if (collectionId != 0) { collectionId = static_cast(collectionId) + static_cast(Game::server->GetZoneID() << 8); - if (missionComponent->HasCollectible(collectionId)) - { + if (missionComponent->HasCollectible(collectionId)) { continue; } } player->ObserveEntity(id); - + ConstructEntity(entity, player->GetSystemAddress()); - + entity->SetObservers(entity->GetObservers() + 1); } } } -void EntityManager::CheckGhosting(Entity* entity) -{ - if (entity == nullptr) - { +void EntityManager::CheckGhosting(Entity* entity) { + if (entity == nullptr) { return; } const auto& referencePoint = entity->GetPosition(); - + auto ghostingDistanceMax = m_GhostDistanceMaxSquared; auto ghostingDistanceMin = m_GhostDistanceMinSqaured; const auto isAudioEmitter = entity->GetLOT() == 6368; - for (auto* player : Player::GetAllPlayers()) - { + for (auto* player : Player::GetAllPlayers()) { const auto& entityPoint = player->GetGhostReferencePoint(); const int32_t id = entity->GetObjectID(); @@ -607,40 +558,33 @@ void EntityManager::CheckGhosting(Entity* entity) const auto distance = NiPoint3::DistanceSquared(referencePoint, entityPoint); - if (observed && distance > ghostingDistanceMax) - { + if (observed && distance > ghostingDistanceMax) { player->GhostEntity(id); DestructEntity(entity, player->GetSystemAddress()); entity->SetObservers(entity->GetObservers() - 1); - } - else if (!observed && ghostingDistanceMin > distance) - { + } else if (!observed && ghostingDistanceMin > distance) { player->ObserveEntity(id); - + ConstructEntity(entity, player->GetSystemAddress()); - + entity->SetObservers(entity->GetObservers() + 1); } } } -Entity* EntityManager::GetGhostCandidate(int32_t id) -{ - for (auto* entity : m_EntitiesToGhost) - { - if (entity->GetObjectID() == id) - { +Entity* EntityManager::GetGhostCandidate(int32_t id) { + for (auto* entity : m_EntitiesToGhost) { + if (entity->GetObjectID() == id) { return entity; } } - + return nullptr; } -bool EntityManager::GetGhostingEnabled() const -{ +bool EntityManager::GetGhostingEnabled() const { return m_GhostingEnabled; } @@ -654,26 +598,23 @@ void EntityManager::ScheduleForKill(Entity* entity) { // Deactivate switches if they die if (!entity) return; - + SwitchComponent* switchComp = entity->GetComponent(); if (switchComp) { - entity->TriggerEvent("OnDectivated"); + entity->TriggerEvent(eTriggerEventType::DEACTIVATED, entity); } const auto objectId = entity->GetObjectID(); - if (std::count(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId)) - { + if (std::count(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId)) { return; } m_EntitiesToKill.push_back(objectId); } -void EntityManager::ScheduleForDeletion(LWOOBJID entity) -{ - if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity)) - { +void EntityManager::ScheduleForDeletion(LWOOBJID entity) { + if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity)) { return; } @@ -689,7 +630,6 @@ void EntityManager::FireEventServerSide(Entity* origin, std::string args) { } } -bool EntityManager::IsExcludedFromGhosting(LOT lot) -{ +bool EntityManager::IsExcludedFromGhosting(LOT lot) { return std::find(m_GhostingExcludedLOTs.begin(), m_GhostingExcludedLOTs.end(), lot) != m_GhostingExcludedLOTs.end(); } diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 8fb2585c..b524344c 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -2,38 +2,41 @@ #define ENTITYMANAGER_H #include "dCommonVars.h" -#include "../thirdparty/raknet/Source/Replica.h" #include #include - -#include "Entity.h" #include +#include + +class Entity; +class EntityInfo; +class Player; +class User; +enum class eReplicaComponentType : uint32_t; struct SystemAddress; -class User; class EntityManager { public: - static EntityManager* Instance() { + static EntityManager* Instance() { if (!m_Address) { m_Address = new EntityManager(); m_Address->Initialize(); } - + return m_Address; } - - void Initialize(); - ~EntityManager(); - - void UpdateEntities(float deltaTime); - Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY); - void DestroyEntity(const LWOOBJID& objectID); + void Initialize(); + + ~EntityManager(); + + void UpdateEntities(float deltaTime); + Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY); + void DestroyEntity(const LWOOBJID& objectID); void DestroyEntity(Entity* entity); - Entity* GetEntity(const LWOOBJID& objectId) const; + Entity* GetEntity(const LWOOBJID& objectId) const; std::vector GetEntitiesInGroup(const std::string& group); - std::vector GetEntitiesByComponent(int componentType) const; + std::vector GetEntitiesByComponent(eReplicaComponentType componentType) const; std::vector GetEntitiesByLOT(const LOT& lot) const; Entity* GetZoneControlEntity() const; @@ -48,12 +51,12 @@ public: const std::unordered_map GetAllEntities() const { return m_Entities; } #endif - void ConstructEntity(Entity * entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, bool skipChecks = false); - void DestructEntity(Entity * entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); + void ConstructEntity(Entity* entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, bool skipChecks = false); + void DestructEntity(Entity* entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SerializeEntity(Entity* entity); - - void ConstructAllEntities(const SystemAddress& sysAddr); - void DestructAllEntities(const SystemAddress& sysAddr); + + void ConstructAllEntities(const SystemAddress& sysAddr); + void DestructAllEntities(const SystemAddress& sysAddr); void SetGhostDistanceMax(float value); float GetGhostDistanceMax() const; @@ -69,19 +72,28 @@ public: void ResetFlags(); void ScheduleForKill(Entity* entity); - + void ScheduleForDeletion(LWOOBJID entity); void FireEventServerSide(Entity* origin, std::string args); - + static bool IsExcludedFromGhosting(LOT lot); + const bool GetHardcoreMode() { return m_HardcoreMode; }; + const uint32_t GetHardcoreLoseUscoreOnDeathPercent() { return m_HardcoreLoseUscoreOnDeathPercent; }; + const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; }; + const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; + private: - static EntityManager* m_Address; //For singleton method + void SerializeEntities(); + void KillEntities(); + void DeleteEntities(); + + static EntityManager* m_Address; //For singleton method static std::vector m_GhostingExcludedZones; static std::vector m_GhostingExcludedLOTs; - std::unordered_map m_Entities; + std::unordered_map m_Entities; std::vector m_EntitiesToKill; std::vector m_EntitiesToDelete; std::vector m_EntitiesToSerialize; @@ -95,11 +107,17 @@ private: float m_GhostDistanceMinSqaured = 100 * 100; float m_GhostDistanceMaxSquared = 150 * 150; bool m_GhostingEnabled = true; - + std::stack m_LostNetworkIds; // Map of spawnname to entity object ID std::unordered_map m_SpawnPoints; + + // hardcore mode vars + bool m_HardcoreMode; + uint32_t m_HardcoreLoseUscoreOnDeathPercent; + bool m_HardcoreDropinventoryOnDeath; + uint32_t m_HardcoreUscoreEnemiesMultiplier; }; #endif // ENTITYMANAGER_H diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index 793d402c..d85a95d4 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -7,246 +7,250 @@ #include "GameMessages.h" #include "dLogger.h" #include "dConfig.h" +#include "CDClientManager.h" +#include "GeneralUtils.h" +#include "Entity.h" + +#include "CDActivitiesTable.h" Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, - LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { - this->relatedPlayer = relatedPlayer; - this->gameID = gameID; - this->weekly = weekly; - this->infoType = infoType; - this->entries = std::move(entries); - this->leaderboardType = leaderboardType; + LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { + this->relatedPlayer = relatedPlayer; + this->gameID = gameID; + this->weekly = weekly; + this->infoType = infoType; + this->entries = std::move(entries); + this->leaderboardType = leaderboardType; } std::u16string Leaderboard::ToString() const { - std::string leaderboard; + std::string leaderboard; - leaderboard += "ADO.Result=7:1\n"; - leaderboard += "Result.Count=1:1\n"; - leaderboard += "Result[0].Index=0:RowNumber\n"; - leaderboard += "Result[0].RowCount=1:" + std::to_string(entries.size()) + "\n"; + leaderboard += "ADO.Result=7:1\n"; + leaderboard += "Result.Count=1:1\n"; + leaderboard += "Result[0].Index=0:RowNumber\n"; + leaderboard += "Result[0].RowCount=1:" + std::to_string(entries.size()) + "\n"; - auto index = 0; - for (const auto& entry : entries) { - leaderboard += "Result[0].Row[" + std::to_string(index) + "].LastPlayed=8:" + std::to_string(entry.lastPlayed) + "\n"; - leaderboard += "Result[0].Row[" + std::to_string(index) + "].CharacterID=8:" + std::to_string(entry.playerID) + "\n"; - leaderboard += "Result[0].Row[" + std::to_string(index) + "].NumPlayed=1:1\n"; - leaderboard += "Result[0].Row[" + std::to_string(index) + "].RowNumber=8:" + std::to_string(entry.placement) + "\n"; - leaderboard += "Result[0].Row[" + std::to_string(index) + "].Time=1:" + std::to_string(entry.time) + "\n"; + auto index = 0; + for (const auto& entry : entries) { + leaderboard += "Result[0].Row[" + std::to_string(index) + "].LastPlayed=8:" + std::to_string(entry.lastPlayed) + "\n"; + leaderboard += "Result[0].Row[" + std::to_string(index) + "].CharacterID=8:" + std::to_string(entry.playerID) + "\n"; + leaderboard += "Result[0].Row[" + std::to_string(index) + "].NumPlayed=1:1\n"; + leaderboard += "Result[0].Row[" + std::to_string(index) + "].RowNumber=8:" + std::to_string(entry.placement) + "\n"; + leaderboard += "Result[0].Row[" + std::to_string(index) + "].Time=1:" + std::to_string(entry.time) + "\n"; - // Only these minigames have a points system - if (leaderboardType == Survival || leaderboardType == ShootingGallery) { - leaderboard += "Result[0].Row[" + std::to_string(index) + "].Points=1:" + std::to_string(entry.score) + "\n"; - } else if (leaderboardType == SurvivalNS) { - leaderboard += "Result[0].Row[" + std::to_string(index) + "].Wave=1:" + std::to_string(entry.score) + "\n"; - } + // Only these minigames have a points system + if (leaderboardType == Survival || leaderboardType == ShootingGallery) { + leaderboard += "Result[0].Row[" + std::to_string(index) + "].Points=1:" + std::to_string(entry.score) + "\n"; + } else if (leaderboardType == SurvivalNS) { + leaderboard += "Result[0].Row[" + std::to_string(index) + "].Wave=1:" + std::to_string(entry.score) + "\n"; + } - leaderboard += "Result[0].Row[" + std::to_string(index) + "].name=0:" + entry.playerName + "\n"; - index++; - } + leaderboard += "Result[0].Row[" + std::to_string(index) + "].name=0:" + entry.playerName + "\n"; + index++; + } - return GeneralUtils::ASCIIToUTF16(leaderboard); + return GeneralUtils::UTF8ToUTF16(leaderboard); } std::vector Leaderboard::GetEntries() { - return entries; + return entries; } uint32_t Leaderboard::GetGameID() const { - return gameID; + return gameID; } uint32_t Leaderboard::GetInfoType() const { - return infoType; + return infoType; } void Leaderboard::Send(LWOOBJID targetID) const { - auto* player = EntityManager::Instance()->GetEntity(relatedPlayer); - if (player != nullptr) { - GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress()); - } + auto* player = EntityManager::Instance()->GetEntity(relatedPlayer); + if (player != nullptr) { + GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress()); + } } void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time) { - const auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - return; + const auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + return; - auto* character = player->GetCharacter(); - if (character == nullptr) - return; + auto* character = player->GetCharacter(); + if (character == nullptr) + return; - auto* select = Database::CreatePreppedStmt("SELECT time, score FROM leaderboard WHERE character_id = ? AND game_id = ?;"); + auto* select = Database::CreatePreppedStmt("SELECT time, score FROM leaderboard WHERE character_id = ? AND game_id = ?;"); - select->setUInt64(1, character->GetID()); - select->setInt(2, gameID); + select->setUInt64(1, character->GetID()); + select->setInt(2, gameID); - auto any = false; - auto* result = select->executeQuery(); - auto leaderboardType = GetLeaderboardType(gameID); + auto any = false; + auto* result = select->executeQuery(); + auto leaderboardType = GetLeaderboardType(gameID); - // Check if the new score is a high score - while (result->next()) { - any = true; + // Check if the new score is a high score + while (result->next()) { + any = true; - const auto storedTime = result->getInt(1); - const auto storedScore = result->getInt(2); - auto highscore = true; - bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; + const auto storedTime = result->getInt(1); + const auto storedScore = result->getInt(2); + auto highscore = true; + bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; - switch (leaderboardType) { - case ShootingGallery: - if (score <= storedScore) - highscore = false; - break; - case Racing: - if (time >= storedTime) - highscore = false; - break; - case MonumentRace: - if (time >= storedTime) - highscore = false; - break; - case FootRace: - if (time <= storedTime) - highscore = false; - break; - case Survival: - if (classicSurvivalScoring) { - if (time <= storedTime) { // Based on time (LU live) - highscore = false; - } - } - else { - if (score <= storedScore) // Based on score (DLU) - highscore = false; - } - break; - case SurvivalNS: - if (!(score > storedScore || (time < storedTime && score >= storedScore))) - highscore = false; - break; - default: - highscore = false; - } + switch (leaderboardType) { + case ShootingGallery: + if (score <= storedScore) + highscore = false; + break; + case Racing: + if (time >= storedTime) + highscore = false; + break; + case MonumentRace: + if (time >= storedTime) + highscore = false; + break; + case FootRace: + if (time <= storedTime) + highscore = false; + break; + case Survival: + if (classicSurvivalScoring) { + if (time <= storedTime) { // Based on time (LU live) + highscore = false; + } + } else { + if (score <= storedScore) // Based on score (DLU) + highscore = false; + } + break; + case SurvivalNS: + if (!(score > storedScore || (time < storedTime && score >= storedScore))) + highscore = false; + break; + default: + highscore = false; + } - if (!highscore) { - delete select; - delete result; - return; - } - } + if (!highscore) { + delete select; + delete result; + return; + } + } - delete select; - delete result; + delete select; + delete result; - if (any) { - auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ?, last_played=SYSDATE() WHERE character_id = ? AND game_id = ?;"); - statement->setInt(1, time); - statement->setInt(2, score); - statement->setUInt64(3, character->GetID()); - statement->setInt(4, gameID); - statement->execute(); + if (any) { + auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ?, last_played=SYSDATE() WHERE character_id = ? AND game_id = ?;"); + statement->setInt(1, time); + statement->setInt(2, score); + statement->setUInt64(3, character->GetID()); + statement->setInt(4, gameID); + statement->execute(); - delete statement; - } else { - // Note: last_played will be set to SYSDATE() by default when inserting into leaderboard - auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);"); - statement->setUInt64(1, character->GetID()); - statement->setInt(2, gameID); - statement->setInt(3, time); - statement->setInt(4, score); - statement->execute(); + delete statement; + } else { + // Note: last_played will be set to SYSDATE() by default when inserting into leaderboard + auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);"); + statement->setUInt64(1, character->GetID()); + statement->setInt(2, gameID); + statement->setInt(3, time); + statement->setInt(4, score); + statement->execute(); - delete statement; - } + delete statement; + } } -Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID) { - auto leaderboardType = GetLeaderboardType(gameID); +Leaderboard* LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID) { + auto leaderboardType = GetLeaderboardType(gameID); - std::string query; - bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; - switch (infoType) { - case InfoType::Standings: - switch (leaderboardType) { - case ShootingGallery: - query = standingsScoreQuery; // Shooting gallery is based on the highest score. - break; - case FootRace: - query = standingsTimeQuery; // The higher your time, the better for FootRace. - break; - case Survival: - query = classicSurvivalScoring ? standingsTimeQuery : standingsScoreQuery; - break; - case SurvivalNS: - query = standingsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. - break; - default: - query = standingsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. - } - break; - case InfoType::Friends: - switch (leaderboardType) { - case ShootingGallery: - query = friendsScoreQuery; // Shooting gallery is based on the highest score. - break; - case FootRace: - query = friendsTimeQuery; // The higher your time, the better for FootRace. - break; - case Survival: - query = classicSurvivalScoring ? friendsTimeQuery : friendsScoreQuery; - break; - case SurvivalNS: - query = friendsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. - break; - default: - query = friendsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. - } - break; + std::string query; + bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; + switch (infoType) { + case InfoType::Standings: + switch (leaderboardType) { + case ShootingGallery: + query = standingsScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = standingsTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? standingsTimeQuery : standingsScoreQuery; + break; + case SurvivalNS: + query = standingsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = standingsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } + break; + case InfoType::Friends: + switch (leaderboardType) { + case ShootingGallery: + query = friendsScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = friendsTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? friendsTimeQuery : friendsScoreQuery; + break; + case SurvivalNS: + query = friendsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = friendsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } + break; - default: - switch (leaderboardType) { - case ShootingGallery: - query = topPlayersScoreQuery; // Shooting gallery is based on the highest score. - break; - case FootRace: - query = topPlayersTimeQuery; // The higher your time, the better for FootRace. - break; - case Survival: - query = classicSurvivalScoring ? topPlayersTimeQuery : topPlayersScoreQuery; - break; - case SurvivalNS: - query = topPlayersScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. - break; - default: - query = topPlayersTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. - } - } + default: + switch (leaderboardType) { + case ShootingGallery: + query = topPlayersScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = topPlayersTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? topPlayersTimeQuery : topPlayersScoreQuery; + break; + case SurvivalNS: + query = topPlayersScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = topPlayersTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } + } - auto* statement = Database::CreatePreppedStmt(query); - statement->setUInt(1, gameID); + auto* statement = Database::CreatePreppedStmt(query); + statement->setUInt(1, gameID); - // Only the standings and friends leaderboards require the character ID to be set - if (infoType == Standings || infoType == Friends) { - auto characterID = 0; + // Only the standings and friends leaderboards require the character ID to be set + if (infoType == Standings || infoType == Friends) { + auto characterID = 0; - const auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - auto* character = player->GetCharacter(); - if (character != nullptr) - characterID = character->GetID(); - } + const auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + auto* character = player->GetCharacter(); + if (character != nullptr) + characterID = character->GetID(); + } - statement->setUInt64(2, characterID); - } + statement->setUInt64(2, characterID); + } - auto* res = statement->executeQuery(); + auto* res = statement->executeQuery(); - std::vector entries {}; + std::vector entries{}; - uint32_t index = 0; - while (res->next()) { + uint32_t index = 0; + while (res->next()) { LeaderboardEntry entry; entry.playerID = res->getUInt64(4); entry.playerName = res->getString(5); @@ -256,124 +260,124 @@ Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy entry.lastPlayed = res->getUInt(6); entries.push_back(entry); - index++; - } + index++; + } - delete res; - delete statement; + delete res; + delete statement; - return new Leaderboard(gameID, infoType, weekly, entries, playerID, leaderboardType); + return new Leaderboard(gameID, infoType, weekly, entries, playerID, leaderboardType); } void LeaderboardManager::SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID, - LWOOBJID playerID) { - const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, infoType, weekly, playerID); - leaderboard->Send(targetID); - delete leaderboard; + LWOOBJID playerID) { + const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, infoType, weekly, playerID); + leaderboard->Send(targetID); + delete leaderboard; } LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) { - auto* activitiesTable = CDClientManager::Instance()->GetTable("Activities"); - std::vector activities = activitiesTable->Query([=](const CDActivities& entry) { - return (entry.ActivityID == gameID); - }); + auto* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](const CDActivities& entry) { + return (entry.ActivityID == gameID); + }); - for (const auto& activity : activities) { - return static_cast(activity.leaderboardType); - } + for (const auto& activity : activities) { + return static_cast(activity.leaderboardType); + } - return LeaderboardType::None; + return LeaderboardType::None; } const std::string LeaderboardManager::topPlayersScoreQuery = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " - "RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " - " FROM leaderboard l " - "INNER JOIN charinfo c ON l.character_id = c.id " - "WHERE l.game_id = ? " - "ORDER BY leaderboard_rank) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales LIMIT 11;"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +"RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +"INNER JOIN charinfo c ON l.character_id = c.id " +"WHERE l.game_id = ? " +"ORDER BY leaderboard_rank) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales LIMIT 11;"; const std::string LeaderboardManager::friendsScoreQuery = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " - " RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " - " FROM leaderboard l " - " INNER JOIN charinfo c ON l.character_id = c.id " - " INNER JOIN friends f ON f.player_id = c.id " - " WHERE l.game_id = ? " - " ORDER BY leaderboard_rank), " - " personal_values AS ( " - " SELECT id as related_player_id, " - " GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " - " GREATEST(leaderboard_rank + 5, 11) AS max_rank " - " FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales, personal_values " - "WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " +" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" INNER JOIN friends f ON f.player_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +" personal_values AS ( " +" SELECT id as related_player_id, " +" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; const std::string LeaderboardManager::standingsScoreQuery = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " - " RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " - " FROM leaderboard l " - " INNER JOIN charinfo c ON l.character_id = c.id " - " WHERE l.game_id = ? " - " ORDER BY leaderboard_rank), " - "personal_values AS ( " - " SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " - " GREATEST(leaderboard_rank + 5, 11) AS max_rank " - " FROM leaderboard_vales WHERE id = ? LIMIT 1) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales, personal_values " - "WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +"personal_values AS ( " +" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; const std::string LeaderboardManager::topPlayersScoreQueryAsc = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " - "RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " - " FROM leaderboard l " - "INNER JOIN charinfo c ON l.character_id = c.id " - "WHERE l.game_id = ? " - "ORDER BY leaderboard_rank) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales LIMIT 11;"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +"RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " +" FROM leaderboard l " +"INNER JOIN charinfo c ON l.character_id = c.id " +"WHERE l.game_id = ? " +"ORDER BY leaderboard_rank) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales LIMIT 11;"; const std::string LeaderboardManager::friendsScoreQueryAsc = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " - " RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " - " FROM leaderboard l " - " INNER JOIN charinfo c ON l.character_id = c.id " - " INNER JOIN friends f ON f.player_id = c.id " - " WHERE l.game_id = ? " - " ORDER BY leaderboard_rank), " - " personal_values AS ( " - " SELECT id as related_player_id, " - " GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " - " GREATEST(leaderboard_rank + 5, 11) AS max_rank " - " FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales, personal_values " - "WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " +" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" INNER JOIN friends f ON f.player_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +" personal_values AS ( " +" SELECT id as related_player_id, " +" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; const std::string LeaderboardManager::standingsScoreQueryAsc = - "WITH leaderboard_vales AS ( " - " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " - " RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " - " FROM leaderboard l " - " INNER JOIN charinfo c ON l.character_id = c.id " - " WHERE l.game_id = ? " - " ORDER BY leaderboard_rank), " - "personal_values AS ( " - " SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " - " GREATEST(leaderboard_rank + 5, 11) AS max_rank " - " FROM leaderboard_vales WHERE id = ? LIMIT 1) " - "SELECT time, score, leaderboard_rank, id, name, last_played " - "FROM leaderboard_vales, personal_values " - "WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +"personal_values AS ( " +" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; const std::string LeaderboardManager::topPlayersTimeQuery = "WITH leaderboard_vales AS ( " diff --git a/dGame/LeaderboardManager.h b/dGame/LeaderboardManager.h index c4479f1a..cabdf2d6 100644 --- a/dGame/LeaderboardManager.h +++ b/dGame/LeaderboardManager.h @@ -4,77 +4,77 @@ #include "dCommonVars.h" struct LeaderboardEntry { - uint64_t playerID; - std::string playerName; - uint32_t time; - uint32_t score; - uint32_t placement; - time_t lastPlayed; + uint64_t playerID; + std::string playerName; + uint32_t time; + uint32_t score; + uint32_t placement; + time_t lastPlayed; }; enum InfoType : uint32_t { - Top, // Top 11 all time players - Standings, // Ranking of the current player - Friends // Ranking between friends + Top, // Top 11 all time players + Standings, // Ranking of the current player + Friends // Ranking between friends }; enum LeaderboardType : uint32_t { - ShootingGallery, - Racing, - MonumentRace, - FootRace, - Survival = 5, - SurvivalNS = 6, - None = UINT_MAX + ShootingGallery, + Racing, + MonumentRace, + FootRace, + Survival = 5, + SurvivalNS = 6, + None = UINT_MAX }; class Leaderboard { public: - Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, - LWOOBJID relatedPlayer = LWOOBJID_EMPTY, LeaderboardType = None); - std::vector GetEntries(); - [[nodiscard]] std::u16string ToString() const; - [[nodiscard]] uint32_t GetGameID() const; - [[nodiscard]] uint32_t GetInfoType() const; - void Send(LWOOBJID targetID) const; + Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, + LWOOBJID relatedPlayer = LWOOBJID_EMPTY, LeaderboardType = None); + std::vector GetEntries(); + [[nodiscard]] std::u16string ToString() const; + [[nodiscard]] uint32_t GetGameID() const; + [[nodiscard]] uint32_t GetInfoType() const; + void Send(LWOOBJID targetID) const; private: - std::vector entries {}; - LWOOBJID relatedPlayer; - uint32_t gameID; - uint32_t infoType; - LeaderboardType leaderboardType; - bool weekly; + std::vector entries{}; + LWOOBJID relatedPlayer; + uint32_t gameID; + uint32_t infoType; + LeaderboardType leaderboardType; + bool weekly; }; class LeaderboardManager { public: - static LeaderboardManager* Instance() { - if (address == nullptr) - address = new LeaderboardManager; - return address; - } - static void SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID, - LWOOBJID playerID = LWOOBJID_EMPTY); - static Leaderboard* GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID = LWOOBJID_EMPTY); - static void SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time); - static LeaderboardType GetLeaderboardType(uint32_t gameID); + static LeaderboardManager* Instance() { + if (address == nullptr) + address = new LeaderboardManager; + return address; + } + static void SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID, + LWOOBJID playerID = LWOOBJID_EMPTY); + static Leaderboard* GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID = LWOOBJID_EMPTY); + static void SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time); + static LeaderboardType GetLeaderboardType(uint32_t gameID); private: - static LeaderboardManager* address; + static LeaderboardManager* address; - // Modified 12/12/2021: Existing queries were renamed to be more descriptive. - static const std::string topPlayersScoreQuery; - static const std::string friendsScoreQuery; - static const std::string standingsScoreQuery; - static const std::string topPlayersScoreQueryAsc; - static const std::string friendsScoreQueryAsc; - static const std::string standingsScoreQueryAsc; + // Modified 12/12/2021: Existing queries were renamed to be more descriptive. + static const std::string topPlayersScoreQuery; + static const std::string friendsScoreQuery; + static const std::string standingsScoreQuery; + static const std::string topPlayersScoreQueryAsc; + static const std::string friendsScoreQueryAsc; + static const std::string standingsScoreQueryAsc; - // Added 12/12/2021: Queries dictated by time are needed for certain minigames. - static const std::string topPlayersTimeQuery; - static const std::string friendsTimeQuery; - static const std::string standingsTimeQuery; - static const std::string topPlayersTimeQueryAsc; - static const std::string friendsTimeQueryAsc; - static const std::string standingsTimeQueryAsc; + // Added 12/12/2021: Queries dictated by time are needed for certain minigames. + static const std::string topPlayersTimeQuery; + static const std::string friendsTimeQuery; + static const std::string standingsTimeQuery; + static const std::string topPlayersTimeQueryAsc; + static const std::string friendsTimeQueryAsc; + static const std::string standingsTimeQueryAsc; }; diff --git a/dGame/Player.cpp b/dGame/Player.cpp index 350ddca5..2e194e6a 100644 --- a/dGame/Player.cpp +++ b/dGame/Player.cpp @@ -1,4 +1,4 @@ -#include "Player.h" +#include "Player.h" #include @@ -13,12 +13,14 @@ #include "dZoneManager.h" #include "CharacterComponent.h" #include "Mail.h" +#include "User.h" #include "CppScripts.h" +#include "Loot.h" +#include "eReplicaComponentType.h" std::vector Player::m_Players = {}; -Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Entity* parentEntity) : Entity(objectID, info, parentEntity) -{ +Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Entity* parentEntity) : Entity(objectID, info, parentEntity) { m_ParentUser = user; m_Character = m_ParentUser->GetLastUsedChar(); m_ParentUser->SetLoggedInChar(objectID); @@ -26,7 +28,7 @@ Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Enti m_SystemAddress = m_ParentUser->GetSystemAddress(); m_DroppedLoot = {}; m_DroppedCoins = 0; - + m_GhostReferencePoint = NiPoint3::ZERO; m_GhostOverridePoint = NiPoint3::ZERO; m_GhostOverride = false; @@ -38,58 +40,48 @@ Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Enti const auto& iter = std::find(m_Players.begin(), m_Players.end(), this); - if (iter != m_Players.end()) - { + if (iter != m_Players.end()) { return; } m_Players.push_back(this); } -User* Player::GetParentUser() const -{ +User* Player::GetParentUser() const { return m_ParentUser; } -SystemAddress Player::GetSystemAddress() const -{ +SystemAddress Player::GetSystemAddress() const { return m_SystemAddress; } -void Player::SetSystemAddress(const SystemAddress& value) -{ +void Player::SetSystemAddress(const SystemAddress& value) { m_SystemAddress = value; } -void Player::SetRespawnPos(const NiPoint3 position) -{ +void Player::SetRespawnPos(const NiPoint3 position) { m_respawnPos = position; m_Character->SetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID(), position); } -void Player::SetRespawnRot(const NiQuaternion rotation) -{ +void Player::SetRespawnRot(const NiQuaternion rotation) { m_respawnRot = rotation; } -NiPoint3 Player::GetRespawnPosition() const -{ +NiPoint3 Player::GetRespawnPosition() const { return m_respawnPos; } -NiQuaternion Player::GetRespawnRotation() const -{ +NiQuaternion Player::GetRespawnRotation() const { return m_respawnRot; } -void Player::SendMail(const LWOOBJID sender, const std::string& senderName, const std::string& subject, const std::string& body, LOT attachment, uint16_t attachmentCount) const -{ +void Player::SendMail(const LWOOBJID sender, const std::string& senderName, const std::string& subject, const std::string& body, LOT attachment, uint16_t attachmentCount) const { Mail::SendMail(sender, senderName, this, subject, body, attachment, attachmentCount); } -void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) -{ +void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) { const auto objid = GetObjectID(); ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { @@ -118,96 +110,78 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) EntityManager::Instance()->DestructEntity(entity); return; - }); + }); } -void Player::AddLimboConstruction(LWOOBJID objectId) -{ +void Player::AddLimboConstruction(LWOOBJID objectId) { const auto& iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId); - if (iter != m_LimboConstructions.end()) - { + if (iter != m_LimboConstructions.end()) { return; } m_LimboConstructions.push_back(objectId); } -void Player::RemoveLimboConstruction(LWOOBJID objectId) -{ +void Player::RemoveLimboConstruction(LWOOBJID objectId) { const auto& iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId); - if (iter == m_LimboConstructions.end()) - { + if (iter == m_LimboConstructions.end()) { return; } m_LimboConstructions.erase(iter); } -void Player::ConstructLimboEntities() -{ - for (const auto objectId : m_LimboConstructions) - { +void Player::ConstructLimboEntities() { + for (const auto objectId : m_LimboConstructions) { auto* entity = EntityManager::Instance()->GetEntity(objectId); - if (entity == nullptr) - { + if (entity == nullptr) { continue; } EntityManager::Instance()->ConstructEntity(entity, m_SystemAddress); } - + m_LimboConstructions.clear(); } -std::map& Player::GetDroppedLoot() -{ +std::map& Player::GetDroppedLoot() { return m_DroppedLoot; } -const NiPoint3& Player::GetGhostReferencePoint() const -{ +const NiPoint3& Player::GetGhostReferencePoint() const { return m_GhostOverride ? m_GhostOverridePoint : m_GhostReferencePoint; } -const NiPoint3& Player::GetOriginGhostReferencePoint() const -{ +const NiPoint3& Player::GetOriginGhostReferencePoint() const { return m_GhostReferencePoint; } -void Player::SetGhostReferencePoint(const NiPoint3& value) -{ +void Player::SetGhostReferencePoint(const NiPoint3& value) { m_GhostReferencePoint = value; } -void Player::SetGhostOverridePoint(const NiPoint3& value) -{ +void Player::SetGhostOverridePoint(const NiPoint3& value) { m_GhostOverridePoint = value; } -const NiPoint3& Player::GetGhostOverridePoint() const -{ +const NiPoint3& Player::GetGhostOverridePoint() const { return m_GhostOverridePoint; } -void Player::SetGhostOverride(bool value) -{ +void Player::SetGhostOverride(bool value) { m_GhostOverride = value; } -bool Player::GetGhostOverride() const -{ +bool Player::GetGhostOverride() const { return m_GhostOverride; } -void Player::ObserveEntity(int32_t id) -{ - for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) - { - if (m_ObservedEntities[i] == 0 || m_ObservedEntities[i] == id) - { +void Player::ObserveEntity(int32_t id) { + for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) { + if (m_ObservedEntities[i] == 0 || m_ObservedEntities[i] == id) { m_ObservedEntities[i] = id; return; @@ -216,8 +190,7 @@ void Player::ObserveEntity(int32_t id) const auto index = m_ObservedEntitiesUsed++; - if (m_ObservedEntitiesUsed > m_ObservedEntitiesLength) - { + if (m_ObservedEntitiesUsed > m_ObservedEntitiesLength) { m_ObservedEntities.resize(m_ObservedEntitiesLength + m_ObservedEntitiesLength); m_ObservedEntitiesLength = m_ObservedEntitiesLength + m_ObservedEntitiesLength; @@ -226,12 +199,9 @@ void Player::ObserveEntity(int32_t id) m_ObservedEntities[index] = id; } -bool Player::IsObserved(int32_t id) -{ - for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) - { - if (m_ObservedEntities[i] == id) - { +bool Player::IsObserved(int32_t id) { + for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) { + if (m_ObservedEntities[i] == id) { return true; } } @@ -239,34 +209,27 @@ bool Player::IsObserved(int32_t id) return false; } -void Player::GhostEntity(int32_t id) -{ - for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) - { - if (m_ObservedEntities[i] == id) - { +void Player::GhostEntity(int32_t id) { + for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) { + if (m_ObservedEntities[i] == id) { m_ObservedEntities[i] = 0; } } } -Player* Player::GetPlayer(const SystemAddress& sysAddr) -{ +Player* Player::GetPlayer(const SystemAddress& sysAddr) { auto* entity = UserManager::Instance()->GetUser(sysAddr)->GetLastUsedChar()->GetEntity(); return static_cast(entity); } -Player* Player::GetPlayer(const std::string& name) -{ - const auto characters = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); +Player* Player::GetPlayer(const std::string& name) { + const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); - for (auto* character : characters) - { + for (auto* character : characters) { if (!character->IsPlayer()) continue; - if (character->GetCharacter()->GetName() == name) - { + if (character->GetCharacter()->GetName() == name) { return static_cast(character); } } @@ -274,21 +237,17 @@ Player* Player::GetPlayer(const std::string& name) return nullptr; } -Player* Player::GetPlayer(LWOOBJID playerID) -{ - for (auto* player : m_Players) - { - if (player->GetObjectID() == playerID) - { +Player* Player::GetPlayer(LWOOBJID playerID) { + for (auto* player : m_Players) { + if (player->GetObjectID() == playerID) { return player; } } - + return nullptr; } -const std::vector& Player::GetAllPlayers() -{ +const std::vector& Player::GetAllPlayers() { return m_Players; } @@ -300,23 +259,19 @@ void Player::SetDroppedCoins(uint64_t value) { m_DroppedCoins = value; } -Player::~Player() -{ - Game::logger->Log("Player", "Deleted player\n"); +Player::~Player() { + Game::logger->Log("Player", "Deleted player"); - for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) - { + for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) { const auto id = m_ObservedEntities[i]; - if (id == 0) - { + if (id == 0) { continue; } auto* entity = EntityManager::Instance()->GetGhostCandidate(id); - if (entity != nullptr) - { + if (entity != nullptr) { entity->SetObservers(entity->GetObservers() - 1); } } @@ -325,25 +280,24 @@ Player::~Player() const auto& iter = std::find(m_Players.begin(), m_Players.end(), this); - if (iter == m_Players.end()) - { + if (iter == m_Players.end()) { return; } if (IsPlayer()) { - Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerExit(zoneControl, this); - } + Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { + script->OnPlayerExit(zoneControl, this); + } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); - for (Entity* scriptEntity : scriptedActs) { - if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerExit(scriptEntity, this); - } - } - } + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (Entity* scriptEntity : scriptedActs) { + if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds + for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { + script->OnPlayerExit(scriptEntity, this); + } + } + } } m_Players.erase(iter); diff --git a/dGame/Player.h b/dGame/Player.h index bba01363..287ee613 100644 --- a/dGame/Player.h +++ b/dGame/Player.h @@ -1,29 +1,29 @@ -#pragma once +#pragma once #include "Entity.h" /** * Extended Entity for player data and behavior. - * + * * Contains properties only a player entity would require, like associated SystemAddress and User. - * + * * Keeps track of which entities are observed by this user for ghosting. */ class Player final : public Entity { public: explicit Player(const LWOOBJID& objectID, EntityInfo info, User* user, Entity* parentEntity = nullptr); - + /** * Getters */ User* GetParentUser() const override; - + SystemAddress GetSystemAddress() const override; - + NiPoint3 GetRespawnPosition() const override; - + NiQuaternion GetRespawnRotation() const override; const NiPoint3& GetGhostReferencePoint() const; @@ -41,11 +41,11 @@ public: /** * Setters */ - + void SetSystemAddress(const SystemAddress& value) override; - + void SetRespawnPos(NiPoint3 position) override; - + void SetRespawnRot(NiQuaternion rotation) override; void SetGhostReferencePoint(const NiPoint3& value); @@ -58,7 +58,7 @@ public: /** * Wrapper for sending an in-game mail. - * + * * @param sender id of the sender. LWOOBJID_EMPTY for system mail * @param senderName name of the sender. Max 32 characters. * @param subject mail subject. Max 50 characters. @@ -67,10 +67,10 @@ public: * @param attachmentCount stack size for attachment. */ void SendMail(LWOOBJID sender, const std::string& senderName, const std::string& subject, const std::string& body, LOT attachment, uint16_t attachmentCount) const; - + /** * Wrapper for transfering the player to another instance. - * + * * @param zoneId zoneID for the new instance. * @param cloneId cloneID for the new instance. */ @@ -81,7 +81,7 @@ public: */ void AddLimboConstruction(LWOOBJID objectId); - + void RemoveLimboConstruction(LWOOBJID objectId); void ConstructLimboEntities(); @@ -99,19 +99,19 @@ public: static Player* GetPlayer(const SystemAddress& sysAddr); static Player* GetPlayer(const std::string& name); - + static Player* GetPlayer(LWOOBJID playerID); static const std::vector& GetAllPlayers(); - + ~Player() override; private: SystemAddress m_SystemAddress; - + NiPoint3 m_respawnPos; - + NiQuaternion m_respawnRot; - + User* m_ParentUser; NiPoint3 m_GhostReferencePoint; @@ -121,7 +121,7 @@ private: bool m_GhostOverride; std::vector m_ObservedEntities; - + int32_t m_ObservedEntitiesLength; int32_t m_ObservedEntitiesUsed; diff --git a/dGame/TeamManager.cpp b/dGame/TeamManager.cpp index 8836dd8d..0258ce3e 100644 --- a/dGame/TeamManager.cpp +++ b/dGame/TeamManager.cpp @@ -3,74 +3,60 @@ TeamManager* TeamManager::m_Address = nullptr; //For singleton method -TeamManager::TeamManager() -{ +TeamManager::TeamManager() { } -Team* TeamManager::GetTeam(LWOOBJID member) const -{ - for (const auto& pair : m_Teams) - { - for (const auto memberId : pair.second->members) - { - if (memberId == member) - { - return pair.second; - } - } - } - - return nullptr; +Team* TeamManager::GetTeam(LWOOBJID member) const { + for (const auto& pair : m_Teams) { + for (const auto memberId : pair.second->members) { + if (memberId == member) { + return pair.second; + } + } + } + + return nullptr; } -LWOOBJID TeamManager::GetNextLootOwner(Team* team) const -{ - team->lootRound++; +LWOOBJID TeamManager::GetNextLootOwner(Team* team) const { + team->lootRound++; - if (team->lootRound >= team->members.size()) - { - team->lootRound = 0; - } + if (team->lootRound >= team->members.size()) { + team->lootRound = 0; + } - return team->members[team->lootRound]; + return team->members[team->lootRound]; } -void TeamManager::UpdateTeam(LWOOBJID teamId, char lootOption, const std::vector& members) -{ - const auto& pair = m_Teams.find(teamId); +void TeamManager::UpdateTeam(LWOOBJID teamId, char lootOption, const std::vector& members) { + const auto& pair = m_Teams.find(teamId); - Team* team; + Team* team; - if (pair == m_Teams.end()) - { - if (members.size() <= 1) - { - return; - } + if (pair == m_Teams.end()) { + if (members.size() <= 1) { + return; + } - team = new Team(); - m_Teams[teamId] = team; - } - else - { - team = pair->second; - } + team = new Team(); + m_Teams[teamId] = team; + } else { + team = pair->second; + } - team->members = members; - team->lootOption = lootOption; + team->members = members; + team->lootOption = lootOption; } -void TeamManager::DeleteTeam(LWOOBJID teamId) -{ - const auto& pair = m_Teams.find(teamId); +void TeamManager::DeleteTeam(LWOOBJID teamId) { + const auto& pair = m_Teams.find(teamId); - if (pair == m_Teams.end()) return; + if (pair == m_Teams.end()) return; - delete pair->second; + delete pair->second; - m_Teams.erase(teamId); + m_Teams.erase(teamId); } -TeamManager::~TeamManager() -{ +TeamManager::~TeamManager() { } diff --git a/dGame/TeamManager.h b/dGame/TeamManager.h index ffab3764..eb1b5c5b 100644 --- a/dGame/TeamManager.h +++ b/dGame/TeamManager.h @@ -6,18 +6,18 @@ struct Team { LWOOBJID teamID = LWOOBJID_EMPTY; char lootOption = 0; - std::vector members {}; + std::vector members{}; char lootRound = 0; }; class TeamManager { public: - static TeamManager* Instance() { + static TeamManager* Instance() { if (!m_Address) { m_Address = new TeamManager(); } - + return m_Address; } @@ -26,11 +26,11 @@ public: void UpdateTeam(LWOOBJID teamId, char lootOption, const std::vector& members); void DeleteTeam(LWOOBJID teamId); - explicit TeamManager(); - ~TeamManager(); + explicit TeamManager(); + ~TeamManager(); private: - static TeamManager* m_Address; //For singleton method - std::unordered_map m_Teams {}; + static TeamManager* m_Address; //For singleton method + std::unordered_map m_Teams{}; }; diff --git a/dGame/TradingManager.cpp b/dGame/TradingManager.cpp index 04a0501d..281c003d 100644 --- a/dGame/TradingManager.cpp +++ b/dGame/TradingManager.cpp @@ -9,300 +9,277 @@ #include "Character.h" #include "CharacterComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" TradingManager* TradingManager::m_Address = nullptr; -Trade::Trade(LWOOBJID tradeId, LWOOBJID participantA, LWOOBJID participantB) -{ - m_TradeId = tradeId; - m_ParticipantA = participantA; - m_ParticipantB = participantB; +Trade::Trade(LWOOBJID tradeId, LWOOBJID participantA, LWOOBJID participantB) { + m_TradeId = tradeId; + m_ParticipantA = participantA; + m_ParticipantB = participantB; } -Trade::~Trade() -{ - +Trade::~Trade() { + } -LWOOBJID Trade::GetTradeId() const -{ - return m_TradeId; +LWOOBJID Trade::GetTradeId() const { + return m_TradeId; } -bool Trade::IsParticipant(LWOOBJID playerId) const -{ - return m_ParticipantA == playerId || m_ParticipantB == playerId; +bool Trade::IsParticipant(LWOOBJID playerId) const { + return m_ParticipantA == playerId || m_ParticipantB == playerId; } -LWOOBJID Trade::GetParticipantA() const -{ - return m_ParticipantA; +LWOOBJID Trade::GetParticipantA() const { + return m_ParticipantA; } -LWOOBJID Trade::GetParticipantB() const -{ - return m_ParticipantB; +LWOOBJID Trade::GetParticipantB() const { + return m_ParticipantB; } -Entity* Trade::GetParticipantAEntity() const -{ - return EntityManager::Instance()->GetEntity(m_ParticipantA); +Entity* Trade::GetParticipantAEntity() const { + return EntityManager::Instance()->GetEntity(m_ParticipantA); } -Entity* Trade::GetParticipantBEntity() const -{ - return EntityManager::Instance()->GetEntity(m_ParticipantB); +Entity* Trade::GetParticipantBEntity() const { + return EntityManager::Instance()->GetEntity(m_ParticipantB); } -void Trade::SetCoins(LWOOBJID participant, uint64_t coins) -{ - if (participant == m_ParticipantA) - { - m_CoinsA = coins; - } - else if (participant == m_ParticipantB) - { - m_CoinsB = coins; - } +void Trade::SetCoins(LWOOBJID participant, uint64_t coins) { + if (participant == m_ParticipantA) { + m_CoinsA = coins; + } else if (participant == m_ParticipantB) { + m_CoinsB = coins; + } } -void Trade::SetItems(LWOOBJID participant, std::vector items) -{ - if (participant == m_ParticipantA) - { - m_ItemsA = items; - } - else if (participant == m_ParticipantB) - { - m_ItemsB = items; - } +void Trade::SetItems(LWOOBJID participant, std::vector items) { + if (participant == m_ParticipantA) { + m_ItemsA = items; + } else if (participant == m_ParticipantB) { + m_ItemsB = items; + } } -void Trade::SetAccepted(LWOOBJID participant, bool value) -{ - if (participant == m_ParticipantA) - { - m_AcceptedA = !value; +void Trade::SetAccepted(LWOOBJID participant, bool value) { + if (participant == m_ParticipantA) { + m_AcceptedA = !value; - Game::logger->Log("Trade", "Accepted from A (%d), B: (%d)\n", value, m_AcceptedB); + Game::logger->Log("Trade", "Accepted from A (%d), B: (%d)", value, m_AcceptedB); - auto* entityB = GetParticipantBEntity(); + auto* entityB = GetParticipantBEntity(); - if (entityB != nullptr) - { - GameMessages::SendServerTradeAccept(m_ParticipantB, value, entityB->GetSystemAddress()); - } - } - else if (participant == m_ParticipantB) - { - m_AcceptedB = !value; + if (entityB != nullptr) { + GameMessages::SendServerTradeAccept(m_ParticipantB, value, entityB->GetSystemAddress()); + } + } else if (participant == m_ParticipantB) { + m_AcceptedB = !value; - Game::logger->Log("Trade", "Accepted from B (%d), A: (%d)\n", value, m_AcceptedA); + Game::logger->Log("Trade", "Accepted from B (%d), A: (%d)", value, m_AcceptedA); - auto* entityA = GetParticipantAEntity(); + auto* entityA = GetParticipantAEntity(); - if (entityA != nullptr) - { - GameMessages::SendServerTradeAccept(m_ParticipantA, value, entityA->GetSystemAddress()); - } - } - - if (m_AcceptedA && m_AcceptedB) - { - auto* entityB = GetParticipantBEntity(); + if (entityA != nullptr) { + GameMessages::SendServerTradeAccept(m_ParticipantA, value, entityA->GetSystemAddress()); + } + } - if (entityB != nullptr) - { - GameMessages::SendServerTradeAccept(m_ParticipantB, false, entityB->GetSystemAddress()); - } - else - { - return; - } - - auto* entityA = GetParticipantAEntity(); + if (m_AcceptedA && m_AcceptedB) { + auto* entityB = GetParticipantBEntity(); - if (entityA != nullptr) - { - GameMessages::SendServerTradeAccept(m_ParticipantA, false, entityA->GetSystemAddress()); - } - else - { - return; - } - - Complete(); - } + if (entityB != nullptr) { + GameMessages::SendServerTradeAccept(m_ParticipantB, false, entityB->GetSystemAddress()); + } else { + return; + } + + auto* entityA = GetParticipantAEntity(); + + if (entityA != nullptr) { + GameMessages::SendServerTradeAccept(m_ParticipantA, false, entityA->GetSystemAddress()); + } else { + return; + } + + Complete(); + TradingManager::Instance()->CancelTrade(m_TradeId); + } } -void Trade::Complete() -{ - auto* entityA = GetParticipantAEntity(); - auto* entityB = GetParticipantBEntity(); - - if (entityA == nullptr || entityB == nullptr) return; +void Trade::Complete() { + auto* entityA = GetParticipantAEntity(); + auto* entityB = GetParticipantBEntity(); - auto* inventoryA = entityA->GetComponent(); - auto* inventoryB = entityB->GetComponent(); - auto* missionsA = entityA->GetComponent(); - auto* missionsB = entityB->GetComponent(); - auto* characterA = entityA->GetCharacter(); - auto* characterB = entityB->GetCharacter(); + if (entityA == nullptr || entityB == nullptr) return; - if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return; + auto* inventoryA = entityA->GetComponent(); + auto* inventoryB = entityB->GetComponent(); + auto* missionsA = entityA->GetComponent(); + auto* missionsB = entityB->GetComponent(); + auto* characterA = entityA->GetCharacter(); + auto* characterB = entityB->GetCharacter(); - characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::LOOT_SOURCE_TRADE); - characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::LOOT_SOURCE_TRADE); + if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return; - for (const auto& tradeItem : m_ItemsA) - { - inventoryA->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); + // First verify both players have the coins and items requested for the trade. + if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) { + Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade."); + return; + } - missionsA->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsB) - { - inventoryB->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); + for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str()); + return; + } + } - missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } + for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } - for (const auto& tradeItem : m_ItemsA) - { - inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); - } + // Now actually do the trade. + characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::TRADE); + characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::TRADE); - for (const auto& tradeItem : m_ItemsB) - { - inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); - } + for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsA->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); + inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::TRADE); + } - TradingManager::Instance()->CancelTrade(m_TradeId); + for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsB->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); + inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::TRADE); + } - characterA->SaveXMLToDatabase(); - characterB->SaveXMLToDatabase(); + characterA->SaveXMLToDatabase(); + characterB->SaveXMLToDatabase(); + return; } -void Trade::Cancel() -{ - auto* entityA = GetParticipantAEntity(); - auto* entityB = GetParticipantBEntity(); - - if (entityA == nullptr || entityB == nullptr) return; +void Trade::Cancel() { + auto* entityA = GetParticipantAEntity(); + auto* entityB = GetParticipantBEntity(); - GameMessages::SendServerTradeCancel(entityA->GetObjectID(), entityA->GetSystemAddress()); - GameMessages::SendServerTradeCancel(entityB->GetObjectID(), entityB->GetSystemAddress()); + if (entityA == nullptr || entityB == nullptr) return; + + GameMessages::SendServerTradeCancel(entityA->GetObjectID(), entityA->GetSystemAddress()); + GameMessages::SendServerTradeCancel(entityB->GetObjectID(), entityB->GetSystemAddress()); } -void Trade::SendUpdateToOther(LWOOBJID participant) -{ - Entity* other = nullptr; - Entity* self = nullptr; - uint64_t coins; - std::vector itemIds; +void Trade::SendUpdateToOther(LWOOBJID participant) { + Entity* other = nullptr; + Entity* self = nullptr; + uint64_t coins; + std::vector itemIds; - Game::logger->Log("Trade", "Attempting to send trade update\n"); - - if (participant == m_ParticipantA) - { - other = GetParticipantBEntity(); - self = GetParticipantAEntity(); - coins = m_CoinsA; - itemIds = m_ItemsA; - } - else if (participant == m_ParticipantB) - { - other = GetParticipantAEntity(); - self = GetParticipantBEntity(); - coins = m_CoinsB; - itemIds = m_ItemsB; - } - else - { - return; - } - - if (other == nullptr || self == nullptr) return; + Game::logger->Log("Trade", "Attempting to send trade update"); - std::vector items {}; - - auto* inventoryComponent = self->GetComponent(); + if (participant == m_ParticipantA) { + other = GetParticipantBEntity(); + self = GetParticipantAEntity(); + coins = m_CoinsA; + itemIds = m_ItemsA; + } else if (participant == m_ParticipantB) { + other = GetParticipantAEntity(); + self = GetParticipantBEntity(); + coins = m_CoinsB; + itemIds = m_ItemsB; + } else { + return; + } - if (inventoryComponent == nullptr) return; + if (other == nullptr || self == nullptr) return; - for (const auto tradeItem : itemIds) - { - auto* item = inventoryComponent->FindItemById(tradeItem.itemId); + std::vector items{}; - if (item == nullptr) return; + auto* inventoryComponent = self->GetComponent(); - if (tradeItem.itemCount > item->GetCount()) return; + if (inventoryComponent == nullptr) return; - items.push_back(tradeItem); - } + for (const auto tradeItem : itemIds) { + auto* item = inventoryComponent->FindItemById(tradeItem.itemId); - Game::logger->Log("Trade", "Sending trade update\n"); - - GameMessages::SendServerTradeUpdate(other->GetObjectID(), coins, items, other->GetSystemAddress()); + if (item == nullptr) return; + + if (tradeItem.itemCount > item->GetCount()) return; + + items.push_back(tradeItem); + } + + Game::logger->Log("Trade", "Sending trade update"); + + GameMessages::SendServerTradeUpdate(other->GetObjectID(), coins, items, other->GetSystemAddress()); } -TradingManager::TradingManager() -{ +TradingManager::TradingManager() { } -TradingManager::~TradingManager() -{ - for (const auto& pair : trades) - { - delete pair.second; - } - - trades.clear(); +TradingManager::~TradingManager() { + for (const auto& pair : trades) { + delete pair.second; + } + + trades.clear(); } -Trade* TradingManager::GetTrade(LWOOBJID tradeId) const -{ - const auto& pair = trades.find(tradeId); +Trade* TradingManager::GetTrade(LWOOBJID tradeId) const { + const auto& pair = trades.find(tradeId); - if (pair == trades.end()) return nullptr; + if (pair == trades.end()) return nullptr; - return pair->second; + return pair->second; } -Trade* TradingManager::GetPlayerTrade(LWOOBJID playerId) const -{ - for (const auto& pair : trades) - { - if (pair.second->IsParticipant(playerId)) - { - return pair.second; - } - } - - return nullptr; +Trade* TradingManager::GetPlayerTrade(LWOOBJID playerId) const { + for (const auto& pair : trades) { + if (pair.second->IsParticipant(playerId)) { + return pair.second; + } + } + + return nullptr; } -void TradingManager::CancelTrade(LWOOBJID tradeId) -{ - auto* trade = GetTrade(tradeId); +void TradingManager::CancelTrade(LWOOBJID tradeId) { + auto* trade = GetTrade(tradeId); - if (trade == nullptr) return; - - delete trade; + if (trade == nullptr) return; - trades.erase(tradeId); + delete trade; + + trades.erase(tradeId); } -Trade* TradingManager::NewTrade(LWOOBJID participantA, LWOOBJID participantB) -{ - const LWOOBJID tradeId = ObjectIDManager::Instance()->GenerateObjectID(); +Trade* TradingManager::NewTrade(LWOOBJID participantA, LWOOBJID participantB) { + const LWOOBJID tradeId = ObjectIDManager::Instance()->GenerateObjectID(); - auto* trade = new Trade(tradeId, participantA, participantB); - - trades[tradeId] = trade; + auto* trade = new Trade(tradeId, participantA, participantB); - Game::logger->Log("TradingManager", "Created new trade between (%llu) <-> (%llu)\n", participantA, participantB); + trades[tradeId] = trade; - return trade; + Game::logger->Log("TradingManager", "Created new trade between (%llu) <-> (%llu)", participantA, participantB); + + return trade; } diff --git a/dGame/TradingManager.h b/dGame/TradingManager.h index 6962acaa..ec0d332f 100644 --- a/dGame/TradingManager.h +++ b/dGame/TradingManager.h @@ -4,73 +4,73 @@ struct TradeItem { - LWOOBJID itemId; - LOT itemLot; - uint32_t itemCount; + LWOOBJID itemId; + LOT itemLot; + uint32_t itemCount; }; class Trade { public: - explicit Trade(LWOOBJID tradeId, LWOOBJID participantA, LWOOBJID participantB); - ~Trade(); + explicit Trade(LWOOBJID tradeId, LWOOBJID participantA, LWOOBJID participantB); + ~Trade(); - LWOOBJID GetTradeId() const; + LWOOBJID GetTradeId() const; - bool IsParticipant(LWOOBJID playerId) const; + bool IsParticipant(LWOOBJID playerId) const; - LWOOBJID GetParticipantA() const; - LWOOBJID GetParticipantB() const; + LWOOBJID GetParticipantA() const; + LWOOBJID GetParticipantB() const; - Entity* GetParticipantAEntity() const; - Entity* GetParticipantBEntity() const; + Entity* GetParticipantAEntity() const; + Entity* GetParticipantBEntity() const; - void SetCoins(LWOOBJID participant, uint64_t coins); - void SetItems(LWOOBJID participant, std::vector items); - void SetAccepted(LWOOBJID participant, bool value); + void SetCoins(LWOOBJID participant, uint64_t coins); + void SetItems(LWOOBJID participant, std::vector items); + void SetAccepted(LWOOBJID participant, bool value); - void Complete(); - void Cancel(); + void Complete(); + void Cancel(); - void SendUpdateToOther(LWOOBJID participant); + void SendUpdateToOther(LWOOBJID participant); private: - LWOOBJID m_TradeId = LWOOBJID_EMPTY; - LWOOBJID m_ParticipantA = LWOOBJID_EMPTY; - LWOOBJID m_ParticipantB = LWOOBJID_EMPTY; + LWOOBJID m_TradeId = LWOOBJID_EMPTY; + LWOOBJID m_ParticipantA = LWOOBJID_EMPTY; + LWOOBJID m_ParticipantB = LWOOBJID_EMPTY; - uint64_t m_CoinsA = 0; - uint64_t m_CoinsB = 0; + uint64_t m_CoinsA = 0; + uint64_t m_CoinsB = 0; - std::vector m_ItemsA {}; - std::vector m_ItemsB {}; + std::vector m_ItemsA{}; + std::vector m_ItemsB{}; - bool m_AcceptedA = false; - bool m_AcceptedB = false; + bool m_AcceptedA = false; + bool m_AcceptedB = false; }; class TradingManager { public: - static TradingManager* Instance() { + static TradingManager* Instance() { if (!m_Address) { m_Address = new TradingManager(); } - + return m_Address; } - explicit TradingManager(); - ~TradingManager(); + explicit TradingManager(); + ~TradingManager(); - Trade* GetTrade(LWOOBJID tradeId) const; - Trade* GetPlayerTrade(LWOOBJID playerId) const; - void CancelTrade(LWOOBJID tradeId); - Trade* NewTrade(LWOOBJID participantA, LWOOBJID participantB); + Trade* GetTrade(LWOOBJID tradeId) const; + Trade* GetPlayerTrade(LWOOBJID playerId) const; + void CancelTrade(LWOOBJID tradeId); + Trade* NewTrade(LWOOBJID participantA, LWOOBJID participantB); private: - static TradingManager* m_Address; //For singleton method + static TradingManager* m_Address; //For singleton method - std::unordered_map trades; + std::unordered_map trades; }; diff --git a/dGame/User.cpp b/dGame/User.cpp index 3efc4d0a..55bbcc09 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -5,120 +5,121 @@ #include "dLogger.h" #include "Game.h" #include "dZoneManager.h" +#include "eServerDisconnectIdentifiers.h" +#include "eGameMasterLevel.h" User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { m_AccountID = 0; m_Username = ""; m_SessionKey = ""; - m_MaxGMLevel = 0; //The max GM level this account can assign to it's characters + m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters m_LastCharID = 0; m_SessionKey = sessionKey; m_SystemAddress = sysAddr; m_Username = username; - m_LoggedInCharID = 0; - + m_LoggedInCharID = 0; + + m_IsBestFriendMap = std::unordered_map(); + //HACK HACK HACK //This needs to be re-enabled / updated whenever the mute stuff is moved to another table. //This was only done because otherwise the website's account page dies and the website is waiting on a migration to wordpress. - + //sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gmlevel, mute_expire FROM accounts WHERE name=? LIMIT 1;"); sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gm_level FROM accounts WHERE name=? LIMIT 1;"); stmt->setString(1, username.c_str()); - + sql::ResultSet* res = stmt->executeQuery(); while (res->next()) { m_AccountID = res->getUInt(1); - m_MaxGMLevel = res->getInt(2); + m_MaxGMLevel = static_cast(res->getInt(2)); m_MuteExpire = 0; //res->getUInt64(3); } - + delete res; delete stmt; - - //If we're loading a zone, we'll load the last used (aka current) character: + + //If we're loading a zone, we'll load the last used (aka current) character: if (Game::server->GetZoneID() != 0) { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 1;"); - stmt->setUInt(1, m_AccountID); - - sql::ResultSet* res = stmt->executeQuery(); - if (res->rowsCount() > 0) { - while (res->next()) { - LWOOBJID objID = res->getUInt64(1); - Character* character = new Character(uint32_t(objID), this); - m_Characters.push_back(character); - Game::logger->Log("User", "Loaded %llu as it is the last used char\n", objID); - } - } - - delete res; - delete stmt; - } + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 1;"); + stmt->setUInt(1, m_AccountID); + + sql::ResultSet* res = stmt->executeQuery(); + if (res->rowsCount() > 0) { + while (res->next()) { + LWOOBJID objID = res->getUInt64(1); + Character* character = new Character(uint32_t(objID), this); + m_Characters.push_back(character); + Game::logger->Log("User", "Loaded %llu as it is the last used char", objID); + } + } + + delete res; + delete stmt; + } } -User::User ( const User& other ) { +User::User(const User& other) { this->m_AccountID = other.m_AccountID; this->m_LastCharID = other.m_LastCharID; this->m_MaxGMLevel = other.m_MaxGMLevel; this->m_SessionKey = other.m_SessionKey; this->m_SystemAddress = other.m_SystemAddress; this->m_Username = other.m_Username; - this->m_LoggedInCharID = other.m_LoggedInCharID; + this->m_LoggedInCharID = other.m_LoggedInCharID; } User::~User() { for (Character* c : m_Characters) { - if (c) { - delete c; - c = nullptr; - } - } + if (c) { + delete c; + c = nullptr; + } + } } -User& User::operator= ( const User& other ) { +User& User::operator= (const User& other) { this->m_AccountID = other.m_AccountID; this->m_LastCharID = other.m_LastCharID; this->m_MaxGMLevel = other.m_MaxGMLevel; this->m_SessionKey = other.m_SessionKey; this->m_SystemAddress = other.m_SystemAddress; this->m_Username = other.m_Username; - this->m_LoggedInCharID = other.m_LoggedInCharID; + this->m_LoggedInCharID = other.m_LoggedInCharID; return *this; } -bool User::operator== ( const User& other ) const { +bool User::operator== (const User& other) const { if (m_Username == other.m_Username || m_SessionKey == other.m_SessionKey || m_SystemAddress == other.m_SystemAddress) return true; - + return false; } -Character * User::GetLastUsedChar() { - if (m_Characters.size() == 0) return nullptr; - else if (m_Characters.size() == 1) return m_Characters[0]; - else { - Character* toReturn = m_Characters[0]; - for (size_t i = 0; i < m_Characters.size(); ++i) { - if (m_Characters[i]->GetLastLogin() > toReturn->GetLastLogin()) toReturn = m_Characters[i]; - } - - return toReturn; - } +Character* User::GetLastUsedChar() { + if (m_Characters.size() == 0) return nullptr; + else if (m_Characters.size() == 1) return m_Characters[0]; + else { + Character* toReturn = m_Characters[0]; + for (size_t i = 0; i < m_Characters.size(); ++i) { + if (m_Characters[i]->GetLastLogin() > toReturn->GetLastLogin()) toReturn = m_Characters[i]; + } + + return toReturn; + } } -bool User::GetIsMuted() const -{ +bool User::GetIsMuted() const { return m_MuteExpire == 1 || m_MuteExpire > time(NULL); } -time_t User::GetMuteExpire() const -{ +time_t User::GetMuteExpire() const { return m_MuteExpire; } -void User::SetMuteExpire(time_t value) -{ +void User::SetMuteExpire(time_t value) { m_MuteExpire = value; } @@ -126,7 +127,7 @@ void User::UserOutOfSync() { m_AmountOfTimesOutOfSync++; if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) { //YEET - Game::logger->Log("User", "User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.\n", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed); - Game::server->Disconnect(this->m_SystemAddress, SERVER_DISCON_KICK); + Game::logger->Log("User", "User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed); + Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE); } } diff --git a/dGame/User.h b/dGame/User.h index 3be9148e..3201538e 100644 --- a/dGame/User.h +++ b/dGame/User.h @@ -9,8 +9,9 @@ #include class Character; +enum class eGameMasterLevel : uint8_t; -struct BehaviorParams{ +struct BehaviorParams { uint32_t behavior; LWOOBJID objid; bool followup; @@ -23,25 +24,28 @@ public: ~User(); User& operator=(const User& other); bool operator==(const User& other) const; - + uint32_t GetAccountID() { return m_AccountID; } std::string& GetUsername() { return m_Username; } std::string& GetSessionKey() { return m_SessionKey; } SystemAddress& GetSystemAddress() { return m_SystemAddress; } - - uint32_t GetMaxGMLevel() { return m_MaxGMLevel; } + + eGameMasterLevel GetMaxGMLevel() { return m_MaxGMLevel; } uint32_t GetLastCharID() { return m_LastCharID; } void SetLastCharID(uint32_t newCharID) { m_LastCharID = newCharID; } - + std::vector& GetCharacters() { return m_Characters; } Character* GetLastUsedChar(); - - void SetLoggedInChar(const LWOOBJID& objID) { m_LoggedInCharID = objID; } - LWOOBJID& GetLoggedInChar() { return m_LoggedInCharID; } + + void SetLoggedInChar(const LWOOBJID& objID) { m_LoggedInCharID = objID; } + LWOOBJID& GetLoggedInChar() { return m_LoggedInCharID; } bool GetLastChatMessageApproved() { return m_LastChatMessageApproved; } void SetLastChatMessageApproved(bool approved) { m_LastChatMessageApproved = approved; } + std::unordered_map GetIsBestFriendMap() { return m_IsBestFriendMap; } + void SetIsBestFriendMap(std::unordered_map mapToSet) { m_IsBestFriendMap = mapToSet; } + bool GetIsMuted() const; time_t GetMuteExpire() const; @@ -49,7 +53,7 @@ public: // Added for GameMessageHandler std::unordered_map uiBehaviorHandles; - + void UserOutOfSync(); private: @@ -57,11 +61,13 @@ private: std::string m_Username; std::string m_SessionKey; SystemAddress m_SystemAddress; - - uint32_t m_MaxGMLevel; //The max GM level this account can assign to it's characters + + eGameMasterLevel m_MaxGMLevel; //The max GM level this account can assign to it's characters uint32_t m_LastCharID; std::vector m_Characters; - LWOOBJID m_LoggedInCharID; + LWOOBJID m_LoggedInCharID; + + std::unordered_map m_IsBestFriendMap; bool m_LastChatMessageApproved = false; int m_AmountOfTimesOutOfSync = 0; diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 1d14cb0a..0161395c 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -20,8 +20,16 @@ #include "Entity.h" #include "EntityManager.h" #include "SkillComponent.h" +#include "AssetManager.h" +#include "CDClientDatabase.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" +#include "eCharacterCreationResponse.h" +#include "eRenameResponse.h" +#include "eConnectionType.h" +#include "eChatInternalMessageType.h" -UserManager * UserManager::m_Address = nullptr; +UserManager* UserManager::m_Address = nullptr; //Local functions as they aren't needed by anything else, leave the implementations at the bottom! uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle); @@ -32,50 +40,66 @@ inline void StripCR(std::string& str) { } void UserManager::Initialize() { - std::string firstNamePath = "./res/names/minifigname_first.txt"; - std::string middleNamePath = "./res/names/minifigname_middle.txt"; - std::string lastNamePath = "./res/names/minifigname_last.txt"; std::string line; - std::fstream fnFile(firstNamePath, std::ios::in); - std::fstream mnFile(middleNamePath, std::ios::in); - std::fstream lnFile(lastNamePath, std::ios::in); - - while (std::getline(fnFile, line, '\n')) { + AssetMemoryBuffer fnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_first.txt"); + if (!fnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream fnStream = std::istream(&fnBuff); + while (std::getline(fnStream, line, '\n')) { std::string name = line; StripCR(name); m_FirstNames.push_back(name); } + fnBuff.close(); - while (std::getline(mnFile, line, '\n')) { + AssetMemoryBuffer mnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_middle.txt"); + if (!mnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream mnStream = std::istream(&mnBuff); + while (std::getline(mnStream, line, '\n')) { std::string name = line; StripCR(name); m_MiddleNames.push_back(name); } + mnBuff.close(); - while (std::getline(lnFile, line, '\n')) { + AssetMemoryBuffer lnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_last.txt"); + if (!lnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream lnStream = std::istream(&lnBuff); + while (std::getline(lnStream, line, '\n')) { std::string name = line; StripCR(name); m_LastNames.push_back(name); } + lnBuff.close(); - fnFile.close(); - mnFile.close(); - lnFile.close(); - //Load our pre-approved names: - std::fstream chatList("./res/chatplus_en_us.txt", std::ios::in); - while (std::getline(chatList, line, '\n')) { + AssetMemoryBuffer chatListBuff = Game::assetManager->GetFileAsBuffer("chatplus_en_us.txt"); + if (!chatListBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing chat whitelist file."); + } + std::istream chatListStream = std::istream(&chatListBuff); + while (std::getline(chatListStream, line, '\n')) { StripCR(line); m_PreapprovedNames.push_back(line); } + chatListBuff.close(); } UserManager::~UserManager() { - + } -User* UserManager::CreateUser ( const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey ) { +User* UserManager::CreateUser(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { User* user = new User(sysAddr, username, sessionKey); if (user && Game::server->IsConnected(sysAddr)) m_Users.insert(std::make_pair(sysAddr, user)); @@ -89,45 +113,42 @@ User* UserManager::CreateUser ( const SystemAddress& sysAddr, const std::string& return user; } -User* UserManager::GetUser ( const SystemAddress& sysAddr ) { +User* UserManager::GetUser(const SystemAddress& sysAddr) { auto it = m_Users.find(sysAddr); if (it != m_Users.end() && it->second) return it->second; - return nullptr; + return nullptr; } -User* UserManager::GetUser ( const std::string& username ) { +User* UserManager::GetUser(const std::string& username) { for (auto p : m_Users) { if (p.second) { if (p.second->GetUsername() == username) return p.second; } } - return nullptr; + return nullptr; } -bool UserManager::DeleteUser ( const SystemAddress& sysAddr ) { +bool UserManager::DeleteUser(const SystemAddress& sysAddr) { const auto& it = m_Users.find(sysAddr); - if (it != m_Users.end()) - { + if (it != m_Users.end()) { if (std::count(m_UsersToDelete.begin(), m_UsersToDelete.end(), it->second)) return false; m_UsersToDelete.push_back(it->second); - + m_Users.erase(it); return true; } - + return false; } -void UserManager::DeletePendingRemovals() -{ - for (auto* user : m_UsersToDelete) - { - Game::logger->Log("UserManager", "Deleted user %i\n", user->GetAccountID()); +void UserManager::DeletePendingRemovals() { + for (auto* user : m_UsersToDelete) { + Game::logger->Log("UserManager", "Deleted user %i", user->GetAccountID()); delete user; } @@ -135,58 +156,57 @@ void UserManager::DeletePendingRemovals() m_UsersToDelete.clear(); } -bool UserManager::IsNameAvailable ( const std::string& requestedName ) { +bool UserManager::IsNameAvailable(const std::string& requestedName) { bool toReturn = false; //To allow for a clean exit sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? OR pending_name=? LIMIT 1;"); stmt->setString(1, requestedName.c_str()); stmt->setString(2, requestedName.c_str()); - + sql::ResultSet* res = stmt->executeQuery(); if (res->rowsCount() == 0) toReturn = true; - + delete stmt; delete res; return toReturn; } -std::string UserManager::GetPredefinedName ( uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex ) { +std::string UserManager::GetPredefinedName(uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex) { if (firstNameIndex > m_FirstNames.size() || middleNameIndex > m_MiddleNames.size() || lastNameIndex > m_LastNames.size()) return std::string("INVALID"); return std::string(m_FirstNames[firstNameIndex] + m_MiddleNames[middleNameIndex] + m_LastNames[lastNameIndex]); } -bool UserManager::IsNamePreapproved ( const std::string& requestedName ) { +bool UserManager::IsNamePreapproved(const std::string& requestedName) { for (std::string& s : m_PreapprovedNames) { if (s == requestedName) return true; } - + for (std::string& s : m_FirstNames) { if (s == requestedName) return true; } - + for (std::string& s : m_MiddleNames) { if (s == requestedName) return true; } - + for (std::string& s : m_LastNames) { if (s == requestedName) return true; } - + return false; } -void UserManager::RequestCharacterList ( const SystemAddress& sysAddr ) { +void UserManager::RequestCharacterList(const SystemAddress& sysAddr) { User* u = GetUser(sysAddr); if (!u) return; - + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 4;"); stmt->setUInt(1, u->GetAccountID()); - + sql::ResultSet* res = stmt->executeQuery(); if (res->rowsCount() > 0) { std::vector& chars = u->GetCharacters(); - - for (size_t i = 0; i < chars.size(); ++i) - { + + for (size_t i = 0; i < chars.size(); ++i) { if (chars[i]->GetEntity() == nullptr) // We don't have entity data to save { delete chars[i]; @@ -196,8 +216,7 @@ void UserManager::RequestCharacterList ( const SystemAddress& sysAddr ) { auto* skillComponent = chars[i]->GetEntity()->GetComponent(); - if (skillComponent != nullptr) - { + if (skillComponent != nullptr) { skillComponent->Reset(); } @@ -209,185 +228,182 @@ void UserManager::RequestCharacterList ( const SystemAddress& sysAddr ) { delete chars[i]; } - + chars.clear(); - + while (res->next()) { LWOOBJID objID = res->getUInt64(1); Character* character = new Character(uint32_t(objID), u); + character->SetIsNewLogin(); chars.push_back(character); } } delete res; delete stmt; - + WorldPackets::SendCharacterList(sysAddr, u); } void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) { - User* u = GetUser(sysAddr); - if (!u) return; - - std::string name = PacketUtils::ReadString(8, packet, true); + User* u = GetUser(sysAddr); + if (!u) return; - uint32_t firstNameIndex = PacketUtils::ReadPacketU32(74, packet); - uint32_t middleNameIndex = PacketUtils::ReadPacketU32(78, packet); - uint32_t lastNameIndex = PacketUtils::ReadPacketU32(82, packet); - std::string predefinedName = GetPredefinedName(firstNameIndex, middleNameIndex, lastNameIndex); + std::string name = PacketUtils::ReadString(8, packet, true); - uint32_t shirtColor = PacketUtils::ReadPacketU32(95, packet); - uint32_t shirtStyle = PacketUtils::ReadPacketU32(99, packet); - uint32_t pantsColor = PacketUtils::ReadPacketU32(103, packet); - uint32_t hairStyle = PacketUtils::ReadPacketU32(107, packet); - uint32_t hairColor = PacketUtils::ReadPacketU32(111, packet); - uint32_t lh = PacketUtils::ReadPacketU32(115, packet); - uint32_t rh = PacketUtils::ReadPacketU32(119, packet); - uint32_t eyebrows = PacketUtils::ReadPacketU32(123, packet); - uint32_t eyes = PacketUtils::ReadPacketU32(127, packet); - uint32_t mouth = PacketUtils::ReadPacketU32(131, packet); - - LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle); + uint32_t firstNameIndex = PacketUtils::ReadPacketU32(74, packet); + uint32_t middleNameIndex = PacketUtils::ReadPacketU32(78, packet); + uint32_t lastNameIndex = PacketUtils::ReadPacketU32(82, packet); + std::string predefinedName = GetPredefinedName(firstNameIndex, middleNameIndex, lastNameIndex); + + uint32_t shirtColor = PacketUtils::ReadPacketU32(95, packet); + uint32_t shirtStyle = PacketUtils::ReadPacketU32(99, packet); + uint32_t pantsColor = PacketUtils::ReadPacketU32(103, packet); + uint32_t hairStyle = PacketUtils::ReadPacketU32(107, packet); + uint32_t hairColor = PacketUtils::ReadPacketU32(111, packet); + uint32_t lh = PacketUtils::ReadPacketU32(115, packet); + uint32_t rh = PacketUtils::ReadPacketU32(119, packet); + uint32_t eyebrows = PacketUtils::ReadPacketU32(123, packet); + uint32_t eyes = PacketUtils::ReadPacketU32(127, packet); + uint32_t mouth = PacketUtils::ReadPacketU32(131, packet); + + LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle); LOT pantsLOT = FindCharPantsID(pantsColor); - - if (name != "" && !UserManager::IsNameAvailable(name)) { - Game::logger->Log("UserManager", "AccountID: %i chose unavailable name: %s\n", u->GetAccountID(), name.c_str()); - WorldPackets::SendCharacterCreationResponse(sysAddr, CREATION_RESPONSE_CUSTOM_NAME_IN_USE); - return; - } - - if (!IsNameAvailable(predefinedName)) { - Game::logger->Log("UserManager", "AccountID: %i chose unavailable predefined name: %s\n", u->GetAccountID(), predefinedName.c_str()); - WorldPackets::SendCharacterCreationResponse(sysAddr, CREATION_RESPONSE_PREDEFINED_NAME_IN_USE); - return; - } - - if (name == "") { - Game::logger->Log("UserManager", "AccountID: %i is creating a character with predefined name: %s\n", u->GetAccountID(), predefinedName.c_str()); - } - else { - Game::logger->Log("UserManager", "AccountID: %i is creating a character with name: %s (temporary: %s)\n", u->GetAccountID(), name.c_str(), predefinedName.c_str()); - } - - //Now that the name is ok, we can get an objectID from Master: - ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) { + + if (name != "" && !UserManager::IsNameAvailable(name)) { + Game::logger->Log("UserManager", "AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str()); + WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE); + return; + } + + if (!IsNameAvailable(predefinedName)) { + Game::logger->Log("UserManager", "AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str()); + WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE); + return; + } + + if (name == "") { + Game::logger->Log("UserManager", "AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str()); + } else { + Game::logger->Log("UserManager", "AccountID: %i is creating a character with name: %s (temporary: %s)", u->GetAccountID(), name.c_str(), predefinedName.c_str()); + } + + //Now that the name is ok, we can get an objectID from Master: + ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) { sql::PreparedStatement* overlapStmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE id = ?"); overlapStmt->setUInt(1, objectID); auto* overlapResult = overlapStmt->executeQuery(); - if (overlapResult->next()) { - Game::logger->Log("UserManager", "Character object id unavailable, check objectidtracker!\n"); - WorldPackets::SendCharacterCreationResponse(sysAddr, CREATION_RESPONSE_OBJECT_ID_UNAVAILABLE); - return; - } - - std::stringstream xml; - xml << ""; - - xml << "GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" "; - xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" "; - xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\">"; - xml << ""; - xml << ""; - std::string xmlSave1 = xml.str(); - - ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforshirt) { - std::stringstream xml2; - - LWOOBJID lwoidforshirt = idforshirt; - lwoidforshirt = GeneralUtils::SetBit(lwoidforshirt, OBJECT_BIT_CHARACTER); - lwoidforshirt = GeneralUtils::SetBit(lwoidforshirt, OBJECT_BIT_PERSISTENT); - xml2 << xmlSave1 << ""; - - std::string xmlSave2 = xml2.str(); - - ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforpants) { - LWOOBJID lwoidforpants = idforpants; - lwoidforpants = GeneralUtils::SetBit(lwoidforpants, OBJECT_BIT_CHARACTER); - lwoidforpants = GeneralUtils::SetBit(lwoidforpants, OBJECT_BIT_PERSISTENT); - - std::stringstream xml3; - xml3 << xmlSave2 << ""; - - xml3 << ""; - - //Check to see if our name was pre-approved: - bool nameOk = IsNamePreapproved(name); - if (!nameOk && u->GetMaxGMLevel() > 1) nameOk = true; - - if (name != "") { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); - stmt->setUInt(1, objectID); - stmt->setUInt(2, u->GetAccountID()); - stmt->setString(3, predefinedName.c_str()); - stmt->setString(4, name.c_str()); - stmt->setBoolean(5, false); - stmt->setUInt64(6, time(NULL)); - - if (nameOk) { - stmt->setString(3, name.c_str()); - stmt->setString(4, ""); - } - - stmt->execute(); - delete stmt; - } else { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); - stmt->setUInt(1, objectID); - stmt->setUInt(2, u->GetAccountID()); - stmt->setString(3, predefinedName.c_str()); - stmt->setString(4, ""); - stmt->setBoolean(5, false); - stmt->setUInt64(6, time(NULL)); - - stmt->execute(); - delete stmt; - } - - //Now finally insert our character xml: - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charxml`(`id`, `xml_data`) VALUES (?,?)"); - stmt->setUInt(1, objectID); - stmt->setString(2, xml3.str().c_str()); - stmt->execute(); - delete stmt; - - WorldPackets::SendCharacterCreationResponse(sysAddr, CREATION_RESPONSE_SUCCESS); - UserManager::RequestCharacterList(sysAddr); - }); - }); - }); + if (overlapResult->next()) { + Game::logger->Log("UserManager", "Character object id unavailable, check objectidtracker!"); + WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE); + return; + } + + std::stringstream xml; + xml << ""; + + xml << "GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" "; + xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" "; + xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\">"; + xml << ""; + xml << ""; + std::string xmlSave1 = xml.str(); + + ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforshirt) { + std::stringstream xml2; + + LWOOBJID lwoidforshirt = idforshirt; + GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER); + GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT); + xml2 << xmlSave1 << ""; + + std::string xmlSave2 = xml2.str(); + + ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforpants) { + LWOOBJID lwoidforpants = idforpants; + GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER); + GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT); + + std::stringstream xml3; + xml3 << xmlSave2 << ""; + + xml3 << ""; + + //Check to see if our name was pre-approved: + bool nameOk = IsNamePreapproved(name); + if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true; + + if (name != "") { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); + stmt->setUInt(1, objectID); + stmt->setUInt(2, u->GetAccountID()); + stmt->setString(3, predefinedName.c_str()); + stmt->setString(4, name.c_str()); + stmt->setBoolean(5, false); + stmt->setUInt64(6, time(NULL)); + + if (nameOk) { + stmt->setString(3, name.c_str()); + stmt->setString(4, ""); + } + + stmt->execute(); + delete stmt; + } else { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); + stmt->setUInt(1, objectID); + stmt->setUInt(2, u->GetAccountID()); + stmt->setString(3, predefinedName.c_str()); + stmt->setString(4, ""); + stmt->setBoolean(5, false); + stmt->setUInt64(6, time(NULL)); + + stmt->execute(); + delete stmt; + } + + //Now finally insert our character xml: + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charxml`(`id`, `xml_data`) VALUES (?,?)"); + stmt->setUInt(1, objectID); + stmt->setString(2, xml3.str().c_str()); + stmt->execute(); + delete stmt; + + WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS); + UserManager::RequestCharacterList(sysAddr); + }); + }); + }); } void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) { - User* u = GetUser(sysAddr); - if (!u) { - Game::logger->Log("UserManager", "Couldn't get user to delete character\n"); - return; - } - - LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_CHARACTER); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_PERSISTENT); - - uint32_t charID = static_cast(objectID); - Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)\n", objectID, charID); - - //Check if this user has this character: - bool hasCharacter = false; - std::vector& characters = u->GetCharacters(); - for (size_t i = 0; i < characters.size(); ++i) { - if (characters[i]->GetID() == charID) { hasCharacter = true; } - } - - if (!hasCharacter) { - Game::logger->Log("UserManager", "User %i tried to delete a character that it does not own!\n", u->GetAccountID()); - WorldPackets::SendCharacterDeleteResponse(sysAddr, false); - } - else { - Game::logger->Log("UserManager", "Deleting character %i\n", charID); + User* u = GetUser(sysAddr); + if (!u) { + Game::logger->Log("UserManager", "Couldn't get user to delete character"); + return; + } + + LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet); + uint32_t charID = static_cast(objectID); + + Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)", objectID, charID); + + //Check if this user has this character: + bool hasCharacter = false; + std::vector& characters = u->GetCharacters(); + for (size_t i = 0; i < characters.size(); ++i) { + if (characters[i]->GetID() == charID) { hasCharacter = true; } + } + + if (!hasCharacter) { + Game::logger->Log("UserManager", "User %i tried to delete a character that it does not own!", u->GetAccountID()); + WorldPackets::SendCharacterDeleteResponse(sysAddr, false); + } else { + Game::logger->Log("UserManager", "Deleting character %i", charID); { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM charxml WHERE id=? LIMIT 1;"); stmt->setUInt64(1, charID); @@ -402,10 +418,14 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) } { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;"); - stmt->setUInt64(1, charID); - stmt->setUInt64(2, charID); + stmt->setUInt(1, charID); + stmt->setUInt(2, charID); stmt->execute(); delete stmt; + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + bitStream.Write(objectID); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;"); @@ -451,116 +471,116 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) stmt->execute(); delete stmt; } - - WorldPackets::SendCharacterDeleteResponse(sysAddr, true); - } + + WorldPackets::SendCharacterDeleteResponse(sysAddr, true); + } } void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet) { - User* u = GetUser(sysAddr); - if (!u) { - Game::logger->Log("UserManager", "Couldn't get user to delete character\n"); - return; - } - - LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_CHARACTER); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_PERSISTENT); - - uint32_t charID = static_cast(objectID); - Game::logger->Log("UserManager", "Received char rename request for ID: %llu (%u)\n", objectID, charID); - - std::string newName = PacketUtils::ReadString(16, packet, true); - - Character* character = nullptr; - - //Check if this user has this character: - bool hasCharacter = false; - std::vector& characters = u->GetCharacters(); - for (size_t i = 0; i < characters.size(); ++i) { - if (characters[i]->GetID() == charID) { hasCharacter = true; character = characters[i]; } - } - - if (!hasCharacter || !character) { - Game::logger->Log("UserManager", "User %i tried to rename a character that it does not own!\n", u->GetAccountID()); - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_UNKNOWN_ERROR); - } else if (hasCharacter && character) { - if (newName == character->GetName()) { - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_NAME_UNAVAILABLE); - return; - } - - if (IsNameAvailable(newName)) { - if (IsNamePreapproved(newName)) { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET name=?, pending_name='', needs_rename=0, last_login=? WHERE id=? LIMIT 1"); - stmt->setString(1, newName); - stmt->setUInt64(2, time(NULL)); - stmt->setUInt(3, character->GetID()); - stmt->execute(); - delete stmt; - - Game::logger->Log("UserManager", "Character %s now known as %s\n", character->GetName().c_str(), newName.c_str()); - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_SUCCESS); - UserManager::RequestCharacterList(sysAddr); - } else { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET pending_name=?, needs_rename=0, last_login=? WHERE id=? LIMIT 1"); - stmt->setString(1, newName); - stmt->setUInt64(2, time(NULL)); - stmt->setUInt(3, character->GetID()); - stmt->execute(); - delete stmt; - - Game::logger->Log("UserManager", "Character %s has been renamed to %s and is pending approval by a moderator.\n", character->GetName().c_str(), newName.c_str()); - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_SUCCESS); - UserManager::RequestCharacterList(sysAddr); - } - } else { - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_NAME_IN_USE); - } - } else { - Game::logger->Log("UserManager", "Unknown error occurred when renaming character, either hasCharacter or character variable != true.\n"); - WorldPackets::SendCharacterRenameResponse(sysAddr, RENAME_RESPONSE_UNKNOWN_ERROR); - } + User* u = GetUser(sysAddr); + if (!u) { + Game::logger->Log("UserManager", "Couldn't get user to delete character"); + return; + } + + LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet); + GeneralUtils::ClearBit(objectID, eObjectBits::CHARACTER); + GeneralUtils::ClearBit(objectID, eObjectBits::PERSISTENT); + + uint32_t charID = static_cast(objectID); + Game::logger->Log("UserManager", "Received char rename request for ID: %llu (%u)", objectID, charID); + + std::string newName = PacketUtils::ReadString(16, packet, true); + + Character* character = nullptr; + + //Check if this user has this character: + bool hasCharacter = false; + std::vector& characters = u->GetCharacters(); + for (size_t i = 0; i < characters.size(); ++i) { + if (characters[i]->GetID() == charID) { hasCharacter = true; character = characters[i]; } + } + + if (!hasCharacter || !character) { + Game::logger->Log("UserManager", "User %i tried to rename a character that it does not own!", u->GetAccountID()); + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR); + } else if (hasCharacter && character) { + if (newName == character->GetName()) { + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_UNAVAILABLE); + return; + } + + if (IsNameAvailable(newName)) { + if (IsNamePreapproved(newName)) { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET name=?, pending_name='', needs_rename=0, last_login=? WHERE id=? LIMIT 1"); + stmt->setString(1, newName); + stmt->setUInt64(2, time(NULL)); + stmt->setUInt(3, character->GetID()); + stmt->execute(); + delete stmt; + + Game::logger->Log("UserManager", "Character %s now known as %s", character->GetName().c_str(), newName.c_str()); + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS); + UserManager::RequestCharacterList(sysAddr); + } else { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET pending_name=?, needs_rename=0, last_login=? WHERE id=? LIMIT 1"); + stmt->setString(1, newName); + stmt->setUInt64(2, time(NULL)); + stmt->setUInt(3, character->GetID()); + stmt->execute(); + delete stmt; + + Game::logger->Log("UserManager", "Character %s has been renamed to %s and is pending approval by a moderator.", character->GetName().c_str(), newName.c_str()); + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS); + UserManager::RequestCharacterList(sysAddr); + } + } else { + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_IN_USE); + } + } else { + Game::logger->Log("UserManager", "Unknown error occurred when renaming character, either hasCharacter or character variable != true."); + WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR); + } } void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID) { - User* u = GetUser(sysAddr); - if (!u) { - Game::logger->Log("UserManager", "Couldn't get user to log in character\n"); - return; - } - - Character* character = nullptr; - bool hasCharacter = false; - std::vector& characters = u->GetCharacters(); - - for (size_t i = 0; i < characters.size(); ++i) { - if (characters[i]->GetID() == playerID) { hasCharacter = true; character = characters[i]; } - } - - if (hasCharacter && character) { - sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET last_login=? WHERE id=? LIMIT 1"); - stmt->setUInt64(1, time(NULL)); - stmt->setUInt(2, playerID); - stmt->execute(); - delete stmt; - - uint32_t zoneID = character->GetZoneID(); + User* u = GetUser(sysAddr); + if (!u) { + Game::logger->Log("UserManager", "Couldn't get user to log in character"); + return; + } + + Character* character = nullptr; + bool hasCharacter = false; + std::vector& characters = u->GetCharacters(); + + for (size_t i = 0; i < characters.size(); ++i) { + if (characters[i]->GetID() == playerID) { hasCharacter = true; character = characters[i]; } + } + + if (hasCharacter && character) { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET last_login=? WHERE id=? LIMIT 1"); + stmt->setUInt64(1, time(NULL)); + stmt->setUInt(2, playerID); + stmt->execute(); + delete stmt; + + uint32_t zoneID = character->GetZoneID(); if (zoneID == LWOZONEID_INVALID) zoneID = 1000; //Send char to VE - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneID, character->GetZoneClone(), false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneID, character->GetZoneClone(), false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (character) { character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); character->SetZoneClone(zoneClone); } WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - return; - }); - } else { - Game::logger->Log("UserManager", "Unknown error occurred when logging in a character, either hasCharacter or character variable != true.\n"); - } + return; + }); + } else { + Game::logger->Log("UserManager", "Unknown error occurred when logging in a character, either hasCharacter or character variable != true."); + } } uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) { @@ -573,8 +593,7 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) { auto shirtLOT = tableData.getIntField(0, -1); tableData.finalize(); return shirtLOT; - } - catch (const std::exception&){ + } catch (const std::exception&) { Game::logger->Log("Character Create", "Failed to execute query! Using backup..."); // in case of no shirt found in CDServer, return problematic red vest. return 4069; @@ -589,8 +608,7 @@ uint32_t FindCharPantsID(uint32_t pantsColor) { auto pantsLOT = tableData.getIntField(0, -1); tableData.finalize(); return pantsLOT; - } - catch (const std::exception&){ + } catch (const std::exception&) { Game::logger->Log("Character Create", "Failed to execute query! Using backup..."); // in case of no pants color found in CDServer, return red pants. return 2508; diff --git a/dGame/UserManager.h b/dGame/UserManager.h index a5db6979..bf9985a1 100644 --- a/dGame/UserManager.h +++ b/dGame/UserManager.h @@ -15,23 +15,23 @@ public: if (!m_Address) { m_Address = new UserManager(); } - + return m_Address; } - + void Initialize(); ~UserManager(); - + User* CreateUser(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey); User* GetUser(const SystemAddress& sysAddr); User* GetUser(const std::string& username); bool DeleteUser(const SystemAddress& sysAddr); //Returns true on succesful deletion void DeletePendingRemovals(); - + bool IsNameAvailable(const std::string& requestedName); std::string GetPredefinedName(uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex); bool IsNamePreapproved(const std::string& requestedName); - + void RequestCharacterList(const SystemAddress& sysAddr); void CreateCharacter(const SystemAddress& sysAddr, Packet* packet); void DeleteCharacter(const SystemAddress& sysAddr, Packet* packet); @@ -46,7 +46,7 @@ private: static UserManager* m_Address; //Singleton std::map m_Users; std::vector m_UsersToDelete; - + std::vector m_FirstNames; std::vector m_MiddleNames; std::vector m_LastNames; diff --git a/dGame/dBehaviors/AirMovementBehavior.cpp b/dGame/dBehaviors/AirMovementBehavior.cpp index ac7bf667..dbfde465 100644 --- a/dGame/dBehaviors/AirMovementBehavior.cpp +++ b/dGame/dBehaviors/AirMovementBehavior.cpp @@ -1,44 +1,51 @@ -#include "AirMovementBehavior.h" +#include "AirMovementBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" -void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - uint32_t handle; +void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("AirMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, this->m_Timeout); } -void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto handle = context->GetUniqueSkillId(); bitStream->Write(handle); } -void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ - uint32_t behaviorId; +void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t behaviorId{}; - bit_stream->Read(behaviorId); + if (!bitStream->Read(behaviorId)) { + Game::logger->Log("AirMovementBehavior", "Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; + LWOOBJID target{}; - bit_stream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AirMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } auto* behavior = CreateBehavior(behaviorId); - if (EntityManager::Instance()->GetEntity(target) != nullptr) - { + if (EntityManager::Instance()->GetEntity(target) != nullptr) { branch.target = target; } - - behavior->Handle(context, bit_stream, branch); + + behavior->Handle(context, bitStream, branch); } -void AirMovementBehavior::Load() -{ +void AirMovementBehavior::Load() { + this->m_Timeout = (GetFloat("timeout_ms") / 1000.0f); } diff --git a/dGame/dBehaviors/AirMovementBehavior.h b/dGame/dBehaviors/AirMovementBehavior.h index 0a9755e6..9d51ef03 100644 --- a/dGame/dBehaviors/AirMovementBehavior.h +++ b/dGame/dBehaviors/AirMovementBehavior.h @@ -1,23 +1,18 @@ -#pragma once +#pragma once #include "Behavior.h" class AirMovementBehavior final : public Behavior { public: - - /* - * Inherited - */ - - explicit AirMovementBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { - } + explicit AirMovementBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {} void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; +private: + float m_Timeout; }; diff --git a/dGame/dBehaviors/AndBehavior.cpp b/dGame/dBehaviors/AndBehavior.cpp index 5fc1e113..67c88679 100644 --- a/dGame/dBehaviors/AndBehavior.cpp +++ b/dGame/dBehaviors/AndBehavior.cpp @@ -1,20 +1,16 @@ -#include "AndBehavior.h" +#include "AndBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" -void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - for (auto* behavior : this->m_behaviors) - { +void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + for (auto* behavior : this->m_behaviors) { behavior->Handle(context, bitStream, branch); } } -void AndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - for (auto* behavior : this->m_behaviors) - { +void AndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + for (auto* behavior : this->m_behaviors) { behavior->Calculate(context, bitStream, branch); } } @@ -25,14 +21,11 @@ void AndBehavior::UnCast(BehaviorContext* context, const BehaviorBranchContext b } } -void AndBehavior::Load() -{ +void AndBehavior::Load() { const auto parameters = GetParameterNames(); - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { + for (const auto& parameter : parameters) { + if (parameter.first.rfind("behavior", 0) == 0) { auto* action = GetAction(parameter.second); this->m_behaviors.push_back(action); diff --git a/dGame/dBehaviors/AndBehavior.h b/dGame/dBehaviors/AndBehavior.h index 9cbce569..0ef7c0fd 100644 --- a/dGame/dBehaviors/AndBehavior.h +++ b/dGame/dBehaviors/AndBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -8,18 +8,17 @@ class AndBehavior final : public Behavior { public: std::vector m_behaviors; - + /* * Inherited */ - explicit AndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit AndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/ApplyBuffBehavior.cpp b/dGame/dBehaviors/ApplyBuffBehavior.cpp index 46422aa1..35b0f269 100644 --- a/dGame/dBehaviors/ApplyBuffBehavior.cpp +++ b/dGame/dBehaviors/ApplyBuffBehavior.cpp @@ -5,48 +5,44 @@ #include "BuffComponent.h" -void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - auto* entity = EntityManager::Instance()->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target); +void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* entity = EntityManager::Instance()->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target); - if (entity == nullptr) return; + if (entity == nullptr) return; - auto* buffComponent = entity->GetComponent(); + auto* buffComponent = entity->GetComponent(); - if (buffComponent == nullptr) return; + if (buffComponent == nullptr) return; - buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath, - cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); + buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath, + cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); } -void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) -{ - auto* entity = EntityManager::Instance()->GetEntity(branch.target); +void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { + auto* entity = EntityManager::Instance()->GetEntity(branch.target); - if (entity == nullptr) return; + if (entity == nullptr) return; - auto* buffComponent = entity->GetComponent(); + auto* buffComponent = entity->GetComponent(); - if (buffComponent == nullptr) return; + if (buffComponent == nullptr) return; - buffComponent->RemoveBuff(m_BuffId); + buffComponent->RemoveBuff(m_BuffId); } -void ApplyBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - Handle(context, bitStream, branch); +void ApplyBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); } -void ApplyBuffBehavior::Load() -{ - m_BuffId = GetInt("buff_id"); - m_Duration = GetFloat("duration_secs"); - addImmunity = GetBoolean("add_immunity"); - cancelOnDamaged = GetBoolean("cancel_on_damaged"); - cancelOnDeath = GetBoolean("cancel_on_death"); - cancelOnLogout = GetBoolean("cancel_on_logout"); - cancelonRemoveBuff = GetBoolean("cancel_on_remove_buff"); - cancelOnUi = GetBoolean("cancel_on_ui"); - cancelOnUnequip = GetBoolean("cancel_on_unequip"); - cancelOnZone = GetBoolean("cancel_on_zone"); +void ApplyBuffBehavior::Load() { + m_BuffId = GetInt("buff_id"); + m_Duration = GetFloat("duration_secs"); + addImmunity = GetBoolean("add_immunity"); + cancelOnDamaged = GetBoolean("cancel_on_damaged"); + cancelOnDeath = GetBoolean("cancel_on_death"); + cancelOnLogout = GetBoolean("cancel_on_logout"); + cancelonRemoveBuff = GetBoolean("cancel_on_remove_buff"); + cancelOnUi = GetBoolean("cancel_on_ui"); + cancelOnUnequip = GetBoolean("cancel_on_unequip"); + cancelOnZone = GetBoolean("cancel_on_zone"); } diff --git a/dGame/dBehaviors/ApplyBuffBehavior.h b/dGame/dBehaviors/ApplyBuffBehavior.h index 536d3501..139082df 100644 --- a/dGame/dBehaviors/ApplyBuffBehavior.h +++ b/dGame/dBehaviors/ApplyBuffBehavior.h @@ -7,29 +7,28 @@ class ApplyBuffBehavior final : public Behavior { public: - int32_t m_BuffId; - float m_Duration; - bool addImmunity; - bool cancelOnDamaged; - bool cancelOnDeath; - bool cancelOnLogout; - bool cancelonRemoveBuff; - bool cancelOnUi; - bool cancelOnUnequip; - bool cancelOnZone; + int32_t m_BuffId; + float m_Duration; + bool addImmunity; + bool cancelOnDamaged; + bool cancelOnDeath; + bool cancelOnLogout; + bool cancelonRemoveBuff; + bool cancelOnUi; + bool cancelOnUnequip; + bool cancelOnZone; /* * Inherited */ - explicit ApplyBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit ApplyBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.cpp b/dGame/dBehaviors/AreaOfEffectBehavior.cpp index 6568f9b8..dedede2a 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.cpp +++ b/dGame/dBehaviors/AreaOfEffectBehavior.cpp @@ -1,4 +1,4 @@ -#include "AreaOfEffectBehavior.h" +#include "AreaOfEffectBehavior.h" #include @@ -9,15 +9,18 @@ #include "BehaviorContext.h" #include "RebuildComponent.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" -void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - uint32_t targetCount; +void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t targetCount{}; - bitStream->Read(targetCount); + if (!bitStream->Read(targetCount)) { + Game::logger->Log("AreaOfEffectBehavior", "Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - if (targetCount > this->m_maxTargets) - { + if (targetCount > this->m_maxTargets) { return; } @@ -25,30 +28,28 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b targets.reserve(targetCount); - for (auto i = 0u; i < targetCount; ++i) - { - LWOOBJID target; + for (auto i = 0u; i < targetCount; ++i) { + LWOOBJID target{}; - bitStream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i); + return; + }; targets.push_back(target); } - for (auto target : targets) - { + for (auto target : targets) { branch.target = target; - + this->m_action->Handle(context, bitStream, branch); } } -void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* self = EntityManager::Instance()->GetEntity(context->caster); - - if (self == nullptr) - { - Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!\n", context->originator); + if (self == nullptr) { + Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator); return; } @@ -59,10 +60,8 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream auto* presetTarget = EntityManager::Instance()->GetEntity(branch.target); - if (presetTarget != nullptr) - { - if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) - { + if (presetTarget != nullptr) { + if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) { targets.push_back(presetTarget); } } @@ -75,78 +74,67 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream } // Gets all of the valid targets, passing in if should target enemies and friends - for (auto validTarget : context->GetValidTargets(m_ignoreFaction , includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) - { + for (auto validTarget : context->GetValidTargets(m_ignoreFaction, includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) { auto* entity = EntityManager::Instance()->GetEntity(validTarget); - if (entity == nullptr) - { - Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!\n", validTarget, context->originator); + if (entity == nullptr) { + Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); continue; } - if (std::find(targets.begin(), targets.end(), entity) != targets.end()) - { + if (std::find(targets.begin(), targets.end(), entity) != targets.end()) { continue; } - + auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent == nullptr) - { + if (destroyableComponent == nullptr) { continue; } - if (destroyableComponent->HasFaction(m_ignoreFaction)) - { + if (destroyableComponent->HasFaction(m_ignoreFaction)) { continue; } const auto distance = Vector3::DistanceSquared(reference, entity->GetPosition()); - if (this->m_radius * this->m_radius >= distance && (this->m_maxTargets == 0 || targets.size() < this->m_maxTargets)) - { + if (this->m_radius * this->m_radius >= distance && (this->m_maxTargets == 0 || targets.size() < this->m_maxTargets)) { targets.push_back(entity); } } - std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) - { + std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) { const auto aDistance = Vector3::DistanceSquared(a->GetPosition(), reference); const auto bDistance = Vector3::DistanceSquared(b->GetPosition(), reference); return aDistance > bDistance; - }); + }); const uint32_t size = targets.size(); - + bitStream->Write(size); - if (size == 0) - { + if (size == 0) { return; } context->foundTarget = true; - for (auto* target : targets) - { + for (auto* target : targets) { bitStream->Write(target->GetObjectID()); - + PlayFx(u"cast", context->originator, target->GetObjectID()); } - - for (auto* target : targets) - { + + for (auto* target : targets) { branch.target = target->GetObjectID(); this->m_action->Calculate(context, bitStream, branch); } } -void AreaOfEffectBehavior::Load() -{ +void AreaOfEffectBehavior::Load() { this->m_action = GetAction("action"); this->m_radius = GetFloat("radius"); @@ -157,7 +145,7 @@ void AreaOfEffectBehavior::Load() this->m_includeFaction = GetInt("include_faction"); - this->m_TargetSelf = GetInt("target_self"); + this->m_TargetSelf = GetInt("target_self"); this->m_targetEnemy = GetInt("target_enemy"); diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.h b/dGame/dBehaviors/AreaOfEffectBehavior.h index 9a8b7290..b5a48ddf 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.h +++ b/dGame/dBehaviors/AreaOfEffectBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class AreaOfEffectBehavior final : public Behavior @@ -14,21 +14,20 @@ public: int32_t m_includeFaction; - int32_t m_TargetSelf; + int32_t m_TargetSelf; int32_t m_targetEnemy; int32_t m_targetFriend; - + /* * Inherited */ - explicit AreaOfEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit AreaOfEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/AttackDelayBehavior.cpp b/dGame/dBehaviors/AttackDelayBehavior.cpp index c536f925..3f12f662 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.cpp +++ b/dGame/dBehaviors/AttackDelayBehavior.cpp @@ -1,51 +1,47 @@ -#include "AttackDelayBehavior.h" +#include "AttackDelayBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "Game.h" #include "dLogger.h" -void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - uint32_t handle; +void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + uint32_t handle{}; - bitStream->Read(handle); - - for (auto i = 0u; i < this->m_numIntervals; ++i) - { - context->RegisterSyncBehavior(handle, this, branch); + if (!bitStream->Read(handle)) { + Game::logger->Log("AttackDelayBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; + + for (auto i = 0u; i < this->m_numIntervals; ++i) { + context->RegisterSyncBehavior(handle, this, branch, this->m_delay * i, m_ignoreInterrupts); } } -void AttackDelayBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void AttackDelayBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { const auto handle = context->GetUniqueSkillId(); bitStream->Write(handle); context->foundTarget = true; - for (auto i = 0u; i < this->m_numIntervals; ++i) - { + for (auto i = 0u; i < this->m_numIntervals; ++i) { const auto multiple = static_cast(i + 1); context->SyncCalculation(handle, this->m_delay * multiple, this, branch, m_ignoreInterrupts); } } -void AttackDelayBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void AttackDelayBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { this->m_action->Handle(context, bitStream, branch); } -void AttackDelayBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void AttackDelayBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { PlayFx(u"cast", context->originator); this->m_action->Calculate(context, bitStream, branch); } -void AttackDelayBehavior::Load() -{ +void AttackDelayBehavior::Load() { this->m_numIntervals = GetInt("num_intervals"); this->m_action = GetAction("action"); @@ -54,8 +50,7 @@ void AttackDelayBehavior::Load() this->m_ignoreInterrupts = GetBoolean("ignore_interrupts"); - if (this->m_numIntervals == 0) - { + if (this->m_numIntervals == 0) { this->m_numIntervals = 1; } } diff --git a/dGame/dBehaviors/AttackDelayBehavior.h b/dGame/dBehaviors/AttackDelayBehavior.h index e798bf87..64271ba5 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.h +++ b/dGame/dBehaviors/AttackDelayBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class AttackDelayBehavior final : public Behavior @@ -15,9 +15,8 @@ public: /* * Inherited */ - - explicit AttackDelayBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + + explicit AttackDelayBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; @@ -27,6 +26,6 @@ public: void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index a9a58245..f8693795 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -1,11 +1,11 @@ -#include "BasicAttackBehavior.h" +#include "BasicAttackBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" #include "EntityManager.h" #include "DestroyableComponent.h" #include "BehaviorContext.h" - +#include "eBasicAttackSuccessTypes.h" void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { if (context->unmanaged) { @@ -14,137 +14,242 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi auto* destroyableComponent = entity->GetComponent(); if (destroyableComponent != nullptr) { PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(this->m_maxDamage, context->originator, context->skillID); + destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID); } - this->m_onSuccess->Handle(context, bitStream, branch); + this->m_OnSuccess->Handle(context, bitStream, branch); return; } - + bitStream->AlignReadToByteBoundary(); - uint16_t allocatedBits; - bitStream->Read(allocatedBits); - + uint16_t allocatedBits{}; + if (!bitStream->Read(allocatedBits) || allocatedBits == 0) { + Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits"); + return; + } + Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits); const auto baseAddress = bitStream->GetReadOffset(); - if (bitStream->ReadBit()) { // Blocked - return; - } - if (bitStream->ReadBit()) { // Immune - return; - } - - if (bitStream->ReadBit()) { // Success - uint32_t unknown; - bitStream->Read(unknown); - - uint32_t damageDealt; - bitStream->Read(damageDealt); - - // A value that's too large may be a cheating attempt, so we set it to MIN too - if (damageDealt > this->m_maxDamage || damageDealt < this->m_minDamage) { - damageDealt = this->m_minDamage; - } - - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - bool died; - bitStream->Read(died); - - if (entity != nullptr) { - auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(damageDealt, context->originator, context->skillID); - } - } - } - - uint8_t successState; - bitStream->Read(successState); - - switch (successState) { - case 1: - this->m_onSuccess->Handle(context, bitStream, branch); - break; - default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!\n", successState); - break; - } + DoHandleBehavior(context, bitStream, branch); bitStream->SetReadOffset(baseAddress + allocatedBits); } -void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) { - Game::logger->Log("BasicAttackBehavior", "Invalid self entity (%llu)!\n", context->originator); +void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target); return; } - + + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent) { + Game::logger->Log("BasicAttackBehavior", "No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT()); + return; + } + + bool isBlocked{}; + bool isImmune{}; + bool isSuccess{}; + + if (!bitStream->Read(isBlocked)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked"); + return; + } + + if (isBlocked) { + destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U)); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Handle(context, bitStream, branch); + return; + } + + if (!bitStream->Read(isImmune)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune"); + return; + } + + if (isImmune) { + this->m_OnFailImmune->Handle(context, bitStream, branch); + return; + } + + if (!bitStream->Read(isSuccess)) { + Game::logger->Log("BasicAttackBehavior", "failed to read success from bitstream"); + return; + } + + if (isSuccess) { + uint32_t armorDamageDealt{}; + if (!bitStream->Read(armorDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read armorDamageDealt"); + return; + } + + uint32_t healthDamageDealt{}; + if (!bitStream->Read(healthDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt"); + return; + } + + uint32_t totalDamageDealt = armorDamageDealt + healthDamageDealt; + + // A value that's too large may be a cheating attempt, so we set it to MIN + if (totalDamageDealt > this->m_MaxDamage) { + totalDamageDealt = this->m_MinDamage; + } + + bool died{}; + if (!bitStream->Read(died)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read died"); + return; + } + auto previousArmor = destroyableComponent->GetArmor(); + auto previousHealth = destroyableComponent->GetHealth(); + PlayFx(u"onhit", targetEntity->GetObjectID()); + destroyableComponent->Damage(totalDamageDealt, context->originator, context->skillID); + } + + uint8_t successState{}; + if (!bitStream->Read(successState)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read success state"); + return; + } + + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: + this->m_OnSuccess->Handle(context, bitStream, branch); + break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Handle(context, bitStream, branch); + break; + default: + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + return; + } + this->m_OnFailImmune->Handle(context, bitStream, branch); + break; + } +} + +void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { bitStream->AlignWriteToByteBoundary(); const auto allocatedAddress = bitStream->GetWriteOffset(); - bitStream->Write(uint16_t(0)); + bitStream->Write(0); const auto startAddress = bitStream->GetWriteOffset(); - bitStream->Write0(); // Blocked - bitStream->Write0(); // Immune - bitStream->Write1(); // Success - - if (true) { - uint32_t unknown3 = 0; - bitStream->Write(unknown3); - - auto damage = this->m_minDamage; - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - - if (entity == nullptr) { - damage = 0; - bitStream->Write(damage); - bitStream->Write(false); - } else { - bitStream->Write(damage); - bitStream->Write(true); - - auto* destroyableComponent = entity->GetComponent(); - if (damage != 0 && destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID(), 1); - destroyableComponent->Damage(damage, context->originator, context->skillID, false); - context->ScheduleUpdate(branch.target); - } - } - } - - uint8_t successState = 1; - bitStream->Write(successState); - - switch (successState) { - case 1: - this->m_onSuccess->Calculate(context, bitStream, branch); - break; - default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!\n", successState); - break; - } + DoBehaviorCalculation(context, bitStream, branch); const auto endAddress = bitStream->GetWriteOffset(); - const uint16_t allocate = endAddress - startAddress + 1; + const uint16_t allocate = endAddress - startAddress; bitStream->SetWriteOffset(allocatedAddress); bitStream->Write(allocate); bitStream->SetWriteOffset(startAddress + allocate); } -void BasicAttackBehavior::Load() { - this->m_minDamage = GetInt("min damage"); - if (this->m_minDamage == 0) this->m_minDamage = 1; +void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target); + return; + } - this->m_maxDamage = GetInt("max damage"); - if (this->m_maxDamage == 0) this->m_maxDamage = 1; + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent || !destroyableComponent->GetParent()) { + Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target); + return; + } - this->m_onSuccess = GetAction("on_success"); + const bool isBlocking = destroyableComponent->GetAttacksToBlock() > 0; + + bitStream->Write(isBlocking); + + if (isBlocking) { + destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Calculate(context, bitStream, branch); + return; + } + + const bool isImmune = destroyableComponent->IsImmune(); + + bitStream->Write(isImmune); + + if (isImmune) { + this->m_OnFailImmune->Calculate(context, bitStream, branch); + return; + } + + bool isSuccess = false; + const uint32_t previousHealth = destroyableComponent->GetHealth(); + const uint32_t previousArmor = destroyableComponent->GetArmor(); + + const auto damage = this->m_MinDamage; + + PlayFx(u"onhit", targetEntity->GetObjectID(), 1); + destroyableComponent->Damage(damage, context->originator, context->skillID, false); + context->ScheduleUpdate(branch.target); + + const uint32_t armorDamageDealt = previousArmor - destroyableComponent->GetArmor(); + const uint32_t healthDamageDealt = previousHealth - destroyableComponent->GetHealth(); + isSuccess = armorDamageDealt > 0 || healthDamageDealt > 0 || (armorDamageDealt + healthDamageDealt) > 0; + + bitStream->Write(isSuccess); + + eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE; + if (isSuccess) { + if (healthDamageDealt >= 1) { + successState = eBasicAttackSuccessTypes::SUCCESS; + } else if (armorDamageDealt >= 1) { + successState = this->m_OnFailArmor->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY ? eBasicAttackSuccessTypes::FAILIMMUNE : eBasicAttackSuccessTypes::FAILARMOR; + } + + bitStream->Write(armorDamageDealt); + bitStream->Write(healthDamageDealt); + bitStream->Write(targetEntity->GetIsDead()); + } + + bitStream->Write(successState); + + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: + this->m_OnSuccess->Calculate(context, bitStream, branch); + break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Calculate(context, bitStream, branch); + break; + default: + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + break; + } + this->m_OnFailImmune->Calculate(context, bitStream, branch); + break; + } +} + +void BasicAttackBehavior::Load() { + this->m_MinDamage = GetInt("min damage"); + if (this->m_MinDamage == 0) this->m_MinDamage = 1; + + this->m_MaxDamage = GetInt("max damage"); + if (this->m_MaxDamage == 0) this->m_MaxDamage = 1; + + // The client sets the minimum damage to maximum, so we'll do the same. These are usually the same value anyways. + if (this->m_MinDamage < this->m_MaxDamage) this->m_MinDamage = this->m_MaxDamage; + + this->m_OnSuccess = GetAction("on_success"); + + this->m_OnFailArmor = GetAction("on_fail_armor"); + + this->m_OnFailImmune = GetAction("on_fail_immune"); + + this->m_OnFailBlocked = GetAction("on_fail_blocked"); } diff --git a/dGame/dBehaviors/BasicAttackBehavior.h b/dGame/dBehaviors/BasicAttackBehavior.h index fa4dc0e8..f6e3fa28 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.h +++ b/dGame/dBehaviors/BasicAttackBehavior.h @@ -1,22 +1,62 @@ -#pragma once +#pragma once #include "Behavior.h" class BasicAttackBehavior final : public Behavior { public: - uint32_t m_minDamage; - - uint32_t m_maxDamage; - - Behavior* m_onSuccess; - - explicit BasicAttackBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit BasicAttackBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } + /** + * @brief Reads a 16bit short from the bitStream and when the actual behavior handling finishes with all of its branches, the bitStream + * is then offset to after the allocated bits for this stream. + * + */ + void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server. + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to deserialize. BitStreams will always check their bounds before reading in a behavior + * and will fail gracefully if an overread is detected. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + /** + * @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number + * of bits used is then written to where the 16bit short initially was. + * + */ void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + + /** + * @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to serialize to. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ + void DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Loads this Behaviors parameters from the database. For this behavior specifically: + * max and min damage will always be the same. If min is less than max, they are both set to max. + * If an action is not in the database, then no action is taken for that result. + * + */ void Load() override; +private: + uint32_t m_MinDamage; + + uint32_t m_MaxDamage; + + Behavior* m_OnSuccess; + + Behavior* m_OnFailArmor; + + Behavior* m_OnFailImmune; + + Behavior* m_OnFailBlocked; }; diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 6188f536..8b34507a 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "Behavior.h" @@ -7,6 +7,7 @@ #include "dLogger.h" #include "BehaviorTemplates.h" #include "BehaviorBranchContext.h" +#include /* * Behavior includes @@ -41,11 +42,13 @@ #include "SkillCastFailedBehavior.h" #include "SpawnBehavior.h" #include "ForceMovementBehavior.h" +#include "RemoveBuffBehavior.h" #include "ImmunityBehavior.h" #include "InterruptBehavior.h" #include "PlayEffectBehavior.h" #include "DamageAbsorptionBehavior.h" #include "VentureVisionBehavior.h" +#include "PropertyTeleportBehavior.h" #include "BlockBehavior.h" #include "ClearTargetBehavior.h" #include "PullToPointBehavior.h" @@ -59,8 +62,10 @@ #include "DamageReductionBehavior.h" #include "JetPackBehavior.h" #include "FallSpeedBehavior.h" +#include "ChangeIdleFlagsBehavior.h" +#include "DarkInspirationBehavior.h" -//CDClient includes + //CDClient includes #include "CDBehaviorParameterTable.h" #include "CDClientDatabase.h" #include "CDClientManager.h" @@ -69,38 +74,33 @@ #include "EntityManager.h" #include "RenderComponent.h" #include "DestroyableComponent.h" +#include "CDBehaviorTemplateTable.h" -std::map Behavior::Cache = {}; +std::unordered_map Behavior::Cache = {}; CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr; -Behavior* Behavior::GetBehavior(const uint32_t behaviorId) -{ - if (BehaviorParameterTable == nullptr) - { - BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); +Behavior* Behavior::GetBehavior(const uint32_t behaviorId) { + if (BehaviorParameterTable == nullptr) { + BehaviorParameterTable = CDClientManager::Instance().GetTable(); } const auto pair = Cache.find(behaviorId); - if (pair == Cache.end()) - { + if (pair == Cache.end()) { return nullptr; } return static_cast(pair->second); } -Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) -{ +Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { auto* cached = GetBehavior(behaviorId); - if (cached != nullptr) - { + if (cached != nullptr) { return cached; } - if (behaviorId == 0) - { + if (behaviorId == 0) { return new EmptyBehavior(0); } @@ -108,8 +108,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) Behavior* behavior = nullptr; - switch (templateId) - { + switch (templateId) { case BehaviorTemplates::BEHAVIOR_EMPTY: break; case BehaviorTemplates::BEHAVIOR_BASIC_ATTACK: behavior = new BasicAttackBehavior(behaviorId); @@ -176,7 +175,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) case BehaviorTemplates::BEHAVIOR_SPEED: behavior = new SpeedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break; + case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: + behavior = new DarkInspirationBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: behavior = new LootBuffBehavior(behaviorId); break; @@ -204,7 +205,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) behavior = new SkillCastFailedBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMITATION_SKUNK_STINK: break; - case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: break; + case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: + behavior = new ChangeIdleFlagsBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_APPLY_BUFF: behavior = new ApplyBuffBehavior(behaviorId); break; @@ -235,7 +238,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) break; case BehaviorTemplates::BEHAVIOR_ALTER_CHAIN_DELAY: break; case BehaviorTemplates::BEHAVIOR_CAMERA: break; - case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: break; + case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: + behavior = new RemoveBuffBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_GRAB: break; case BehaviorTemplates::BEHAVIOR_MODULAR_BUILD: break; case BehaviorTemplates::BEHAVIOR_NPC_COMBAT_SKILL: @@ -263,7 +268,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) case BehaviorTemplates::BEHAVIOR_DAMAGE_REDUCTION: behavior = new DamageReductionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: break; + case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: + behavior = new PropertyTeleportBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_PROPERTY_CLEAR_TARGET: behavior = new ClearTargetBehavior(behaviorId); break; @@ -271,13 +278,12 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) case BehaviorTemplates::BEHAVIOR_MOUNT: break; case BehaviorTemplates::BEHAVIOR_SKILL_SET: break; default: - //Game::logger->Log("Behavior", "Failed to load behavior with invalid template id (%i)!\n", templateId); + //Game::logger->Log("Behavior", "Failed to load behavior with invalid template id (%i)!", templateId); break; } - if (behavior == nullptr) - { - //Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!\n", templateId); + if (behavior == nullptr) { + //Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!", templateId); behavior = new EmptyBehavior(behaviorId); } @@ -288,44 +294,35 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) } BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT templateID FROM BehaviorTemplate WHERE behaviorID = ?;"); - query.bind(1, (int) behaviorId); + auto behaviorTemplateTable = CDClientManager::Instance().GetTable(); - auto result = query.execQuery(); - - // Make sure we do not proceed if we are trying to load an invalid behavior - if (result.eof()) - { - if (behaviorId != 0) - { - Game::logger->Log("Behavior::GetBehaviorTemplate", "Failed to load behavior template with id (%i)!\n", behaviorId); + BehaviorTemplates templateID = BehaviorTemplates::BEHAVIOR_EMPTY; + // Find behavior template by its behavior id. Default to 0. + if (behaviorTemplateTable) { + auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId); + if (templateEntry.behaviorID == behaviorId) { + templateID = static_cast(templateEntry.templateID); } - - return BehaviorTemplates::BEHAVIOR_EMPTY; } - const auto id = static_cast(result.getIntField(0)); + if (templateID == BehaviorTemplates::BEHAVIOR_EMPTY && behaviorId != 0) { + Game::logger->Log("Behavior", "Failed to load behavior template with id (%i)!", behaviorId); + } - result.finalize(); - - return id; + return templateID; } // For use with enemies, to display the correct damage animations on the players -void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) -{ +void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) { auto* targetEntity = EntityManager::Instance()->GetEntity(target); - if (targetEntity == nullptr) - { + if (targetEntity == nullptr) { return; } const auto effectId = this->m_effectId; - if (effectId == 0) - { + if (effectId == 0) { GameMessages::SendPlayFXEffect(targetEntity, -1, type, "", secondary, 1, 1, true); return; @@ -335,23 +332,17 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID const auto typeString = GeneralUtils::UTF16ToWTF8(type); - if (m_effectNames == nullptr) - { + if (m_effectNames == nullptr) { m_effectNames = new std::unordered_map(); - } - else - { + } else { const auto pair = m_effectNames->find(typeString); - if (type.empty()) - { + if (type.empty()) { type = GeneralUtils::ASCIIToUTF16(*m_effectType); } - if (pair != m_effectNames->end()) - { - if (renderComponent == nullptr) - { + if (pair != m_effectNames->end()) { + if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true); return; @@ -374,24 +365,22 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID if (!type.empty()) { typeQuery.bind(1, typeString.c_str()); - typeQuery.bind(2, (int) effectId); + typeQuery.bind(2, (int)effectId); result = typeQuery.execQuery(); } else { - idQuery.bind(1, (int) effectId); + idQuery.bind(1, (int)effectId); result = idQuery.execQuery(); } - if (result.eof() || result.fieldIsNull(0)) - { + if (result.eof() || result.fieldIsNull(0)) { return; } const auto name = std::string(result.getStringField(0)); - if (type.empty()) - { + if (type.empty()) { const auto typeResult = result.getStringField(1); type = GeneralUtils::ASCIIToUTF16(typeResult); @@ -403,8 +392,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID m_effectNames->insert_or_assign(typeString, name); - if (renderComponent == nullptr) - { + if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true); return; @@ -413,8 +401,18 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID renderComponent->PlayEffect(effectId, type, name, secondary); } -Behavior::Behavior(const uint32_t behaviorId) -{ +Behavior::Behavior(const uint32_t behaviorId) { + auto behaviorTemplateTable = CDClientManager::Instance().GetTable(); + + CDBehaviorTemplate templateInDatabase{}; + + if (behaviorTemplateTable) { + auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId); + if (templateEntry.behaviorID == behaviorId) { + templateInDatabase = templateEntry; + } + } + this->m_behaviorId = behaviorId; // Add to cache @@ -426,16 +424,9 @@ Behavior::Behavior(const uint32_t behaviorId) this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; } - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT templateID, effectID, effectHandle FROM BehaviorTemplate WHERE behaviorID = ?;"); - query.bind(1, (int) behaviorId); - - auto result = query.execQuery(); - // Make sure we do not proceed if we are trying to load an invalid behavior - if (result.eof()) - { - Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!\n", behaviorId); + if (templateInDatabase.behaviorID == 0) { + Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!", behaviorId); this->m_effectId = 0; this->m_effectHandle = nullptr; @@ -444,117 +435,77 @@ Behavior::Behavior(const uint32_t behaviorId) return; } - this->m_templateId = static_cast(result.getIntField(0)); + this->m_templateId = static_cast(templateInDatabase.templateID); - this->m_effectId = result.getIntField(1); + this->m_effectId = templateInDatabase.effectID; - if (!result.fieldIsNull(2)) - { - const std::string effectHandle = result.getStringField(2); - if (effectHandle == "") - { - this->m_effectHandle = nullptr; - } - else - { - this->m_effectHandle = new std::string(effectHandle); - } - } - else - { - this->m_effectHandle = nullptr; - } - - result.finalize(); + this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr; } -float Behavior::GetFloat(const std::string& name, const float defaultValue) const -{ - return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue); +float Behavior::GetFloat(const std::string& name, const float defaultValue) const { + // Get the behavior parameter entry and return its value. + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance().GetTable(); + return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue); } -bool Behavior::GetBoolean(const std::string& name, const bool defaultValue) const -{ +bool Behavior::GetBoolean(const std::string& name, const bool defaultValue) const { return GetFloat(name, defaultValue) > 0; } -int32_t Behavior::GetInt(const std::string& name, const int defaultValue) const -{ +int32_t Behavior::GetInt(const std::string& name, const int defaultValue) const { return static_cast(GetFloat(name, defaultValue)); } -Behavior* Behavior::GetAction(const std::string& name) const -{ +Behavior* Behavior::GetAction(const std::string& name) const { const auto id = GetInt(name); return CreateBehavior(id); } -Behavior* Behavior::GetAction(float value) const -{ +Behavior* Behavior::GetAction(float value) const { return CreateBehavior(static_cast(value)); } -std::map Behavior::GetParameterNames() const -{ - std::map parameters; - - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = ?;"); - query.bind(1, (int) this->m_behaviorId); - - auto tableData = query.execQuery(); - - while (!tableData.eof()) - { - parameters.insert_or_assign(tableData.getStringField(0, ""), tableData.getFloatField(1, 0)); - - tableData.nextRow(); +std::map Behavior::GetParameterNames() const { + std::map templatesInDatabase; + // Find behavior template by its behavior id. + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance().GetTable(); + if (BehaviorParameterTable) { + templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(this->m_behaviorId); } - tableData.finalize(); - - return parameters; + return templatesInDatabase; } -void Behavior::Load() -{ +void Behavior::Load() { } -void Behavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void Behavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -void Behavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void Behavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -void Behavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) -{ +void Behavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { } -void Behavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ +void Behavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { } -void Behavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ +void Behavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { } -void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -Behavior::~Behavior() -{ +Behavior::~Behavior() { delete m_effectNames; delete m_effectType; delete m_effectHandle; diff --git a/dGame/dBehaviors/Behavior.h b/dGame/dBehaviors/Behavior.h index e8700f48..ca1c23e5 100644 --- a/dGame/dBehaviors/Behavior.h +++ b/dGame/dBehaviors/Behavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -19,7 +19,7 @@ public: /* * Static */ - static std::map Cache; + static std::unordered_map Cache; static CDBehaviorParameterTable* BehaviorParameterTable; static Behavior* GetBehavior(uint32_t behaviorId); @@ -31,24 +31,24 @@ public: /* * Utilities */ - + void PlayFx(std::u16string type, LWOOBJID target, LWOOBJID secondary = LWOOBJID_EMPTY); /* * Members */ - + uint32_t m_behaviorId; BehaviorTemplates m_templateId; uint32_t m_effectId; std::string* m_effectHandle = nullptr; std::unordered_map* m_effectNames = nullptr; std::string* m_effectType = nullptr; - + /* * Behavior parameters */ - + float GetFloat(const std::string& name, const float defaultValue = 0) const; bool GetBoolean(const std::string& name, const bool defaultValue = false) const; @@ -60,7 +60,7 @@ public: Behavior* GetAction(float value) const; std::map GetParameterNames() const; - + /* * Virtual */ @@ -69,15 +69,15 @@ public: // Player side virtual void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); - + virtual void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); virtual void UnCast(BehaviorContext* context, BehaviorBranchContext branch); virtual void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second); - + virtual void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second); - + // Npc side virtual void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); @@ -86,7 +86,7 @@ public: /* * Creations/destruction */ - + explicit Behavior(uint32_t behaviorId); virtual ~Behavior(); }; diff --git a/dGame/dBehaviors/BehaviorBranchContext.cpp b/dGame/dBehaviors/BehaviorBranchContext.cpp index 91791d89..3237997a 100644 --- a/dGame/dBehaviors/BehaviorBranchContext.cpp +++ b/dGame/dBehaviors/BehaviorBranchContext.cpp @@ -1,13 +1,11 @@ -#include "BehaviorBranchContext.h" +#include "BehaviorBranchContext.h" -BehaviorBranchContext::BehaviorBranchContext() -{ +BehaviorBranchContext::BehaviorBranchContext() { this->isProjectile = false; } -BehaviorBranchContext::BehaviorBranchContext(const LWOOBJID target, const float duration, const NiPoint3& referencePosition) -{ +BehaviorBranchContext::BehaviorBranchContext(const LWOOBJID target, const float duration, const NiPoint3& referencePosition) { this->target = target; this->duration = duration; this->referencePosition = referencePosition; diff --git a/dGame/dBehaviors/BehaviorBranchContext.h b/dGame/dBehaviors/BehaviorBranchContext.h index bd4e6722..2e56cd35 100644 --- a/dGame/dBehaviors/BehaviorBranchContext.h +++ b/dGame/dBehaviors/BehaviorBranchContext.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "dCommonVars.h" #include "NiPoint3.h" @@ -6,16 +6,18 @@ struct BehaviorBranchContext { LWOOBJID target = LWOOBJID_EMPTY; - + float duration = 0; - + NiPoint3 referencePosition = {}; bool isProjectile = false; uint32_t start = 0; + bool isSync = false; + BehaviorBranchContext(); - + BehaviorBranchContext(LWOOBJID target, float duration = 0, const NiPoint3& referencePosition = NiPoint3(0, 0, 0)); }; diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index c7bf912f..c7db4208 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -1,4 +1,4 @@ -#include "BehaviorContext.h" +#include "BehaviorContext.h" #include "Behavior.h" #include "BehaviorBranchContext.h" #include "EntityManager.h" @@ -10,39 +10,35 @@ #include - #include "DestroyableComponent.h" +#include "EchoSyncSkill.h" #include "PhantomPhysicsComponent.h" #include "RebuildComponent.h" +#include "eReplicaComponentType.h" +#include "eConnectionType.h" -BehaviorSyncEntry::BehaviorSyncEntry() -{ +BehaviorSyncEntry::BehaviorSyncEntry() { } -BehaviorTimerEntry::BehaviorTimerEntry() -{ +BehaviorTimerEntry::BehaviorTimerEntry() { } -BehaviorEndEntry::BehaviorEndEntry() -{ +BehaviorEndEntry::BehaviorEndEntry() { } -uint32_t BehaviorContext::GetUniqueSkillId() const -{ +uint32_t BehaviorContext::GetUniqueSkillId() const { auto* entity = EntityManager::Instance()->GetEntity(this->originator); - if (entity == nullptr) - { - Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!\n", this->originator); + if (entity == nullptr) { + Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator); return 0; } auto* component = entity->GetComponent(); - if (component == nullptr) - { - Game::logger->Log("BehaviorContext", "No skill component attached to (%llu)!\n", this->originator);; + if (component == nullptr) { + Game::logger->Log("BehaviorContext", "No skill component attached to (%llu)!", this->originator);; return 0; } @@ -51,21 +47,24 @@ uint32_t BehaviorContext::GetUniqueSkillId() const } -void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext) -{ +void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, const float duration, bool ignoreInterrupts) { auto entry = BehaviorSyncEntry(); entry.handle = syncId; entry.behavior = behavior; entry.branchContext = branchContext; + entry.branchContext.isSync = true; + entry.ignoreInterrupts = ignoreInterrupts; + // Add 10 seconds + duration time to account for lag and give clients time to send their syncs to the server. + constexpr float lagTime = 10.0f; + entry.time = lagTime + duration; this->syncEntries.push_back(entry); } -void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) -{ +void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) { BehaviorTimerEntry entry; - + entry.time = branchContext.duration; entry.behavior = behavior; entry.branchContext = branchContext; @@ -74,8 +73,7 @@ void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBr this->timerEntries.push_back(entry); } -void BehaviorContext::RegisterEndBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) -{ +void BehaviorContext::RegisterEndBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) { BehaviorEndEntry entry; entry.behavior = behavior; @@ -86,44 +84,37 @@ void BehaviorContext::RegisterEndBehavior(Behavior* behavior, const BehaviorBran this->endEntries.push_back(entry); } -void BehaviorContext::ScheduleUpdate(const LWOOBJID id) -{ - if (std::find(this->scheduledUpdates.begin(), this->scheduledUpdates.end(), id) != this->scheduledUpdates.end()) - { +void BehaviorContext::ScheduleUpdate(const LWOOBJID id) { + if (std::find(this->scheduledUpdates.begin(), this->scheduledUpdates.end(), id) != this->scheduledUpdates.end()) { return; } this->scheduledUpdates.push_back(id); } -void BehaviorContext::ExecuteUpdates() -{ - for (const auto& id : this->scheduledUpdates) - { +void BehaviorContext::ExecuteUpdates() { + for (const auto& id : this->scheduledUpdates) { auto* entity = EntityManager::Instance()->GetEntity(id); if (entity == nullptr) continue; - + EntityManager::Instance()->SerializeEntity(entity); } this->scheduledUpdates.clear(); } -void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bitStream) -{ +void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bitStream) { BehaviorSyncEntry entry; auto found = false; /* * There may be more than one of each handle */ - for (auto i = 0u; i < this->syncEntries.size(); ++i) - { + for (auto i = 0u; i < this->syncEntries.size(); ++i) { const auto syncEntry = this->syncEntries.at(i); - - if (syncEntry.handle == syncId) - { + + if (syncEntry.handle == syncId) { found = true; entry = syncEntry; @@ -133,9 +124,8 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bit } } - if (!found) - { - Game::logger->Log("BehaviorContext", "Failed to find behavior sync entry with sync id (%i)!\n", syncId); + if (!found) { + Game::logger->Log("BehaviorContext", "Failed to find behavior sync entry with sync id (%i)!", syncId); return; } @@ -143,10 +133,9 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bit auto* behavior = entry.behavior; const auto branch = entry.branchContext; - if (behavior == nullptr) - { - Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!\n", syncId); - + if (behavior == nullptr) { + Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!", syncId); + return; } @@ -154,33 +143,27 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bit } -void BehaviorContext::Update(const float deltaTime) -{ - for (auto i = 0u; i < this->timerEntries.size(); ++i) - { +void BehaviorContext::Update(const float deltaTime) { + for (auto i = 0u; i < this->timerEntries.size(); ++i) { auto entry = this->timerEntries.at(i); - if (entry.time > 0) - { + if (entry.time > 0) { entry.time -= deltaTime; this->timerEntries[i] = entry; } - - if (entry.time > 0) - { + + if (entry.time > 0) { continue; } entry.behavior->Timer(this, entry.branchContext, entry.second); } - + std::vector valid; - for (const auto& entry : this->timerEntries) - { - if (entry.time <= 0) - { + for (const auto& entry : this->timerEntries) { + if (entry.time <= 0) { continue; } @@ -191,8 +174,7 @@ void BehaviorContext::Update(const float deltaTime) } -void BehaviorContext::SyncCalculation(const uint32_t syncId, const float time, Behavior* behavior, const BehaviorBranchContext& branch, const bool ignoreInterrupts) -{ +void BehaviorContext::SyncCalculation(const uint32_t syncId, const float time, Behavior* behavior, const BehaviorBranchContext& branch, const bool ignoreInterrupts) { BehaviorSyncEntry entry; entry.behavior = behavior; @@ -204,14 +186,26 @@ void BehaviorContext::SyncCalculation(const uint32_t syncId, const float time, B this->syncEntries.push_back(entry); } -void BehaviorContext::InvokeEnd(const uint32_t id) -{ +void BehaviorContext::UpdatePlayerSyncs(float deltaTime) { + uint32_t i = 0; + while (i < this->syncEntries.size()) { + auto& entry = this->syncEntries.at(i); + + entry.time -= deltaTime; + + if (entry.time >= 0.0f) { + i++; + continue; + } + this->syncEntries.erase(this->syncEntries.begin() + i); + } +} + +void BehaviorContext::InvokeEnd(const uint32_t id) { std::vector entries; - for (const auto& entry : this->endEntries) - { - if (entry.start == id) - { + for (const auto& entry : this->endEntries) { + if (entry.start == id) { entry.behavior->End(this, entry.branchContext, entry.second); continue; @@ -223,30 +217,26 @@ void BehaviorContext::InvokeEnd(const uint32_t id) this->endEntries = entries; } -bool BehaviorContext::CalculateUpdate(const float deltaTime) -{ +bool BehaviorContext::CalculateUpdate(const float deltaTime) { auto any = false; - - for (auto i = 0u; i < this->syncEntries.size(); ++i) - { + + for (auto i = 0u; i < this->syncEntries.size(); ++i) { auto entry = this->syncEntries.at(i); - if (entry.time > 0) - { + if (entry.time > 0) { entry.time -= deltaTime; this->syncEntries[i] = entry; } - if (entry.time > 0) - { + if (entry.time > 0) { any = true; - + continue; } // Echo sync - GameMessages::EchoSyncSkill echo; + EchoSyncSkill echo; echo.bDone = true; echo.uiBehaviorHandle = entry.handle; @@ -257,17 +247,16 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) // Calculate sync entry.behavior->SyncCalculation(this, bitStream, entry.branchContext); - if (!clientInitalized) - { - echo.sBitStream.assign((char*) bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); + if (!clientInitalized) { + echo.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); // Write message RakNet::BitStream message; - PacketUtils::WriteHeader(message, CLIENT, MSG_CLIENT_GAME_MSG); + PacketUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->originator); echo.Serialize(&message); - + Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true); } @@ -278,10 +267,8 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) std::vector valid; - for (const auto& entry : this->syncEntries) - { - if (entry.time <= 0) - { + for (const auto& entry : this->syncEntries) { + if (entry.time <= 0) { continue; } @@ -293,29 +280,24 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) return any; } -void BehaviorContext::Interrupt() -{ - std::vector keptSync {}; +void BehaviorContext::Interrupt() { + std::vector keptSync{}; - for (const auto& entry : this->syncEntries) - { + for (const auto& entry : this->syncEntries) { if (!entry.ignoreInterrupts) continue; keptSync.push_back(entry); } - + this->syncEntries = keptSync; } -void BehaviorContext::Reset() -{ - for (const auto& entry : this->timerEntries) - { +void BehaviorContext::Reset() { + for (const auto& entry : this->timerEntries) { entry.behavior->Timer(this, entry.branchContext, entry.second); } - for (const auto& entry : this->endEntries) - { + for (const auto& entry : this->endEntries) { entry.behavior->End(this, entry.branchContext, entry.second); } @@ -325,27 +307,22 @@ void BehaviorContext::Reset() this->scheduledUpdates.clear(); } -std::vector BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const -{ +std::vector BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const { auto* entity = EntityManager::Instance()->GetEntity(this->caster); std::vector targets; - - if (entity == nullptr) - { - Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!\n", this->originator); + + if (entity == nullptr) { + Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator); return targets; } - if (!ignoreFaction && !includeFaction) - { - for (auto entry : entity->GetTargetsInPhantom()) - { + if (!ignoreFaction && !includeFaction) { + for (auto entry : entity->GetTargetsInPhantom()) { auto* instance = EntityManager::Instance()->GetEntity(entry); - if (instance == nullptr) - { + if (instance == nullptr) { continue; } @@ -353,21 +330,17 @@ std::vector BehaviorContext::GetValidTargets(int32_t ignoreFaction, in } } - if (ignoreFaction || includeFaction || (!entity->HasComponent(COMPONENT_TYPE_PHANTOM_PHYSICS) && targets.empty())) - { - DestroyableComponent* destroyableComponent; - if (!entity->TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) - { + if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) { + DestroyableComponent* destroyableComponent; + if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) { return targets; } - - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS); - for (auto* candidate : entities) - { + + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS); + for (auto* candidate : entities) { const auto id = candidate->GetObjectID(); - - if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) - { + + if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) { targets.push_back(id); } } @@ -377,23 +350,18 @@ std::vector BehaviorContext::GetValidTargets(int32_t ignoreFaction, in } -BehaviorContext::BehaviorContext(const LWOOBJID originator, const bool calculation) -{ +BehaviorContext::BehaviorContext(const LWOOBJID originator, const bool calculation) { this->originator = originator; this->syncEntries = {}; this->timerEntries = {}; - if (calculation) - { + if (calculation) { this->skillUId = GetUniqueSkillId(); - } - else - { + } else { this->skillUId = 0; } } -BehaviorContext::~BehaviorContext() -{ +BehaviorContext::~BehaviorContext() { Reset(); } diff --git a/dGame/dBehaviors/BehaviorContext.h b/dGame/dBehaviors/BehaviorContext.h index f27889f1..117f328d 100644 --- a/dGame/dBehaviors/BehaviorContext.h +++ b/dGame/dBehaviors/BehaviorContext.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "RakPeerInterface.h" #include "dCommonVars.h" @@ -16,7 +16,7 @@ struct BehaviorSyncEntry float time = 0; bool ignoreInterrupts = false; - + Behavior* behavior = nullptr; BehaviorBranchContext branchContext; @@ -46,7 +46,7 @@ struct BehaviorEndEntry BehaviorBranchContext branchContext; LWOOBJID second = LWOOBJID_EMPTY; - + BehaviorEndEntry(); }; @@ -65,11 +65,11 @@ struct BehaviorContext bool failed = false; bool clientInitalized = false; - + std::vector syncEntries; - + std::vector timerEntries; - + std::vector endEntries; std::vector scheduledUpdates; @@ -80,7 +80,9 @@ struct BehaviorContext uint32_t GetUniqueSkillId() const; - void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext); + void UpdatePlayerSyncs(float deltaTime); + + void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, const float duration, bool ignoreInterrupts = false); void RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, LWOOBJID second = LWOOBJID_EMPTY); @@ -89,15 +91,15 @@ struct BehaviorContext void ScheduleUpdate(LWOOBJID id); void ExecuteUpdates(); - + void SyncBehavior(uint32_t syncId, RakNet::BitStream* bitStream); void Update(float deltaTime); - + void SyncCalculation(uint32_t syncId, float time, Behavior* behavior, const BehaviorBranchContext& branch, bool ignoreInterrupts = false); void InvokeEnd(uint32_t id); - + bool CalculateUpdate(float deltaTime); void Interrupt(); @@ -105,7 +107,7 @@ struct BehaviorContext void Reset(); std::vector GetValidTargets(int32_t ignoreFaction = 0, int32_t includeFaction = 0, const bool targetSelf = false, const bool targetEnemy = true, const bool targetFriend = false) const; - + explicit BehaviorContext(LWOOBJID originator, bool calculation = false); ~BehaviorContext(); diff --git a/dGame/dBehaviors/BehaviorSlot.h b/dGame/dBehaviors/BehaviorSlot.h index af0d4e03..51219b80 100644 --- a/dGame/dBehaviors/BehaviorSlot.h +++ b/dGame/dBehaviors/BehaviorSlot.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #ifndef BEHAVIORSLOT_H #define BEHAVIORSLOT_H diff --git a/dGame/dBehaviors/BehaviorTemplates.cpp b/dGame/dBehaviors/BehaviorTemplates.cpp index 85d0074f..8719fbe7 100644 --- a/dGame/dBehaviors/BehaviorTemplates.cpp +++ b/dGame/dBehaviors/BehaviorTemplates.cpp @@ -1 +1 @@ -#include "BehaviorTemplates.h" +#include "BehaviorTemplates.h" diff --git a/dGame/dBehaviors/BehaviorTemplates.h b/dGame/dBehaviors/BehaviorTemplates.h index 04c15fc0..87cde694 100644 --- a/dGame/dBehaviors/BehaviorTemplates.h +++ b/dGame/dBehaviors/BehaviorTemplates.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once enum class BehaviorTemplates : unsigned int { BEHAVIOR_EMPTY, // Not a real behavior, indicates invalid behaviors @@ -67,4 +67,4 @@ enum class BehaviorTemplates : unsigned int { BEHAVIOR_TAKE_PICTURE, BEHAVIOR_MOUNT, BEHAVIOR_SKILL_SET -}; \ No newline at end of file +}; diff --git a/dGame/dBehaviors/BlockBehavior.cpp b/dGame/dBehaviors/BlockBehavior.cpp index 8f66b182..cdbb3d80 100644 --- a/dGame/dBehaviors/BlockBehavior.cpp +++ b/dGame/dBehaviors/BlockBehavior.cpp @@ -1,4 +1,4 @@ -#include "BlockBehavior.h" +#include "BlockBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" @@ -7,52 +7,43 @@ #include "dLogger.h" #include "DestroyableComponent.h" -void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto target = context->originator; auto* entity = EntityManager::Instance()->GetEntity(target); - if (entity == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", branch.target); + if (entity == nullptr) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); return; } auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent == nullptr) - { + if (destroyableComponent == nullptr) { return; } destroyableComponent->SetAttacksToBlock(this->m_numAttacksCanBlock); - if (branch.start > 0) - { + if (branch.start > 0) { context->RegisterEndBehavior(this, branch); - } - else if (branch.duration > 0) - { + } else if (branch.duration > 0) { context->RegisterTimerBehavior(this, branch); } } -void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) -{ +void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { const auto target = context->originator; auto* entity = EntityManager::Instance()->GetEntity(target); - if (entity == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", branch.target); + if (entity == nullptr) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); return; } @@ -61,25 +52,21 @@ void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branc destroyableComponent->SetAttacksToBlock(this->m_numAttacksCanBlock); - if (destroyableComponent == nullptr) - { + if (destroyableComponent == nullptr) { return; } destroyableComponent->SetAttacksToBlock(0); } -void BlockBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ +void BlockBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { UnCast(context, branch); } -void BlockBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ +void BlockBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { UnCast(context, branch); } -void BlockBehavior::Load() -{ +void BlockBehavior::Load() { this->m_numAttacksCanBlock = GetInt("num_attacks_can_block"); } diff --git a/dGame/dBehaviors/BlockBehavior.h b/dGame/dBehaviors/BlockBehavior.h index 5de3d309..e0d639ed 100644 --- a/dGame/dBehaviors/BlockBehavior.h +++ b/dGame/dBehaviors/BlockBehavior.h @@ -1,17 +1,16 @@ -#pragma once +#pragma once #include "Behavior.h" class BlockBehavior final : public Behavior { public: int32_t m_numAttacksCanBlock; - + /* * Inherited */ - explicit BlockBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit BlockBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; @@ -19,10 +18,10 @@ public: void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; - + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/BuffBehavior.cpp b/dGame/dBehaviors/BuffBehavior.cpp index e2490f16..a39fd165 100644 --- a/dGame/dBehaviors/BuffBehavior.cpp +++ b/dGame/dBehaviors/BuffBehavior.cpp @@ -1,4 +1,4 @@ -#include "BuffBehavior.h" +#include "BuffBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" @@ -7,24 +7,21 @@ #include "dLogger.h" #include "DestroyableComponent.h" -void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; - + auto* entity = EntityManager::Instance()->GetEntity(target); - if (entity == nullptr) - { - Game::logger->Log("BuffBehavior", "Invalid target (%llu)!\n", target); + if (entity == nullptr) { + Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target); return; } auto* component = entity->GetComponent(); - if (component == nullptr) - { - Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!\n", target); + if (component == nullptr) { + Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target); return; } @@ -35,37 +32,30 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream EntityManager::Instance()->SerializeEntity(entity); - if (!context->unmanaged) - { - if (branch.duration > 0) - { + if (!context->unmanaged) { + if (branch.duration > 0) { context->RegisterTimerBehavior(this, branch); - } - else if (branch.start > 0) - { + } else if (branch.start > 0) { context->RegisterEndBehavior(this, branch); } } } -void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) -{ +void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; - + auto* entity = EntityManager::Instance()->GetEntity(target); - if (entity == nullptr) - { - Game::logger->Log("BuffBehavior", "Invalid target (%llu)!\n", target); + if (entity == nullptr) { + Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target); return; } auto* component = entity->GetComponent(); - if (component == nullptr) - { - Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!\n", target); + if (component == nullptr) { + Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target); return; } @@ -73,22 +63,19 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch component->SetMaxHealth(component->GetMaxHealth() - this->m_health); component->SetMaxArmor(component->GetMaxArmor() - this->m_armor); component->SetMaxImagination(component->GetMaxImagination() - this->m_imagination); - + EntityManager::Instance()->SerializeEntity(entity); } -void BuffBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) -{ +void BuffBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) { UnCast(context, branch); } -void BuffBehavior::End(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) -{ +void BuffBehavior::End(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) { UnCast(context, branch); } -void BuffBehavior::Load() -{ +void BuffBehavior::Load() { this->m_health = GetInt("life"); this->m_armor = GetInt("armor"); diff --git a/dGame/dBehaviors/BuffBehavior.h b/dGame/dBehaviors/BuffBehavior.h index cfb26aef..b7c805b3 100644 --- a/dGame/dBehaviors/BuffBehavior.h +++ b/dGame/dBehaviors/BuffBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class BuffBehavior final : public Behavior @@ -9,12 +9,11 @@ public: uint32_t m_armor; uint32_t m_imagination; - + /* * Inherited */ - explicit BuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit BuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; @@ -24,6 +23,6 @@ public: void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt new file mode 100644 index 00000000..7b331fe0 --- /dev/null +++ b/dGame/dBehaviors/CMakeLists.txt @@ -0,0 +1,55 @@ +set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" + "AndBehavior.cpp" + "ApplyBuffBehavior.cpp" + "AreaOfEffectBehavior.cpp" + "AttackDelayBehavior.cpp" + "BasicAttackBehavior.cpp" + "Behavior.cpp" + "BehaviorBranchContext.cpp" + "BehaviorContext.cpp" + "BehaviorTemplates.cpp" + "BlockBehavior.cpp" + "BuffBehavior.cpp" + "CarBoostBehavior.cpp" + "ChainBehavior.cpp" + "ChangeIdleFlagsBehavior.cpp" + "ChangeOrientationBehavior.cpp" + "ChargeUpBehavior.cpp" + "ClearTargetBehavior.cpp" + "DamageAbsorptionBehavior.cpp" + "DamageReductionBehavior.cpp" + "DarkInspirationBehavior.cpp" + "DurationBehavior.cpp" + "EmptyBehavior.cpp" + "EndBehavior.cpp" + "ForceMovementBehavior.cpp" + "HealBehavior.cpp" + "ImaginationBehavior.cpp" + "ImmunityBehavior.cpp" + "InterruptBehavior.cpp" + "JetPackBehavior.cpp" + "KnockbackBehavior.cpp" + "LootBuffBehavior.cpp" + "MovementSwitchBehavior.cpp" + "NpcCombatSkillBehavior.cpp" + "OverTimeBehavior.cpp" + "PlayEffectBehavior.cpp" + "ProjectileAttackBehavior.cpp" + "PropertyTeleportBehavior.cpp" + "PullToPointBehavior.cpp" + "RemoveBuffBehavior.cpp" + "RepairBehavior.cpp" + "SkillCastFailedBehavior.cpp" + "SkillEventBehavior.cpp" + "SpawnBehavior.cpp" + "SpawnQuickbuildBehavior.cpp" + "SpeedBehavior.cpp" + "StartBehavior.cpp" + "StunBehavior.cpp" + "SwitchBehavior.cpp" + "SwitchMultipleBehavior.cpp" + "TacArcBehavior.cpp" + "TargetCasterBehavior.cpp" + "TauntBehavior.cpp" + "VentureVisionBehavior.cpp" + "VerifyBehavior.cpp" PARENT_SCOPE) diff --git a/dGame/dBehaviors/CarBoostBehavior.cpp b/dGame/dBehaviors/CarBoostBehavior.cpp index 7c726030..1ab0af95 100644 --- a/dGame/dBehaviors/CarBoostBehavior.cpp +++ b/dGame/dBehaviors/CarBoostBehavior.cpp @@ -8,44 +8,41 @@ #include "dLogger.h" #include "PossessableComponent.h" -void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS); +void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS); - auto* entity = EntityManager::Instance()->GetEntity(context->originator); + auto* entity = EntityManager::Instance()->GetEntity(context->originator); - if (entity == nullptr) - { - return; - } + if (entity == nullptr) { + return; + } - Game::logger->Log("Car boost", "Activating car boost!\n"); + Game::logger->Log("Car boost", "Activating car boost!"); - auto* possessableComponent = entity->GetComponent(); - if (possessableComponent != nullptr) { + auto* possessableComponent = entity->GetComponent(); + if (possessableComponent != nullptr) { - auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (possessor != nullptr) { + auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + if (possessor != nullptr) { - auto* characterComponent = possessor->GetComponent(); - if (characterComponent != nullptr) { - Game::logger->Log("Car boost", "Tracking car boost!\n"); - characterComponent->UpdatePlayerStatistic(RacingCarBoostsActivated); - } - } - } + auto* characterComponent = possessor->GetComponent(); + if (characterComponent != nullptr) { + Game::logger->Log("Car boost", "Tracking car boost!"); + characterComponent->UpdatePlayerStatistic(RacingCarBoostsActivated); + } + } + } - m_Action->Handle(context, bitStream, branch); + m_Action->Handle(context, bitStream, branch); - entity->AddCallbackTimer(m_Time, [entity] () { - GameMessages::SendVehicleRemovePassiveBoostAction(entity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - }); + entity->AddCallbackTimer(m_Time, [entity]() { + GameMessages::SendVehicleRemovePassiveBoostAction(entity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + }); } -void CarBoostBehavior::Load() -{ - m_Action = GetAction("action"); +void CarBoostBehavior::Load() { + m_Action = GetAction("action"); - m_Time = GetFloat("time"); + m_Time = GetFloat("time"); } diff --git a/dGame/dBehaviors/CarBoostBehavior.h b/dGame/dBehaviors/CarBoostBehavior.h index 32eb00c8..3f4265b9 100644 --- a/dGame/dBehaviors/CarBoostBehavior.h +++ b/dGame/dBehaviors/CarBoostBehavior.h @@ -14,10 +14,9 @@ public: * Inherited */ - explicit CarBoostBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit CarBoostBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/ChainBehavior.cpp b/dGame/dBehaviors/ChainBehavior.cpp index 0d49de82..ec0f8969 100644 --- a/dGame/dBehaviors/ChainBehavior.cpp +++ b/dGame/dBehaviors/ChainBehavior.cpp @@ -1,37 +1,36 @@ -#include "ChainBehavior.h" +#include "ChainBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" -void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - uint32_t chain_index; +void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + uint32_t chainIndex{}; - bitStream->Read(chain_index); + if (!bitStream->Read(chainIndex)) { + Game::logger->Log("ChainBehavior", "Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - chain_index--; + chainIndex--; - if (chain_index < this->m_behaviors.size()) - { - this->m_behaviors.at(chain_index)->Handle(context, bitStream, branch); + if (chainIndex < this->m_behaviors.size()) { + this->m_behaviors.at(chainIndex)->Handle(context, bitStream, branch); + } else { + Game::logger->Log("ChainBehavior", "chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits()); } } -void ChainBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void ChainBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { bitStream->Write(1); this->m_behaviors.at(0)->Calculate(context, bitStream, branch); } -void ChainBehavior::Load() -{ +void ChainBehavior::Load() { const auto parameters = GetParameterNames(); - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { + for (const auto& parameter : parameters) { + if (parameter.first.rfind("behavior", 0) == 0) { auto* action = GetAction(parameter.second); this->m_behaviors.push_back(action); diff --git a/dGame/dBehaviors/ChainBehavior.h b/dGame/dBehaviors/ChainBehavior.h index 733707dc..c31d5358 100644 --- a/dGame/dBehaviors/ChainBehavior.h +++ b/dGame/dBehaviors/ChainBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" @@ -13,10 +13,9 @@ public: * Inherited */ - explicit ChainBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit ChainBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp new file mode 100644 index 00000000..06a79fa7 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp @@ -0,0 +1,37 @@ + +#include "ChangeIdleFlagsBehavior.h" +#include "BehaviorContext.h" +#include "BehaviorBranchContext.h" + +void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + + GameMessages::SendChangeIdleFlags(target, m_FlagsOn, m_FlagsOff, UNASSIGNED_SYSTEM_ADDRESS); + + if (branch.duration > 0.0f) { + context->RegisterTimerBehavior(this, branch); + } else if (branch.start > 0) { + context->RegisterEndBehavior(this, branch); + } +} + +void ChangeIdleFlagsBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); +} + +void ChangeIdleFlagsBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + // flip on and off to end behavior + GameMessages::SendChangeIdleFlags(target, m_FlagsOff, m_FlagsOn, UNASSIGNED_SYSTEM_ADDRESS); +} + +void ChangeIdleFlagsBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + +void ChangeIdleFlagsBehavior::Load() { + m_FlagsOff = static_cast(GetInt("flags_off", 0)); + m_FlagsOn = static_cast(GetInt("flags_on", 0)); +} diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h new file mode 100644 index 00000000..91f802f4 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h @@ -0,0 +1,23 @@ + +#pragma once +#include "Behavior.h" +#include "eAninmationFlags.h" + +class ChangeIdleFlagsBehavior final : public Behavior { +public: + + /* + * Inherited + */ + explicit ChangeIdleFlagsBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void Load() override; + +private: + eAnimationFlags m_FlagsOff; + eAnimationFlags m_FlagsOn; +}; diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.cpp b/dGame/dBehaviors/ChangeOrientationBehavior.cpp index 60dcf2ac..36a2e6a8 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.cpp +++ b/dGame/dBehaviors/ChangeOrientationBehavior.cpp @@ -2,49 +2,35 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" -#include "BaseCombatAIComponent.h" -void ChangeOrientationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Entity* sourceEntity; + if (this->m_orientCaster) sourceEntity = EntityManager::Instance()->GetEntity(context->originator); + else sourceEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!sourceEntity) return; + + if (this->m_toTarget) { + Entity* destinationEntity; + if (this->m_orientCaster) destinationEntity = EntityManager::Instance()->GetEntity(branch.target); + else destinationEntity = EntityManager::Instance()->GetEntity(context->originator); + if (!destinationEntity) return; + + sourceEntity->SetRotation( + NiQuaternion::LookAt(sourceEntity->GetPosition(), destinationEntity->GetPosition()) + ); + } else if (this->m_toAngle){ + auto baseAngle = NiPoint3(0, 0, this->m_angle); + if (this->m_relative) baseAngle += sourceEntity->GetRotation().GetForwardVector(); + sourceEntity->SetRotation(NiQuaternion::FromEulerAngles(baseAngle)); + } else return; + EntityManager::Instance()->SerializeEntity(sourceEntity); + return; } -void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - if (!m_ToTarget) return; // TODO: Add the other arguments to this behavior - - auto* self = EntityManager::Instance()->GetEntity(context->originator); - auto* other = EntityManager::Instance()->GetEntity(branch.target); - - if (self == nullptr || other == nullptr) return; - - const auto source = self->GetPosition(); - const auto destination = self->GetPosition(); - - if (m_OrientCaster) - { - auto* baseCombatAIComponent = self->GetComponent(); - - /*if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->LookAt(destination); - } - else*/ - { - self->SetRotation(NiQuaternion::LookAt(source, destination)); - } - - EntityManager::Instance()->SerializeEntity(self); - } - else - { - other->SetRotation(NiQuaternion::LookAt(destination, source)); - - EntityManager::Instance()->SerializeEntity(other); - } -} - -void ChangeOrientationBehavior::Load() -{ - m_OrientCaster = GetBoolean("orient_caster"); - m_ToTarget = GetBoolean("to_target"); +void ChangeOrientationBehavior::Load() { + this->m_orientCaster = GetBoolean("orient_caster", true); + this->m_toTarget = GetBoolean("to_target", false); + this->m_toAngle = GetBoolean("to_angle", false); + this->m_angle = GetFloat("angle", 0.0f); + this->m_relative = GetBoolean("relative", false); } diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.h b/dGame/dBehaviors/ChangeOrientationBehavior.h index 960ec8ea..22c92bb8 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.h +++ b/dGame/dBehaviors/ChangeOrientationBehavior.h @@ -2,25 +2,15 @@ #include "Behavior.h" -#include - -class ChangeOrientationBehavior final : public Behavior -{ +class ChangeOrientationBehavior final : public Behavior { public: - bool m_OrientCaster; - bool m_ToTarget; - - /* - * Inherited - */ - - explicit ChangeOrientationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { - } - - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + explicit ChangeOrientationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Load() override; +private: + bool m_orientCaster; + bool m_toTarget; + bool m_toAngle; + float m_angle; + bool m_relative; }; diff --git a/dGame/dBehaviors/ChargeUpBehavior.cpp b/dGame/dBehaviors/ChargeUpBehavior.cpp index c9259801..4c7c3dac 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.cpp +++ b/dGame/dBehaviors/ChargeUpBehavior.cpp @@ -1,27 +1,28 @@ -#include "ChargeUpBehavior.h" +#include "ChargeUpBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" +#include "Game.h" #include "dLogger.h" -void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - uint32_t handle; +void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("ChargeUpBehavior", "Unable to read handle from bitStream, aborting Handle! variable_type"); + return; + }; - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, this->m_MaxDuration); } -void ChargeUpBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ChargeUpBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -void ChargeUpBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void ChargeUpBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { this->m_action->Handle(context, bitStream, branch); } -void ChargeUpBehavior::Load() -{ +void ChargeUpBehavior::Load() { this->m_action = GetAction("action"); + this->m_MaxDuration = GetFloat("max_duration"); } diff --git a/dGame/dBehaviors/ChargeUpBehavior.h b/dGame/dBehaviors/ChargeUpBehavior.h index f9c8d30a..ceb40f6c 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.h +++ b/dGame/dBehaviors/ChargeUpBehavior.h @@ -1,24 +1,19 @@ -#pragma once +#pragma once #include "Behavior.h" class ChargeUpBehavior final : public Behavior { public: - Behavior* m_action; - - /* - * Inherited - */ - - explicit ChargeUpBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { - } + explicit ChargeUpBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; +private: + Behavior* m_action; + float m_MaxDuration; }; diff --git a/dGame/dBehaviors/ClearTargetBehavior.cpp b/dGame/dBehaviors/ClearTargetBehavior.cpp index 3428e754..ec0c0db6 100644 --- a/dGame/dBehaviors/ClearTargetBehavior.cpp +++ b/dGame/dBehaviors/ClearTargetBehavior.cpp @@ -1,25 +1,22 @@ -#include "ClearTargetBehavior.h" +#include "ClearTargetBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void ClearTargetBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ClearTargetBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { branch.target = LWOOBJID_EMPTY; this->m_action->Handle(context, bitStream, branch); } -void ClearTargetBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ClearTargetBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { branch.target = LWOOBJID_EMPTY; this->m_action->Calculate(context, bitStream, branch); } -void ClearTargetBehavior::Load() -{ +void ClearTargetBehavior::Load() { this->m_action = GetAction("action"); - + this->m_clearIfCaster = GetBoolean("clear_if_caster"); } diff --git a/dGame/dBehaviors/ClearTargetBehavior.h b/dGame/dBehaviors/ClearTargetBehavior.h index ccb631a4..0ed57fb4 100644 --- a/dGame/dBehaviors/ClearTargetBehavior.h +++ b/dGame/dBehaviors/ClearTargetBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class ClearTargetBehavior final : public Behavior @@ -7,12 +7,11 @@ public: Behavior* m_action; bool m_clearIfCaster; - + /* * Inherited */ - explicit ClearTargetBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit ClearTargetBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp index bb94f9b3..48dbf705 100644 --- a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp +++ b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp @@ -1,4 +1,4 @@ -#include "DamageAbsorptionBehavior.h" +#include "DamageAbsorptionBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" @@ -7,21 +7,18 @@ #include "dLogger.h" #include "DestroyableComponent.h" -void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); return; } auto* destroyable = target->GetComponent(); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { return; } @@ -32,37 +29,32 @@ void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStrea context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) -{ +void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(second); - if (target == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", second); + if (target == nullptr) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); return; } - + auto* destroyable = target->GetComponent(); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { return; } const auto present = static_cast(destroyable->GetDamageToAbsorb()); - + const auto toRemove = std::min(present, this->m_absorbAmount); destroyable->SetDamageToAbsorb(present - toRemove); } -void DamageAbsorptionBehavior::Load() -{ +void DamageAbsorptionBehavior::Load() { this->m_absorbAmount = GetInt("absorb_amount"); } diff --git a/dGame/dBehaviors/DamageAbsorptionBehavior.h b/dGame/dBehaviors/DamageAbsorptionBehavior.h index 34b564a5..1b865e87 100644 --- a/dGame/dBehaviors/DamageAbsorptionBehavior.h +++ b/dGame/dBehaviors/DamageAbsorptionBehavior.h @@ -1,17 +1,16 @@ -#pragma once +#pragma once #include "Behavior.h" class DamageAbsorptionBehavior final : public Behavior { public: uint32_t m_absorbAmount; - + /* * Inherited */ - explicit DamageAbsorptionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit DamageAbsorptionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/DamageReductionBehavior.cpp b/dGame/dBehaviors/DamageReductionBehavior.cpp index 96c32a03..2b18b7c2 100644 --- a/dGame/dBehaviors/DamageReductionBehavior.cpp +++ b/dGame/dBehaviors/DamageReductionBehavior.cpp @@ -7,56 +7,48 @@ #include "dLogger.h" #include "DestroyableComponent.h" -void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target); return; } auto* destroyable = target->GetComponent(); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { return; } destroyable->SetDamageReduction(m_ReductionAmount); - + context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) -{ +void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(second); - if (target == nullptr) - { - Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!\n", second); + if (target == nullptr) { + Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second); return; } - + auto* destroyable = target->GetComponent(); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { return; } destroyable->SetDamageReduction(0); } -void DamageReductionBehavior::Load() -{ +void DamageReductionBehavior::Load() { this->m_ReductionAmount = GetInt("reduction_amount"); } diff --git a/dGame/dBehaviors/DamageReductionBehavior.h b/dGame/dBehaviors/DamageReductionBehavior.h index 8881b88d..bddd31fb 100644 --- a/dGame/dBehaviors/DamageReductionBehavior.h +++ b/dGame/dBehaviors/DamageReductionBehavior.h @@ -5,13 +5,12 @@ class DamageReductionBehavior final : public Behavior { public: uint32_t m_ReductionAmount; - + /* * Inherited */ - explicit DamageReductionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit DamageReductionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/DarkInspirationBehavior.cpp b/dGame/dBehaviors/DarkInspirationBehavior.cpp new file mode 100644 index 00000000..ea80cbba --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.cpp @@ -0,0 +1,52 @@ +#include "DarkInspirationBehavior.h" + +#include "BehaviorBranchContext.h" +#include "Entity.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "BehaviorContext.h" + +void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Handle(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Calculate(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Load() { + this->m_ActionIfFactionMatches = GetAction("action"); + + this->m_FactionList = GetInt("faction_list"); +} diff --git a/dGame/dBehaviors/DarkInspirationBehavior.h b/dGame/dBehaviors/DarkInspirationBehavior.h new file mode 100644 index 00000000..f8298742 --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.h @@ -0,0 +1,22 @@ +#pragma once +#include "Behavior.h" + +class DarkInspirationBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit DarkInspirationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; +private: + Behavior* m_ActionIfFactionMatches; + uint32_t m_FactionList; +}; diff --git a/dGame/dBehaviors/DurationBehavior.cpp b/dGame/dBehaviors/DurationBehavior.cpp index 1f95d7d4..c0bc5585 100644 --- a/dGame/dBehaviors/DurationBehavior.cpp +++ b/dGame/dBehaviors/DurationBehavior.cpp @@ -1,23 +1,20 @@ -#include "DurationBehavior.h" +#include "DurationBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void DurationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void DurationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { branch.duration = this->m_duration; this->m_action->Handle(context, bitStream, branch); } -void DurationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void DurationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { branch.duration = this->m_duration; this->m_action->Calculate(context, bitStream, branch); } -void DurationBehavior::Load() -{ +void DurationBehavior::Load() { this->m_duration = GetFloat("duration"); this->m_action = GetAction("action"); diff --git a/dGame/dBehaviors/DurationBehavior.h b/dGame/dBehaviors/DurationBehavior.h index 82bc3230..164754b1 100644 --- a/dGame/dBehaviors/DurationBehavior.h +++ b/dGame/dBehaviors/DurationBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class DurationBehavior final : public Behavior @@ -7,11 +7,10 @@ public: float m_duration; Behavior* m_action; - - explicit DurationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + + explicit DurationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/EmptyBehavior.cpp b/dGame/dBehaviors/EmptyBehavior.cpp index 4f8a5266..8828f5de 100644 --- a/dGame/dBehaviors/EmptyBehavior.cpp +++ b/dGame/dBehaviors/EmptyBehavior.cpp @@ -1,2 +1,2 @@ -#include "EmptyBehavior.h" +#include "EmptyBehavior.h" diff --git a/dGame/dBehaviors/EmptyBehavior.h b/dGame/dBehaviors/EmptyBehavior.h index f3f6a77f..52121f6c 100644 --- a/dGame/dBehaviors/EmptyBehavior.h +++ b/dGame/dBehaviors/EmptyBehavior.h @@ -1,11 +1,10 @@ -#pragma once +#pragma once #include "Behavior.h" class EmptyBehavior final : public Behavior { public: - explicit EmptyBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit EmptyBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } }; diff --git a/dGame/dBehaviors/EndBehavior.cpp b/dGame/dBehaviors/EndBehavior.cpp index 4e7b8351..c67f3215 100644 --- a/dGame/dBehaviors/EndBehavior.cpp +++ b/dGame/dBehaviors/EndBehavior.cpp @@ -1,19 +1,16 @@ -#include "EndBehavior.h" +#include "EndBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void EndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void EndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { context->InvokeEnd(this->m_startBehavior); } -void EndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void EndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { context->InvokeEnd(this->m_startBehavior); } -void EndBehavior::Load() -{ +void EndBehavior::Load() { this->m_startBehavior = GetInt("start_action"); } diff --git a/dGame/dBehaviors/EndBehavior.h b/dGame/dBehaviors/EndBehavior.h index afa539ce..e1c06068 100644 --- a/dGame/dBehaviors/EndBehavior.h +++ b/dGame/dBehaviors/EndBehavior.h @@ -1,21 +1,20 @@ -#pragma once +#pragma once #include "Behavior.h" class EndBehavior final : public Behavior { public: uint32_t m_startBehavior; - + /* * Inherited */ - explicit EndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit EndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/ForceMovementBehavior.cpp b/dGame/dBehaviors/ForceMovementBehavior.cpp index ea8c04a7..52359cf7 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.cpp +++ b/dGame/dBehaviors/ForceMovementBehavior.cpp @@ -1,81 +1,90 @@ -#include "ForceMovementBehavior.h" +#include "ForceMovementBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { - return; - } + if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + return; + } - uint32_t handle; - bitStream->Read(handle); - context->RegisterSyncBehavior(handle, this, branch); + uint32_t handle{}; + if (!bitStream->Read(handle)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } + context->RegisterSyncBehavior(handle, this, branch, this->m_Duration); } -void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - uint32_t next; - bitStream->Read(next); +void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t next{}; + if (!bitStream->Read(next)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; - bitStream->Read(target); + LWOOBJID target{}; + if (!bitStream->Read(target)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - branch.target = target; - auto* behavior = CreateBehavior(next); - behavior->Handle(context, bitStream, branch); + branch.target = target; + auto* behavior = CreateBehavior(next); + behavior->Handle(context, bitStream, branch); } void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { - return; - } + if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + return; + } - auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); - if (casterEntity != nullptr) { - auto* controllablePhysicsComponent = casterEntity->GetComponent(); - if (controllablePhysicsComponent != nullptr) { + auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); + if (casterEntity != nullptr) { + auto* controllablePhysicsComponent = casterEntity->GetComponent(); + if (controllablePhysicsComponent != nullptr) { - if (m_Forward == 1) { - controllablePhysicsComponent->SetVelocity(controllablePhysicsComponent->GetRotation().GetForwardVector() * 25); - } + if (m_Forward == 1) { + controllablePhysicsComponent->SetVelocity(controllablePhysicsComponent->GetRotation().GetForwardVector() * 25); + } - EntityManager::Instance()->SerializeEntity(casterEntity); - } - } + EntityManager::Instance()->SerializeEntity(casterEntity); + } + } - const auto skillHandle = context->GetUniqueSkillId(); - bitStream->Write(skillHandle); + const auto skillHandle = context->GetUniqueSkillId(); + bitStream->Write(skillHandle); - context->SyncCalculation(skillHandle, this->m_Duration, this, branch); + context->SyncCalculation(skillHandle, this->m_Duration, this, branch); } -void ForceMovementBehavior::Load() -{ - this->m_hitAction = GetAction("hit_action"); - this->m_hitEnemyAction = GetAction("hit_action_enemy"); - this->m_hitFactionAction = GetAction("hit_action_faction"); - this->m_Duration = GetFloat("duration"); - this->m_Forward = GetFloat("forward"); - this->m_Left = GetFloat("left"); - this->m_Yaw = GetFloat("yaw"); +void ForceMovementBehavior::Load() { + this->m_hitAction = GetAction("hit_action"); + this->m_hitEnemyAction = GetAction("hit_action_enemy"); + this->m_hitFactionAction = GetAction("hit_action_faction"); + this->m_Duration = GetFloat("duration"); + this->m_Forward = GetFloat("forward"); + this->m_Left = GetFloat("left"); + this->m_Yaw = GetFloat("yaw"); } void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); - if (casterEntity != nullptr) { - auto* controllablePhysicsComponent = casterEntity->GetComponent(); - if (controllablePhysicsComponent != nullptr) { + auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); + if (casterEntity != nullptr) { + auto* controllablePhysicsComponent = casterEntity->GetComponent(); + if (controllablePhysicsComponent != nullptr) { - controllablePhysicsComponent->SetPosition(controllablePhysicsComponent->GetPosition() + controllablePhysicsComponent->GetVelocity() * m_Duration); - controllablePhysicsComponent->SetVelocity({}); + controllablePhysicsComponent->SetPosition(controllablePhysicsComponent->GetPosition() + controllablePhysicsComponent->GetVelocity() * m_Duration); + controllablePhysicsComponent->SetVelocity({}); - EntityManager::Instance()->SerializeEntity(casterEntity); - } - } + EntityManager::Instance()->SerializeEntity(casterEntity); + } + } - this->m_hitAction->Calculate(context, bitStream, branch); - this->m_hitEnemyAction->Calculate(context, bitStream, branch); - this->m_hitEnemyAction->Calculate(context, bitStream, branch); + this->m_hitAction->Calculate(context, bitStream, branch); + this->m_hitEnemyAction->Calculate(context, bitStream, branch); + this->m_hitFactionAction->Calculate(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ForceMovementBehavior.h b/dGame/dBehaviors/ForceMovementBehavior.h index 50b0aa26..8d5fd9f4 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.h +++ b/dGame/dBehaviors/ForceMovementBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class ForceMovementBehavior final : public Behavior @@ -10,27 +10,26 @@ public: Behavior* m_hitFactionAction; - float_t m_Duration; - float_t m_Forward; - float_t m_Left; - float_t m_Yaw; - + float_t m_Duration; + float_t m_Forward; + float_t m_Left; + float_t m_Yaw; + /* * Inherited */ - explicit ForceMovementBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit ForceMovementBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Calculate(BehaviorContext *context, RakNet::BitStream *bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void SyncCalculation(BehaviorContext *context, RakNet::BitStream *bitStream, BehaviorBranchContext branch) override; + void SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; - + }; diff --git a/dGame/dBehaviors/HealBehavior.cpp b/dGame/dBehaviors/HealBehavior.cpp index eebf24f8..66fe2c79 100644 --- a/dGame/dBehaviors/HealBehavior.cpp +++ b/dGame/dBehaviors/HealBehavior.cpp @@ -1,42 +1,38 @@ -#include "HealBehavior.h" +#include "HealBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" #include "EntityManager.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" -void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); - if (entity == nullptr) - { - Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!\n", branch.target); + if (entity == nullptr) { + Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target); return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (destroyable == nullptr) - { - Game::logger->Log("HealBehavior", "Failed to find destroyable component for %(llu)!\n", branch.target); + if (destroyable == nullptr) { + Game::logger->Log("HealBehavior", "Failed to find destroyable component for %(llu)!", branch.target); return; } - + destroyable->Heal(this->m_health); } -void HealBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void HealBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } -void HealBehavior::Load() -{ +void HealBehavior::Load() { this->m_health = GetInt("health"); } diff --git a/dGame/dBehaviors/HealBehavior.h b/dGame/dBehaviors/HealBehavior.h index f5568551..e967135a 100644 --- a/dGame/dBehaviors/HealBehavior.h +++ b/dGame/dBehaviors/HealBehavior.h @@ -1,17 +1,16 @@ -#pragma once +#pragma once #include "Behavior.h" class HealBehavior final : public Behavior { public: uint32_t m_health; - + /* * Inherited */ - explicit HealBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit HealBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/ImaginationBehavior.cpp b/dGame/dBehaviors/ImaginationBehavior.cpp index d2d50fbe..59b192b0 100644 --- a/dGame/dBehaviors/ImaginationBehavior.cpp +++ b/dGame/dBehaviors/ImaginationBehavior.cpp @@ -1,4 +1,4 @@ -#include "ImaginationBehavior.h" +#include "ImaginationBehavior.h" #include "BehaviorBranchContext.h" #include "DestroyableComponent.h" #include "dpWorld.h" @@ -6,19 +6,16 @@ #include "dLogger.h" -void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); - if (entity == nullptr) - { + if (entity == nullptr) { return; } auto* destroyable = entity->GetComponent(); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { return; } @@ -26,12 +23,10 @@ void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi } -void ImaginationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void ImaginationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } -void ImaginationBehavior::Load() -{ +void ImaginationBehavior::Load() { this->m_imagination = GetInt("imagination"); } diff --git a/dGame/dBehaviors/ImaginationBehavior.h b/dGame/dBehaviors/ImaginationBehavior.h index 52a2c1b3..a35c2ddd 100644 --- a/dGame/dBehaviors/ImaginationBehavior.h +++ b/dGame/dBehaviors/ImaginationBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class ImaginationBehavior final : public Behavior @@ -10,8 +10,7 @@ public: * Inherited */ - explicit ImaginationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit ImaginationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/ImmunityBehavior.cpp b/dGame/dBehaviors/ImmunityBehavior.cpp index 73dde1fa..a5dd4c85 100644 --- a/dGame/dBehaviors/ImmunityBehavior.cpp +++ b/dGame/dBehaviors/ImmunityBehavior.cpp @@ -1,4 +1,4 @@ -#include "ImmunityBehavior.h" +#include "ImmunityBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" @@ -6,62 +6,112 @@ #include "Game.h" #include "dLogger.h" #include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" +#include "eStateChangeType.h" -void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", branch.target); - + if (!target) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); return; } - auto* destroyable = static_cast(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) - { - return; + auto* destroyableComponent = target->GetComponent(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); } - if (!this->m_immuneBasicAttack) - { - return; + auto* controllablePhysicsComponent = target->GetComponent(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PushImmunity(); - context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) -{ +void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(second); - if (target == nullptr) - { - Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!\n", second); - + if (!target) { + Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); return; } - auto* destroyable = static_cast(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) - { - return; + auto* destroyableComponent = target->GetComponent(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); + } + + auto* controllablePhysicsComponent = target->GetComponent(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PopImmunity(); } -void ImmunityBehavior::Load() -{ - this->m_immuneBasicAttack = GetBoolean("immune_basic_attack"); +void ImmunityBehavior::Load() { + //Stun + this->m_ImmuneToStunAttack = GetBoolean("immune_stun_attack", false); + this->m_ImmuneToStunEquip = GetBoolean("immune_stun_equip", false); + this->m_ImmuneToStunInteract = GetBoolean("immune_stun_interact", false); + this->m_ImmuneToStunMove = GetBoolean("immune_stun_move", false); + this->m_ImmuneToStunTurn = GetBoolean("immune_stun_rotate", false); + + // Status + this->m_ImmuneToBasicAttack = GetBoolean("immune_basic_attack", false); + this->m_ImmuneToDamageOverTime = GetBoolean("immune_damage_over_time", false); + this->m_ImmuneToKnockback = GetBoolean("immune_knockback", false); + this->m_ImmuneToInterrupt = GetBoolean("immune_interrupt", false); + this->m_ImmuneToSpeed = GetBoolean("immune_speed", false); + this->m_ImmuneToImaginationGain = GetBoolean("immune_imagination_gain", false); + this->m_ImmuneToImaginationLoss = GetBoolean("immune_imagination_loss", false); + this->m_ImmuneToQuickbuildInterrupt = GetBoolean("immune_quickbuild_interrupts", false); + this->m_ImmuneToPullToPoint = GetBoolean("immune_pulltopoint", false); } diff --git a/dGame/dBehaviors/ImmunityBehavior.h b/dGame/dBehaviors/ImmunityBehavior.h index 72ea843b..02cc0fae 100644 --- a/dGame/dBehaviors/ImmunityBehavior.h +++ b/dGame/dBehaviors/ImmunityBehavior.h @@ -1,17 +1,14 @@ -#pragma once +#pragma once #include "Behavior.h" class ImmunityBehavior final : public Behavior { public: - uint32_t m_immuneBasicAttack; - /* * Inherited */ - explicit ImmunityBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit ImmunityBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; @@ -21,4 +18,25 @@ public: void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void Load() override; + +private: + // stuns + bool m_ImmuneToStunAttack = false; + bool m_ImmuneToStunEquip = false; + bool m_ImmuneToStunInteract = false; + bool m_ImmuneToStunJump = false; // Unused + bool m_ImmuneToStunMove = false; + bool m_ImmuneToStunTurn = false; + bool m_ImmuneToStunUseItem = false; // Unused + + //status + bool m_ImmuneToBasicAttack = false; + bool m_ImmuneToDamageOverTime = false; + bool m_ImmuneToKnockback = false; + bool m_ImmuneToInterrupt = false; + bool m_ImmuneToSpeed = false; + bool m_ImmuneToImaginationGain = false; + bool m_ImmuneToImaginationLoss = false; + bool m_ImmuneToQuickbuildInterrupt = false; + bool m_ImmuneToPullToPoint = false; // Unused in cdclient, but used in client }; diff --git a/dGame/dBehaviors/InterruptBehavior.cpp b/dGame/dBehaviors/InterruptBehavior.cpp index 559a699d..9035c092 100644 --- a/dGame/dBehaviors/InterruptBehavior.cpp +++ b/dGame/dBehaviors/InterruptBehavior.cpp @@ -1,4 +1,4 @@ -#include "InterruptBehavior.h" +#include "InterruptBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "Game.h" @@ -7,22 +7,25 @@ #include "SkillComponent.h" -void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - if (branch.target != context->originator) - { +void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + if (branch.target != context->originator) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } - if (!this->m_interruptBlock) - { + if (!this->m_interruptBlock) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } @@ -31,7 +34,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } if (branch.target == context->originator) return; @@ -48,15 +54,12 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS } -void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - if (branch.target != context->originator) - { +void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + if (branch.target != context->originator) { bitStream->Write(false); } - if (!this->m_interruptBlock) - { + if (!this->m_interruptBlock) { bitStream->Write(false); } @@ -71,14 +74,13 @@ void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* b auto* skillComponent = target->GetComponent(); if (skillComponent == nullptr) return; - + skillComponent->Interrupt(); } -void InterruptBehavior::Load() -{ +void InterruptBehavior::Load() { this->m_target = GetBoolean("target"); - + this->m_interruptBlock = GetBoolean("interrupt_block"); } diff --git a/dGame/dBehaviors/InterruptBehavior.h b/dGame/dBehaviors/InterruptBehavior.h index b5e3b6f6..9ba272c7 100644 --- a/dGame/dBehaviors/InterruptBehavior.h +++ b/dGame/dBehaviors/InterruptBehavior.h @@ -1,24 +1,23 @@ -#pragma once +#pragma once #include "Behavior.h" class InterruptBehavior final : public Behavior { public: bool m_target; - + bool m_interruptBlock; /* * Inherited */ - explicit InterruptBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit InterruptBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/JetPackBehavior.cpp b/dGame/dBehaviors/JetPackBehavior.cpp index 63c0c6a9..e7d76560 100644 --- a/dGame/dBehaviors/JetPackBehavior.cpp +++ b/dGame/dBehaviors/JetPackBehavior.cpp @@ -3,27 +3,45 @@ #include "BehaviorBranchContext.h" #include "GameMessages.h" +#include "Character.h" + void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - + auto* entity = EntityManager::Instance()->GetEntity(branch.target); + GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID); + + if (entity->IsPlayer()) { + auto* character = entity->GetCharacter(); + + if (character) { + character->SetIsFlying(true); + } + } } void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { - auto* entity = EntityManager::Instance()->GetEntity(branch.target); + auto* entity = EntityManager::Instance()->GetEntity(branch.target); GameMessages::SendSetJetPackMode(entity, false); + + if (entity->IsPlayer()) { + auto* character = entity->GetCharacter(); + + if (character) { + character->SetIsFlying(false); + } + } } void JetPackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { - Handle(context, bit_stream, branch); + Handle(context, bit_stream, branch); } void JetPackBehavior::Load() { - this->m_WarningEffectID = GetInt("warning_effect_id"); - this->m_Airspeed = GetFloat("airspeed"); - this->m_MaxAirspeed = GetFloat("max_airspeed"); - this->m_VerticalVelocity = GetFloat("vertical_velocity"); - this->m_EnableHover = GetBoolean("enable_hover"); - this->m_BypassChecks = GetBoolean("bypass_checks", true); + this->m_WarningEffectID = GetInt("warning_effect_id"); + this->m_Airspeed = GetFloat("airspeed"); + this->m_MaxAirspeed = GetFloat("max_airspeed"); + this->m_VerticalVelocity = GetFloat("vertical_velocity"); + this->m_EnableHover = GetBoolean("enable_hover"); + this->m_BypassChecks = GetBoolean("bypass_checks", true); } diff --git a/dGame/dBehaviors/JetPackBehavior.h b/dGame/dBehaviors/JetPackBehavior.h index d891bf54..0cc6c399 100644 --- a/dGame/dBehaviors/JetPackBehavior.h +++ b/dGame/dBehaviors/JetPackBehavior.h @@ -1,7 +1,7 @@ #pragma once #include "Behavior.h" -class JetPackBehavior final : public Behavior +class JetPackBehavior final : public Behavior { public: int32_t m_WarningEffectID; diff --git a/dGame/dBehaviors/KnockbackBehavior.cpp b/dGame/dBehaviors/KnockbackBehavior.cpp index 37092536..1b878ed0 100644 --- a/dGame/dBehaviors/KnockbackBehavior.cpp +++ b/dGame/dBehaviors/KnockbackBehavior.cpp @@ -1,4 +1,4 @@ -#define _USE_MATH_DEFINES +#define _USE_MATH_DEFINES #include #include "KnockbackBehavior.h" #include "BehaviorBranchContext.h" @@ -6,26 +6,27 @@ #include "EntityManager.h" #include "GameMessages.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" -void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - bool unknown; +void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + bool unknown{}; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("KnockbackBehavior", "Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } -void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { bool blocked = false; auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target != nullptr) - { + if (target != nullptr) { auto* destroyableComponent = target->GetComponent(); - if (destroyableComponent != nullptr) - { + if (destroyableComponent != nullptr) { blocked = destroyableComponent->IsKnockbackImmune(); } } @@ -33,8 +34,7 @@ void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* b bitStream->Write(blocked); } -void KnockbackBehavior::Load() -{ +void KnockbackBehavior::Load() { this->m_strength = GetInt("strength"); this->m_angle = GetInt("angle"); this->m_relative = GetBoolean("relative"); diff --git a/dGame/dBehaviors/KnockbackBehavior.h b/dGame/dBehaviors/KnockbackBehavior.h index 0f939acd..c952bb41 100644 --- a/dGame/dBehaviors/KnockbackBehavior.h +++ b/dGame/dBehaviors/KnockbackBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class KnockbackBehavior final : public Behavior @@ -12,10 +12,9 @@ public: uint32_t m_angle; bool m_relative; uint32_t m_time; - - explicit KnockbackBehavior(const uint32_t behaviorID) : Behavior(behaviorID) - { + + explicit KnockbackBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/LootBuffBehavior.cpp b/dGame/dBehaviors/LootBuffBehavior.cpp index fe46f7bb..6e5634fc 100644 --- a/dGame/dBehaviors/LootBuffBehavior.cpp +++ b/dGame/dBehaviors/LootBuffBehavior.cpp @@ -1,38 +1,38 @@ #include "LootBuffBehavior.h" -void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto target = EntityManager::Instance()->GetEntity(context->caster); - if (!target) return; +void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto target = EntityManager::Instance()->GetEntity(context->caster); + if (!target) return; - auto controllablePhysicsComponent = target->GetComponent(); - if (!controllablePhysicsComponent) return; + auto controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - controllablePhysicsComponent->AddPickupRadiusScale(m_Scale); - EntityManager::Instance()->SerializeEntity(target); + controllablePhysicsComponent->AddPickupRadiusScale(m_Scale); + EntityManager::Instance()->SerializeEntity(target); - if (branch.duration > 0) context->RegisterTimerBehavior(this, branch); + if (branch.duration > 0) context->RegisterTimerBehavior(this, branch); } void LootBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - Handle(context, bitStream, branch); + Handle(context, bitStream, branch); } void LootBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { - auto target = EntityManager::Instance()->GetEntity(context->caster); - if (!target) return; + auto target = EntityManager::Instance()->GetEntity(context->caster); + if (!target) return; - auto controllablePhysicsComponent = target->GetComponent(); - if (!controllablePhysicsComponent) return; + auto controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - controllablePhysicsComponent->RemovePickupRadiusScale(m_Scale); - EntityManager::Instance()->SerializeEntity(target); + controllablePhysicsComponent->RemovePickupRadiusScale(m_Scale); + EntityManager::Instance()->SerializeEntity(target); } void LootBuffBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { - UnCast(context, branch); + UnCast(context, branch); } void LootBuffBehavior::Load() { - this->m_Scale = GetFloat("scale"); -} \ No newline at end of file + this->m_Scale = GetFloat("scale"); +} diff --git a/dGame/dBehaviors/LootBuffBehavior.h b/dGame/dBehaviors/LootBuffBehavior.h index 0f85b3b0..b6f700ca 100644 --- a/dGame/dBehaviors/LootBuffBehavior.h +++ b/dGame/dBehaviors/LootBuffBehavior.h @@ -6,7 +6,7 @@ /** * @brief This is the behavior class to be used for all Loot Buff behavior nodes in the Behavior tree. - * + * */ class LootBuffBehavior final : public Behavior { @@ -17,13 +17,13 @@ public: /* * Inherited */ - + explicit LootBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index a77b114e..0c11380f 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -1,26 +1,25 @@ -#include "MovementSwitchBehavior.h" +#include "MovementSwitchBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" -void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) - { +void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + uint32_t movementType{}; + if (!bitStream->Read(movementType)) { + if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_movingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + return; + } + Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; - } - - uint32_t movementType; + }; - bitStream->Read(movementType); - - switch (movementType) - { + switch (movementType) { case 1: this->m_groundAction->Handle(context, bitStream, branch); break; @@ -28,35 +27,40 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* this->m_jumpAction->Handle(context, bitStream, branch); break; case 3: - this->m_fallingAction->Handle(context, bitStream, branch); + this->m_airAction->Handle(context, bitStream, branch); break; case 4: this->m_doubleJumpAction->Handle(context, bitStream, branch); break; case 5: - this->m_airAction->Handle(context, bitStream, branch); + this->m_fallingAction->Handle(context, bitStream, branch); break; case 6: this->m_jetpackAction->Handle(context, bitStream, branch); break; default: - Game::logger->Log("MovementSwitchBehavior", "Invalid movement behavior type (%i)!\n", movementType); + this->m_groundAction->Handle(context, bitStream, branch); break; } } -void MovementSwitchBehavior::Load() -{ - this->m_airAction = GetAction("air_action"); - - this->m_doubleJumpAction = GetAction("double_jump_action"); - - this->m_fallingAction = GetAction("falling_action"); - - this->m_groundAction = GetAction("ground_action"); - - this->m_jetpackAction = GetAction("jetpack_action"); - - this->m_jumpAction = GetAction("jump_action"); +Behavior* MovementSwitchBehavior::LoadMovementType(std::string movementType) { + float actionValue = GetFloat(movementType, -1.0f); + auto loadedBehavior = GetAction(actionValue != -1.0f ? actionValue : 0.0f); + if (actionValue == -1.0f && loadedBehavior->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + loadedBehavior = this->m_groundAction; + } + return loadedBehavior; } +void MovementSwitchBehavior::Load() { + float groundActionValue = GetFloat("ground_action", -1.0f); + this->m_groundAction = GetAction(groundActionValue != -1.0f ? groundActionValue : 0.0f); + + this->m_airAction = LoadMovementType("air_action"); + this->m_doubleJumpAction = LoadMovementType("double_jump_action"); + this->m_fallingAction = LoadMovementType("falling_action"); + this->m_jetpackAction = LoadMovementType("jetpack_action"); + this->m_jumpAction = LoadMovementType("jump_action"); + this->m_movingAction = LoadMovementType("moving_action"); +} diff --git a/dGame/dBehaviors/MovementSwitchBehavior.h b/dGame/dBehaviors/MovementSwitchBehavior.h index 59069eff..e6ff96f6 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.h +++ b/dGame/dBehaviors/MovementSwitchBehavior.h @@ -1,14 +1,14 @@ -#pragma once +#pragma once #include "Behavior.h" class MovementSwitchBehavior final : public Behavior { -public: +private: /* * Members */ Behavior* m_airAction; - + Behavior* m_doubleJumpAction; Behavior* m_fallingAction; @@ -18,14 +18,24 @@ public: Behavior* m_jetpackAction; Behavior* m_jumpAction; - + + Behavior* m_movingAction; + + /** + * @brief Loads a movement type from the database into a behavior + * + * @param movementType The movement type to lookup in the database + * @param behaviorToLoad The Behavior where the result will be stored + */ + Behavior* LoadMovementType(std::string movementType); + +public: /* * Inherited */ - explicit MovementSwitchBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit MovementSwitchBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp index c2aff256..5a8d03cf 100644 --- a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp +++ b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp @@ -1,28 +1,23 @@ -#include "NpcCombatSkillBehavior.h" +#include "NpcCombatSkillBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void NpcCombatSkillBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void NpcCombatSkillBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { context->skillTime = this->m_npcSkillTime; - - for (auto* behavior : this->m_behaviors) - { + + for (auto* behavior : this->m_behaviors) { behavior->Calculate(context, bit_stream, branch); } } -void NpcCombatSkillBehavior::Load() -{ +void NpcCombatSkillBehavior::Load() { this->m_npcSkillTime = GetFloat("npc skill time"); - + const auto parameters = GetParameterNames(); - for (const auto& parameter : parameters) - { - if (parameter.first.rfind("behavior", 0) == 0) - { + for (const auto& parameter : parameters) { + if (parameter.first.rfind("behavior", 0) == 0) { auto* action = GetAction(parameter.second); this->m_behaviors.push_back(action); diff --git a/dGame/dBehaviors/NpcCombatSkillBehavior.h b/dGame/dBehaviors/NpcCombatSkillBehavior.h index a5523acd..19ff3483 100644 --- a/dGame/dBehaviors/NpcCombatSkillBehavior.h +++ b/dGame/dBehaviors/NpcCombatSkillBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class NpcCombatSkillBehavior final : public Behavior @@ -12,10 +12,9 @@ public: * Inherited */ - explicit NpcCombatSkillBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit NpcCombatSkillBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/OverTimeBehavior.cpp b/dGame/dBehaviors/OverTimeBehavior.cpp index 9e8618df..5afbbd26 100644 --- a/dGame/dBehaviors/OverTimeBehavior.cpp +++ b/dGame/dBehaviors/OverTimeBehavior.cpp @@ -6,44 +6,44 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "CDClientDatabase.h" +#include "CDClientManager.h" -void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - const auto originator = context->originator; +#include "CDSkillBehaviorTable.h" - auto* entity = EntityManager::Instance()->GetEntity(originator); +void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + const auto originator = context->originator; - if (entity == nullptr) return; + auto* entity = EntityManager::Instance()->GetEntity(originator); - for (size_t i = 0; i < m_NumIntervals; i++) - { - entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() { - auto* entity = EntityManager::Instance()->GetEntity(originator); + if (entity == nullptr) return; - if (entity == nullptr) return; + for (size_t i = 0; i < m_NumIntervals; i++) { + entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() { + auto* entity = EntityManager::Instance()->GetEntity(originator); - auto* skillComponent = entity->GetComponent(); + if (entity == nullptr) return; - if (skillComponent == nullptr) return; + auto* skillComponent = entity->GetComponent(); - skillComponent->CalculateBehavior(m_Action, m_ActionBehaviorId, branch.target, true, true); - }); - } + if (skillComponent == nullptr) return; + + skillComponent->CalculateBehavior(m_Action, m_ActionBehaviorId, branch.target, true, true); + }); + } } -void OverTimeBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - +void OverTimeBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + } -void OverTimeBehavior::Load() -{ - m_Action = GetInt("action"); - // Since m_Action is a skillID and not a behavior, get is correlated behaviorID. +void OverTimeBehavior::Load() { + m_Action = GetInt("action"); + // Since m_Action is a skillID and not a behavior, get is correlated behaviorID. - CDSkillBehaviorTable* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); - m_ActionBehaviorId = skillTable->GetSkillByID(m_Action).behaviorID; + CDSkillBehaviorTable* skillTable = CDClientManager::Instance().GetTable(); + m_ActionBehaviorId = skillTable->GetSkillByID(m_Action).behaviorID; - m_Delay = GetFloat("delay"); - m_NumIntervals = GetInt("num_intervals"); + m_Delay = GetFloat("delay"); + m_NumIntervals = GetInt("num_intervals"); } diff --git a/dGame/dBehaviors/OverTimeBehavior.h b/dGame/dBehaviors/OverTimeBehavior.h index 5c177926..73a07865 100644 --- a/dGame/dBehaviors/OverTimeBehavior.h +++ b/dGame/dBehaviors/OverTimeBehavior.h @@ -4,19 +4,18 @@ class OverTimeBehavior final : public Behavior { public: - uint32_t m_Action; + uint32_t m_Action; uint32_t m_ActionBehaviorId; - float m_Delay; - int32_t m_NumIntervals; + float m_Delay; + int32_t m_NumIntervals; /* * Inherited */ - explicit OverTimeBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit OverTimeBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/PlayEffectBehavior.cpp b/dGame/dBehaviors/PlayEffectBehavior.cpp index 20148132..acd606a9 100644 --- a/dGame/dBehaviors/PlayEffectBehavior.cpp +++ b/dGame/dBehaviors/PlayEffectBehavior.cpp @@ -1,10 +1,9 @@ -#include "PlayEffectBehavior.h" +#include "PlayEffectBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { // On managed behaviors this is handled by the client if (!context->unmanaged) return; @@ -14,13 +13,11 @@ void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit PlayFx(u"", target); } -void PlayEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void PlayEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto& target = branch.target == LWOOBJID_EMPTY ? context->originator : branch.target; //PlayFx(u"", target); } -void PlayEffectBehavior::Load() -{ +void PlayEffectBehavior::Load() { } diff --git a/dGame/dBehaviors/PlayEffectBehavior.h b/dGame/dBehaviors/PlayEffectBehavior.h index 3f49f38c..5ef49161 100644 --- a/dGame/dBehaviors/PlayEffectBehavior.h +++ b/dGame/dBehaviors/PlayEffectBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class PlayEffectBehavior final : public Behavior @@ -7,13 +7,12 @@ public: /* * Inherited */ - explicit PlayEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit PlayEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Load() override; }; diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index 905a630c..f65421cb 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -1,4 +1,4 @@ -#include "ProjectileAttackBehavior.h" +#include "ProjectileAttackBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" @@ -6,45 +6,50 @@ #include "dLogger.h" #include "SkillComponent.h" #include "../dWorldServer/ObjectIDManager.h" +#include "eObjectBits.h" -void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - LWOOBJID target; +void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + LWOOBJID target{}; + + if (!bitStream->Read(target)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; - bitStream->Read(target); - auto* entity = EntityManager::Instance()->GetEntity(context->originator); - if (entity == nullptr) - { - Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!\n", context->originator); + if (entity == nullptr) { + Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); return; } auto* skillComponent = entity->GetComponent(); - if (skillComponent == nullptr) - { - Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!\n", -context->originator); + if (skillComponent == nullptr) { + Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", -context->originator); return; } - if (m_useMouseposit) - { + if (m_useMouseposit && !branch.isSync) { NiPoint3 targetPosition = NiPoint3::ZERO; - bitStream->Read(targetPosition); + if (!bitStream->Read(targetPosition)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } auto* targetEntity = EntityManager::Instance()->GetEntity(target); - for (auto i = 0u; i < this->m_projectileCount; ++i) - { - LWOOBJID projectileId; + for (auto i = 0u; i < this->m_projectileCount; ++i) { + LWOOBJID projectileId{}; + + if (!bitStream->Read(projectileId)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; - bitStream->Read(projectileId); - branch.target = target; branch.isProjectile = true; branch.referencePosition = targetEntity == nullptr ? entity->GetPosition() : targetEntity->GetPosition(); @@ -53,24 +58,21 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea } } -void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { bitStream->Write(branch.target); auto* entity = EntityManager::Instance()->GetEntity(context->originator); - if (entity == nullptr) - { - Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!\n", context->originator); + if (entity == nullptr) { + Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); return; } auto* skillComponent = entity->GetComponent(); - if (skillComponent == nullptr) - { - Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!\n", context->originator); + if (skillComponent == nullptr) { + Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", context->originator); return; @@ -78,10 +80,9 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt auto* other = EntityManager::Instance()->GetEntity(branch.target); - if (other == nullptr) - { - Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!\n", branch.target); - + if (other == nullptr) { + Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target); + return; } @@ -104,11 +105,10 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt const auto maxTime = this->m_maxDistance / this->m_projectileSpeed; - for (auto i = 0u; i < this->m_projectileCount; ++i) - { + for (auto i = 0u; i < this->m_projectileCount; ++i) { auto id = static_cast(ObjectIDManager::Instance()->GenerateObjectID()); - id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT); + GeneralUtils::SetBit(id, eObjectBits::SPAWNED); bitStream->Write(id); @@ -128,25 +128,20 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt skillComponent->RegisterCalculatedProjectile(id, context, branch, this->m_lot, maxTime, position, direction * this->m_projectileSpeed, this->m_trackTarget, this->m_trackRadius); // No idea how to calculate this properly - if (this->m_projectileCount == 2) - { + if (this->m_projectileCount == 2) { angle += angleDelta; - } - else if (this->m_projectileCount == 3) - { + } else if (this->m_projectileCount == 3) { angle += angleStep; } } } -void ProjectileAttackBehavior::Load() -{ +void ProjectileAttackBehavior::Load() { this->m_lot = GetInt("LOT_ID"); this->m_projectileCount = GetInt("spread_count"); - if (this->m_projectileCount == 0) - { + if (this->m_projectileCount == 0) { this->m_projectileCount = 1; } @@ -163,4 +158,6 @@ void ProjectileAttackBehavior::Load() this->m_trackRadius = GetFloat("track_radius"); this->m_useMouseposit = GetBoolean("use_mouseposit"); + + this->m_ProjectileType = GetInt("projectile_type"); } diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.h b/dGame/dBehaviors/ProjectileAttackBehavior.h index 9d40e97c..b307e66c 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.h +++ b/dGame/dBehaviors/ProjectileAttackBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" #include "NiPoint3.h" @@ -23,12 +23,13 @@ public: bool m_useMouseposit; + int32_t m_ProjectileType; + /* * Inherited */ - explicit ProjectileAttackBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit ProjectileAttackBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.cpp b/dGame/dBehaviors/PropertyTeleportBehavior.cpp new file mode 100644 index 00000000..447b085b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.cpp @@ -0,0 +1,61 @@ +#include "PropertyTeleportBehavior.h" + +#include "BehaviorBranchContext.h" +#include "BehaviorContext.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "ChatPackets.h" +#include "WorldPackets.h" +#include "EntityManager.h" +#include "Game.h" +#include "ZoneInstanceManager.h" +#include "dZoneManager.h" + +void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* caster = EntityManager::Instance()->GetEntity(context->caster); + if (!caster) return; + + auto* character = caster->GetCharacter(); + if (!character) return; + + LWOOBJID objId = caster->GetObjectID(); + + LWOMAPID targetMapId = m_MapId; + LWOCLONEID targetCloneId = character->GetPropertyCloneID(); + + if (dZoneManager::Instance()->GetZoneID().GetCloneID() == character->GetPropertyCloneID()) { + targetMapId = character->GetLastNonInstanceZoneID(); + targetCloneId = 0; + } else { + character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZoneID().GetMapID()); + } + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, targetMapId, targetCloneId, false, [objId](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + + auto* entity = EntityManager::Instance()->GetEntity(objId); + if (!entity) return; + + const auto sysAddr = entity->GetSystemAddress(); + + if (zoneClone != 0) ChatPackets::SendSystemMessage(sysAddr, u"Transfering to your property!"); + else ChatPackets::SendSystemMessage(sysAddr, u"Transfering back to previous world!"); + + Game::logger->Log("PropertyTeleportBehavior", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent()->SetLastRocketConfig(u""); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + return; + }); +} + +void PropertyTeleportBehavior::Load() { + this->m_CancelIfInteracting = GetBoolean("cancel_if_interacting"); // TODO unused + this->m_MapId = LWOMAPID(GetInt("mapID")); +} diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.h b/dGame/dBehaviors/PropertyTeleportBehavior.h new file mode 100644 index 00000000..74eed03b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.h @@ -0,0 +1,21 @@ +#pragma once +#include "Behavior.h" + +class PropertyTeleportBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit PropertyTeleportBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; + +private: + LWOMAPID m_MapId; + bool m_CancelIfInteracting; +}; diff --git a/dGame/dBehaviors/PullToPointBehavior.cpp b/dGame/dBehaviors/PullToPointBehavior.cpp index 8b87cbfb..7427ccc4 100644 --- a/dGame/dBehaviors/PullToPointBehavior.cpp +++ b/dGame/dBehaviors/PullToPointBehavior.cpp @@ -1,25 +1,22 @@ -#include "PullToPointBehavior.h" +#include "PullToPointBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" #include "EntityManager.h" #include "MovementAIComponent.h" -void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(context->originator); - + auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (entity == nullptr || target == nullptr) - { + if (entity == nullptr || target == nullptr) { return; } - + auto* movement = target->GetComponent(); - if (movement == nullptr) - { + if (movement == nullptr) { return; } @@ -28,11 +25,9 @@ void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi movement->PullToPoint(position); } -void PullToPointBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void PullToPointBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void PullToPointBehavior::Load() -{ +void PullToPointBehavior::Load() { } diff --git a/dGame/dBehaviors/PullToPointBehavior.h b/dGame/dBehaviors/PullToPointBehavior.h index ecd50bab..d448ad8d 100644 --- a/dGame/dBehaviors/PullToPointBehavior.h +++ b/dGame/dBehaviors/PullToPointBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class PullToPointBehavior final : public Behavior @@ -9,8 +9,7 @@ public: * Inherited */ - explicit PullToPointBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit PullToPointBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/RemoveBuffBehavior.cpp b/dGame/dBehaviors/RemoveBuffBehavior.cpp new file mode 100644 index 00000000..be3066ac --- /dev/null +++ b/dGame/dBehaviors/RemoveBuffBehavior.cpp @@ -0,0 +1,21 @@ +#include "RemoveBuffBehavior.h" + +#include "BehaviorBranchContext.h" +#include "BehaviorContext.h" +#include "EntityManager.h" +#include "BuffComponent.h" + +void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* entity = EntityManager::Instance()->GetEntity(context->caster); + if (!entity) return; + + auto* buffComponent = entity->GetComponent(); + if (!buffComponent) return; + + buffComponent->RemoveBuff(m_BuffId, false, m_RemoveImmunity); +} + +void RemoveBuffBehavior::Load() { + this->m_RemoveImmunity = GetBoolean("remove_immunity"); + this->m_BuffId = GetInt("buff_id"); +} diff --git a/dGame/dBehaviors/RemoveBuffBehavior.h b/dGame/dBehaviors/RemoveBuffBehavior.h new file mode 100644 index 00000000..f2d8547b --- /dev/null +++ b/dGame/dBehaviors/RemoveBuffBehavior.h @@ -0,0 +1,22 @@ +#pragma once +#include "Behavior.h" + +class RemoveBuffBehavior final : public Behavior +{ +public: + + /* + * Inherited + */ + + explicit RemoveBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; + +private: + bool m_RemoveImmunity; + uint32_t m_BuffId; +}; diff --git a/dGame/dBehaviors/RepairBehavior.cpp b/dGame/dBehaviors/RepairBehavior.cpp index 1a418cae..ce2e5fd2 100644 --- a/dGame/dBehaviors/RepairBehavior.cpp +++ b/dGame/dBehaviors/RepairBehavior.cpp @@ -1,40 +1,36 @@ -#include "RepairBehavior.h" +#include "RepairBehavior.h" #include "BehaviorBranchContext.h" #include "DestroyableComponent.h" #include "dpWorld.h" #include "EntityManager.h" #include "dLogger.h" #include "Game.h" +#include "eReplicaComponentType.h" -void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); - if (entity == nullptr) - { - Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!\n", branch.target); + if (entity == nullptr) { + Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!", branch.target); return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (destroyable == nullptr) - { - Game::logger->Log("RepairBehavior", "Failed to find destroyable component for %(llu)!\n", branch.target); + if (destroyable == nullptr) { + Game::logger->Log("RepairBehavior", "Failed to find destroyable component for %(llu)!", branch.target); return; } - + destroyable->Repair(this->m_armor); } -void RepairBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) -{ +void RepairBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } -void RepairBehavior::Load() -{ +void RepairBehavior::Load() { this->m_armor = GetInt("armor"); } diff --git a/dGame/dBehaviors/RepairBehavior.h b/dGame/dBehaviors/RepairBehavior.h index 46ca6bfb..8d2f14e4 100644 --- a/dGame/dBehaviors/RepairBehavior.h +++ b/dGame/dBehaviors/RepairBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class RepairBehavior final : public Behavior @@ -10,8 +10,7 @@ public: * Inherited */ - explicit RepairBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit RepairBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/SkillCastFailedBehavior.cpp b/dGame/dBehaviors/SkillCastFailedBehavior.cpp index ef8ba3e1..a663e709 100644 --- a/dGame/dBehaviors/SkillCastFailedBehavior.cpp +++ b/dGame/dBehaviors/SkillCastFailedBehavior.cpp @@ -1,18 +1,15 @@ -#include "SkillCastFailedBehavior.h" +#include "SkillCastFailedBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void SkillCastFailedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SkillCastFailedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { context->failed = true; } -void SkillCastFailedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SkillCastFailedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { context->failed = true; } -void SkillCastFailedBehavior::Load() -{ +void SkillCastFailedBehavior::Load() { } diff --git a/dGame/dBehaviors/SkillCastFailedBehavior.h b/dGame/dBehaviors/SkillCastFailedBehavior.h index cdd2adb4..5359cb42 100644 --- a/dGame/dBehaviors/SkillCastFailedBehavior.h +++ b/dGame/dBehaviors/SkillCastFailedBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class SkillCastFailedBehavior final : public Behavior @@ -8,12 +8,11 @@ public: /* * Inherited */ - explicit SkillCastFailedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit SkillCastFailedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/SkillEventBehavior.cpp b/dGame/dBehaviors/SkillEventBehavior.cpp index 35a9aa6f..837d70c9 100644 --- a/dGame/dBehaviors/SkillEventBehavior.cpp +++ b/dGame/dBehaviors/SkillEventBehavior.cpp @@ -4,25 +4,25 @@ #include "EntityManager.h" #include "CppScripts.h" -void SkillEventBehavior::Handle(BehaviorContext *context, RakNet::BitStream *bitStream, BehaviorBranchContext branch) { - auto* target = EntityManager::Instance()->GetEntity(branch.target); - auto* caster = EntityManager::Instance()->GetEntity(context->originator); +void SkillEventBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + auto* caster = EntityManager::Instance()->GetEntity(context->originator); - if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { - script->OnSkillEventFired(target, caster, *this->m_effectHandle); - } - } + if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { + script->OnSkillEventFired(target, caster, *this->m_effectHandle); + } + } } void -SkillEventBehavior::Calculate(BehaviorContext *context, RakNet::BitStream *bitStream, BehaviorBranchContext branch) { - auto* target = EntityManager::Instance()->GetEntity(branch.target); - auto* caster = EntityManager::Instance()->GetEntity(context->originator); +SkillEventBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + auto* caster = EntityManager::Instance()->GetEntity(context->originator); - if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { - script->OnSkillEventFired(target, caster, *this->m_effectHandle); - } - } + if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { + script->OnSkillEventFired(target, caster, *this->m_effectHandle); + } + } } diff --git a/dGame/dBehaviors/SkillEventBehavior.h b/dGame/dBehaviors/SkillEventBehavior.h index 720cd440..540f6d4a 100644 --- a/dGame/dBehaviors/SkillEventBehavior.h +++ b/dGame/dBehaviors/SkillEventBehavior.h @@ -6,10 +6,10 @@ */ class SkillEventBehavior final : public Behavior { public: - explicit SkillEventBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { - } + explicit SkillEventBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { + } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext *context, RakNet::BitStream *bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; }; diff --git a/dGame/dBehaviors/SpawnBehavior.cpp b/dGame/dBehaviors/SpawnBehavior.cpp index 800eb86d..75c84f6c 100644 --- a/dGame/dBehaviors/SpawnBehavior.cpp +++ b/dGame/dBehaviors/SpawnBehavior.cpp @@ -1,4 +1,4 @@ -#include "SpawnBehavior.h" +#include "SpawnBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" @@ -7,28 +7,27 @@ #include "dLogger.h" #include "DestroyableComponent.h" #include "RebuildComponent.h" +#include "Entity.h" +#include "EntityInfo.h" +#include "eReplicaComponentType.h" -void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* origin = EntityManager::Instance()->GetEntity(context->originator); - if (origin == nullptr) - { - Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!\n", context->originator); + if (origin == nullptr) { + Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!", context->originator); return; } - if (branch.isProjectile) - { + if (branch.isProjectile) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target != nullptr) - { + if (target != nullptr) { origin = target; } } - + EntityInfo info; info.lot = this->m_lot; info.pos = origin->GetPosition(); @@ -42,12 +41,11 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea auto* entity = EntityManager::Instance()->CreateEntity( info, nullptr, - EntityManager::Instance()->GetEntity(context->originator) + EntityManager::Instance()->GetEntity(context->originator) ); - if (entity == nullptr) - { - Game::logger->Log("SpawnBehavior", "Failed to spawn entity (%i)!\n", this->m_lot); + if (entity == nullptr) { + Game::logger->Log("SpawnBehavior", "Failed to spawn entity (%i)!", this->m_lot); return; } @@ -57,64 +55,55 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea // Unset the flag to reposition the player, this makes it harder to glitch out of the map auto* rebuildComponent = entity->GetComponent(); - if (rebuildComponent != nullptr) - { + if (rebuildComponent != nullptr) { rebuildComponent->SetRepositionPlayer(false); } - + EntityManager::Instance()->ConstructEntity(entity); - if (branch.duration > 0) - { + if (branch.duration > 0) { context->RegisterTimerBehavior(this, branch, entity->GetObjectID()); } - if (branch.start != 0) - { + if (branch.start != 0) { context->RegisterEndBehavior(this, branch, entity->GetObjectID()); } - entity->AddCallbackTimer(60, [entity] () { + entity->AddCallbackTimer(60, [entity]() { entity->Smash(); - }); + }); } -void SpawnBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SpawnBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } -void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) -{ +void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) { auto* entity = EntityManager::Instance()->GetEntity(second); - if (entity == nullptr) - { - Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!\n", second); + if (entity == nullptr) { + Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!", second); return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (destroyable == nullptr) - { + if (destroyable == nullptr) { entity->Smash(context->originator); - + return; } destroyable->Smash(second); } -void SpawnBehavior::End(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) -{ +void SpawnBehavior::End(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) { Timer(context, branch, second); } -void SpawnBehavior::Load() -{ +void SpawnBehavior::Load() { this->m_lot = GetInt("LOT_ID"); this->m_Distance = GetFloat("distance"); } diff --git a/dGame/dBehaviors/SpawnBehavior.h b/dGame/dBehaviors/SpawnBehavior.h index a4adbcad..875e0a2b 100644 --- a/dGame/dBehaviors/SpawnBehavior.h +++ b/dGame/dBehaviors/SpawnBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class SpawnBehavior final : public Behavior @@ -6,21 +6,20 @@ class SpawnBehavior final : public Behavior public: LOT m_lot; float m_Distance; - + /* * Inherited */ - explicit SpawnBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit SpawnBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; - + void Load() override; -}; \ No newline at end of file +}; diff --git a/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp b/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp index 3072d53c..514ae27a 100644 --- a/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp +++ b/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp @@ -1,13 +1,10 @@ -#include "SpawnQuickbuildBehavior.h" +#include "SpawnQuickbuildBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void SpawnQuickbuildBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SpawnQuickbuildBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } -void SpawnQuickbuildBehavior::Load() -{ +void SpawnQuickbuildBehavior::Load() { } - \ No newline at end of file diff --git a/dGame/dBehaviors/SpawnQuickbuildBehavior.h b/dGame/dBehaviors/SpawnQuickbuildBehavior.h index 2172d25e..653c60e8 100644 --- a/dGame/dBehaviors/SpawnQuickbuildBehavior.h +++ b/dGame/dBehaviors/SpawnQuickbuildBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class SpawnQuickbuildBehavior final : public Behavior @@ -8,8 +8,7 @@ public: /* * Inherited */ - explicit SpawnQuickbuildBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit SpawnQuickbuildBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index 73bc9029..d326aa45 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -6,101 +6,49 @@ #include "dLogger.h" -void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - if (m_AffectsCaster) - { - branch.target = context->caster; - } +void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + if (m_AffectsCaster) branch.target = context->caster; auto* target = EntityManager::Instance()->GetEntity(branch.target); + if (!target) return; - if (target == nullptr) - { - return; - } + auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - auto* controllablePhysicsComponent = target->GetComponent(); + controllablePhysicsComponent->AddSpeedboost(m_RunSpeed); + EntityManager::Instance()->SerializeEntity(target); - if (controllablePhysicsComponent == nullptr) - { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); - - if (branch.duration > 0.0f) - { - context->RegisterTimerBehavior(this, branch); - } - else if (branch.start > 0) - { - controllablePhysicsComponent->SetIgnoreMultipliers(true); - - context->RegisterEndBehavior(this, branch); - } + if (branch.duration > 0.0f) { + context->RegisterTimerBehavior(this, branch); + } else if (branch.start > 0) { + context->RegisterEndBehavior(this, branch); + } } -void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ - auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) - { - return; - } - - auto* controllablePhysicsComponent = target->GetComponent(); - - if (controllablePhysicsComponent == nullptr) - { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); +void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); } -void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) -{ - auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) - { - return; - } - - auto* controllablePhysicsComponent = target->GetComponent(); - - if (controllablePhysicsComponent == nullptr) - { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetIgnoreMultipliers(false); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); +void SpeedBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { + End(context, branch, LWOOBJID_EMPTY); } -void SpeedBehavior::Load() -{ - m_RunSpeed = GetFloat("run_speed"); - - if (m_RunSpeed < 500.0f) - { - m_RunSpeed = 500.0f; - } - - m_AffectsCaster = GetBoolean("affects_caster"); +void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + +void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + if (!target) return; + + auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; + + controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed); + EntityManager::Instance()->SerializeEntity(target); +} + +void SpeedBehavior::Load() { + m_RunSpeed = GetFloat("run_speed"); + m_AffectsCaster = GetBoolean("affects_caster"); } diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 9b8aa688..88b85820 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -8,20 +8,23 @@ public: /* * Inherited */ - explicit SpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit SpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - - void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; - void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + + void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void Load() override; private: - float m_RunSpeed; + float m_RunSpeed; - bool m_AffectsCaster; + bool m_AffectsCaster; }; diff --git a/dGame/dBehaviors/StartBehavior.cpp b/dGame/dBehaviors/StartBehavior.cpp index af03c333..2bcaf325 100644 --- a/dGame/dBehaviors/StartBehavior.cpp +++ b/dGame/dBehaviors/StartBehavior.cpp @@ -1,21 +1,18 @@ -#include "StartBehavior.h" +#include "StartBehavior.h" #include "BehaviorBranchContext.h" -void StartBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void StartBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { branch.start = this->m_behaviorId; - + this->m_action->Handle(context, bit_stream, branch); } -void StartBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void StartBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { branch.start = this->m_behaviorId; this->m_action->Calculate(context, bit_stream, branch); } -void StartBehavior::Load() -{ +void StartBehavior::Load() { this->m_action = GetAction("action"); } diff --git a/dGame/dBehaviors/StartBehavior.h b/dGame/dBehaviors/StartBehavior.h index d93526f6..384fe64a 100644 --- a/dGame/dBehaviors/StartBehavior.h +++ b/dGame/dBehaviors/StartBehavior.h @@ -1,17 +1,16 @@ -#pragma once +#pragma once #include "Behavior.h" class StartBehavior final : public Behavior { public: Behavior* m_action; - + /* * Inherited */ - explicit StartBehavior(const uint32_t behaviorID) : Behavior(behaviorID) - { + explicit StartBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/StunBehavior.cpp b/dGame/dBehaviors/StunBehavior.cpp index 994295bd..4e34d3a2 100644 --- a/dGame/dBehaviors/StunBehavior.cpp +++ b/dGame/dBehaviors/StunBehavior.cpp @@ -1,4 +1,4 @@ -#include "StunBehavior.h" +#include "StunBehavior.h" #include "BaseCombatAIComponent.h" #include "BehaviorBranchContext.h" @@ -7,22 +7,24 @@ #include "Game.h" #include "dLogger.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" -void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { if (this->m_stunCaster || branch.target == context->originator) { return; } - bool blocked; - bitStream->Read(blocked); + bool blocked{}; + if (!bitStream->Read(blocked)) { + Game::logger->Log("StunBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("StunBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target); return; } @@ -30,26 +32,22 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream /* * If our target is an enemy we can go ahead and stun it. */ - - auto* combatAiComponent = static_cast(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); - if (combatAiComponent == nullptr) - { + auto* combatAiComponent = static_cast(target->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); + + if (combatAiComponent == nullptr) { return; } combatAiComponent->Stun(branch.duration); } -void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ - if (this->m_stunCaster || branch.target == context->originator) - { +void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + if (this->m_stunCaster || branch.target == context->originator) { auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) - { - Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!\n", context->originator); + if (self == nullptr) { + Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!", context->originator); return; } @@ -57,16 +55,15 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr /* * See if we can stun ourselves */ - - auto* combatAiComponent = static_cast(self->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); - if (combatAiComponent == nullptr) - { + auto* combatAiComponent = static_cast(self->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); + + if (combatAiComponent == nullptr) { return; } combatAiComponent->Stun(branch.duration); - + return; } @@ -74,21 +71,18 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target != nullptr) - { + if (target != nullptr) { auto* destroyableComponent = target->GetComponent(); - if (destroyableComponent != nullptr) - { + if (destroyableComponent != nullptr) { blocked = destroyableComponent->IsKnockbackImmune(); } } bitStream->Write(blocked); - if (target == nullptr) - { - Game::logger->Log("StunBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target); return; } @@ -97,17 +91,15 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr * If our target is an enemy we can go ahead and stun it. */ - auto* combatAiComponent = static_cast(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + auto* combatAiComponent = static_cast(target->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); - if (combatAiComponent == nullptr) - { + if (combatAiComponent == nullptr) { return; } combatAiComponent->Stun(branch.duration); } -void StunBehavior::Load() -{ +void StunBehavior::Load() { this->m_stunCaster = GetBoolean("stun_caster"); } diff --git a/dGame/dBehaviors/StunBehavior.h b/dGame/dBehaviors/StunBehavior.h index 0ec36129..f4851b47 100644 --- a/dGame/dBehaviors/StunBehavior.h +++ b/dGame/dBehaviors/StunBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class StunBehavior final : public Behavior @@ -9,10 +9,9 @@ public: /* * Inherited */ - explicit StunBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit StunBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index d6cb1438..c010f31b 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -1,4 +1,4 @@ -#include "SwitchBehavior.h" +#include "SwitchBehavior.h" #include "BehaviorBranchContext.h" #include "EntityManager.h" #include "dLogger.h" @@ -6,57 +6,49 @@ #include "BehaviorContext.h" #include "BuffComponent.h" -void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) -{ +void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto state = true; - if (this->m_imagination > 0 || !this->m_isEnemyFaction) - { - bitStream->Read(state); + if (this->m_imagination > 0 || !this->m_isEnemyFaction) { + if (!bitStream->Read(state)) { + Game::logger->Log("SwitchBehavior", "Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } - auto* entity = EntityManager::Instance()->GetEntity(context->originator); + auto* entity = EntityManager::Instance()->GetEntity(context->originator); - if (entity == nullptr) - { - return; - } - - auto* destroyableComponent = entity->GetComponent(); - - if (destroyableComponent == nullptr) - { + if (entity == nullptr) { return; } - Game::logger->Log("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)\n", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); + auto* destroyableComponent = entity->GetComponent(); - if (state || (entity->GetLOT() == 8092 && destroyableComponent->GetImagination() >= m_imagination)) - { - this->m_actionTrue->Handle(context, bitStream, branch); + if (destroyableComponent == nullptr) { + return; } - else - { + + Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); + + if (state || (entity->GetLOT() == 8092 && destroyableComponent->GetImagination() >= m_imagination)) { + this->m_actionTrue->Handle(context, bitStream, branch); + } else { this->m_actionFalse->Handle(context, bitStream, branch); } } -void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto state = true; - - if (this->m_imagination > 0 || !this->m_isEnemyFaction) - { + + if (this->m_imagination > 0 || !this->m_isEnemyFaction) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); state = entity != nullptr; - if (state && m_targetHasBuff != 0) - { - auto* buffComponent = entity->GetComponent(); + if (state && m_targetHasBuff != 0) { + auto* buffComponent = entity->GetComponent(); - if (buffComponent != nullptr && !buffComponent->HasBuff(m_targetHasBuff)) - { + if (buffComponent != nullptr && !buffComponent->HasBuff(m_targetHasBuff)) { state = false; } } @@ -64,24 +56,20 @@ void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS bitStream->Write(state); } - if (state) - { + if (state) { this->m_actionTrue->Calculate(context, bitStream, branch); - } - else - { + } else { this->m_actionFalse->Calculate(context, bitStream, branch); } } -void SwitchBehavior::Load() -{ +void SwitchBehavior::Load() { this->m_actionTrue = GetAction("action_true"); - + this->m_actionFalse = GetAction("action_false"); - + this->m_imagination = GetInt("imagination"); - + this->m_isEnemyFaction = GetBoolean("isEnemyFaction"); this->m_targetHasBuff = GetInt("target_has_buff"); diff --git a/dGame/dBehaviors/SwitchBehavior.h b/dGame/dBehaviors/SwitchBehavior.h index 8dc43e71..5e40d659 100644 --- a/dGame/dBehaviors/SwitchBehavior.h +++ b/dGame/dBehaviors/SwitchBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class SwitchBehavior final : public Behavior @@ -13,13 +13,12 @@ public: bool m_isEnemyFaction; int32_t m_targetHasBuff; - + /* * Inherited */ - explicit SwitchBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit SwitchBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index 93662060..23411429 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -1,4 +1,4 @@ -#include "SwitchMultipleBehavior.h" +#include "SwitchMultipleBehavior.h" #include @@ -9,33 +9,30 @@ #include "EntityManager.h" -void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ - float value; +void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + float value{}; + + if (!bitStream->Read(value)) { + Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; - bit_stream->Read(value); - uint32_t trigger = 0; for (unsigned int i = 0; i < this->m_behaviors.size(); i++) { - - const double data = this->m_behaviors.at(i).first; - - if (value <= data) { - - trigger = i; - break; - } + const double data = this->m_behaviors.at(i).first; + trigger = i; + + if (value <= data) break; } auto* behavior = this->m_behaviors.at(trigger).second; - behavior->Handle(context, bit_stream, branch); + behavior->Handle(context, bitStream, branch); } -void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { // TODO } @@ -45,7 +42,7 @@ void SwitchMultipleBehavior::Load() { "(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = ?1 AND bP2.parameterID LIKE 'value %' " "AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value " "FROM BehaviorParameter bP1 WHERE bP1.behaviorID = ?1 AND bP1.parameterID LIKE 'behavior %';"); - query.bind(1, (int) this->m_behaviorId); + query.bind(1, (int)this->m_behaviorId); auto result = query.execQuery(); @@ -57,7 +54,7 @@ void SwitchMultipleBehavior::Load() { auto value = result.getFloatField(2); this->m_behaviors.emplace_back(value, behavior); - + result.nextRow(); } } diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.h b/dGame/dBehaviors/SwitchMultipleBehavior.h index c25049ae..1e3dfe64 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.h +++ b/dGame/dBehaviors/SwitchMultipleBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" #include @@ -7,13 +7,12 @@ class SwitchMultipleBehavior final : public Behavior { public: std::vector> m_behaviors; - + /* * Inherited */ - explicit SwitchMultipleBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit SwitchMultipleBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/TacArcBehavior.cpp b/dGame/dBehaviors/TacArcBehavior.cpp index 46ec03b9..91df3879 100644 --- a/dGame/dBehaviors/TacArcBehavior.cpp +++ b/dGame/dBehaviors/TacArcBehavior.cpp @@ -1,4 +1,4 @@ -#include "TacArcBehavior.h" +#include "TacArcBehavior.h" #include "BehaviorBranchContext.h" #include "Game.h" #include "dLogger.h" @@ -11,10 +11,8 @@ #include -void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - if (this->m_targetEnemy && this->m_usePickedTarget && branch.target > 0) - { +void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + if (this->m_targetEnemy && this->m_usePickedTarget && branch.target > 0) { this->m_action->Handle(context, bitStream, branch); return; @@ -22,87 +20,89 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre bool hit = false; - bitStream->Read(hit); + if (!bitStream->Read(hit)) { + Game::logger->Log("TacArcBehavior", "Unable to read hit from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; - if (this->m_checkEnv) - { + if (this->m_checkEnv) { bool blocked = false; - - bitStream->Read(blocked); - if (blocked) - { + if (!bitStream->Read(blocked)) { + Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; + + if (blocked) { this->m_blockedAction->Handle(context, bitStream, branch); return; } } - if (hit) - { + if (hit) { uint32_t count = 0; - bitStream->Read(count); + if (!bitStream->Read(count)) { + Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; - if (count > m_maxTargets && m_maxTargets > 0) - { + if (count > m_maxTargets && m_maxTargets > 0) { count = m_maxTargets; } std::vector targets; - for (auto i = 0u; i < count; ++i) - { - LWOOBJID id; + for (auto i = 0u; i < count; ++i) { + LWOOBJID id{}; - bitStream->Read(id); + if (!bitStream->Read(id)) { + Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; targets.push_back(id); } - for (auto target : targets) - { + for (auto target : targets) { branch.target = target; - + this->m_action->Handle(context, bitStream, branch); } - } - else - { + } else { this->m_missAction->Handle(context, bitStream, branch); } } -void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ - auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) { - Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!\n", context->originator); - return; - } +void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* self = EntityManager::Instance()->GetEntity(context->originator); + if (self == nullptr) { + Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator); + return; + } - const auto* destroyableComponent = self->GetComponent(); + const auto* destroyableComponent = self->GetComponent(); - if ((this->m_usePickedTarget || context->clientInitalized) && branch.target > 0) { - const auto* target = EntityManager::Instance()->GetEntity(branch.target); + if ((this->m_usePickedTarget || context->clientInitalized) && branch.target > 0) { + const auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { + if (target == nullptr) { return; } - // If the game is specific about who to target, check that - if (destroyableComponent == nullptr || ((!m_targetFriend && !m_targetEnemy - || m_targetFriend && destroyableComponent->IsFriend(target) - || m_targetEnemy && destroyableComponent->IsEnemy(target)))) { - this->m_action->Calculate(context, bitStream, branch); - } + // If the game is specific about who to target, check that + if (destroyableComponent == nullptr || ((!m_targetFriend && !m_targetEnemy + || m_targetFriend && destroyableComponent->IsFriend(target) + || m_targetEnemy && destroyableComponent->IsEnemy(target)))) { + this->m_action->Calculate(context, bitStream, branch); + } - return; - } + return; + } auto* combatAi = self->GetComponent(); - + const auto casterPosition = self->GetPosition(); auto reference = self->GetPosition(); //+ m_offset; @@ -111,46 +111,40 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS std::vector validTargets; - if (combatAi != nullptr) - { - if (combatAi->GetTarget() != LWOOBJID_EMPTY) - { + if (combatAi != nullptr) { + if (combatAi->GetTarget() != LWOOBJID_EMPTY) { validTargets.push_back(combatAi->GetTarget()); } } // Find all valid targets, based on whether we target enemies or friends for (const auto& contextTarget : context->GetValidTargets()) { - if (destroyableComponent != nullptr) { - const auto* targetEntity = EntityManager::Instance()->GetEntity(contextTarget); + if (destroyableComponent != nullptr) { + const auto* targetEntity = EntityManager::Instance()->GetEntity(contextTarget); - if (m_targetEnemy && destroyableComponent->IsEnemy(targetEntity) - || m_targetFriend && destroyableComponent->IsFriend(targetEntity)) { - validTargets.push_back(contextTarget); - } - } else { - validTargets.push_back(contextTarget); - } + if (m_targetEnemy && destroyableComponent->IsEnemy(targetEntity) + || m_targetFriend && destroyableComponent->IsFriend(targetEntity)) { + validTargets.push_back(contextTarget); + } + } else { + validTargets.push_back(contextTarget); + } } - for (auto validTarget : validTargets) - { - if (targets.size() >= this->m_maxTargets) - { + for (auto validTarget : validTargets) { + if (targets.size() >= this->m_maxTargets) { break; } auto* entity = EntityManager::Instance()->GetEntity(validTarget); - if (entity == nullptr) - { - Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!\n", validTarget, context->originator); + if (entity == nullptr) { + Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); continue; } - if (std::find(targets.begin(), targets.end(), entity) != targets.end()) - { + if (std::find(targets.begin(), targets.end(), entity) != targets.end()) { continue; } @@ -171,81 +165,69 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS // otherPosition is the position of the target. // reference is the position of the caster. // If we cast a ray forward from the caster, does it come within m_farWidth of the target? - + const auto distance = Vector3::Distance(reference, otherPosition); - if (m_method == 2) - { + if (m_method == 2) { NiPoint3 rayPoint = casterPosition + forward * distance; - if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, otherPosition) > this->m_farWidth * this->m_farWidth) - { + if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, otherPosition) > this->m_farWidth * this->m_farWidth) { continue; } } auto normalized = (reference - otherPosition) / distance; - + const float degreeAngle = std::abs(Vector3::Angle(forward, normalized) * (180 / 3.14) - 180); - if (distance >= this->m_minDistance && this->m_maxDistance >= distance && degreeAngle <= 2 * this->m_angle) - { + if (distance >= this->m_minDistance && this->m_maxDistance >= distance && degreeAngle <= 2 * this->m_angle) { targets.push_back(entity); } } - std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) - { + std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) { const auto aDistance = Vector3::DistanceSquared(reference, a->GetPosition()); const auto bDistance = Vector3::DistanceSquared(reference, b->GetPosition()); return aDistance > bDistance; - }); + }); const auto hit = !targets.empty(); bitStream->Write(hit); - if (this->m_checkEnv) - { + if (this->m_checkEnv) { const auto blocked = false; // TODO bitStream->Write(blocked); } - if (hit) - { - if (combatAi != nullptr) - { + if (hit) { + if (combatAi != nullptr) { combatAi->LookAt(targets[0]->GetPosition()); } context->foundTarget = true; // We want to continue with this behavior - + const auto count = static_cast(targets.size()); bitStream->Write(count); - for (auto* target : targets) - { + for (auto* target : targets) { bitStream->Write(target->GetObjectID()); } - for (auto* target : targets) - { + for (auto* target : targets) { branch.target = target->GetObjectID(); this->m_action->Calculate(context, bitStream, branch); } - } - else - { + } else { this->m_missAction->Calculate(context, bitStream, branch); } } -void TacArcBehavior::Load() -{ +void TacArcBehavior::Load() { this->m_usePickedTarget = GetBoolean("use_picked_target"); this->m_action = GetAction("action"); diff --git a/dGame/dBehaviors/TacArcBehavior.h b/dGame/dBehaviors/TacArcBehavior.h index 774e65a1..87a22051 100644 --- a/dGame/dBehaviors/TacArcBehavior.h +++ b/dGame/dBehaviors/TacArcBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" #include "dCommonVars.h" #include "NiPoint3.h" @@ -45,11 +45,10 @@ public: /* * Inherited */ - - explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + + explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/TargetCasterBehavior.cpp b/dGame/dBehaviors/TargetCasterBehavior.cpp index 41b5e73a..ff9cfc03 100644 --- a/dGame/dBehaviors/TargetCasterBehavior.cpp +++ b/dGame/dBehaviors/TargetCasterBehavior.cpp @@ -1,29 +1,25 @@ -#include "TargetCasterBehavior.h" +#include "TargetCasterBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void TargetCasterBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void TargetCasterBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { branch.target = context->caster; this->m_action->Handle(context, bit_stream, branch); } -void TargetCasterBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) -{ +void TargetCasterBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { this->m_action->UnCast(context, branch); } -void TargetCasterBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) -{ +void TargetCasterBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { branch.target = context->caster; this->m_action->Calculate(context, bit_stream, branch); } -void TargetCasterBehavior::Load() -{ +void TargetCasterBehavior::Load() { this->m_action = GetAction("action"); } diff --git a/dGame/dBehaviors/TargetCasterBehavior.h b/dGame/dBehaviors/TargetCasterBehavior.h index 4054f81d..387d2732 100644 --- a/dGame/dBehaviors/TargetCasterBehavior.h +++ b/dGame/dBehaviors/TargetCasterBehavior.h @@ -1,22 +1,21 @@ -#pragma once +#pragma once #include "Behavior.h" class TargetCasterBehavior final : public Behavior { public: Behavior* m_action; - + /* * Inherited */ - explicit TargetCasterBehavior(const uint32_t behavior_id) : Behavior(behavior_id) - { + explicit TargetCasterBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; - void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/TauntBehavior.cpp b/dGame/dBehaviors/TauntBehavior.cpp index 7240dc14..7ed3b897 100644 --- a/dGame/dBehaviors/TauntBehavior.cpp +++ b/dGame/dBehaviors/TauntBehavior.cpp @@ -6,46 +6,39 @@ #include "dLogger.h" -void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target); return; } auto* combatComponent = target->GetComponent(); - - if (combatComponent != nullptr) - { + + if (combatComponent != nullptr) { combatComponent->Taunt(context->originator, m_threatToAdd); } } -void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) - { - Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!\n", branch.target); + if (target == nullptr) { + Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target); return; } auto* combatComponent = target->GetComponent(); - - if (combatComponent != nullptr) - { + + if (combatComponent != nullptr) { combatComponent->Taunt(context->originator, m_threatToAdd); } } -void TauntBehavior::Load() -{ +void TauntBehavior::Load() { this->m_threatToAdd = GetFloat("threat to add"); } diff --git a/dGame/dBehaviors/TauntBehavior.h b/dGame/dBehaviors/TauntBehavior.h index a482d0b5..3ae7db9d 100644 --- a/dGame/dBehaviors/TauntBehavior.h +++ b/dGame/dBehaviors/TauntBehavior.h @@ -6,13 +6,12 @@ class TauntBehavior final : public Behavior { public: float m_threatToAdd; - + /* * Inherited */ - explicit TauntBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit TauntBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/VentureVisionBehavior.cpp b/dGame/dBehaviors/VentureVisionBehavior.cpp index 9061deb7..93feb8e9 100644 --- a/dGame/dBehaviors/VentureVisionBehavior.cpp +++ b/dGame/dBehaviors/VentureVisionBehavior.cpp @@ -2,8 +2,8 @@ #include "BehaviorBranchContext.h" #include "CharacterComponent.h" #include "BehaviorContext.h" - -void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch){ + +void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto targetEntity = EntityManager::Instance()->GetEntity(branch.target); @@ -38,7 +38,7 @@ void VentureVisionBehavior::Timer(BehaviorContext* context, BehaviorBranchContex UnCast(context, branch); } -void VentureVisionBehavior::Load(){ +void VentureVisionBehavior::Load() { this->m_show_pet_digs = GetBoolean("show_pet_digs"); this->m_show_minibosses = GetBoolean("show_minibosses"); diff --git a/dGame/dBehaviors/VentureVisionBehavior.h b/dGame/dBehaviors/VentureVisionBehavior.h index 96b2642b..72758949 100644 --- a/dGame/dBehaviors/VentureVisionBehavior.h +++ b/dGame/dBehaviors/VentureVisionBehavior.h @@ -25,10 +25,9 @@ public: * Inherited */ - explicit VentureVisionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit VentureVisionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/VerifyBehavior.cpp b/dGame/dBehaviors/VerifyBehavior.cpp index f4edfece..608e965b 100644 --- a/dGame/dBehaviors/VerifyBehavior.cpp +++ b/dGame/dBehaviors/VerifyBehavior.cpp @@ -1,4 +1,4 @@ -#include "VerifyBehavior.h" +#include "VerifyBehavior.h" #include "BehaviorBranchContext.h" #include "EntityManager.h" #include "NiPoint3.h" @@ -7,61 +7,49 @@ #include "dLogger.h" -void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) -{ +void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto success = true; - if (entity == nullptr) - { + if (entity == nullptr) { success = false; - } - else if (this->m_rangeCheck) - { + } else if (this->m_rangeCheck) { auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) - { - Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)\n", context->originator); + if (self == nullptr) { + Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)", context->originator); return; } - + const auto distance = Vector3::DistanceSquared(self->GetPosition(), entity->GetPosition()); - if (distance > this->m_range * this->m_range) - { + if (distance > this->m_range * this->m_range) { success = false; } - } - else if (this->m_blockCheck) - { + } else if (this->m_blockCheck) { // TODO } - if (branch.target != LWOOBJID_EMPTY && branch.target != context->originator) - { + if (branch.target != LWOOBJID_EMPTY && branch.target != context->originator) { bitStream->Write(success); - if (success) - { + if (success) { bitStream->Write(1); bitStream->Write0(); bitStream->Write0(); } } - if (!success) - { + if (!success) { branch.target = LWOOBJID_EMPTY; } m_action->Calculate(context, bitStream, branch); } -void VerifyBehavior::Load() -{ +void VerifyBehavior::Load() { this->m_rangeCheck = GetBoolean("check_range"); this->m_blockCheck = GetBoolean("check blocking"); diff --git a/dGame/dBehaviors/VerifyBehavior.h b/dGame/dBehaviors/VerifyBehavior.h index f4f295aa..a91ff7cf 100644 --- a/dGame/dBehaviors/VerifyBehavior.h +++ b/dGame/dBehaviors/VerifyBehavior.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Behavior.h" class VerifyBehavior final : public Behavior @@ -16,10 +16,9 @@ public: * Inherited */ - explicit VerifyBehavior(const uint32_t behaviorId) : Behavior(behaviorId) - { + explicit VerifyBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dComponents/AchievementCacheKey.h b/dGame/dComponents/AchievementCacheKey.h new file mode 100644 index 00000000..398e0231 --- /dev/null +++ b/dGame/dComponents/AchievementCacheKey.h @@ -0,0 +1,45 @@ +#include "eMissionTaskType.h" + +#ifndef __ACHIEVEMENTCACHEKEY__H__ +#define __ACHIEVEMENTCACHEKEY__H__ + +class AchievementCacheKey { +public: + AchievementCacheKey() { + targets = ""; + value = 0; + type = eMissionTaskType::UNKNOWN; + }; + + bool operator==(const AchievementCacheKey& point) const { + return this->targets == point.targets && this->value == point.value && this->type == point.type; + }; + void SetTargets(const std::string value) { this->targets = value; }; + void SetValue(uint32_t value) { this->value = value; }; + void SetType(eMissionTaskType value) { this->type = value; }; + + std::string GetTargets() const { return this->targets; }; + uint32_t GetValue() const { return this->value; }; + eMissionTaskType GetType() const { return this->type; }; +private: + std::string targets; + uint32_t value; + eMissionTaskType type; + +}; + +// Specialization of hash for the above class +namespace std { + template<> + struct hash { + size_t operator()(const AchievementCacheKey& key) const { + size_t hash = 0; + GeneralUtils::hash_combine(hash, key.GetType()); + GeneralUtils::hash_combine(hash, key.GetValue()); + GeneralUtils::hash_combine(hash, key.GetTargets()); + return hash; + }; + }; +}; + +#endif //!__ACHIEVEMENTCACHEKEY__H__ diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index 0903e621..cccaad23 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -22,10 +22,13 @@ #include "SkillComponent.h" #include "RebuildComponent.h" #include "DestroyableComponent.h" +#include "Metrics.hpp" +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" -BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) : Component(parent) { +BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) { m_Target = LWOOBJID_EMPTY; - m_State = AiState::spawn; + SetAiState(AiState::spawn); m_Timer = 1.0f; m_StartPosition = parent->GetPosition(); m_MovementAI = nullptr; @@ -37,12 +40,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) //Grab the aggro information from BaseCombatAI: auto componentQuery = CDClientDatabase::CreatePreppedStmt( "SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = ?;"); - componentQuery.bind(1, (int) id); - + componentQuery.bind(1, (int)id); + auto componentResult = componentQuery.execQuery(); - if (!componentResult.eof()) - { + if (!componentResult.eof()) { if (!componentResult.fieldIsNull(0)) m_AggroRadius = componentResult.getFloatField(0); @@ -61,13 +63,22 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) componentResult.finalize(); + // Get aggro and tether radius from settings and use this if it is present. Only overwrite the + // radii if it is greater than the one in the database. + if (m_Parent) { + auto aggroRadius = m_Parent->GetVar(u"aggroRadius"); + m_AggroRadius = aggroRadius != 0 ? aggroRadius : m_AggroRadius; + auto tetherRadius = m_Parent->GetVar(u"tetherRadius"); + m_HardTetherRadius = tetherRadius != 0 ? tetherRadius : m_HardTetherRadius; + } + /* * Find skills */ auto skillQuery = CDClientDatabase::CreatePreppedStmt( "SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); - skillQuery.bind(1, (int) parent->GetLOT()); - + skillQuery.bind(1, (int)parent->GetLOT()); + auto result = skillQuery.execQuery(); while (!result.eof()) { @@ -96,16 +107,14 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) int32_t collisionGroup = (COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_ENEMY); - CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_CONTROLLABLE_PHYSICS); + CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::CONTROLLABLE_PHYSICS); - CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable(); - if (physicsComponentTable != nullptr) - { + if (physicsComponentTable != nullptr) { auto* info = physicsComponentTable->GetByID(componentID); - if (info != nullptr) - { + if (info != nullptr) { collisionGroup = info->bStatic ? COLLISION_GROUP_NEUTRAL : info->collisionGroup; } } @@ -157,41 +166,36 @@ void BaseCombatAIComponent::Update(const float deltaTime) { if (m_Target != LWOOBJID_EMPTY || (NiPoint3::DistanceSquared( m_StartPosition, m_Parent->GetPosition()) < 20 * 20 && m_TetherTime <= 0) - ) { + ) { GameMessages::SendStopFXEffect(m_Parent, true, "tether"); m_TetherEffectActive = false; } } - if (m_SoftTimer <= 0.0f) - { + if (m_SoftTimer <= 0.0f) { EntityManager::Instance()->SerializeEntity(m_Parent); m_SoftTimer = 5.0f; - } - else - { + } else { m_SoftTimer -= deltaTime; } if (m_Disabled || m_Parent->GetIsDead()) - return; - + return; + bool stunnedThisFrame = m_Stunned; CalculateCombat(deltaTime); // Putting this here for now - if (m_StartPosition == NiPoint3::ZERO) - { + if (m_StartPosition == NiPoint3::ZERO) { m_StartPosition = m_Parent->GetPosition(); } m_MovementAI = m_Parent->GetComponent(); - if (m_MovementAI == nullptr) - { + if (m_MovementAI == nullptr) { return; } - if (m_Stunned) { + if (stunnedThisFrame) { m_MovementAI->Stop(); return; @@ -205,7 +209,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { switch (m_State) { case AiState::spawn: Stun(2.0f); - m_State = AiState::idle; + SetAiState(AiState::idle); break; case AiState::idle: @@ -213,7 +217,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { break; case AiState::aggro: - OnAggro(); + OnAggro(); break; case AiState::tether: @@ -227,41 +231,49 @@ void BaseCombatAIComponent::Update(const float deltaTime) { void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { + bool hasSkillToCast = false; + for (auto& entry : m_SkillEntries) { + if (entry.cooldown > 0.0f) { + entry.cooldown -= deltaTime; + } else { + hasSkillToCast = true; + } + } + + bool hadRemainingDowntime = m_SkillTime > 0.0f; + if (m_SkillTime > 0.0f) m_SkillTime -= deltaTime; + auto* rebuild = m_Parent->GetComponent(); if (rebuild != nullptr) { const auto state = rebuild->GetState(); - if (state != REBUILD_COMPLETED) { + if (state != eRebuildState::COMPLETED) { return; } } auto* skillComponent = m_Parent->GetComponent(); - if (skillComponent == nullptr) - { + if (skillComponent == nullptr) { return; } skillComponent->CalculateUpdate(deltaTime); - + if (m_Disabled) return; - if (m_StunTime > 0.0f) - { + if (m_Stunned) { m_StunTime -= deltaTime; if (m_StunTime > 0.0f) { return; } - + m_StunTime = 0.0f; m_Stunned = false; } - if (m_Stunned) { - return; - } + if (m_Stunned || hadRemainingDowntime) return; auto newTarget = FindTarget(); @@ -269,8 +281,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { if (m_Target != LWOOBJID_EMPTY && newTarget == LWOOBJID_EMPTY) { m_OutOfCombat = true; m_OutOfCombatTime = 1.0f; - } - else if (newTarget != LWOOBJID_EMPTY) { + } else if (newTarget != LWOOBJID_EMPTY) { m_OutOfCombat = false; m_OutOfCombatTime = 0.0f; } @@ -322,54 +333,28 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_Timer = 0; } - m_State = AiState::aggro; + SetAiState(AiState::aggro); + } else { + SetAiState(AiState::idle); } - else { - m_State = AiState::idle; + + if (!hasSkillToCast) return; + + if (m_Target == LWOOBJID_EMPTY) { + SetAiState(AiState::idle); + + return; + } + + auto* target = GetTargetEntity(); + + if (target != nullptr) { + LookAt(target->GetPosition()); } for (auto i = 0; i < m_SkillEntries.size(); ++i) { auto entry = m_SkillEntries.at(i); - if (entry.cooldown > 0) { - entry.cooldown -= deltaTime; - - m_SkillEntries[i] = entry; - } - } - - if (m_SkillTime > 0) { - m_SkillTime -= deltaTime; - - return; - } - - if (m_Downtime > 0) { - m_Downtime -= deltaTime; - - return; - } - - if (m_Target == LWOOBJID_EMPTY) - { - m_State = AiState::idle; - - return; - } - - m_Downtime = 0.5f; - - auto* target = GetTargetEntity(); - - if (target != nullptr) - { - LookAt(target->GetPosition()); - } - - for (auto i = 0; i < m_SkillEntries.size(); ++i) - { - auto entry = m_SkillEntries.at(i); - if (entry.cooldown > 0) { continue; } @@ -381,7 +366,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_MovementAI->Stop(); } - m_State = AiState::aggro; + SetAiState(AiState::aggro); m_Timer = 0; @@ -404,13 +389,11 @@ LWOOBJID BaseCombatAIComponent::FindTarget() { if (m_MovementAI) reference = m_MovementAI->ApproximateLocation(); auto* target = GetTargetEntity(); - - if (target != nullptr && !m_DirtyThreat) - { + + if (target != nullptr && !m_DirtyThreat) { const auto targetPosition = target->GetPosition(); - - if (Vector3::DistanceSquared(targetPosition, m_StartPosition) < m_HardTetherRadius * m_HardTetherRadius) - { + + if (Vector3::DistanceSquared(targetPosition, m_StartPosition) < m_HardTetherRadius * m_HardTetherRadius) { return m_Target; } @@ -419,8 +402,7 @@ LWOOBJID BaseCombatAIComponent::FindTarget() { auto possibleTargets = GetTargetWithinAggroRange(); - if (possibleTargets.empty() && m_ThreatEntries.empty()) - { + if (possibleTargets.empty() && m_ThreatEntries.empty()) { m_DirtyThreat = false; return LWOOBJID_EMPTY; @@ -429,8 +411,7 @@ LWOOBJID BaseCombatAIComponent::FindTarget() { Entity* optimalTarget = nullptr; float biggestThreat = 0; - for (const auto& entry : possibleTargets) - { + for (const auto& entry : possibleTargets) { auto* entity = EntityManager::Instance()->GetEntity(entry); if (entity == nullptr) { @@ -443,53 +424,43 @@ LWOOBJID BaseCombatAIComponent::FindTarget() { const auto maxDistanceSquared = m_HardTetherRadius * m_HardTetherRadius; - if (Vector3::DistanceSquared(targetPosition, m_StartPosition) > maxDistanceSquared) - { - if (threat > 0) - { + if (Vector3::DistanceSquared(targetPosition, m_StartPosition) > maxDistanceSquared) { + if (threat > 0) { SetThreat(entry, 0); } continue; } - if (threat > biggestThreat) - { + if (threat > biggestThreat) { biggestThreat = threat; optimalTarget = entity; continue; } - const auto proximityThreat = - (Vector3::DistanceSquared(targetPosition, reference) - maxDistanceSquared) / 100; // Proximity threat takes last priority + const auto proximityThreat = -(Vector3::DistanceSquared(targetPosition, reference) - maxDistanceSquared) / 100; // Proximity threat takes last priority - if (proximityThreat > biggestThreat) - { + if (proximityThreat > biggestThreat) { biggestThreat = proximityThreat; optimalTarget = entity; } } - if (!m_DirtyThreat) - { - if (optimalTarget == nullptr) - { + if (!m_DirtyThreat) { + if (optimalTarget == nullptr) { return LWOOBJID_EMPTY; - } - else - { + } else { return optimalTarget->GetObjectID(); } } - std::vector deadThreats {}; - - for (const auto& threatTarget : m_ThreatEntries) - { + std::vector deadThreats{}; + + for (const auto& threatTarget : m_ThreatEntries) { auto* entity = EntityManager::Instance()->GetEntity(threatTarget.first); - if (entity == nullptr) - { + if (entity == nullptr) { deadThreats.push_back(threatTarget.first); continue; @@ -497,33 +468,27 @@ LWOOBJID BaseCombatAIComponent::FindTarget() { const auto targetPosition = entity->GetPosition(); - if (Vector3::DistanceSquared(targetPosition, m_StartPosition) > m_HardTetherRadius * m_HardTetherRadius) - { + if (Vector3::DistanceSquared(targetPosition, m_StartPosition) > m_HardTetherRadius * m_HardTetherRadius) { deadThreats.push_back(threatTarget.first); continue; } - if (threatTarget.second > biggestThreat) - { + if (threatTarget.second > biggestThreat) { optimalTarget = entity; biggestThreat = threatTarget.second; } } - for (const auto& deadThreat : deadThreats) - { + for (const auto& deadThreat : deadThreats) { SetThreat(deadThreat, 0); } m_DirtyThreat = false; - - if (optimalTarget == nullptr) - { + + if (optimalTarget == nullptr) { return LWOOBJID_EMPTY; - } - else - { + } else { return optimalTarget->GetObjectID(); } } @@ -558,17 +523,26 @@ bool BaseCombatAIComponent::IsMech() { void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write1(); - outBitStream->Write(uint32_t(m_State)); - outBitStream->Write(m_Target); + outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate); + if (m_DirtyStateOrTarget || bIsInitialUpdate) { + outBitStream->Write(uint32_t(m_State)); + outBitStream->Write(m_Target); + m_DirtyStateOrTarget = false; + } } +void BaseCombatAIComponent::SetAiState(AiState newState) { + if (newState == this->m_State) return; + this->m_State = newState; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); +} bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { auto* entity = EntityManager::Instance()->GetEntity(target); if (entity == nullptr) { - Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!\n", target); + Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!", target); return false; } @@ -582,19 +556,17 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { auto* referenceDestroyable = m_Parent->GetComponent(); if (referenceDestroyable == nullptr) { - Game::logger->Log("BaseCombatAIComponent", "Invalid reference destroyable component on (%llu)!\n", m_Parent->GetObjectID()); + Game::logger->Log("BaseCombatAIComponent", "Invalid reference destroyable component on (%llu)!", m_Parent->GetObjectID()); return false; } auto* quickbuild = entity->GetComponent(); - if (quickbuild != nullptr) - { + if (quickbuild != nullptr) { const auto state = quickbuild->GetState(); - - if (state != REBUILD_COMPLETED) - { + + if (state != eRebuildState::COMPLETED) { return false; } } @@ -613,7 +585,10 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { } void BaseCombatAIComponent::SetTarget(const LWOOBJID target) { + if (this->m_Target == target) return; m_Target = target; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); } Entity* BaseCombatAIComponent::GetTargetEntity() const { @@ -621,9 +596,9 @@ Entity* BaseCombatAIComponent::GetTargetEntity() const { } void BaseCombatAIComponent::Taunt(LWOOBJID offender, float threat) { - // Can't taunt self - if (offender == m_Parent->GetObjectID()) - return; + // Can't taunt self + if (offender == m_Parent->GetObjectID()) + return; m_ThreatEntries[offender] += threat; m_DirtyThreat = true; @@ -640,21 +615,18 @@ float BaseCombatAIComponent::GetThreat(LWOOBJID offender) { void BaseCombatAIComponent::SetThreat(LWOOBJID offender, float threat) { if (threat == 0) { m_ThreatEntries.erase(offender); - } - else { + } else { m_ThreatEntries[offender] = threat; } m_DirtyThreat = true; } -const NiPoint3& BaseCombatAIComponent::GetStartPosition() const -{ +const NiPoint3& BaseCombatAIComponent::GetStartPosition() const { return m_StartPosition; } -void BaseCombatAIComponent::ClearThreat() -{ +void BaseCombatAIComponent::ClearThreat() { m_ThreatEntries.clear(); m_DirtyThreat = true; @@ -666,12 +638,12 @@ void BaseCombatAIComponent::Wander() { } m_MovementAI->SetHaltDistance(0); - + const auto& info = m_MovementAI->GetInfo(); const auto div = static_cast(info.wanderDelayMax); m_Timer = (div == 0 ? 0 : GeneralUtils::GenerateRandomNumber(0, div)) + info.wanderDelayMin; //set a random timer to stay put. - + const float radius = info.wanderRadius * sqrt(static_cast(GeneralUtils::GenerateRandomNumber(0, 1))); //our wander radius + a bit of random range const float theta = ((static_cast(GeneralUtils::GenerateRandomNumber(0, 1)) * 2 * PI)); @@ -685,7 +657,7 @@ void BaseCombatAIComponent::Wander() { auto destination = m_StartPosition + delta; if (dpWorld::Instance().IsLoaded()) { - destination.y = dpWorld::Instance().GetHeightAtPoint(destination); + destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination); } if (Vector3::DistanceSquared(destination, m_MovementAI->GetCurrentPosition()) < 2 * 2) { @@ -711,21 +683,19 @@ void BaseCombatAIComponent::OnAggro() { } m_MovementAI->SetHaltDistance(m_AttackRadius); - + NiPoint3 targetPos = target->GetPosition(); NiPoint3 currentPos = m_MovementAI->GetCurrentPosition(); // If the player's position is within range, attack if (Vector3::DistanceSquared(currentPos, targetPos) <= m_AttackRadius * m_AttackRadius) { m_MovementAI->Stop(); - } - else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far + } else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far { m_MovementAI->SetSpeed(m_PursuitSpeed); - + m_MovementAI->SetDestination(m_StartPosition); - } - else //Chase the player's new position + } else //Chase the player's new position { if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return; @@ -733,7 +703,7 @@ void BaseCombatAIComponent::OnAggro() { m_MovementAI->SetDestination(targetPos); - m_State = AiState::tether; + SetAiState(AiState::tether); } m_Timer += 0.5f; @@ -753,16 +723,14 @@ void BaseCombatAIComponent::OnTether() { if (Vector3::DistanceSquared(currentPos, targetPos) <= m_AttackRadius * m_AttackRadius) { m_MovementAI->Stop(); - } - else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far + } else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far { m_MovementAI->SetSpeed(m_PursuitSpeed); m_MovementAI->SetDestination(m_StartPosition); - - m_State = AiState::aggro; - } - else { + + SetAiState(AiState::aggro); + } else { if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return; m_MovementAI->SetSpeed(m_PursuitSpeed); @@ -781,23 +749,19 @@ void BaseCombatAIComponent::SetStunned(const bool value) { m_Stunned = value; } -bool BaseCombatAIComponent::GetStunImmune() const -{ +bool BaseCombatAIComponent::GetStunImmune() const { return m_StunImmune; } -void BaseCombatAIComponent::SetStunImmune(bool value) -{ +void BaseCombatAIComponent::SetStunImmune(bool value) { m_StunImmune = value; } -float BaseCombatAIComponent::GetTetherSpeed() const -{ +float BaseCombatAIComponent::GetTetherSpeed() const { return m_TetherSpeed; } -void BaseCombatAIComponent::SetTetherSpeed(float value) -{ +void BaseCombatAIComponent::SetTetherSpeed(float value) { m_TetherSpeed = value; } @@ -807,7 +771,7 @@ void BaseCombatAIComponent::Stun(const float time) { } m_StunTime = time; - + m_Stunned = true; } @@ -819,34 +783,28 @@ void BaseCombatAIComponent::SetAggroRadius(const float value) { m_AggroRadius = value; } -void BaseCombatAIComponent::LookAt(const NiPoint3& point) -{ - if (m_Stunned) - { +void BaseCombatAIComponent::LookAt(const NiPoint3& point) { + if (m_Stunned) { return; } m_Parent->SetRotation(NiQuaternion::LookAt(m_Parent->GetPosition(), point)); } -void BaseCombatAIComponent::SetDisabled(bool value) -{ +void BaseCombatAIComponent::SetDisabled(bool value) { m_Disabled = value; } -bool BaseCombatAIComponent::GetDistabled() const -{ +bool BaseCombatAIComponent::GetDistabled() const { return m_Disabled; } -void BaseCombatAIComponent::Sleep() -{ +void BaseCombatAIComponent::Sleep() { m_dpEntity->SetSleeping(true); m_dpEntityEnemy->SetSleeping(true); } -void BaseCombatAIComponent::Wake() -{ +void BaseCombatAIComponent::Wake() { m_dpEntity->SetSleeping(false); m_dpEntityEnemy->SetSleeping(false); -} \ No newline at end of file +} diff --git a/dGame/dComponents/BaseCombatAIComponent.h b/dGame/dComponents/BaseCombatAIComponent.h index ff291736..8bf6140a 100644 --- a/dGame/dComponents/BaseCombatAIComponent.h +++ b/dGame/dComponents/BaseCombatAIComponent.h @@ -8,6 +8,7 @@ #include "dpWorld.h" #include "dpEntity.h" #include "Component.h" +#include "eReplicaComponentType.h" #include #include @@ -46,7 +47,7 @@ struct AiSkillEntry */ class BaseCombatAIComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BASE_COMBAT_AI; + static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI; BaseCombatAIComponent(Entity* parentEntity, uint32_t id); ~BaseCombatAIComponent() override; @@ -60,320 +61,327 @@ public: */ AiState GetState() const { return m_State; } - /** - * Set the current behavioral state of the enemy - * @param state the state to change to - */ + /** + * Set the current behavioral state of the enemy + * @param state the state to change to + */ void SetState(AiState state) { m_State = state; } - /** - * Checks if the target may be an enemy of this entity - * @param target the target to check for - * @return whether the target is a valid enemy for this entity or not - */ + /** + * Checks if the target may be an enemy of this entity + * @param target the target to check for + * @return whether the target is a valid enemy for this entity or not + */ bool IsEnemy(LWOOBJID target) const; - /** - * Gets the current target ID that this entity will attack - * @return the current target ID of this entity - */ + /** + * Gets the current target ID that this entity will attack + * @return the current target ID of this entity + */ LWOOBJID GetTarget() const { return m_Target; } - /** - * Sets the target that this entity will attack - * @param target the target to set - */ + /** + * Sets the target that this entity will attack + * @param target the target to set + */ void SetTarget(LWOOBJID target); - /** - * Gets the current target entity that this entity will attack - * @return the current target entity of this entity - */ + /** + * Gets the current target entity that this entity will attack + * @return the current target entity of this entity + */ Entity* GetTargetEntity() const; - /** - * Taunts this entity, making it a higher or lower threat for this entity. Increasing or decreasing the chance to - * be attacked. - * @param offender the entity that triggered the taunt - * @param threat how high to increase the threat for the offender - */ + /** + * Taunts this entity, making it a higher or lower threat for this entity. Increasing or decreasing the chance to + * be attacked. + * @param offender the entity that triggered the taunt + * @param threat how high to increase the threat for the offender + */ void Taunt(LWOOBJID offender, float threat); - /** - * Gets the current threat level for an offending entity - * @param offender the entity to get the threat for - * @return the current threat level of the offending entity, 0 if the entity is not a threat - */ + /** + * Gets the current threat level for an offending entity + * @param offender the entity to get the threat for + * @return the current threat level of the offending entity, 0 if the entity is not a threat + */ float GetThreat(LWOOBJID offender); - /** - * Sets the threat level for an entity - * @param offender the entity to set the threat level for - * @param threat the threat level to set - */ + /** + * Sets the threat level for an entity + * @param offender the entity to set the threat level for + * @param threat the threat level to set + */ void SetThreat(LWOOBJID offender, float threat); - /** - * Gets the position where the entity spawned - * @return the position where the entity spawned - */ + /** + * Gets the position where the entity spawned + * @return the position where the entity spawned + */ const NiPoint3& GetStartPosition() const; - /** - * Removes all threats for this entities, and thus chances for it attacking other entities - */ + /** + * Removes all threats for this entities, and thus chances for it attacking other entities + */ void ClearThreat(); - /** - * Makes the entity continue to wander to a random point around it's starting position - */ + /** + * Makes the entity continue to wander to a random point around it's starting position + */ void Wander(); - /** - * Continues a step in the aggro state, making sure that the entity is around its start position, if an entity - * crosses its aggro range this will set the state to tether. - */ + /** + * Continues a step in the aggro state, making sure that the entity is around its start position, if an entity + * crosses its aggro range this will set the state to tether. + */ void OnAggro(); - /** - * Continues a step in the tether state, making the entity run towards its target, if the target is outside of its - * tether range, this will change the state to aggro - */ + /** + * Continues a step in the tether state, making the entity run towards its target, if the target is outside of its + * tether range, this will change the state to aggro + */ void OnTether(); - /** - * Gets whether or not the entity is currently stunned - * @return whether the entity is currently stunned - */ - bool GetStunned() const; + /** + * Gets whether or not the entity is currently stunned + * @return whether the entity is currently stunned + */ + bool GetStunned() const; - /** - * (un)stuns the entity, determining whether it'll be able to attack other entities - * @param value whether the enemy is stunned - */ + /** + * (un)stuns the entity, determining whether it'll be able to attack other entities + * @param value whether the enemy is stunned + */ void SetStunned(bool value); - /** - * Gets if this entity may be stunned - * @return if this entity may be stunned - */ + /** + * Gets if this entity may be stunned + * @return if this entity may be stunned + */ bool GetStunImmune() const; - /** - * Set the stun immune value, determining if the entity may be stunned - * @param value - */ + /** + * Set the stun immune value, determining if the entity may be stunned + * @param value + */ void SetStunImmune(bool value); - /** - * Gets the current speed at which an entity runs when tethering - * @return the current speed at which an entity runs when tethering - */ + /** + * Gets the current speed at which an entity runs when tethering + * @return the current speed at which an entity runs when tethering + */ float GetTetherSpeed() const; - /** - * Sets the speed at which an entity will tether - * @param value the new tether speed - */ + /** + * Sets the speed at which an entity will tether + * @param value the new tether speed + */ void SetTetherSpeed(float value); - /** - * Stuns the entity for a certain amount of time, will not work if the entity is stun immune - * @param time the time to stun the entity, if stunnable - */ + /** + * Stuns the entity for a certain amount of time, will not work if the entity is stun immune + * @param time the time to stun the entity, if stunnable + */ void Stun(float time); - /** - * Gets the radius that will cause this entity to get aggro'd, causing a target chase - * @return the aggro radius of the entity - */ + /** + * Gets the radius that will cause this entity to get aggro'd, causing a target chase + * @return the aggro radius of the entity + */ float GetAggroRadius() const; - /** - * Sets the aggro radius, causing the entity to start chasing enemies in this range - * @param value the aggro radius to set - */ + /** + * Sets the aggro radius, causing the entity to start chasing enemies in this range + * @param value the aggro radius to set + */ void SetAggroRadius(float value); - /** - * Makes the entity look at a certain point in space - * @param point the point to look at - */ + /** + * Makes the entity look at a certain point in space + * @param point the point to look at + */ void LookAt(const NiPoint3& point); - /** - * (dis)ables the AI, causing it to stop/start attacking enemies - * @param value - */ + /** + * (dis)ables the AI, causing it to stop/start attacking enemies + * @param value + */ void SetDisabled(bool value); - /** - * Gets the current state of the AI, whether or not it's looking for enemies to attack - * @return - */ + /** + * Gets the current state of the AI, whether or not it's looking for enemies to attack + * @return + */ bool GetDistabled() const; - /** - * Turns the entity asleep, stopping updates to its physics volumes - */ + /** + * Turns the entity asleep, stopping updates to its physics volumes + */ void Sleep(); - /** - * Wakes the entity, allowing updates to its physics volumes - */ + /** + * Wakes the entity, allowing updates to its physics volumes + */ void Wake(); private: - /** - * Returns the current target or the target that currently is the largest threat to this entity - * @return the current highest priority enemy of this entity - */ + /** + * Returns the current target or the target that currently is the largest threat to this entity + * @return the current highest priority enemy of this entity + */ LWOOBJID FindTarget(); - /** - * Handles anything attack related for the game loop, e.g.: finding targets, sticking with targets and attacking - * them, depending on cooldowns. - * @param deltaTime the time since the last game tick - */ + /** + * Handles anything attack related for the game loop, e.g.: finding targets, sticking with targets and attacking + * them, depending on cooldowns. + * @param deltaTime the time since the last game tick + */ void CalculateCombat(float deltaTime); - /** - * Gets all the targets that are in the aggro collision phantom of this entity - * @return the targets within the aggro range of this entity - */ + /** + * Gets all the targets that are in the aggro collision phantom of this entity + * @return the targets within the aggro range of this entity + */ std::vector GetTargetWithinAggroRange() const; - /** - * The current state of the AI - */ + /** + * @brief Sets the AiState and prepares the entity for serialization next frame. + * + */ + void SetAiState(AiState newState); + + /** + * The current state of the AI + */ AiState m_State; - /** - * The target this entity is currently trying to attack - */ + /** + * The target this entity is currently trying to attack + */ LWOOBJID m_Target; - /** - * The aggro physics volumes of this entity - */ + /** + * The aggro physics volumes of this entity + */ dpEntity* m_dpEntity; dpEntity* m_dpEntityEnemy; - /** - * The max radius of this entity to an enemy allowing it to be chased - */ + /** + * The max radius of this entity to an enemy allowing it to be chased + */ float m_HardTetherRadius = 100; - /** - * A soft radius for the tether, currently unused - */ + /** + * A soft radius for the tether, currently unused + */ float m_SoftTetherRadius = 25; - /** - * The speed at which this entity chases enemies - */ + /** + * The speed at which this entity chases enemies + */ float m_PursuitSpeed = 2; - /** - * The radius that can cause enemies to aggro this entity - */ + /** + * The radius that can cause enemies to aggro this entity + */ float m_AggroRadius = 25; - /** - * The speed at which an enemy wanders around - */ + /** + * The speed at which an enemy wanders around + */ float m_TetherSpeed = 4; - /** - * How close this entity needs to be to an enemy to allow attacks - */ + /** + * How close this entity needs to be to an enemy to allow attacks + */ float m_AttackRadius = 5.0f; - /** - * Timer before we start attacking others - */ + /** + * Timer before we start attacking others + */ float m_Timer = 0.0f; - /** - * Timer to serializing this entity - */ + /** + * Timer to serializing this entity + */ float m_SoftTimer = 0.0f; - /** - * The skills this entity can cast on enemies - */ + /** + * The skills this entity can cast on enemies + */ std::vector m_SkillEntries; - /** - * The current enemies and their respective threats to this entity - */ + /** + * The current enemies and their respective threats to this entity + */ std::map m_ThreatEntries; - /** - * The component that handles movement AI, also owned by this entity - */ + /** + * The component that handles movement AI, also owned by this entity + */ MovementAIComponent* m_MovementAI; - /** - * The position at which this entity spawned - */ + /** + * The position at which this entity spawned + */ NiPoint3 m_StartPosition; - /** - * For how long this entity has been stunned - */ + /** + * For how long this entity has been stunned + */ float m_StunTime = 0; - /** - * If this entity is stunned - */ + /** + * If this entity is stunned + */ bool m_Stunned = false; - /** - * If this entity is immune to stunds - */ + /** + * If this entity is immune to stunds + */ bool m_StunImmune = false; - /** - * Time taken between actions - */ - float m_Downtime = 0; - - /** - * How long this entity needs to execute its skill - */ + /** + * How long this entity needs to execute its skill + */ float m_SkillTime = 0; - /** - * If the entity is currently showing the exclamation mark icon above its head - */ + /** + * If the entity is currently showing the exclamation mark icon above its head + */ bool m_TetherEffectActive = false; - /** - * How long the tether effect will remain active - */ + /** + * How long the tether effect will remain active + */ float m_TetherTime = 0; - /** - * How long until we will consider this entity out of combat, resetting its health and armor - */ + /** + * How long until we will consider this entity out of combat, resetting its health and armor + */ float m_OutOfCombatTime = 0; - /** - * If the entity is currently out of combat, resetting its health and armor if it just came out of combat - */ + /** + * If the entity is currently out of combat, resetting its health and armor if it just came out of combat + */ bool m_OutOfCombat = false; - /** - * If the AI is currently disabled - */ + /** + * If the AI is currently disabled + */ bool m_Disabled = false; - /** - * If the threat list should be updated - */ + /** + * If the threat list should be updated + */ bool m_DirtyThreat = false; + /** + * Whether or not the Component has dirty information and should update next frame + * + */ + bool m_DirtyStateOrTarget = false; + /** * Whether the current entity is a mech enemy, needed as mechs tether radius works differently * @return whether this entity is a mech diff --git a/dGame/dComponents/BouncerComponent.cpp b/dGame/dComponents/BouncerComponent.cpp index 38370f39..f6a53261 100644 --- a/dGame/dComponents/BouncerComponent.cpp +++ b/dGame/dComponents/BouncerComponent.cpp @@ -7,14 +7,14 @@ #include "dLogger.h" #include "GameMessages.h" #include +#include "eTriggerEventType.h" BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) { m_PetEnabled = false; m_PetBouncerEnabled = false; m_PetSwitchLoaded = false; - - if (parent->GetLOT() == 7625) - { + + if (parent->GetLOT() == 7625) { LookupPetSwitch(); } } @@ -22,86 +22,75 @@ BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) { BouncerComponent::~BouncerComponent() { } -void BouncerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags){ +void BouncerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { outBitStream->Write(m_PetEnabled); if (m_PetEnabled) { outBitStream->Write(m_PetBouncerEnabled); } } -Entity* BouncerComponent::GetParentEntity() const -{ +Entity* BouncerComponent::GetParentEntity() const { return m_Parent; } -void BouncerComponent::SetPetEnabled(bool value) -{ +void BouncerComponent::SetPetEnabled(bool value) { m_PetEnabled = value; EntityManager::Instance()->SerializeEntity(m_Parent); } -void BouncerComponent::SetPetBouncerEnabled(bool value) -{ +void BouncerComponent::SetPetBouncerEnabled(bool value) { m_PetBouncerEnabled = value; GameMessages::SendBouncerActiveStatus(m_Parent->GetObjectID(), value, UNASSIGNED_SYSTEM_ADDRESS); EntityManager::Instance()->SerializeEntity(m_Parent); - if (value) - { + if (value) { + m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent); GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true); - } - else - { + } else { + m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent); GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch"); } - + } -bool BouncerComponent::GetPetEnabled() const -{ +bool BouncerComponent::GetPetEnabled() const { return m_PetEnabled; } -bool BouncerComponent::GetPetBouncerEnabled() const -{ +bool BouncerComponent::GetPetBouncerEnabled() const { return m_PetBouncerEnabled; } -void BouncerComponent::LookupPetSwitch() -{ +void BouncerComponent::LookupPetSwitch() { const auto& groups = m_Parent->GetGroups(); - for (const auto& group : groups) - { + for (const auto& group : groups) { const auto& entities = EntityManager::Instance()->GetEntitiesInGroup(group); - for (auto* entity : entities) - { + for (auto* entity : entities) { auto* switchComponent = entity->GetComponent(); - if (switchComponent != nullptr) - { + if (switchComponent != nullptr) { switchComponent->SetPetBouncer(this); - + m_PetSwitchLoaded = true; m_PetEnabled = true; EntityManager::Instance()->SerializeEntity(m_Parent); - Game::logger->Log("BouncerComponent", "Loaded pet bouncer\n"); + Game::logger->Log("BouncerComponent", "Loaded pet bouncer"); } } } - if (!m_PetSwitchLoaded) - { - Game::logger->Log("BouncerComponent", "Failed to load pet bouncer\n"); - + if (!m_PetSwitchLoaded) { + Game::logger->Log("BouncerComponent", "Failed to load pet bouncer"); + m_Parent->AddCallbackTimer(0.5f, [this]() { LookupPetSwitch(); - }); + }); } } diff --git a/dGame/dComponents/BouncerComponent.h b/dGame/dComponents/BouncerComponent.h index 557f737f..15665cc1 100644 --- a/dGame/dComponents/BouncerComponent.h +++ b/dGame/dComponents/BouncerComponent.h @@ -5,14 +5,15 @@ #include "RakNetTypes.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Attached to bouncer entities, allowing other entities to bounce off of it */ class BouncerComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BOUNCER; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER; + BouncerComponent(Entity* parentEntity); ~BouncerComponent() override; @@ -20,50 +21,50 @@ public: Entity* GetParentEntity() const; - /** - * Sets whether or not this bouncer needs to be activated by a pet - * @param value whether or not this bouncer needs to be activated by a pet - */ + /** + * Sets whether or not this bouncer needs to be activated by a pet + * @param value whether or not this bouncer needs to be activated by a pet + */ void SetPetEnabled(bool value); - /** - * Sets whether or not this bouncer is currently being activated by a pet, allowing entities to bounce off of it, - * also displays FX accordingly. - * @param value whether or not this bouncer is activated by a pet - */ + /** + * Sets whether or not this bouncer is currently being activated by a pet, allowing entities to bounce off of it, + * also displays FX accordingly. + * @param value whether or not this bouncer is activated by a pet + */ void SetPetBouncerEnabled(bool value); - /** - * Gets whether this bouncer should be enabled using pets - * @return whether this bouncer should be enabled using pets - */ + /** + * Gets whether this bouncer should be enabled using pets + * @return whether this bouncer should be enabled using pets + */ bool GetPetEnabled() const; - /** - * Gets whether this bouncer is currently activated by a pet - * @return whether this bouncer is currently activated by a pet - */ + /** + * Gets whether this bouncer is currently activated by a pet + * @return whether this bouncer is currently activated by a pet + */ bool GetPetBouncerEnabled() const; - /** - * Finds the switch used to activate this bouncer if its pet-enabled and stores this components' state there - */ + /** + * Finds the switch used to activate this bouncer if its pet-enabled and stores this components' state there + */ void LookupPetSwitch(); private: - /** - * Whether this bouncer needs to be activated by a pet - */ + /** + * Whether this bouncer needs to be activated by a pet + */ bool m_PetEnabled; - /** - * Whether this bouncer is currently being activated by a pet - */ + /** + * Whether this bouncer is currently being activated by a pet + */ bool m_PetBouncerEnabled; - /** - * Whether the pet switch for this bouncer has been located - */ + /** + * Whether the pet switch for this bouncer has been located + */ bool m_PetSwitchLoaded; }; diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 9c12e87d..68b5182c 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -9,29 +9,26 @@ #include "SkillComponent.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "CDClientManager.h" +#include "CDSkillBehaviorTable.h" -std::unordered_map> BuffComponent::m_Cache {}; +std::unordered_map> BuffComponent::m_Cache{}; -BuffComponent::BuffComponent(Entity* parent) : Component(parent) -{ +BuffComponent::BuffComponent(Entity* parent) : Component(parent) { } BuffComponent::~BuffComponent() { } void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (!bIsInitialUpdate) return; - if (m_Buffs.empty()) - { + if (!bIsInitialUpdate) return; + if (m_Buffs.empty()) { outBitStream->Write0(); - } - else - { + } else { outBitStream->Write1(); outBitStream->Write(m_Buffs.size()); - for (const auto& buff : m_Buffs) - { + for (const auto& buff : m_Buffs) { outBitStream->Write(buff.first); outBitStream->Write0(); outBitStream->Write0(); @@ -49,25 +46,21 @@ void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUp outBitStream->Write(0); } } - + outBitStream->Write0(); } -void BuffComponent::Update(float deltaTime) -{ +void BuffComponent::Update(float deltaTime) { /** * Loop through all buffs and apply deltaTime to ther time. * If they have expired, remove the buff and break. */ - for (auto& buff : m_Buffs) - { + for (auto& buff : m_Buffs) { // For damage buffs - if (buff.second.tick != 0.0f && buff.second.stacks > 0) - { + if (buff.second.tick != 0.0f && buff.second.stacks > 0) { buff.second.tickTime -= deltaTime; - if (buff.second.tickTime <= 0.0f) - { + if (buff.second.tickTime <= 0.0f) { buff.second.tickTime = buff.second.tick; buff.second.stacks--; @@ -76,15 +69,13 @@ void BuffComponent::Update(float deltaTime) } // These are indefinate buffs, don't update them. - if (buff.second.time == 0.0f) - { + if (buff.second.time == 0.0f) { continue; } buff.second.time -= deltaTime; - if (buff.second.time <= 0.0f) - { + if (buff.second.time <= 0.0f) { RemoveBuff(buff.first); break; @@ -93,29 +84,25 @@ void BuffComponent::Update(float deltaTime) } void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity, - bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff, - bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) -{ + bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff, + bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) { // Prevent buffs from stacking. - if (HasBuff(id)) - { + if (HasBuff(id)) { return; } - GameMessages::SendAddBuff(const_cast(m_Parent->GetObjectID()), source, (uint32_t) id, - (uint32_t) duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath, - cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); + GameMessages::SendAddBuff(const_cast(m_Parent->GetObjectID()), source, (uint32_t)id, + (uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath, + cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); float tick = 0; float stacks = 0; int32_t behaviorID = 0; const auto& parameters = GetBuffParameters(id); - for (const auto& parameter : parameters) - { - if (parameter.name == "overtime") - { - auto* behaviorTemplateTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + for (const auto& parameter : parameters) { + if (parameter.name == "overtime") { + auto* behaviorTemplateTable = CDClientManager::Instance().GetTable(); behaviorID = behaviorTemplateTable->GetSkillByID(parameter.values[0]).behaviorID; stacks = static_cast(parameter.values[1]); @@ -138,32 +125,28 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO m_Buffs.emplace(id, buff); } -void BuffComponent::RemoveBuff(int32_t id) -{ +void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) { const auto& iter = m_Buffs.find(id); - if (iter == m_Buffs.end()) - { + if (iter == m_Buffs.end()) { return; } - + + GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id); + m_Buffs.erase(iter); RemoveBuffEffect(id); } -bool BuffComponent::HasBuff(int32_t id) -{ +bool BuffComponent::HasBuff(int32_t id) { return m_Buffs.find(id) != m_Buffs.end(); } -void BuffComponent::ApplyBuffEffect(int32_t id) -{ +void BuffComponent::ApplyBuffEffect(int32_t id) { const auto& parameters = GetBuffParameters(id); - for (const auto& parameter : parameters) - { - if (parameter.name == "max_health") - { + for (const auto& parameter : parameters) { + if (parameter.name == "max_health") { const auto maxHealth = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -171,9 +154,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxHealth(destroyable->GetMaxHealth() + maxHealth); - } - else if (parameter.name == "max_armor") - { + } else if (parameter.name == "max_armor") { const auto maxArmor = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -181,9 +162,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxArmor(destroyable->GetMaxArmor() + maxArmor); - } - else if (parameter.name == "max_imagination") - { + } else if (parameter.name == "max_imagination") { const auto maxImagination = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -191,31 +170,19 @@ void BuffComponent::ApplyBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxImagination(destroyable->GetMaxImagination() + maxImagination); - } - else if (parameter.name == "speed") - { - const auto speed = parameter.value; - + } else if (parameter.name == "speed") { auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->AddSpeedboost(speed); } } } -void BuffComponent::RemoveBuffEffect(int32_t id) -{ +void BuffComponent::RemoveBuffEffect(int32_t id) { const auto& parameters = GetBuffParameters(id); - for (const auto& parameter : parameters) - { - if (parameter.name == "max_health") - { + for (const auto& parameter : parameters) { + if (parameter.name == "max_health") { const auto maxHealth = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -223,9 +190,7 @@ void BuffComponent::RemoveBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxHealth(destroyable->GetMaxHealth() - maxHealth); - } - else if (parameter.name == "max_armor") - { + } else if (parameter.name == "max_armor") { const auto maxArmor = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -233,9 +198,7 @@ void BuffComponent::RemoveBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxArmor(destroyable->GetMaxArmor() - maxArmor); - } - else if (parameter.name == "max_imagination") - { + } else if (parameter.name == "max_imagination") { const auto maxImagination = parameter.value; auto* destroyable = this->GetParent()->GetComponent(); @@ -243,70 +206,52 @@ void BuffComponent::RemoveBuffEffect(int32_t id) if (destroyable == nullptr) return; destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination); - } - else if (parameter.name == "speed") - { - const auto speed = parameter.value; - + } else if (parameter.name == "speed") { auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->RemoveSpeedboost(speed); } } } -void BuffComponent::RemoveAllBuffs() -{ - for (const auto& buff : m_Buffs) - { +void BuffComponent::RemoveAllBuffs() { + for (const auto& buff : m_Buffs) { RemoveBuffEffect(buff.first); } m_Buffs.clear(); } -void BuffComponent::Reset() -{ +void BuffComponent::Reset() { RemoveAllBuffs(); } -void BuffComponent::ReApplyBuffs() -{ - for (const auto& buff : m_Buffs) - { +void BuffComponent::ReApplyBuffs() { + for (const auto& buff : m_Buffs) { ApplyBuffEffect(buff.first); } } -Entity* BuffComponent::GetParent() const -{ +Entity* BuffComponent::GetParent() const { return m_Parent; } -void BuffComponent::LoadFromXML(tinyxml2::XMLDocument* doc) -{ +void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { // Load buffs auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); - + // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); - + // Old character, no buffs to load - if (buffElement == nullptr) - { + if (buffElement == nullptr) { return; } auto* buffEntry = buffElement->FirstChildElement("b"); - while (buffEntry != nullptr) - { + while (buffEntry != nullptr) { int32_t id = buffEntry->IntAttribute("id"); float t = buffEntry->FloatAttribute("t"); float tk = buffEntry->FloatAttribute("tk"); @@ -328,27 +273,22 @@ void BuffComponent::LoadFromXML(tinyxml2::XMLDocument* doc) } } -void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) -{ +void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) { // Save buffs auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); - + // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); - - if (buffElement == nullptr) - { + + if (buffElement == nullptr) { buffElement = doc->NewElement("buff"); dest->LinkEndChild(buffElement); - } - else - { + } else { buffElement->DeleteChildren(); } - for (const auto& buff : m_Buffs) - { + for (const auto& buff : m_Buffs) { auto* buffEntry = doc->NewElement("b"); buffEntry->SetAttribute("id", buff.first); @@ -357,52 +297,44 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) buffEntry->SetAttribute("s", buff.second.stacks); buffEntry->SetAttribute("sr", buff.second.source); buffEntry->SetAttribute("b", buff.second.behaviorID); - + buffElement->LinkEndChild(buffEntry); } } -const std::vector& BuffComponent::GetBuffParameters(int32_t buffId) -{ +const std::vector& BuffComponent::GetBuffParameters(int32_t buffId) { const auto& pair = m_Cache.find(buffId); - if (pair != m_Cache.end()) - { + if (pair != m_Cache.end()) { return pair->second; } auto query = CDClientDatabase::CreatePreppedStmt( "SELECT * FROM BuffParameters WHERE BuffID = ?;"); - query.bind(1, (int) buffId); + query.bind(1, (int)buffId); auto result = query.execQuery(); - - std::vector parameters {}; - while (!result.eof()) - { + std::vector parameters{}; + + while (!result.eof()) { BuffParameter param; param.buffId = buffId; param.name = result.getStringField(1); param.value = result.getFloatField(2); - if (!result.fieldIsNull(3)) - { + if (!result.fieldIsNull(3)) { std::istringstream stream(result.getStringField(3)); std::string token; - while (std::getline(stream, token, ',')) - { - try - { + while (std::getline(stream, token, ',')) { + try { const auto value = std::stof(token); param.values.push_back(value); - } - catch (std::invalid_argument& exception) - { - Game::logger->Log("BuffComponent", "Failed to parse value (%s): (%s)!\n", token.c_str(), exception.what()); + } catch (std::invalid_argument& exception) { + Game::logger->Log("BuffComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what()); } } } @@ -411,7 +343,7 @@ const std::vector& BuffComponent::GetBuffParameters(int32_t buffI result.nextRow(); } - + m_Cache.insert_or_assign(buffId, parameters); return m_Cache.find(buffId)->second; diff --git a/dGame/dComponents/BuffComponent.h b/dGame/dComponents/BuffComponent.h index ba22c08b..d9175883 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -7,6 +7,7 @@ #include #include #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -15,11 +16,11 @@ class Entity; */ struct BuffParameter { - int32_t buffId; - std::string name; - float value; - std::vector values; - int32_t effectId; + int32_t buffId; + std::string name; + float value; + std::vector values; + int32_t effectId; }; /** @@ -27,13 +28,13 @@ struct BuffParameter */ struct Buff { - int32_t id = 0; - float time = 0; - float tick = 0; - float tickTime = 0; - int32_t stacks = 0; - LWOOBJID source = 0; - int32_t behaviorID = 0; + int32_t id = 0; + float time = 0; + float tick = 0; + float tickTime = 0; + int32_t stacks = 0; + LWOOBJID source = 0; + int32_t behaviorID = 0; }; /** @@ -41,97 +42,98 @@ struct Buff */ class BuffComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BUFF; - - explicit BuffComponent(Entity* parent); + static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF; - ~BuffComponent(); + explicit BuffComponent(Entity* parent); - Entity* GetParent() const; + ~BuffComponent(); - void LoadFromXML(tinyxml2::XMLDocument* doc); + Entity* GetParent() const; - void UpdateXml(tinyxml2::XMLDocument* doc) override; - - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void Update(float deltaTime) override; + void UpdateXml(tinyxml2::XMLDocument* doc) override; - /** - * Applies a buff to the parent entity - * @param id the id of the buff to apply - * @param duration the duration of the buff in seconds - * @param source an optional source entity that cast the buff - * @param addImmunity client flag - * @param cancelOnDamaged client flag to indicate that the buff should disappear when damaged - * @param cancelOnDeath client flag to indicate that the buff should disappear when dying - * @param cancelOnLogout client flag to indicate that the buff should disappear when logging out - * @param cancelOnRemoveBuff client flag to indicate that the buff should disappear when a concrete GM to do so comes around - * @param cancelOnUi client flag to indicate that the buff should disappear when interacting with UI - * @param cancelOnUnequip client flag to indicate that the buff should disappear when the triggering item is unequipped - * @param cancelOnZone client flag to indicate that the buff should disappear when changing zones - */ - void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false, - bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, - bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Removes a buff from the parent entity, reversing its effects - * @param id the id of the buff to remove - */ - void RemoveBuff(int32_t id); + void Update(float deltaTime) override; - /** - * Returns whether or not the entity has a buff identified by `id` - * @param id the id of the buff to find - * @return whether or not the entity has a buff with the specified id active - */ - bool HasBuff(int32_t id); + /** + * Applies a buff to the parent entity + * @param id the id of the buff to apply + * @param duration the duration of the buff in seconds + * @param source an optional source entity that cast the buff + * @param addImmunity client flag + * @param cancelOnDamaged client flag to indicate that the buff should disappear when damaged + * @param cancelOnDeath client flag to indicate that the buff should disappear when dying + * @param cancelOnLogout client flag to indicate that the buff should disappear when logging out + * @param cancelOnRemoveBuff client flag to indicate that the buff should disappear when a concrete GM to do so comes around + * @param cancelOnUi client flag to indicate that the buff should disappear when interacting with UI + * @param cancelOnUnequip client flag to indicate that the buff should disappear when the triggering item is unequipped + * @param cancelOnZone client flag to indicate that the buff should disappear when changing zones + */ + void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false, + bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, + bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false); - /** - * Applies the effects of the buffs on the entity, e.g.: changing armor, health, imag, etc. - * @param id the id of the buff effects to apply - */ - void ApplyBuffEffect(int32_t id); + /** + * Removes a buff from the parent entity, reversing its effects + * @param id the id of the buff to remove + * @param removeImmunity whether or not to remove immunity on removing the buff + */ + void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false); - /** - * Reverses the effects of the applied buff - * @param id the id of the buff for which to remove the effects - */ - void RemoveBuffEffect(int32_t id); + /** + * Returns whether or not the entity has a buff identified by `id` + * @param id the id of the buff to find + * @return whether or not the entity has a buff with the specified id active + */ + bool HasBuff(int32_t id); - /** - * Removes all buffs for the entity and reverses all of their effects - */ - void RemoveAllBuffs(); + /** + * Applies the effects of the buffs on the entity, e.g.: changing armor, health, imag, etc. + * @param id the id of the buff effects to apply + */ + void ApplyBuffEffect(int32_t id); - /** - * Removes all buffs for the entity and reverses all of their effects - */ - void Reset(); + /** + * Reverses the effects of the applied buff + * @param id the id of the buff for which to remove the effects + */ + void RemoveBuffEffect(int32_t id); - /** - * Applies all effects for all buffs, active or not, again - */ - void ReApplyBuffs(); + /** + * Removes all buffs for the entity and reverses all of their effects + */ + void RemoveAllBuffs(); - /** - * Gets all the parameters (= effects), for the buffs that belong to this component - * @param buffId - * @return - */ - const std::vector& GetBuffParameters(int32_t buffId); + /** + * Removes all buffs for the entity and reverses all of their effects + */ + void Reset(); + + /** + * Applies all effects for all buffs, active or not, again + */ + void ReApplyBuffs(); + + /** + * Gets all the parameters (= effects), for the buffs that belong to this component + * @param buffId + * @return + */ + const std::vector& GetBuffParameters(int32_t buffId); private: - /** - * The currently active buffs - */ - std::map m_Buffs; + /** + * The currently active buffs + */ + std::map m_Buffs; - /** - * Parameters (=effects) for each buff - */ - static std::unordered_map> m_Cache; + /** + * Parameters (=effects) for each buff + */ + static std::unordered_map> m_Cache; }; #endif // BUFFCOMPONENT_H diff --git a/dGame/dComponents/BuildBorderComponent.cpp b/dGame/dComponents/BuildBorderComponent.cpp index 1747f0ed..f9ead9e4 100644 --- a/dGame/dComponents/BuildBorderComponent.cpp +++ b/dGame/dComponents/BuildBorderComponent.cpp @@ -9,12 +9,10 @@ #include "Item.h" #include "PropertyManagementComponent.h" -BuildBorderComponent::BuildBorderComponent(Entity* parent) : Component(parent) -{ +BuildBorderComponent::BuildBorderComponent(Entity* parent) : Component(parent) { } -BuildBorderComponent::~BuildBorderComponent() -{ +BuildBorderComponent::~BuildBorderComponent() { } void BuildBorderComponent::OnUse(Entity* originator) { @@ -23,11 +21,10 @@ void BuildBorderComponent::OnUse(Entity* originator) { auto buildArea = m_Parent->GetObjectID(); - if (!entities.empty()) - { + if (!entities.empty()) { buildArea = entities[0]->GetObjectID(); - - Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque\n"); + + Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque"); } auto* inventoryComponent = originator->GetComponent(); @@ -44,7 +41,7 @@ void BuildBorderComponent::OnUse(Entity* originator) { inventoryComponent->PushEquippedItems(); - Game::logger->Log("BuildBorderComponent", "Starting with %llu\n", buildArea); + Game::logger->Log("BuildBorderComponent", "Starting with %llu", buildArea); if (PropertyManagementComponent::Instance() != nullptr) { GameMessages::SendStartArrangingWithItem( @@ -62,8 +59,7 @@ void BuildBorderComponent::OnUse(Entity* originator) { NiPoint3::ZERO, 0 ); - } - else { + } else { GameMessages::SendStartArrangingWithItem(originator, originator->GetSystemAddress(), true, buildArea, originator->GetPosition()); } diff --git a/dGame/dComponents/BuildBorderComponent.h b/dGame/dComponents/BuildBorderComponent.h index bd615b48..dc5afc8a 100644 --- a/dGame/dComponents/BuildBorderComponent.h +++ b/dGame/dComponents/BuildBorderComponent.h @@ -9,21 +9,22 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * Component for the build border, allowing the user to start building when interacting with it - */ + /** + * Component for the build border, allowing the user to start building when interacting with it + */ class BuildBorderComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BUILD_BORDER; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::BUILD_BORDER; + BuildBorderComponent(Entity* parent); ~BuildBorderComponent() override; - /** - * Causes the originator to start build with this entity as a reference point - * @param originator the entity (probably a player) that triggered the event - */ + /** + * Causes the originator to start build with this entity as a reference point + * @param originator the entity (probably a player) that triggered the event + */ void OnUse(Entity* originator) override; private: }; diff --git a/dGame/dComponents/CMakeLists.txt b/dGame/dComponents/CMakeLists.txt new file mode 100644 index 00000000..b396829a --- /dev/null +++ b/dGame/dComponents/CMakeLists.txt @@ -0,0 +1,43 @@ +set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp" + "BouncerComponent.cpp" + "BuffComponent.cpp" + "BuildBorderComponent.cpp" + "CharacterComponent.cpp" + "Component.cpp" + "ControllablePhysicsComponent.cpp" + "DestroyableComponent.cpp" + "InventoryComponent.cpp" + "LevelProgressionComponent.cpp" + "LUPExhibitComponent.cpp" + "MissionComponent.cpp" + "MissionOfferComponent.cpp" + "ModelComponent.cpp" + "ModuleAssemblyComponent.cpp" + "MovementAIComponent.cpp" + "MovingPlatformComponent.cpp" + "PetComponent.cpp" + "PhantomPhysicsComponent.cpp" + "PlayerForcedMovementComponent.cpp" + "PossessableComponent.cpp" + "PossessorComponent.cpp" + "PropertyComponent.cpp" + "PropertyEntranceComponent.cpp" + "PropertyManagementComponent.cpp" + "PropertyVendorComponent.cpp" + "ProximityMonitorComponent.cpp" + "RacingControlComponent.cpp" + "RailActivatorComponent.cpp" + "RebuildComponent.cpp" + "RenderComponent.cpp" + "RigidbodyPhantomPhysicsComponent.cpp" + "RocketLaunchLupComponent.cpp" + "RocketLaunchpadControlComponent.cpp" + "ScriptedActivityComponent.cpp" + "ShootingGalleryComponent.cpp" + "SimplePhysicsComponent.cpp" + "SkillComponent.cpp" + "SoundTriggerComponent.cpp" + "SwitchComponent.cpp" + "TriggerComponent.cpp" + "VehiclePhysicsComponent.cpp" + "VendorComponent.cpp" PARENT_SCOPE) diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index dd2b69bb..82ad5507 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -13,6 +13,9 @@ #include "VehiclePhysicsComponent.h" #include "GameMessages.h" #include "Item.h" +#include "AMFFormat.h" +#include "eGameMasterLevel.h" +#include "eGameActivity.h" CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { m_Character = character; @@ -21,7 +24,6 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character) : C m_IsGM = false; m_IsLanding = false; m_IsLEGOClubMember = true; - m_Level = 1; m_DirtyCurrentActivity = false; m_DirtyGMInfo = false; @@ -32,33 +34,22 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character) : C m_EditorEnabled = false; m_EditorLevel = m_GMLevel; - m_Reputation = 0; + m_Reputation = 0; - m_CurrentActivity = 0; + m_CurrentActivity = eGameActivity::NONE; m_CountryCode = 0; m_LastUpdateTimestamp = std::time(nullptr); - - LoadFromXML(); - - //Check to see if we're landing: - if (character->GetZoneID() != Game::server->GetZoneID()) { - m_IsLanding = true; - } - - if (LandingAnimDisabled(character->GetZoneID()) || LandingAnimDisabled(Game::server->GetZoneID()) || m_LastRocketConfig.empty()) { - m_IsLanding = false; //Don't make us land on VE/minigames lol - } } bool CharacterComponent::LandingAnimDisabled(int zoneID) { switch (zoneID) { case 0: case 556: - case 1001: case 1101: case 1202: case 1203: case 1204: + case 1261: case 1301: case 1302: case 1303: @@ -80,16 +71,13 @@ CharacterComponent::~CharacterComponent() { } void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write1(); - outBitStream->Write(m_Level); - outBitStream->Write0(); - + if (bIsInitialUpdate) { outBitStream->Write0(); outBitStream->Write0(); outBitStream->Write0(); outBitStream->Write0(); - + outBitStream->Write(m_Character->GetHairColor()); outBitStream->Write(m_Character->GetHairStyle()); outBitStream->Write(0); //Default "head" @@ -134,7 +122,7 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit outBitStream->Write(m_RacingSmashablesSmashed); outBitStream->Write(m_RacesFinished); outBitStream->Write(m_FirstPlaceRaceFinishes); - + outBitStream->Write0(); outBitStream->Write(m_IsLanding); if (m_IsLanding) { @@ -153,165 +141,107 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit outBitStream->Write(m_EditorEnabled); outBitStream->Write(m_EditorLevel); } - + outBitStream->Write(m_DirtyCurrentActivity); if (m_DirtyCurrentActivity) outBitStream->Write(m_CurrentActivity); - + outBitStream->Write(m_DirtySocialInfo); if (m_DirtySocialInfo) { outBitStream->Write(m_GuildID); outBitStream->Write(static_cast(m_GuildName.size())); if (!m_GuildName.empty()) outBitStream->WriteBits(reinterpret_cast(m_GuildName.c_str()), static_cast(m_GuildName.size()) * sizeof(wchar_t) * 8); - + outBitStream->Write(m_IsLEGOClubMember); outBitStream->Write(m_CountryCode); } } -bool CharacterComponent::GetPvpEnabled() const -{ +bool CharacterComponent::GetPvpEnabled() const { return m_PvpEnabled; } -void CharacterComponent::SetPvpEnabled(const bool value) -{ +void CharacterComponent::SetPvpEnabled(const bool value) { m_DirtyGMInfo = true; - + m_PvpEnabled = value; } -void CharacterComponent::HandleLevelUp() -{ - auto* rewardsTable = CDClientManager::Instance()->GetTable("Rewards"); - - const auto& rewards = rewardsTable->GetByLevelID(m_Level); - bool rewardingItem = rewards.size() > 0; - - auto* parent = m_Character->GetEntity(); - - if (parent == nullptr) - { - return; - } - - auto* inventoryComponent = parent->GetComponent(); - auto* controllablePhysicsComponent = parent->GetComponent(); - - if (inventoryComponent == nullptr || controllablePhysicsComponent == nullptr) - { - return; - } - // Tell the client we beginning to send level rewards. - if(rewardingItem) GameMessages::NotifyLevelRewards(parent->GetObjectID(), parent->GetSystemAddress(), m_Level, rewardingItem); - - for (auto* reward : rewards) - { - switch (reward->rewardType) - { - case 0: - inventoryComponent->AddItem(reward->value, reward->count, eLootSourceType::LOOT_SOURCE_LEVEL_REWARD); - break; - case 4: - { - auto* items = inventoryComponent->GetInventory(eInventoryType::ITEMS); - items->SetSize(items->GetSize() + reward->value); - } - break; - case 9: - controllablePhysicsComponent->SetSpeedMultiplier(static_cast(reward->value) / 500.0f); - break; - case 11: - case 12: - break; - default: - break; - } - } - // Tell the client we have finished sending level rewards. - if(rewardingItem) GameMessages::NotifyLevelRewards(parent->GetObjectID(), parent->GetSystemAddress(), m_Level, !rewardingItem); -} - -void CharacterComponent::SetGMLevel(int gmlevel) { +void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) { m_DirtyGMInfo = true; - if (gmlevel > 0) m_IsGM = true; + if (gmlevel > eGameMasterLevel::CIVILIAN) m_IsGM = true; else m_IsGM = false; m_GMLevel = gmlevel; } -void CharacterComponent::LoadFromXML() { - if (!m_Character) return; - - tinyxml2::XMLDocument* doc = m_Character->GetXMLDoc(); - if (!doc) return; - +void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { + tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); if (!character) { - Game::logger->Log("CharacterComponent", "Failed to find char tag while loading XML!\n"); + Game::logger->Log("CharacterComponent", "Failed to find char tag while loading XML!"); return; } - if (character->QueryAttribute("rpt", &m_Reputation) == tinyxml2::XML_NO_ATTRIBUTE) { - SetReputation(0); - } - + if (character->QueryAttribute("rpt", &m_Reputation) == tinyxml2::XML_NO_ATTRIBUTE) { + SetReputation(0); + } + character->QueryInt64Attribute("ls", &m_Uscore); // Load the statistics - const auto* statisticsAttribute = character->FindAttribute("stt"); - if (statisticsAttribute) { - InitializeStatisticsFromString(std::string(statisticsAttribute->Value())); - } else { - InitializeEmptyStatistics(); - } - - // Load the zone statistics - m_ZoneStatistics = {}; - auto zoneStatistics = character->FirstChildElement("zs"); - - if (zoneStatistics) { - auto child = zoneStatistics->FirstChildElement(); - while (child) { - ZoneStatistics statistics = {}; - - child->QueryUnsigned64Attribute("ac", &statistics.m_AchievementsCollected); - child->QueryUnsigned64Attribute("bc", &statistics.m_BricksCollected); - child->QueryUnsigned64Attribute("cc", &statistics.m_CoinsCollected); - child->QueryUnsigned64Attribute("es", &statistics.m_EnemiesSmashed); - child->QueryUnsigned64Attribute("qbc", &statistics.m_QuickBuildsCompleted); - - uint32_t mapID; - child->QueryAttribute("map", &mapID); - - m_ZoneStatistics.insert({ (LWOMAPID) mapID, statistics }); - - child = child->NextSiblingElement(); - } - } - - const tinyxml2::XMLAttribute *rocketConfig = character->FindAttribute("lcbp"); - if (rocketConfig) { - m_LastRocketConfig = GeneralUtils::ASCIIToUTF16(std::string(rocketConfig->Value())); + const auto* statisticsAttribute = character->FindAttribute("stt"); + if (statisticsAttribute) { + InitializeStatisticsFromString(std::string(statisticsAttribute->Value())); + } else { + InitializeEmptyStatistics(); } - else - { + + // Load the zone statistics + m_ZoneStatistics = {}; + auto zoneStatistics = character->FirstChildElement("zs"); + + if (zoneStatistics) { + auto child = zoneStatistics->FirstChildElement(); + while (child) { + ZoneStatistics statistics = {}; + + child->QueryUnsigned64Attribute("ac", &statistics.m_AchievementsCollected); + child->QueryInt64Attribute("bc", &statistics.m_BricksCollected); + child->QueryUnsigned64Attribute("cc", &statistics.m_CoinsCollected); + child->QueryUnsigned64Attribute("es", &statistics.m_EnemiesSmashed); + child->QueryUnsigned64Attribute("qbc", &statistics.m_QuickBuildsCompleted); + + uint32_t mapID; + child->QueryAttribute("map", &mapID); + + m_ZoneStatistics.insert({ (LWOMAPID)mapID, statistics }); + + child = child->NextSiblingElement(); + } + } + + const tinyxml2::XMLAttribute* rocketConfig = character->FindAttribute("lcbp"); + + if (rocketConfig) { + m_LastRocketConfig = GeneralUtils::ASCIIToUTF16(rocketConfig->Value()); + } else { m_LastRocketConfig = u""; } - // - // Begin custom attributes - // + // + // Begin custom attributes + // - // Load the last rocket item ID - const tinyxml2::XMLAttribute *lastRocketItemID = character->FindAttribute("lrid"); - if (lastRocketItemID) { - m_LastRocketItemID = lastRocketItemID->Int64Value(); - } + // Load the last rocket item ID + const tinyxml2::XMLAttribute* lastRocketItemID = character->FindAttribute("lrid"); + if (lastRocketItemID) { + m_LastRocketItemID = lastRocketItemID->Int64Value(); + } - // - // End custom attributes - // + // + // End custom attributes + // - if (m_GMLevel > 0) { + if (m_GMLevel > eGameMasterLevel::CIVILIAN) { m_IsGM = true; m_DirtyGMInfo = true; m_EditorLevel = m_GMLevel; @@ -319,64 +249,67 @@ void CharacterComponent::LoadFromXML() { } //Annoying guild bs: - const tinyxml2::XMLAttribute *guildName = character->FindAttribute("gn"); + const tinyxml2::XMLAttribute* guildName = character->FindAttribute("gn"); if (guildName) { const char* gn = guildName->Value(); int64_t gid = 0; character->QueryInt64Attribute("gid", &gid); if (gid != 0) { std::string guildname(gn); - m_GuildName = GeneralUtils::ASCIIToUTF16(guildname); + m_GuildName = GeneralUtils::UTF8ToUTF16(guildname); m_GuildID = gid; m_DirtySocialInfo = true; } } - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); - if (!level) { - Game::logger->Log("CharacterComponent", "Failed to find lvl tag while loading XML!\n"); - return; + if (character->FindAttribute("time")) { + character->QueryUnsigned64Attribute("time", &m_TotalTimePlayed); + } else { + m_TotalTimePlayed = 0; } - level->QueryAttribute("l", &m_Level); + if (!m_Character) return; - if (character->FindAttribute("time")) { - character->QueryUnsigned64Attribute("time", &m_TotalTimePlayed); - } else { - m_TotalTimePlayed = 0; + //Check to see if we're landing: + if (m_Character->GetZoneID() != Game::server->GetZoneID()) { + m_IsLanding = true; + } + + if (LandingAnimDisabled(m_Character->GetZoneID()) || LandingAnimDisabled(Game::server->GetZoneID()) || m_LastRocketConfig.empty()) { + m_IsLanding = false; //Don't make us land on VE/minigames lol } } void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* minifig = doc->FirstChildElement("obj")->FirstChildElement("mf"); + tinyxml2::XMLElement* minifig = doc->FirstChildElement("obj")->FirstChildElement("mf"); if (!minifig) { - Game::logger->Log("CharacterComponent", "Failed to find mf tag while updating XML!\n"); + Game::logger->Log("CharacterComponent", "Failed to find mf tag while updating XML!"); return; } - // write minifig information that might have been changed by commands + // write minifig information that might have been changed by commands - minifig->SetAttribute("es", m_Character->GetEyebrows()); - minifig->SetAttribute("ess", m_Character->GetEyes()); - minifig->SetAttribute("hc", m_Character->GetHairColor()); - minifig->SetAttribute("hs", m_Character->GetHairStyle()); - minifig->SetAttribute("l", m_Character->GetPantsColor()); - minifig->SetAttribute("lh", m_Character->GetLeftHand()); - minifig->SetAttribute("ms", m_Character->GetMouth()); - minifig->SetAttribute("rh", m_Character->GetRightHand()); - minifig->SetAttribute("t", m_Character->GetShirtColor()); + minifig->SetAttribute("es", m_Character->GetEyebrows()); + minifig->SetAttribute("ess", m_Character->GetEyes()); + minifig->SetAttribute("hc", m_Character->GetHairColor()); + minifig->SetAttribute("hs", m_Character->GetHairStyle()); + minifig->SetAttribute("l", m_Character->GetPantsColor()); + minifig->SetAttribute("lh", m_Character->GetLeftHand()); + minifig->SetAttribute("ms", m_Character->GetMouth()); + minifig->SetAttribute("rh", m_Character->GetRightHand()); + minifig->SetAttribute("t", m_Character->GetShirtColor()); - // done with minifig + // done with minifig tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); if (!character) { - Game::logger->Log("CharacterComponent", "Failed to find char tag while updating XML!\n"); + Game::logger->Log("CharacterComponent", "Failed to find char tag while updating XML!"); return; } character->SetAttribute("ls", m_Uscore); - // Custom attribute to keep track of reputation. - character->SetAttribute("rpt", GetReputation()); + // Custom attribute to keep track of reputation. + character->SetAttribute("rpt", GetReputation()); character->SetAttribute("stt", StatisticsToString().c_str()); // Set the zone statistics of the form ... @@ -385,16 +318,16 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { zoneStatistics->DeleteChildren(); for (auto pair : m_ZoneStatistics) { - auto zoneStatistic = doc->NewElement("s"); + auto zoneStatistic = doc->NewElement("s"); - zoneStatistic->SetAttribute("map", pair.first); - zoneStatistic->SetAttribute("ac", pair.second.m_AchievementsCollected); - zoneStatistic->SetAttribute("bc", pair.second.m_BricksCollected); - zoneStatistic->SetAttribute("cc", pair.second.m_CoinsCollected); - zoneStatistic->SetAttribute("es", pair.second.m_EnemiesSmashed); - zoneStatistic->SetAttribute("qbc", pair.second.m_QuickBuildsCompleted); + zoneStatistic->SetAttribute("map", pair.first); + zoneStatistic->SetAttribute("ac", pair.second.m_AchievementsCollected); + zoneStatistic->SetAttribute("bc", pair.second.m_BricksCollected); + zoneStatistic->SetAttribute("cc", pair.second.m_CoinsCollected); + zoneStatistic->SetAttribute("es", pair.second.m_EnemiesSmashed); + zoneStatistic->SetAttribute("qbc", pair.second.m_QuickBuildsCompleted); - zoneStatistics->LinkEndChild(zoneStatistic); + zoneStatistics->LinkEndChild(zoneStatistic); } character->LinkEndChild(zoneStatistics); @@ -402,33 +335,23 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { if (!m_LastRocketConfig.empty()) { std::string config = GeneralUtils::UTF16ToWTF8(m_LastRocketConfig); character->SetAttribute("lcbp", config.c_str()); - } - else - { + } else { character->DeleteAttribute("lcbp"); } - // - // Begin custom attributes - // + // + // Begin custom attributes + // - // Store last rocket item ID - character->SetAttribute("lrid", m_LastRocketItemID); + // Store last rocket item ID + character->SetAttribute("lrid", m_LastRocketItemID); - // - // End custom attributes - // - - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); - if (!level) { - Game::logger->Log("CharacterComponent", "Failed to find lvl tag while updating XML!\n"); - return; - } - - level->SetAttribute("l", m_Level); + // + // End custom attributes + // auto newUpdateTimestamp = std::time(nullptr); - Game::logger->Log("TotalTimePlayed", "Time since last save: %d\n", newUpdateTimestamp - m_LastUpdateTimestamp); + Game::logger->Log("TotalTimePlayed", "Time since last save: %d", newUpdateTimestamp - m_LastUpdateTimestamp); m_TotalTimePlayed += newUpdateTimestamp - m_LastUpdateTimestamp; character->SetAttribute("time", m_TotalTimePlayed); @@ -449,7 +372,7 @@ Item* CharacterComponent::GetRocket(Entity* player) { if (!inventoryComponent) return rocket; // Select the rocket - if (!rocket){ + if (!rocket) { rocket = inventoryComponent->FindItemById(GetLastRocketItemID()); } @@ -458,7 +381,7 @@ Item* CharacterComponent::GetRocket(Entity* player) { } if (!rocket) { - Game::logger->Log("CharacterComponent", "Unable to find rocket to equip!\n"); + Game::logger->Log("CharacterComponent", "Unable to find rocket to equip!"); return rocket; } return rocket; @@ -492,325 +415,325 @@ void CharacterComponent::RocketUnEquip(Entity* player) { } void CharacterComponent::TrackMissionCompletion(bool isAchievement) { - UpdatePlayerStatistic(MissionsCompleted); + UpdatePlayerStatistic(MissionsCompleted); - // Achievements are tracked separately for the zone - if (isAchievement) { - const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); - GetZoneStatisticsForMap(mapID).m_AchievementsCollected++; - } + // Achievements are tracked separately for the zone + if (isAchievement) { + const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); + GetZoneStatisticsForMap(mapID).m_AchievementsCollected++; + } } void CharacterComponent::TrackLOTCollection(LOT lot) { - switch (lot) { - // Handle all the imagination powerup lots - case 935: // 1 point - case 4035: // 2 points - case 11910: // 3 points - case 11911: // 5 points - case 11918: // 10 points - UpdatePlayerStatistic(ImaginationPowerUpsCollected); - break; - // Handle all the armor powerup lots - case 6431: // 1 point - case 11912: // 2 points - case 11913: // 3 points - case 11914: // 5 points - case 11919: // 10 points - UpdatePlayerStatistic(ArmorPowerUpsCollected); - break; - // Handle all the life powerup lots - case 177: // 1 point - case 11915: // 2 points - case 11916: // 3 points - case 11917: // 5 points - case 11920: // 10 points - UpdatePlayerStatistic(LifePowerUpsCollected); - break; - default: - break; - } + switch (lot) { + // Handle all the imagination powerup lots + case 935: // 1 point + case 4035: // 2 points + case 11910: // 3 points + case 11911: // 5 points + case 11918: // 10 points + UpdatePlayerStatistic(ImaginationPowerUpsCollected); + break; + // Handle all the armor powerup lots + case 6431: // 1 point + case 11912: // 2 points + case 11913: // 3 points + case 11914: // 5 points + case 11919: // 10 points + UpdatePlayerStatistic(ArmorPowerUpsCollected); + break; + // Handle all the life powerup lots + case 177: // 1 point + case 11915: // 2 points + case 11916: // 3 points + case 11917: // 5 points + case 11920: // 10 points + UpdatePlayerStatistic(LifePowerUpsCollected); + break; + default: + break; + } } void CharacterComponent::TrackHealthDelta(int32_t health) { - if (health > 0) { - UpdatePlayerStatistic(TotalDamageHealed, health); - } else { - UpdatePlayerStatistic(TotalDamageTaken, -health); - } + if (health > 0) { + UpdatePlayerStatistic(TotalDamageHealed, health); + } else { + UpdatePlayerStatistic(TotalDamageTaken, -health); + } } void CharacterComponent::TrackImaginationDelta(int32_t imagination) { - if (imagination > 0) { - UpdatePlayerStatistic(TotalImaginationRestored, imagination); - } else { - UpdatePlayerStatistic(TotalImaginationUsed, -imagination); - } + if (imagination > 0) { + UpdatePlayerStatistic(TotalImaginationRestored, imagination); + } else { + UpdatePlayerStatistic(TotalImaginationUsed, -imagination); + } } void CharacterComponent::TrackArmorDelta(int32_t armor) { - if (armor > 0) { - UpdatePlayerStatistic(TotalArmorRepaired, armor); - } + if (armor > 0) { + UpdatePlayerStatistic(TotalArmorRepaired, armor); + } } void CharacterComponent::TrackRebuildComplete() { - UpdatePlayerStatistic(QuickBuildsCompleted); + UpdatePlayerStatistic(QuickBuildsCompleted); - const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); - GetZoneStatisticsForMap(mapID).m_QuickBuildsCompleted++; + const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); + GetZoneStatisticsForMap(mapID).m_QuickBuildsCompleted++; } void CharacterComponent::TrackRaceCompleted(bool won) { - m_RacesFinished++; - if (won) - m_FirstPlaceRaceFinishes++; + m_RacesFinished++; + if (won) + m_FirstPlaceRaceFinishes++; } void CharacterComponent::TrackPositionUpdate(const NiPoint3& newPosition) { - const auto distance = NiPoint3::Distance(newPosition, m_Parent->GetPosition()); + const auto distance = NiPoint3::Distance(newPosition, m_Parent->GetPosition()); - if (m_IsRacing) { - UpdatePlayerStatistic(DistanceDriven, (uint64_t) distance); - } else { - UpdatePlayerStatistic(MetersTraveled, (uint64_t) distance); - } + if (m_IsRacing) { + UpdatePlayerStatistic(DistanceDriven, (uint64_t)distance); + } else { + UpdatePlayerStatistic(MetersTraveled, (uint64_t)distance); + } } -void CharacterComponent::HandleZoneStatisticsUpdate(LWOMAPID zoneID, const std::u16string &name, int32_t value) { - auto zoneStatistics = &GetZoneStatisticsForMap(zoneID); +void CharacterComponent::HandleZoneStatisticsUpdate(LWOMAPID zoneID, const std::u16string& name, int32_t value) { + auto zoneStatistics = &GetZoneStatisticsForMap(zoneID); - if (name == u"BricksCollected") { - m_BricksCollected += value; - zoneStatistics->m_BricksCollected += value; - } else if (name == u"CoinsCollected") { - m_CurrencyCollected += value; - zoneStatistics->m_CoinsCollected += value; - } else if (name == u"EnemiesSmashed") { - m_EnemiesSmashed += value; - zoneStatistics->m_EnemiesSmashed += value; - } + if (name == u"BricksCollected") { + m_BricksCollected += value; + zoneStatistics->m_BricksCollected += value; + } else if (name == u"CoinsCollected") { + m_CurrencyCollected += value; + zoneStatistics->m_CoinsCollected += value; + } else if (name == u"EnemiesSmashed") { + m_EnemiesSmashed += value; + zoneStatistics->m_EnemiesSmashed += value; + } } void CharacterComponent::UpdatePlayerStatistic(StatisticID updateID, uint64_t updateValue) { - switch (updateID) { - case CurrencyCollected: - m_CurrencyCollected += updateValue; - break; - case BricksCollected: - m_BricksCollected += updateValue; - break; - case SmashablesSmashed: - m_SmashablesSmashed += updateValue; - break; - case QuickBuildsCompleted: - m_QuickBuildsCompleted += updateValue; - break; - case EnemiesSmashed: - m_EnemiesSmashed += updateValue; - break; - case RocketsUsed: - m_RocketsUsed += updateValue; - break; - case MissionsCompleted: - m_MissionsCompleted += updateValue; - break; - case PetsTamed: - m_PetsTamed += updateValue; - break; - case ImaginationPowerUpsCollected: - m_ImaginationPowerUpsCollected += updateValue; - break; - case LifePowerUpsCollected: - m_LifePowerUpsCollected += updateValue; - break; - case ArmorPowerUpsCollected: - m_ArmorPowerUpsCollected += updateValue; - break; - case MetersTraveled: - m_MetersTraveled += updateValue; - break; - case TimesSmashed: - m_TimesSmashed += updateValue; - break; - case TotalDamageTaken: - m_TotalDamageTaken += updateValue; - break; - case TotalDamageHealed: - m_TotalDamageHealed += updateValue; - break; - case TotalArmorRepaired: - m_TotalArmorRepaired += updateValue; - break; - case TotalImaginationRestored: - m_TotalImaginationRestored += updateValue; - break; - case TotalImaginationUsed: - m_TotalImaginationUsed += updateValue; - break; - case DistanceDriven: - m_DistanceDriven += updateValue; - break; - case TimeAirborneInCar: - m_TimeAirborneInCar += updateValue; - break; - case RacingImaginationPowerUpsCollected: - m_RacingImaginationPowerUpsCollected += updateValue; - break; - case RacingImaginationCratesSmashed: - m_RacingImaginationCratesSmashed += updateValue; - break; - case RacingCarBoostsActivated: - m_RacingCarBoostsActivated += updateValue; - break; - case RacingTimesWrecked: - m_RacingTimesWrecked += updateValue; - break; - case RacingSmashablesSmashed: - m_RacingSmashablesSmashed += updateValue; - break; - case RacesFinished: - m_RacesFinished += updateValue; - break; - case FirstPlaceRaceFinishes: - m_FirstPlaceRaceFinishes += updateValue; - break; - default: - break; - } + switch (updateID) { + case CurrencyCollected: + m_CurrencyCollected += updateValue; + break; + case BricksCollected: + m_BricksCollected += updateValue; + break; + case SmashablesSmashed: + m_SmashablesSmashed += updateValue; + break; + case QuickBuildsCompleted: + m_QuickBuildsCompleted += updateValue; + break; + case EnemiesSmashed: + m_EnemiesSmashed += updateValue; + break; + case RocketsUsed: + m_RocketsUsed += updateValue; + break; + case MissionsCompleted: + m_MissionsCompleted += updateValue; + break; + case PetsTamed: + m_PetsTamed += updateValue; + break; + case ImaginationPowerUpsCollected: + m_ImaginationPowerUpsCollected += updateValue; + break; + case LifePowerUpsCollected: + m_LifePowerUpsCollected += updateValue; + break; + case ArmorPowerUpsCollected: + m_ArmorPowerUpsCollected += updateValue; + break; + case MetersTraveled: + m_MetersTraveled += updateValue; + break; + case TimesSmashed: + m_TimesSmashed += updateValue; + break; + case TotalDamageTaken: + m_TotalDamageTaken += updateValue; + break; + case TotalDamageHealed: + m_TotalDamageHealed += updateValue; + break; + case TotalArmorRepaired: + m_TotalArmorRepaired += updateValue; + break; + case TotalImaginationRestored: + m_TotalImaginationRestored += updateValue; + break; + case TotalImaginationUsed: + m_TotalImaginationUsed += updateValue; + break; + case DistanceDriven: + m_DistanceDriven += updateValue; + break; + case TimeAirborneInCar: + m_TimeAirborneInCar += updateValue; + break; + case RacingImaginationPowerUpsCollected: + m_RacingImaginationPowerUpsCollected += updateValue; + break; + case RacingImaginationCratesSmashed: + m_RacingImaginationCratesSmashed += updateValue; + break; + case RacingCarBoostsActivated: + m_RacingCarBoostsActivated += updateValue; + break; + case RacingTimesWrecked: + m_RacingTimesWrecked += updateValue; + break; + case RacingSmashablesSmashed: + m_RacingSmashablesSmashed += updateValue; + break; + case RacesFinished: + m_RacesFinished += updateValue; + break; + case FirstPlaceRaceFinishes: + m_FirstPlaceRaceFinishes += updateValue; + break; + default: + break; + } } -void CharacterComponent::InitializeStatisticsFromString(const std::string &statisticsString) { - auto split = GeneralUtils::SplitString(statisticsString, ';'); +void CharacterComponent::InitializeStatisticsFromString(const std::string& statisticsString) { + auto split = GeneralUtils::SplitString(statisticsString, ';'); - m_CurrencyCollected = GetStatisticFromSplit(split, 0); - m_BricksCollected = GetStatisticFromSplit(split, 1); - m_SmashablesSmashed = GetStatisticFromSplit(split, 2); - m_QuickBuildsCompleted = GetStatisticFromSplit(split, 3); - m_EnemiesSmashed = GetStatisticFromSplit(split, 4); - m_RocketsUsed = GetStatisticFromSplit(split, 5); - m_MissionsCompleted = GetStatisticFromSplit(split, 6); - m_PetsTamed = GetStatisticFromSplit(split, 7); - m_ImaginationPowerUpsCollected = GetStatisticFromSplit(split, 8); - m_LifePowerUpsCollected = GetStatisticFromSplit(split, 9); - m_ArmorPowerUpsCollected = GetStatisticFromSplit(split, 10); - m_MetersTraveled = GetStatisticFromSplit(split, 11); - m_TimesSmashed = GetStatisticFromSplit(split, 12); - m_TotalDamageTaken = GetStatisticFromSplit(split, 13); - m_TotalDamageHealed = GetStatisticFromSplit(split, 14); - m_TotalArmorRepaired = GetStatisticFromSplit(split, 15); - m_TotalImaginationRestored = GetStatisticFromSplit(split, 16); - m_TotalImaginationUsed = GetStatisticFromSplit(split, 17); - m_DistanceDriven = GetStatisticFromSplit(split, 18); - m_TimeAirborneInCar = GetStatisticFromSplit(split, 19); // WONTFIX - m_RacingImaginationPowerUpsCollected = GetStatisticFromSplit(split, 20); - m_RacingImaginationCratesSmashed = GetStatisticFromSplit(split, 21); - m_RacingCarBoostsActivated = GetStatisticFromSplit(split, 22); - m_RacingTimesWrecked = GetStatisticFromSplit(split, 23); - m_RacingSmashablesSmashed = GetStatisticFromSplit(split, 24); - m_RacesFinished = GetStatisticFromSplit(split, 25); - m_FirstPlaceRaceFinishes = GetStatisticFromSplit(split, 26); + m_CurrencyCollected = GetStatisticFromSplit(split, 0); + m_BricksCollected = GetStatisticFromSplit(split, 1); + m_SmashablesSmashed = GetStatisticFromSplit(split, 2); + m_QuickBuildsCompleted = GetStatisticFromSplit(split, 3); + m_EnemiesSmashed = GetStatisticFromSplit(split, 4); + m_RocketsUsed = GetStatisticFromSplit(split, 5); + m_MissionsCompleted = GetStatisticFromSplit(split, 6); + m_PetsTamed = GetStatisticFromSplit(split, 7); + m_ImaginationPowerUpsCollected = GetStatisticFromSplit(split, 8); + m_LifePowerUpsCollected = GetStatisticFromSplit(split, 9); + m_ArmorPowerUpsCollected = GetStatisticFromSplit(split, 10); + m_MetersTraveled = GetStatisticFromSplit(split, 11); + m_TimesSmashed = GetStatisticFromSplit(split, 12); + m_TotalDamageTaken = GetStatisticFromSplit(split, 13); + m_TotalDamageHealed = GetStatisticFromSplit(split, 14); + m_TotalArmorRepaired = GetStatisticFromSplit(split, 15); + m_TotalImaginationRestored = GetStatisticFromSplit(split, 16); + m_TotalImaginationUsed = GetStatisticFromSplit(split, 17); + m_DistanceDriven = GetStatisticFromSplit(split, 18); + m_TimeAirborneInCar = GetStatisticFromSplit(split, 19); // WONTFIX + m_RacingImaginationPowerUpsCollected = GetStatisticFromSplit(split, 20); + m_RacingImaginationCratesSmashed = GetStatisticFromSplit(split, 21); + m_RacingCarBoostsActivated = GetStatisticFromSplit(split, 22); + m_RacingTimesWrecked = GetStatisticFromSplit(split, 23); + m_RacingSmashablesSmashed = GetStatisticFromSplit(split, 24); + m_RacesFinished = GetStatisticFromSplit(split, 25); + m_FirstPlaceRaceFinishes = GetStatisticFromSplit(split, 26); } void CharacterComponent::InitializeEmptyStatistics() { - m_CurrencyCollected = 0; - m_BricksCollected = 0; - m_SmashablesSmashed = 0; - m_QuickBuildsCompleted = 0; - m_EnemiesSmashed = 0; - m_RocketsUsed = 0; - m_MissionsCompleted = 0; - m_PetsTamed = 0; - m_ImaginationPowerUpsCollected = 0; - m_LifePowerUpsCollected = 0; - m_ArmorPowerUpsCollected = 0; - m_MetersTraveled = 0; - m_TimesSmashed = 0; - m_TotalDamageTaken = 0; - m_TotalDamageHealed = 0; - m_TotalArmorRepaired = 0; - m_TotalImaginationRestored = 0; - m_TotalImaginationUsed = 0; - m_DistanceDriven = 0; - m_TimeAirborneInCar = 0; - m_RacingImaginationPowerUpsCollected = 0; - m_RacingImaginationCratesSmashed = 0; - m_RacingCarBoostsActivated = 0; - m_RacingTimesWrecked = 0; - m_RacingSmashablesSmashed = 0; - m_RacesFinished = 0; - m_FirstPlaceRaceFinishes = 0; + m_CurrencyCollected = 0; + m_BricksCollected = 0; + m_SmashablesSmashed = 0; + m_QuickBuildsCompleted = 0; + m_EnemiesSmashed = 0; + m_RocketsUsed = 0; + m_MissionsCompleted = 0; + m_PetsTamed = 0; + m_ImaginationPowerUpsCollected = 0; + m_LifePowerUpsCollected = 0; + m_ArmorPowerUpsCollected = 0; + m_MetersTraveled = 0; + m_TimesSmashed = 0; + m_TotalDamageTaken = 0; + m_TotalDamageHealed = 0; + m_TotalArmorRepaired = 0; + m_TotalImaginationRestored = 0; + m_TotalImaginationUsed = 0; + m_DistanceDriven = 0; + m_TimeAirborneInCar = 0; + m_RacingImaginationPowerUpsCollected = 0; + m_RacingImaginationCratesSmashed = 0; + m_RacingCarBoostsActivated = 0; + m_RacingTimesWrecked = 0; + m_RacingSmashablesSmashed = 0; + m_RacesFinished = 0; + m_FirstPlaceRaceFinishes = 0; } std::string CharacterComponent::StatisticsToString() const { - std::stringstream result; - result << std::to_string(m_CurrencyCollected) << ';' - << std::to_string(m_BricksCollected) << ';' - << std::to_string(m_SmashablesSmashed) << ';' - << std::to_string(m_QuickBuildsCompleted) << ';' - << std::to_string(m_EnemiesSmashed) << ';' - << std::to_string(m_RocketsUsed) << ';' - << std::to_string(m_MissionsCompleted) << ';' - << std::to_string(m_PetsTamed) << ';' - << std::to_string(m_ImaginationPowerUpsCollected) << ';' - << std::to_string(m_LifePowerUpsCollected) << ';' - << std::to_string(m_ArmorPowerUpsCollected) << ';' - << std::to_string(m_MetersTraveled) << ';' - << std::to_string(m_TimesSmashed) << ';' - << std::to_string(m_TotalDamageTaken) << ';' - << std::to_string(m_TotalDamageHealed) << ';' - << std::to_string(m_TotalArmorRepaired) << ';' - << std::to_string(m_TotalImaginationRestored) << ';' - << std::to_string(m_TotalImaginationUsed) << ';' - << std::to_string(m_DistanceDriven) << ';' - << std::to_string(m_TimeAirborneInCar) << ';' - << std::to_string(m_RacingImaginationPowerUpsCollected) << ';' - << std::to_string(m_RacingImaginationCratesSmashed) << ';' - << std::to_string(m_RacingCarBoostsActivated) << ';' - << std::to_string(m_RacingTimesWrecked) << ';' - << std::to_string(m_RacingSmashablesSmashed) << ';' - << std::to_string(m_RacesFinished) << ';' - << std::to_string(m_FirstPlaceRaceFinishes) << ';'; + std::stringstream result; + result << std::to_string(m_CurrencyCollected) << ';' + << std::to_string(m_BricksCollected) << ';' + << std::to_string(m_SmashablesSmashed) << ';' + << std::to_string(m_QuickBuildsCompleted) << ';' + << std::to_string(m_EnemiesSmashed) << ';' + << std::to_string(m_RocketsUsed) << ';' + << std::to_string(m_MissionsCompleted) << ';' + << std::to_string(m_PetsTamed) << ';' + << std::to_string(m_ImaginationPowerUpsCollected) << ';' + << std::to_string(m_LifePowerUpsCollected) << ';' + << std::to_string(m_ArmorPowerUpsCollected) << ';' + << std::to_string(m_MetersTraveled) << ';' + << std::to_string(m_TimesSmashed) << ';' + << std::to_string(m_TotalDamageTaken) << ';' + << std::to_string(m_TotalDamageHealed) << ';' + << std::to_string(m_TotalArmorRepaired) << ';' + << std::to_string(m_TotalImaginationRestored) << ';' + << std::to_string(m_TotalImaginationUsed) << ';' + << std::to_string(m_DistanceDriven) << ';' + << std::to_string(m_TimeAirborneInCar) << ';' + << std::to_string(m_RacingImaginationPowerUpsCollected) << ';' + << std::to_string(m_RacingImaginationCratesSmashed) << ';' + << std::to_string(m_RacingCarBoostsActivated) << ';' + << std::to_string(m_RacingTimesWrecked) << ';' + << std::to_string(m_RacingSmashablesSmashed) << ';' + << std::to_string(m_RacesFinished) << ';' + << std::to_string(m_FirstPlaceRaceFinishes) << ';'; - return result.str(); + return result.str(); } uint64_t CharacterComponent::GetStatisticFromSplit(std::vector split, uint32_t index) { - return split.size() > index ? std::stoul(split.at(index)) : 0; + return split.size() > index ? std::stoul(split.at(index)) : 0; } ZoneStatistics& CharacterComponent::GetZoneStatisticsForMap(LWOMAPID mapID) { - auto stats = m_ZoneStatistics.find(mapID); - if (stats == m_ZoneStatistics.end()) - m_ZoneStatistics.insert({ mapID, {0, 0, 0, 0, 0 } }); - return m_ZoneStatistics.at(mapID); + auto stats = m_ZoneStatistics.find(mapID); + if (stats == m_ZoneStatistics.end()) + m_ZoneStatistics.insert({ mapID, {0, 0, 0, 0, 0 } }); + return m_ZoneStatistics.at(mapID); } void CharacterComponent::AddVentureVisionEffect(std::string ventureVisionType) { - const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); + const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); - if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { - ventureVisionTypeIterator->second = ++ventureVisionTypeIterator->second; - } else { - // If the effect it not found, insert it into the active effects. - m_ActiveVentureVisionEffects.insert(std::make_pair(ventureVisionType, 1U)); - } + if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { + ventureVisionTypeIterator->second = ++ventureVisionTypeIterator->second; + } else { + // If the effect it not found, insert it into the active effects. + m_ActiveVentureVisionEffects.insert(std::make_pair(ventureVisionType, 1U)); + } - UpdateClientMinimap(true, ventureVisionType); + UpdateClientMinimap(true, ventureVisionType); } void CharacterComponent::RemoveVentureVisionEffect(std::string ventureVisionType) { - const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); + const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); - if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { - ventureVisionTypeIterator->second = --ventureVisionTypeIterator->second; - UpdateClientMinimap(ventureVisionTypeIterator->second != 0U, ventureVisionType); - } + if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { + ventureVisionTypeIterator->second = --ventureVisionTypeIterator->second; + UpdateClientMinimap(ventureVisionTypeIterator->second != 0U, ventureVisionType); + } } void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const { - if (!m_Parent) return; - AMFArrayValue arrayToSend; - arrayToSend.InsertValue(ventureVisionType, showFaction ? static_cast(new AMFTrueValue()) : static_cast(new AMFFalseValue())); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", &arrayToSend); + if (!m_Parent) return; + AMFArrayValue arrayToSend; + arrayToSend.InsertValue(ventureVisionType, showFaction ? static_cast(new AMFTrueValue()) : static_cast(new AMFFalseValue())); + GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", &arrayToSend); } diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index c7706325..e5ca6da5 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -9,49 +9,52 @@ #include #include "CDMissionsTable.h" #include "tinyxml2.h" +#include "eReplicaComponentType.h" + +enum class eGameActivity : uint32_t; /** * The statistics that can be achieved per zone */ struct ZoneStatistics { - uint64_t m_AchievementsCollected; - uint64_t m_BricksCollected; - uint64_t m_CoinsCollected; - uint64_t m_EnemiesSmashed; - uint64_t m_QuickBuildsCompleted; + uint64_t m_AchievementsCollected; + int64_t m_BricksCollected; + uint64_t m_CoinsCollected; + uint64_t m_EnemiesSmashed; + uint64_t m_QuickBuildsCompleted; }; /** * The IDs of each of the possible statistics */ enum StatisticID { - CurrencyCollected = 1, - BricksCollected, - SmashablesSmashed, - QuickBuildsCompleted, - EnemiesSmashed, - RocketsUsed, - MissionsCompleted, - PetsTamed, - ImaginationPowerUpsCollected, - LifePowerUpsCollected, - ArmorPowerUpsCollected, - MetersTraveled, - TimesSmashed, - TotalDamageTaken, - TotalDamageHealed, - TotalArmorRepaired, - TotalImaginationRestored, - TotalImaginationUsed, - DistanceDriven, - TimeAirborneInCar, - RacingImaginationPowerUpsCollected, - RacingImaginationCratesSmashed, - RacingCarBoostsActivated, - RacingTimesWrecked, - RacingSmashablesSmashed, - RacesFinished, - FirstPlaceRaceFinishes, + CurrencyCollected = 1, + BricksCollected, + SmashablesSmashed, + QuickBuildsCompleted, + EnemiesSmashed, + RocketsUsed, + MissionsCompleted, + PetsTamed, + ImaginationPowerUpsCollected, + LifePowerUpsCollected, + ArmorPowerUpsCollected, + MetersTraveled, + TimesSmashed, + TotalDamageTaken, + TotalDamageHealed, + TotalArmorRepaired, + TotalImaginationRestored, + TotalImaginationUsed, + DistanceDriven, + TimeAirborneInCar, + RacingImaginationPowerUpsCollected, + RacingImaginationCratesSmashed, + RacingCarBoostsActivated, + RacingTimesWrecked, + RacingSmashablesSmashed, + RacesFinished, + FirstPlaceRaceFinishes, }; /** @@ -59,20 +62,20 @@ enum StatisticID { */ class CharacterComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_CHARACTER; - - CharacterComponent(Entity* parent, Character* character); - ~CharacterComponent() override; - - void LoadFromXML(); + static const eReplicaComponentType ComponentType = eReplicaComponentType::CHARACTER; + + CharacterComponent(Entity* parent, Character* character); + ~CharacterComponent() override; + + void LoadFromXml(tinyxml2::XMLDocument* doc) override; void UpdateXml(tinyxml2::XMLDocument* doc) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Updates the rocket configuration using a LOT string separated by commas - * @param config the rocket config to use - */ + /** + * Updates the rocket configuration using a LOT string separated by commas + * @param config the rocket config to use + */ void SetLastRocketConfig(std::u16string config); /** @@ -95,129 +98,112 @@ public: */ void RocketUnEquip(Entity* player); - /** - * Gets the current level of the entity - * @return the current level of the entity - */ - const uint32_t GetLevel() const { return m_Level; } - - /** - * Sets the level of the entity - * @param level the level to set - */ - void SetLevel(uint32_t level) { m_Level = level; } - - /** - * Gets the universe score of the entity - * @return the universe score of the entity - */ + /** + * Gets the universe score of the entity + * @return the universe score of the entity + */ const int64_t GetUScore() const { return m_Uscore; } - /** - * Sets the universe score for this entity - * @param uscore the universe score to set - */ + /** + * Sets the universe score for this entity + * @param uscore the universe score to set + */ void SetUScore(int64_t uscore) { m_Uscore = uscore; } - /** - * Gets the current activity that the character is partaking in, see ScriptedActivityComponent for more details - * @return the current activity that the character is partaking in - */ - const uint32_t GetCurrentActivity() const { return m_CurrentActivity; } + /** + * Gets the current activity that the character is partaking in, see ScriptedActivityComponent for more details + * @return the current activity that the character is partaking in + */ + const eGameActivity GetCurrentActivity() const { return m_CurrentActivity; } - /** - * Set the current activity of the character, see ScriptedActivityComponent for more details - * @param currentActivity the activity to set - */ - void SetCurrentActivity(uint32_t currentActivity) { m_CurrentActivity = currentActivity; m_DirtyCurrentActivity = true; } + /** + * Set the current activity of the character, see ScriptedActivityComponent for more details + * @param currentActivity the activity to set + */ + void SetCurrentActivity(eGameActivity currentActivity) { m_CurrentActivity = currentActivity; m_DirtyCurrentActivity = true; } - /** - * Gets if the entity is currently racing - * @return whether the entity is currently racing - */ + /** + * Gets if the entity is currently racing + * @return whether the entity is currently racing + */ const bool GetIsRacing() const { return m_IsRacing; } - /** - * Sets the state of whether the character is racing - * @param isRacing whether the character is racing - */ + /** + * Sets the state of whether the character is racing + * @param isRacing whether the character is racing + */ void SetIsRacing(bool isRacing) { m_IsRacing = isRacing; } - /** - * Gets whether this character has PvP enabled, allowing combat between players - * @return - */ + /** + * Gets whether this character has PvP enabled, allowing combat between players + * @return + */ bool GetPvpEnabled() const; - /** - * Returns the characters lifetime reputation - * @return The lifetime reputation of this character. - */ - int64_t GetReputation() { return m_Reputation; }; + /** + * Returns the characters lifetime reputation + * @return The lifetime reputation of this character. + */ + int64_t GetReputation() { return m_Reputation; }; - /** - * Sets the lifetime reputation of the character to newValue - * @param newValue the value to set reputation to - */ - void SetReputation(int64_t newValue) { m_Reputation = newValue; }; + /** + * Sets the lifetime reputation of the character to newValue + * @param newValue the value to set reputation to + */ + void SetReputation(int64_t newValue) { m_Reputation = newValue; }; - /** - * Sets the current value of PvP combat being enabled - * @param value whether to enable PvP combat - */ + /** + * Sets the current value of PvP combat being enabled + * @param value whether to enable PvP combat + */ void SetPvpEnabled(bool value); - /** - * Gets the object ID of the rocket that was last used, allowing it to be rendered on launch pads - * @return the object ID of the rocket that was last used, if available - */ + /** + * Gets the object ID of the rocket that was last used, allowing it to be rendered on launch pads + * @return the object ID of the rocket that was last used, if available + */ LWOOBJID GetLastRocketItemID() const { return m_LastRocketItemID; } - /** - * Sets the object ID of the last used rocket - * @param lastRocketItemID the object ID of the last used rocket - */ + /** + * Sets the object ID of the last used rocket + * @param lastRocketItemID the object ID of the last used rocket + */ void SetLastRocketItemID(LWOOBJID lastRocketItemID) { m_LastRocketItemID = lastRocketItemID; } - /** - * Gives the player rewards for the last level that they leveled up from - */ - void HandleLevelUp(); - - /** - * Gets the name of this character - * @return the name of this character - */ + /** + * Gets the name of this character + * @return the name of this character + */ std::string GetName() const { return m_Character->GetName(); } - /** - * Sets the GM level of the character, should be called in the entity. Here it's set for serialization - * @param gmlevel the gm level to set - */ - void SetGMLevel(int gmlevel); + /** + * Sets the GM level of the character, should be called in the entity. Here it's set for serialization + * @param gmlevel the gm level to set + */ + void SetGMLevel(eGameMasterLevel gmlevel); - /** - * Initializes the player statistics from the string stored in the XML - * @param statisticsString the string to parse - */ + /** + * Initializes the player statistics from the string stored in the XML + * @param statisticsString the string to parse + */ void InitializeStatisticsFromString(const std::string& statisticsString); - /** - * Initializes all the statistics with empty stats when there's no stats available up until that point - */ + /** + * Initializes all the statistics with empty stats when there's no stats available up until that point + */ void InitializeEmptyStatistics(); - /** - * Turns character statistics into a stats string - * @return the statistics of the character as a string, in order, split by semicolon (;) - */ + /** + * Turns character statistics into a stats string + * @return the statistics of the character as a string, in order, split by semicolon (;) + */ std::string StatisticsToString() const; /** * Updates the statistics for when a user completes a mission * @param mission the mission info to track */ - void TrackMissionCompletion(bool isAchievement); + void TrackMissionCompletion(bool isAchievement); /** * Handles statistics related to collecting heart flags and imagination bricks @@ -274,306 +260,301 @@ public: */ void UpdatePlayerStatistic(StatisticID updateID, uint64_t updateValue = 1); - /** - * Add a venture vision effect to the player minimap. - */ - void AddVentureVisionEffect(std::string ventureVisionType); + /** + * Add a venture vision effect to the player minimap. + */ + void AddVentureVisionEffect(std::string ventureVisionType); - /** - * Remove a venture vision effect from the player minimap. - * When an effect hits 0 active effects, it is deactivated. - */ - void RemoveVentureVisionEffect(std::string ventureVisionType); + /** + * Remove a venture vision effect from the player minimap. + * When an effect hits 0 active effects, it is deactivated. + */ + void RemoveVentureVisionEffect(std::string ventureVisionType); - /** - * Update the client minimap to reveal the specified factions - */ - void UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const; + /** + * Update the client minimap to reveal the specified factions + */ + void UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const; - /** - * Character info regarding this character, including clothing styles, etc. - */ - Character* m_Character; + /** + * Character info regarding this character, including clothing styles, etc. + */ + Character* m_Character; private: - - /** - * The map of active venture vision effects - */ - std::map m_ActiveVentureVisionEffects; - /** - * Whether this character is racing - */ + /** + * The map of active venture vision effects + */ + std::map m_ActiveVentureVisionEffects; + + /** + * Whether this character is racing + */ bool m_IsRacing; - /** - * Possessible type, used by the shooting gallery - */ + /** + * Possessible type, used by the shooting gallery + */ uint8_t m_PossessableType = 1; - /** - * Level of the entity - */ - uint32_t m_Level; - - /** - * Universe score of the entity - */ + /** + * Universe score of the entity + */ int64_t m_Uscore; - /** - * The lifetime reputation earned by the entity - */ - int64_t m_Reputation; + /** + * The lifetime reputation earned by the entity + */ + int64_t m_Reputation; - /** - * Whether the character is landing by rocket - */ + /** + * Whether the character is landing by rocket + */ bool m_IsLanding; - /** - * The configuration of the last used rocket, essentially a string of LOTs separated by commas - */ + /** + * The configuration of the last used rocket, essentially a string of LOTs separated by commas + */ std::u16string m_LastRocketConfig; - /** - * Whether the GM info has been changed - */ + /** + * Whether the GM info has been changed + */ bool m_DirtyGMInfo = false; - /** - * Whether PvP is enabled for this entity - */ + /** + * Whether PvP is enabled for this entity + */ bool m_PvpEnabled; - /** - * Whether this entity is a GM - */ + /** + * Whether this entity is a GM + */ bool m_IsGM; - /** - * The current GM level of this character (anything > 0 counts as a GM) - */ - unsigned char m_GMLevel; + /** + * The current GM level of this character (anything > 0 counts as a GM) + */ + eGameMasterLevel m_GMLevel; - /** - * Whether the character has HF enabled - */ + /** + * Whether the character has HF enabled + */ bool m_EditorEnabled; - /** - * The level of the character in HF - */ - unsigned char m_EditorLevel; + /** + * The level of the character in HF + */ + eGameMasterLevel m_EditorLevel; - /** - * Whether the currently active activity has been changed - */ + /** + * Whether the currently active activity has been changed + */ bool m_DirtyCurrentActivity = false; - /** - * The ID of the curently active activity - */ - int m_CurrentActivity; + /** + * The ID of the curently active activity + */ + eGameActivity m_CurrentActivity; - /** - * Whether the social info has been changed - */ + /** + * Whether the social info has been changed + */ bool m_DirtySocialInfo = false; - /** - * The guild this character is in - */ + /** + * The guild this character is in + */ LWOOBJID m_GuildID; - /** - * The name of the guild this character is in - */ + /** + * The name of the guild this character is in + */ std::u16string m_GuildName; - /** - * Whether this character is a lego club member - */ + /** + * Whether this character is a lego club member + */ bool m_IsLEGOClubMember; - /** - * The country code that the character is from - */ + /** + * The country code that the character is from + */ int m_CountryCode; - /** - * Returns whether the landing animation is enabled for a certain zone - * @param zoneID the zone to check for - * @return whether the landing animation is enabled for that zone - */ + /** + * Returns whether the landing animation is enabled for a certain zone + * @param zoneID the zone to check for + * @return whether the landing animation is enabled for that zone + */ bool LandingAnimDisabled(int zoneID); - /** - * Returns the statistics for a certain statistics ID, from a statistics string - * @param split the statistics string to look in - * @param index the statistics ID in the string - * @return the integer value of this statistic, parsed from the string - */ + /** + * Returns the statistics for a certain statistics ID, from a statistics string + * @param split the statistics string to look in + * @param index the statistics ID in the string + * @return the integer value of this statistic, parsed from the string + */ static uint64_t GetStatisticFromSplit(std::vector split, uint32_t index); - /** - * Gets all the statistics for a certain map, if it doesn't exist, it creates empty stats - * @param mapID the ID of the zone to get statistics for - * @return the statistics for the zone - */ + /** + * Gets all the statistics for a certain map, if it doesn't exist, it creates empty stats + * @param mapID the ID of the zone to get statistics for + * @return the statistics for the zone + */ ZoneStatistics& GetZoneStatisticsForMap(const LWOMAPID mapID); - /** - * The last time we saved this character, used to update the total time played - */ - time_t m_LastUpdateTimestamp; + /** + * The last time we saved this character, used to update the total time played + */ + time_t m_LastUpdateTimestamp; - /** - * The total time the character has played, in MS - */ - uint64_t m_TotalTimePlayed; + /** + * The total time the character has played, in MS + */ + uint64_t m_TotalTimePlayed; - /** - * The total amount of currency collected by this character - */ - uint64_t m_CurrencyCollected; + /** + * The total amount of currency collected by this character + */ + uint64_t m_CurrencyCollected; - /** - * The total amount of bricks collected by this character - */ - uint64_t m_BricksCollected; + /** + * The total amount of bricks collected by this character + */ + int64_t m_BricksCollected; - /** - * The total amount of entities smashed by this character - */ - uint64_t m_SmashablesSmashed; + /** + * The total amount of entities smashed by this character + */ + uint64_t m_SmashablesSmashed; - /** - * The total amount of quickbuilds completed by this character - */ - uint64_t m_QuickBuildsCompleted; + /** + * The total amount of quickbuilds completed by this character + */ + uint64_t m_QuickBuildsCompleted; - /** - * The total amount of enemies killd by this character - */ - uint64_t m_EnemiesSmashed; + /** + * The total amount of enemies killd by this character + */ + uint64_t m_EnemiesSmashed; - /** - * The total amount of rockets used by this character - */ - uint64_t m_RocketsUsed; + /** + * The total amount of rockets used by this character + */ + uint64_t m_RocketsUsed; - /** - * The total amount of missions completed by this character - */ - uint64_t m_MissionsCompleted; + /** + * The total amount of missions completed by this character + */ + uint64_t m_MissionsCompleted; - /** - * The total number of pets tamed by this character - */ - uint64_t m_PetsTamed; + /** + * The total number of pets tamed by this character + */ + uint64_t m_PetsTamed; - /** - * The total amount of imagination powerups collected by this character, this includes the ones in racing - */ - uint64_t m_ImaginationPowerUpsCollected; + /** + * The total amount of imagination powerups collected by this character, this includes the ones in racing + */ + uint64_t m_ImaginationPowerUpsCollected; - /** - * The total amount of life powerups collected (note: not the total amount of life gained) - */ - uint64_t m_LifePowerUpsCollected; + /** + * The total amount of life powerups collected (note: not the total amount of life gained) + */ + uint64_t m_LifePowerUpsCollected; - /** - * The total amount of armor powerups collected (note: not the total amount of armor gained) - */ - uint64_t m_ArmorPowerUpsCollected; + /** + * The total amount of armor powerups collected (note: not the total amount of armor gained) + */ + uint64_t m_ArmorPowerUpsCollected; - /** - * Total amount of meters traveled by this character - */ - uint64_t m_MetersTraveled; + /** + * Total amount of meters traveled by this character + */ + uint64_t m_MetersTraveled; - /** - * Total amount of times this character was smashed, either by other entities or by going out of bounds - */ - uint64_t m_TimesSmashed; + /** + * Total amount of times this character was smashed, either by other entities or by going out of bounds + */ + uint64_t m_TimesSmashed; - /** - * The total amount of damage inflicted on this character - */ - uint64_t m_TotalDamageTaken; + /** + * The total amount of damage inflicted on this character + */ + uint64_t m_TotalDamageTaken; - /** - * The total amount of damage healed by this character (excludes armor polish, etc) - */ - uint64_t m_TotalDamageHealed; + /** + * The total amount of damage healed by this character (excludes armor polish, etc) + */ + uint64_t m_TotalDamageHealed; - /** - * Total amount of armor repaired by this character - */ - uint64_t m_TotalArmorRepaired; + /** + * Total amount of armor repaired by this character + */ + uint64_t m_TotalArmorRepaired; - /** - * Total amount of imagination resored by this character - */ - uint64_t m_TotalImaginationRestored; + /** + * Total amount of imagination resored by this character + */ + uint64_t m_TotalImaginationRestored; - /** - * Total amount of imagination used by this character - */ - uint64_t m_TotalImaginationUsed; + /** + * Total amount of imagination used by this character + */ + uint64_t m_TotalImaginationUsed; - /** - * Amount of distance driven, mutually exclusively tracked to meters travelled based on whether the charcter - * is currently driving - */ - uint64_t m_DistanceDriven; + /** + * Amount of distance driven, mutually exclusively tracked to meters travelled based on whether the charcter + * is currently driving + */ + uint64_t m_DistanceDriven; - /** - * Time airborne in a car, currently untracked. - * Honestly, who even cares about this. - */ - uint64_t m_TimeAirborneInCar; + /** + * Time airborne in a car, currently untracked. + * Honestly, who even cares about this. + */ + uint64_t m_TimeAirborneInCar; - /** - * Amount of imagination powerups found on racing tracks being collected, generally triggered by scripts - */ - uint64_t m_RacingImaginationPowerUpsCollected; + /** + * Amount of imagination powerups found on racing tracks being collected, generally triggered by scripts + */ + uint64_t m_RacingImaginationPowerUpsCollected; - /** - * Total amount of racing imagination crates smashed, generally tracked by scripts - */ - uint64_t m_RacingImaginationCratesSmashed; + /** + * Total amount of racing imagination crates smashed, generally tracked by scripts + */ + uint64_t m_RacingImaginationCratesSmashed; - /** - * The amount of times this character triggered a car boost - */ - uint64_t m_RacingCarBoostsActivated; + /** + * The amount of times this character triggered a car boost + */ + uint64_t m_RacingCarBoostsActivated; - /** - * The amount of times a car of this character was wrecked - */ - uint64_t m_RacingTimesWrecked; + /** + * The amount of times a car of this character was wrecked + */ + uint64_t m_RacingTimesWrecked; - /** - * The amount of entities smashed by the character while driving - */ - uint64_t m_RacingSmashablesSmashed; + /** + * The amount of entities smashed by the character while driving + */ + uint64_t m_RacingSmashablesSmashed; - /** - * The total amount of races completed by this character - */ - uint64_t m_RacesFinished; + /** + * The total amount of races completed by this character + */ + uint64_t m_RacesFinished; - /** - * The total amount of races won by this character - */ - uint64_t m_FirstPlaceRaceFinishes; + /** + * The total amount of races won by this character + */ + uint64_t m_FirstPlaceRaceFinishes; - /** - * Special stats which are tracked per zone - */ - std::map m_ZoneStatistics {}; + /** + * Special stats which are tracked per zone + */ + std::map m_ZoneStatistics{}; /** * ID of the last rocket used diff --git a/dGame/dComponents/Component.cpp b/dGame/dComponents/Component.cpp index 1a38b871..ca018c29 100644 --- a/dGame/dComponents/Component.cpp +++ b/dGame/dComponents/Component.cpp @@ -1,36 +1,30 @@ #include "Component.h" -Component::Component(Entity* parent) -{ - m_Parent = parent; +Component::Component(Entity* parent) { + m_Parent = parent; } -Component::~Component() -{ - -} - -Entity* Component::GetParent() const -{ - return m_Parent; -} - -void Component::Update(float deltaTime) -{ - -} - -void Component::OnUse(Entity* originator) -{ - -} - -void Component::UpdateXml(tinyxml2::XMLDocument* doc) -{ - -} - -void Component::LoadFromXml(tinyxml2::XMLDocument *doc) { +Component::~Component() { + +} + +Entity* Component::GetParent() const { + return m_Parent; +} + +void Component::Update(float deltaTime) { + +} + +void Component::OnUse(Entity* originator) { + +} + +void Component::UpdateXml(tinyxml2::XMLDocument* doc) { + +} + +void Component::LoadFromXml(tinyxml2::XMLDocument* doc) { } diff --git a/dGame/dComponents/Component.h b/dGame/dComponents/Component.h index b84537bc..9b0df9fd 100644 --- a/dGame/dComponents/Component.h +++ b/dGame/dComponents/Component.h @@ -10,43 +10,43 @@ class Entity; class Component { public: - Component(Entity* parent); - virtual ~Component(); + Component(Entity* parent); + virtual ~Component(); - /** - * Gets the owner of this component - * @return the owner of this component - */ - Entity* GetParent() const; + /** + * Gets the owner of this component + * @return the owner of this component + */ + Entity* GetParent() const; - /** - * Updates the component in the game loop - * @param deltaTime time passed since last update - */ - virtual void Update(float deltaTime); + /** + * Updates the component in the game loop + * @param deltaTime time passed since last update + */ + virtual void Update(float deltaTime); - /** - * Event called when this component is being used, e.g. when some entity interacted with it - * @param originator - */ - virtual void OnUse(Entity* originator); + /** + * Event called when this component is being used, e.g. when some entity interacted with it + * @param originator + */ + virtual void OnUse(Entity* originator); - /** - * Save data from this componennt to character XML - * @param doc the document to write data to - */ - virtual void UpdateXml(tinyxml2::XMLDocument* doc); + /** + * Save data from this componennt to character XML + * @param doc the document to write data to + */ + virtual void UpdateXml(tinyxml2::XMLDocument* doc); - /** - * Load base data for this component from character XML - * @param doc the document to read data from - */ - virtual void LoadFromXml(tinyxml2::XMLDocument* doc); + /** + * Load base data for this component from character XML + * @param doc the document to read data from + */ + virtual void LoadFromXml(tinyxml2::XMLDocument* doc); protected: - /** - * The entity that owns this component - */ - Entity* m_Parent; + /** + * The entity that owns this component + */ + Entity* m_Parent; }; diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index 648b1471..1b8627a7 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -11,6 +11,9 @@ #include "CDClientManager.h" #include "EntityManager.h" #include "Character.h" +#include "dZoneManager.h" +#include "LevelProgressionComponent.h" +#include "eStateChangeType.h" ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) { m_Position = {}; @@ -29,14 +32,30 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com m_GravityScale = 1; m_DirtyCheats = false; m_IgnoreMultipliers = false; + + m_DirtyEquippedItemInfo = true; m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + + m_DirtyBubble = false; + m_IsInBubble = false; + m_SpecialAnims = false; + m_BubbleType = eBubbleType::DEFAULT; + + m_IsTeleporting = false; + + m_ImmuneToStunAttackCount = 0; + m_ImmuneToStunEquipCount = 0; + m_ImmuneToStunInteractCount = 0; + m_ImmuneToStunJumpCount = 0; + m_ImmuneToStunMoveCount = 0; + m_ImmuneToStunTurnCount = 0; + m_ImmuneToStunUseItemCount = 0; if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI return; if (entity->GetLOT() == 1) { - Game::logger->Log("ControllablePhysicsComponent", "Using patch to load minifig physics\n"); + Game::logger->Log("ControllablePhysicsComponent", "Using patch to load minifig physics"); float radius = 1.5f; m_dpEntity = new dpEntity(m_Parent->GetObjectID(), radius, false); @@ -68,16 +87,17 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write(m_JetpackBypassChecks); } - outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out. + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToStunMoveCount); + outBitStream->Write(m_ImmuneToStunJumpCount); + outBitStream->Write(m_ImmuneToStunTurnCount); + outBitStream->Write(m_ImmuneToStunAttackCount); + outBitStream->Write(m_ImmuneToStunUseItemCount); + outBitStream->Write(m_ImmuneToStunEquipCount); + outBitStream->Write(m_ImmuneToStunInteractCount); } - if (m_SpeedMultiplier < 1.0f) { - m_DirtyCheats = false; - } - - if (m_IgnoreMultipliers) { - m_DirtyCheats = false; - } + if (m_IgnoreMultipliers) m_DirtyCheats = false; outBitStream->Write(m_DirtyCheats); if (m_DirtyCheats) { @@ -87,14 +107,22 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo m_DirtyCheats = false; } - outBitStream->Write(m_DirtyPickupRadiusScale); - if (m_DirtyPickupRadiusScale) { + outBitStream->Write(m_DirtyEquippedItemInfo); + if (m_DirtyEquippedItemInfo) { outBitStream->Write(m_PickupRadius); - outBitStream->Write0(); //No clue what this is so im leaving it false. - m_DirtyPickupRadiusScale = false; + outBitStream->Write(m_InJetpackMode); + m_DirtyEquippedItemInfo = false; } - outBitStream->Write0(); + outBitStream->Write(m_DirtyBubble); + if (m_DirtyBubble) { + outBitStream->Write(m_IsInBubble); + if (m_IsInBubble) { + outBitStream->Write(m_BubbleType); + outBitStream->Write(m_SpecialAnims); + } + m_DirtyBubble = false; + } outBitStream->Write(m_DirtyPosition || bIsInitialUpdate); if (m_DirtyPosition || bIsInitialUpdate) { @@ -127,16 +155,19 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write0(); } - if (!bIsInitialUpdate) outBitStream->Write0(); + if (!bIsInitialUpdate) { + outBitStream->Write(m_IsTeleporting); + m_IsTeleporting = false; + } } -void ControllablePhysicsComponent::LoadFromXML(tinyxml2::XMLDocument* doc) { +void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); if (!character) { - Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag!\n"); + Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag!"); return; } - + m_Parent->GetCharacter()->LoadXmlRespawnCheckpoints(); character->QueryAttribute("lzx", &m_Position.x); @@ -159,17 +190,21 @@ void ControllablePhysicsComponent::ResetFlags() { void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) { tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); if (!character) { - Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag while updating XML!\n"); + Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag while updating XML!"); return; } - character->SetAttribute("lzx", m_Position.x); - character->SetAttribute("lzy", m_Position.y); - character->SetAttribute("lzz", m_Position.z); - character->SetAttribute("lzrx", m_Rotation.x); - character->SetAttribute("lzry", m_Rotation.y); - character->SetAttribute("lzrz", m_Rotation.z); - character->SetAttribute("lzrw", m_Rotation.w); + auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); + + if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) { + character->SetAttribute("lzx", m_Position.x); + character->SetAttribute("lzy", m_Position.y); + character->SetAttribute("lzz", m_Position.z); + character->SetAttribute("lzrx", m_Rotation.x); + character->SetAttribute("lzry", m_Rotation.y); + character->SetAttribute("lzrz", m_Rotation.z); + character->SetAttribute("lzrw", m_Rotation.w); + } } void ControllablePhysicsComponent::SetPosition(const NiPoint3& pos) { @@ -244,7 +279,7 @@ void ControllablePhysicsComponent::AddPickupRadiusScale(float value) { m_ActivePickupRadiusScales.push_back(value); if (value > m_PickupRadius) { m_PickupRadius = value; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; } } @@ -254,16 +289,102 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { if (pos != m_ActivePickupRadiusScales.end()) { m_ActivePickupRadiusScales.erase(pos); } else { - Game::logger->Log("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.\n", value, m_ActivePickupRadiusScales.size()); + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); return; } // Recalculate pickup radius since we removed one by now m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; for (uint32_t i = 0; i < m_ActivePickupRadiusScales.size(); i++) { auto candidateRadius = m_ActivePickupRadiusScales[i]; if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius; } EntityManager::Instance()->SerializeEntity(m_Parent); } + +void ControllablePhysicsComponent::AddSpeedboost(float value) { + m_ActiveSpeedBoosts.push_back(value); + m_SpeedBoost = value; + SetSpeedMultiplier(value / 500.0f); // 500 being the base speed +} + +void ControllablePhysicsComponent::RemoveSpeedboost(float value) { + const auto pos = std::find(m_ActiveSpeedBoosts.begin(), m_ActiveSpeedBoosts.end(), value); + if (pos != m_ActiveSpeedBoosts.end()) { + m_ActiveSpeedBoosts.erase(pos); + } else { + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size()); + return; + } + + // Recalculate speedboost since we removed one + m_SpeedBoost = 0.0f; + if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed + auto* levelProgressionComponent = m_Parent->GetComponent(); + if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase(); + } else { // Used the last applied speedboost + m_SpeedBoost = m_ActiveSpeedBoosts.back(); + } + SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){ + if (m_IsInBubble) { + Game::logger->Log("ControllablePhysicsComponent", "Already in bubble"); + return; + } + m_BubbleType = bubbleType; + m_IsInBubble = true; + m_DirtyBubble = true; + m_SpecialAnims = specialAnims; + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void ControllablePhysicsComponent::DeactivateBubbleBuff(){ + m_DirtyBubble = true; + m_IsInBubble = false; + EntityManager::Instance()->SerializeEntity(m_Parent); +}; + +void ControllablePhysicsComponent::SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator, + const bool bImmuneToStunAttack, + const bool bImmuneToStunEquip, + const bool bImmuneToStunInteract, + const bool bImmuneToStunJump, + const bool bImmuneToStunMove, + const bool bImmuneToStunTurn, + const bool bImmuneToStunUseItem){ + + if (state == eStateChangeType::POP){ + if (bImmuneToStunAttack && m_ImmuneToStunAttackCount > 0) m_ImmuneToStunAttackCount -= 1; + if (bImmuneToStunEquip && m_ImmuneToStunEquipCount > 0) m_ImmuneToStunEquipCount -= 1; + if (bImmuneToStunInteract && m_ImmuneToStunInteractCount > 0) m_ImmuneToStunInteractCount -= 1; + if (bImmuneToStunJump && m_ImmuneToStunJumpCount > 0) m_ImmuneToStunJumpCount -= 1; + if (bImmuneToStunMove && m_ImmuneToStunMoveCount > 0) m_ImmuneToStunMoveCount -= 1; + if (bImmuneToStunTurn && m_ImmuneToStunTurnCount > 0) m_ImmuneToStunTurnCount -= 1; + if (bImmuneToStunUseItem && m_ImmuneToStunUseItemCount > 0) m_ImmuneToStunUseItemCount -= 1; + } else if (state == eStateChangeType::PUSH) { + if (bImmuneToStunAttack) m_ImmuneToStunAttackCount += 1; + if (bImmuneToStunEquip) m_ImmuneToStunEquipCount += 1; + if (bImmuneToStunInteract) m_ImmuneToStunInteractCount += 1; + if (bImmuneToStunJump) m_ImmuneToStunJumpCount += 1; + if (bImmuneToStunMove) m_ImmuneToStunMoveCount += 1; + if (bImmuneToStunTurn) m_ImmuneToStunTurnCount += 1; + if (bImmuneToStunUseItem) m_ImmuneToStunUseItemCount += 1; + } + + GameMessages::SendSetStunImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), originator, + bImmuneToStunAttack, + bImmuneToStunEquip, + bImmuneToStunInteract, + bImmuneToStunJump, + bImmuneToStunMove, + bImmuneToStunTurn, + bImmuneToStunUseItem + ); +} diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index c7acec62..d6088718 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -9,352 +9,470 @@ #include "Component.h" #include "dpCollisionChecks.h" #include "PhantomPhysicsComponent.h" +#include "eBubbleType.h" +#include "eReplicaComponentType.h" class Entity; class dpEntity; +enum class eStateChangeType : uint32_t; /** * Handles the movement of controllable Entities, e.g. enemies and players */ class ControllablePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_CONTROLLABLE_PHYSICS; - - ControllablePhysicsComponent(Entity* entity); - ~ControllablePhysicsComponent() override; - - void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadFromXML(tinyxml2::XMLDocument* doc); - void ResetFlags(); - void UpdateXml(tinyxml2::XMLDocument* doc) override; - - /** - * Sets the position of this entity, also ensures this update is serialized next tick. - * If the entity is static, this is a no-op. - * @param pos The position to set - */ - void SetPosition(const NiPoint3& pos); + static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS; - /** - * Returns the current position of the entity - * @return The current position of the entity - */ - const NiPoint3& GetPosition() const { return m_Position; } + ControllablePhysicsComponent(Entity* entity); + ~ControllablePhysicsComponent() override; - /** - * Sets the rotation of this entity, ensures this change is serialized next tick. If the entity is static, this is - * a no-op. - * @param rot the rotation to set - */ - void SetRotation(const NiQuaternion& rot); + void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void ResetFlags(); + void UpdateXml(tinyxml2::XMLDocument* doc) override; - /** - * Returns the current rotation of this entity - * @return the current rotation of this entity - */ - const NiQuaternion& GetRotation() const { return m_Rotation; } + /** + * Sets the position of this entity, also ensures this update is serialized next tick. + * If the entity is static, this is a no-op. + * @param pos The position to set + */ + void SetPosition(const NiPoint3& pos); - /** - * Sets the current velocity of this entity, ensures that this change is serialized next tick. If the entity is - * marked as static this is a no-op. - * @param vel the velocity to set - */ - void SetVelocity(const NiPoint3& vel); + /** + * Returns the current position of the entity + * @return The current position of the entity + */ + const NiPoint3& GetPosition() const { return m_Position; } - /** - * Returns the current velocity of this entity - * @return the current velocity of this entity - */ - const NiPoint3& GetVelocity() const { return m_Velocity; } + /** + * Sets the rotation of this entity, ensures this change is serialized next tick. If the entity is static, this is + * a no-op. + * @param rot the rotation to set + */ + void SetRotation(const NiQuaternion& rot); - /** - * Sets the angular velocity (e.g. rotational velocity) of this entity and ensures this is serialized next tick. - * If the entity is marked as static this is a no-op. - * @param vel the angular velocity to set. - */ - void SetAngularVelocity(const NiPoint3& vel); + /** + * Returns the current rotation of this entity + * @return the current rotation of this entity + */ + const NiQuaternion& GetRotation() const { return m_Rotation; } - /** - * Returns the current angular velocity of this entity - * @return the current angular velocity of this entity - */ - const NiPoint3& GetAngularVelocity() const { return m_AngularVelocity; } + /** + * Sets the current velocity of this entity, ensures that this change is serialized next tick. If the entity is + * marked as static this is a no-op. + * @param vel the velocity to set + */ + void SetVelocity(const NiPoint3& vel); - /** - * Sets the IsOnGround value, determining whether or not the entity is stuck to the ground. Note that this is mostly - * a client side flag as no server-side entities jump around and therefore this does not have to be updated server - * side. - * @param val whether the entity is on the ground. - */ - void SetIsOnGround(bool val); + /** + * Returns the current velocity of this entity + * @return the current velocity of this entity + */ + const NiPoint3& GetVelocity() const { return m_Velocity; } - /** - * Returns whether or not the entity is currently on the ground - * @return whether the entity is currently on the ground - */ - const bool GetIsOnGround() const { return m_IsOnGround; } + /** + * Sets the angular velocity (e.g. rotational velocity) of this entity and ensures this is serialized next tick. + * If the entity is marked as static this is a no-op. + * @param vel the angular velocity to set. + */ + void SetAngularVelocity(const NiPoint3& vel); - /** - * Sets the on-rail parameter, determining if a player is currently on a rail (e.g. the lamps in Ninjago). - * Also ensures that this change is serialized. - * @param val whether the player is currently on a rail - */ - void SetIsOnRail(bool val); + /** + * Returns the current angular velocity of this entity + * @return the current angular velocity of this entity + */ + const NiPoint3& GetAngularVelocity() const { return m_AngularVelocity; } - /** - * Returns whether or not this entity is currently on a rail. - * @return whether or not this entity is currently on a rail - */ - const bool GetIsOnRail() const { return m_IsOnRail; } + /** + * Sets the IsOnGround value, determining whether or not the entity is stuck to the ground. Note that this is mostly + * a client side flag as no server-side entities jump around and therefore this does not have to be updated server + * side. + * @param val whether the entity is on the ground. + */ + void SetIsOnGround(bool val); - /** - * Mark the position as dirty, forcing a serialization update next tick - * @param val whether or not the position is dirty - */ - void SetDirtyPosition(bool val); + /** + * Returns whether or not the entity is currently on the ground + * @return whether the entity is currently on the ground + */ + const bool GetIsOnGround() const { return m_IsOnGround; } - /** - * Mark the velocity as dirty, forcing a serializtion update next tick - * @param val whether or not the velocity is dirty - */ - void SetDirtyVelocity(bool val); + /** + * Sets the on-rail parameter, determining if a player is currently on a rail (e.g. the lamps in Ninjago). + * Also ensures that this change is serialized. + * @param val whether the player is currently on a rail + */ + void SetIsOnRail(bool val); - /** - * Mark the angular velocity as dirty, forcing a serialization update next tick - * @param val whether or not the angular velocity is dirty - */ - void SetDirtyAngularVelocity(bool val); + /** + * Returns whether or not this entity is currently on a rail. + * @return whether or not this entity is currently on a rail + */ + const bool GetIsOnRail() const { return m_IsOnRail; } - /** - * Sets whether or not the entity is currently wearing a jetpack - * @param val whether or not the entity is currently wearing a jetpack - */ - void SetInJetpackMode(bool val) { m_InJetpackMode = val; } + /** + * Mark the position as dirty, forcing a serialization update next tick + * @param val whether or not the position is dirty + */ + void SetDirtyPosition(bool val); - /** - * Returns whether or not the entity is currently wearing a jetpack - * @return whether or not the entity is currently wearing a jetpack - */ - const bool GetInJetpackMode() const { return m_InJetpackMode; } + /** + * Mark the velocity as dirty, forcing a serializtion update next tick + * @param val whether or not the velocity is dirty + */ + void SetDirtyVelocity(bool val); - /** - * Sets whether or not the entity is currently flying a jetpack - * @param val whether or not the entity is currently flying a jetpack - */ - void SetJetpackFlying(bool val) { m_JetpackFlying = val; } + /** + * Mark the angular velocity as dirty, forcing a serialization update next tick + * @param val whether or not the angular velocity is dirty + */ + void SetDirtyAngularVelocity(bool val); - /** - * Returns whether or not an entity is currently flying a jetpack - * @return whether or not an entity is currently flying a jetpack - */ - const bool GetJetpackFlying() const { return m_JetpackFlying; } + /** + * Sets whether or not the entity is currently wearing a jetpack + * @param val whether or not the entity is currently wearing a jetpack + */ + void SetInJetpackMode(bool val) { m_InJetpackMode = val; } - /** - * UNUSED: necessary for serialization - */ - void SetJetpackBypassChecks(bool val) { m_JetpackBypassChecks = val; } + /** + * Returns whether or not the entity is currently wearing a jetpack + * @return whether or not the entity is currently wearing a jetpack + */ + const bool GetInJetpackMode() const { return m_InJetpackMode; } - /** - * UNUSUED: necessary for serialization - */ - const bool GetJetpackBypassChecks() const { return m_JetpackBypassChecks; } + /** + * Sets whether or not the entity is currently flying a jetpack + * @param val whether or not the entity is currently flying a jetpack + */ + void SetJetpackFlying(bool val) { m_JetpackFlying = val; } - /** - * Set the jetpack effect ID - * @param effectID the effect to play while using the jetpack - */ - void SetJetpackEffectID(int effectID) { m_JetpackEffectID = effectID; } + /** + * Returns whether or not an entity is currently flying a jetpack + * @return whether or not an entity is currently flying a jetpack + */ + const bool GetJetpackFlying() const { return m_JetpackFlying; } - /** - * Returns the current jetpack effect ID - * @return the current jetpack effect ID - */ - const int GetJetpackEffectID() const { return m_JetpackEffectID; } + /** + * UNUSED: necessary for serialization + */ + void SetJetpackBypassChecks(bool val) { m_JetpackBypassChecks = val; } - /** - * Sets a speed multiplier, altering the entities speed - * @param value the multiplier to set - */ - void SetSpeedMultiplier(float value) { m_SpeedMultiplier = value; m_DirtyCheats = true; } + /** + * UNUSUED: necessary for serialization + */ + const bool GetJetpackBypassChecks() const { return m_JetpackBypassChecks; } - /** - * Returns the current speed multiplier - * @return the current speed multiplier - */ - const float GetSpeedMultiplier() const { return m_SpeedMultiplier; } + /** + * Set the jetpack effect ID + * @param effectID the effect to play while using the jetpack + */ + void SetJetpackEffectID(int effectID) { m_JetpackEffectID = effectID; } - /** - * Sets the current gravity scale, allowing the entity to move using altered gravity - * @param value the gravity value to set - */ - void SetGravityScale(float value) { m_GravityScale = value; m_DirtyCheats = true; } + /** + * Returns the current jetpack effect ID + * @return the current jetpack effect ID + */ + const int GetJetpackEffectID() const { return m_JetpackEffectID; } - /** - * Returns the current gravity scale - * @return the current gravity scale - */ - const float GetGravityScale() const { return m_GravityScale; } + /** + * Sets a speed multiplier, altering the entities speed + * @param value the multiplier to set + */ + void SetSpeedMultiplier(float value) { m_SpeedMultiplier = value; m_DirtyCheats = true; } - /** - * Sets the ignore multipliers value, allowing you to skip the serialization of speed and gravity multipliers - * @param value whether or not to ignore multipliers - */ - void SetIgnoreMultipliers(bool value) { m_IgnoreMultipliers = value; } + /** + * Returns the current speed multiplier + * @return the current speed multiplier + */ + const float GetSpeedMultiplier() const { return m_SpeedMultiplier; } - /** - * Returns the current ignore multipliers value - * @return the current ignore multipliers value - */ - const bool GetIgnoreMultipliers() const { return m_IgnoreMultipliers; } + /** + * Sets the current gravity scale, allowing the entity to move using altered gravity + * @param value the gravity value to set + */ + void SetGravityScale(float value) { m_GravityScale = value; m_DirtyCheats = true; } - /** - * Can make an entity static, making it unable to move around - * @param value whether or not the entity is static - */ - void SetStatic(const bool value) { m_Static = value; } + /** + * Returns the current gravity scale + * @return the current gravity scale + */ + const float GetGravityScale() const { return m_GravityScale; } - /** - * Returns whether or not this entity is currently static - * @return whether or not this entity is currently static - */ - bool GetStatic() const { return m_Static; } + /** + * Sets the ignore multipliers value, allowing you to skip the serialization of speed and gravity multipliers + * @param value whether or not to ignore multipliers + */ + void SetIgnoreMultipliers(bool value) { m_IgnoreMultipliers = value; } - /** - * Returns the Physics entity for the component - * @return Physics entity for the component - */ + /** + * Returns the current ignore multipliers value + * @return the current ignore multipliers value + */ + const bool GetIgnoreMultipliers() const { return m_IgnoreMultipliers; } - dpEntity* GetdpEntity() const { return m_dpEntity; } + /** + * Can make an entity static, making it unable to move around + * @param value whether or not the entity is static + */ + void SetStatic(const bool value) { m_Static = value; } - /** - * I store this in a vector because if I have 2 separate pickup radii being applied to the player, I dont know which one is correctly active. - * This method adds the pickup radius to the vector of active radii and if its larger than the current one, is applied as the new pickup radius. - */ - void AddPickupRadiusScale(float value) ; + /** + * Returns whether or not this entity is currently static + * @return whether or not this entity is currently static + */ + bool GetStatic() const { return m_Static; } - /** - * Removes the provided pickup radius scale from our list of buffs - * The recalculates what our pickup radius is. - */ - void RemovePickupRadiusScale(float value) ; + /** + * Sets if the entity is Teleporting, + * @param value whether or not the entity is Is Teleporting + */ + void SetIsTeleporting(const bool value) { m_IsTeleporting = value; } - /** - * The pickup radii of this component. - * @return All active radii scales for this component. - */ - std::vector GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; + /** + * Returns whether or not this entity is currently is teleporting + * @return whether or not this entity is currently is teleporting + */ + bool GetIsTeleporting() const { return m_IsTeleporting; } + + /** + * Returns the Physics entity for the component + * @return Physics entity for the component + */ + + dpEntity* GetdpEntity() const { return m_dpEntity; } + + /** + * I store this in a vector because if I have 2 separate pickup radii being applied to the player, I dont know which one is correctly active. + * This method adds the pickup radius to the vector of active radii and if its larger than the current one, is applied as the new pickup radius. + */ + void AddPickupRadiusScale(float value); + + /** + * Removes the provided pickup radius scale from our list of buffs + * The recalculates what our pickup radius is. + */ + void RemovePickupRadiusScale(float value); + + /** + * The pickup radii of this component. + * @return All active radii scales for this component. + */ + std::vector GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; + + /** + * Add a Speed boost to the entity + * This will recalculate the speed boost based on what is being added + */ + void AddSpeedboost(float value); + + /** + * Remove speed boost from entity + * This will recalculate the speed boost based on what is the last one in te vector + */ + void RemoveSpeedboost(float value); + + /** + * The speed boosts of this component. + * @return All active Speed boosts for this component. + */ + std::vector GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; + + /** + * Activates the Bubble Buff + */ + void ActivateBubbleBuff(eBubbleType bubbleType = eBubbleType::DEFAULT, bool specialAnims = true); + + /** + * Deactivates the Bubble Buff + */ + void DeactivateBubbleBuff(); + + /** + * Gets if the Entity is in a bubble + */ + bool GetIsInBubble(){ return m_IsInBubble; }; + + /** + * Push or Pop a layer of stun immunity to this entity + */ + void SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator = LWOOBJID_EMPTY, + const bool bImmuneToStunAttack = false, + const bool bImmuneToStunEquip = false, + const bool bImmuneToStunInteract = false, + const bool bImmuneToStunJump = false, + const bool bImmuneToStunMove = false, + const bool bImmuneToStunTurn = false, + const bool bImmuneToStunUseItem = false + ); + + // getters for stun immunities + const bool GetImmuneToStunAttack() { return m_ImmuneToStunAttackCount > 0;}; + const bool GetImmuneToStunEquip() { return m_ImmuneToStunEquipCount > 0;}; + const bool GetImmuneToStunInteract() { return m_ImmuneToStunInteractCount > 0;}; + const bool GetImmuneToStunJump() { return m_ImmuneToStunJumpCount > 0;}; + const bool GetImmuneToStunMove() { return m_ImmuneToStunMoveCount > 0;}; + const bool GetImmuneToStunTurn() { return m_ImmuneToStunTurnCount > 0;}; + const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;}; private: - /** - * The entity that owns this component - */ - dpEntity* m_dpEntity; + /** + * The entity that owns this component + */ + dpEntity* m_dpEntity; - /** - * Whether or not the position is dirty, forcing a serialization update of the position - */ - bool m_DirtyPosition; + /** + * Whether or not the position is dirty, forcing a serialization update of the position + */ + bool m_DirtyPosition; - /** - * The current position of the entity - */ - NiPoint3 m_Position; + /** + * The current position of the entity + */ + NiPoint3 m_Position; - /** - * The current rotation of the entity - */ - NiQuaternion m_Rotation; + /** + * The current rotation of the entity + */ + NiQuaternion m_Rotation; - /** - * Whether or not the velocity is dirty, forcing a serialization of the velocity - */ - bool m_DirtyVelocity; + /** + * Whether or not the velocity is dirty, forcing a serialization of the velocity + */ + bool m_DirtyVelocity; - /** - * The current velocity of the entity - */ - NiPoint3 m_Velocity; + /** + * The current velocity of the entity + */ + NiPoint3 m_Velocity; - /** - * Whether or not the angular velocity is dirty, forcing a serialization - */ - bool m_DirtyAngularVelocity; + /** + * Whether or not the angular velocity is dirty, forcing a serialization + */ + bool m_DirtyAngularVelocity; - /** - * The current angular velocity of the entity - */ - NiPoint3 m_AngularVelocity; + /** + * The current angular velocity of the entity + */ + NiPoint3 m_AngularVelocity; - /** - * Whether or not the entity is on the ground, generally unused - */ - bool m_IsOnGround; + /** + * Whether or not the entity is on the ground, generally unused + */ + bool m_IsOnGround; - /** - * Whether or not the entity is on a rail, e.g. in Ninjago - */ - bool m_IsOnRail; + /** + * Whether or not the entity is on a rail, e.g. in Ninjago + */ + bool m_IsOnRail; - /** - * Whether or not this entity has a jetpack equipped - */ - bool m_InJetpackMode; + /** + * Whether or not this entity has a jetpack equipped + */ + bool m_InJetpackMode; - /** - * Whether or not this entity is currently flying a jetpack - */ - bool m_JetpackFlying; + /** + * Whether or not this entity is currently flying a jetpack + */ + bool m_JetpackFlying; - /** - * Bypass jetpack checks, currently unused - */ - bool m_JetpackBypassChecks; + /** + * Bypass jetpack checks, currently unused + */ + bool m_JetpackBypassChecks; - /** - * The effect that plays while using the jetpack - */ - int32_t m_JetpackEffectID; + /** + * The effect that plays while using the jetpack + */ + int32_t m_JetpackEffectID; - /** - * The current speed multiplier, allowing an entity to run faster - */ - float m_SpeedMultiplier; + /** + * The current speed multiplier, allowing an entity to run faster + */ + float m_SpeedMultiplier; - /** - * The current gravity scale, allowing an entity to move at an altered gravity - */ - float m_GravityScale; + /** + * The current gravity scale, allowing an entity to move at an altered gravity + */ + float m_GravityScale; - /** - * Forces a serialization of the speed multiplier and the gravity scale - */ - bool m_DirtyCheats; + /** + * Forces a serialization of the speed multiplier and the gravity scale + */ + bool m_DirtyCheats; - /** - * Makes it so that the speed multiplier and gravity scale are no longer serialized if false - */ - bool m_IgnoreMultipliers; + /** + * Makes it so that the speed multiplier and gravity scale are no longer serialized if false + */ + bool m_IgnoreMultipliers; - /** - * Whether this entity is static, making it unable to move - */ - bool m_Static; + /** + * Whether this entity is static, making it unable to move + */ + bool m_Static; - /** - * Whether the pickup scale is dirty. - */ - bool m_DirtyPickupRadiusScale; + /** + * Whether the pickup scale is dirty. + */ + bool m_DirtyEquippedItemInfo; - /** - * The list of pickup radius scales for this entity - */ - std::vector m_ActivePickupRadiusScales; + /** + * The list of pickup radius scales for this entity + */ + std::vector m_ActivePickupRadiusScales; - /** - * The active pickup radius for this entity - */ - float m_PickupRadius; + /** + * The active pickup radius for this entity + */ + float m_PickupRadius; + + /** + * If the entity is teleporting + */ + bool m_IsTeleporting; + + /** + * The list of speed boosts for this entity + */ + std::vector m_ActiveSpeedBoosts; + + /** + * The active speed boost for this entity + */ + float m_SpeedBoost; + + /* + * If Bubble info is dirty + */ + bool m_DirtyBubble; + + /* + * If the entity is in a bubble + */ + bool m_IsInBubble; + + /* + * The type of bubble the entity has + */ + eBubbleType m_BubbleType; + + /* + * If the entity should be using the special animations + */ + bool m_SpecialAnims; + + /** + * stun immunity counters + */ + int32_t m_ImmuneToStunAttackCount; + int32_t m_ImmuneToStunEquipCount; + int32_t m_ImmuneToStunInteractCount; + int32_t m_ImmuneToStunJumpCount; + int32_t m_ImmuneToStunMoveCount; + int32_t m_ImmuneToStunTurnCount; + int32_t m_ImmuneToStunUseItemCount; }; #endif // CONTROLLABLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 72194568..7e7d44aa 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -2,6 +2,7 @@ #include #include "dLogger.h" #include "Game.h" +#include "dConfig.h" #include "AMFFormat.h" #include "AMFFormat_BitStream.h" @@ -26,24 +27,33 @@ #include "MissionComponent.h" #include "CharacterComponent.h" +#include "PossessableComponent.h" +#include "PossessorComponent.h" +#include "InventoryComponent.h" #include "dZoneManager.h" +#include "WorldConfig.h" +#include "eMissionTaskType.h" +#include "eStateChangeType.h" +#include "eGameActivity.h" + +#include "CDComponentsRegistryTable.h" DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { - m_iArmor = 0; - m_fMaxArmor = 0.0f; - m_iImagination = 0; - m_fMaxImagination = 0.0f; - m_FactionIDs = std::vector(); - m_EnemyFactionIDs = std::vector(); - m_IsSmashable = false; - m_IsDead = false; - m_IsSmashed = false; - m_IsGMImmune = false; - m_IsShielded = false; - m_DamageToAbsorb = 0; - m_HasBricks = false; - m_DirtyThreatList = false; - m_HasThreats = false; + m_iArmor = 0; + m_fMaxArmor = 0.0f; + m_iImagination = 0; + m_fMaxImagination = 0.0f; + m_FactionIDs = std::vector(); + m_EnemyFactionIDs = std::vector(); + m_IsSmashable = false; + m_IsDead = false; + m_IsSmashed = false; + m_IsGMImmune = false; + m_IsShielded = false; + m_DamageToAbsorb = 0; + m_HasBricks = false; + m_DirtyThreatList = false; + m_HasThreats = false; m_ExplodeFactor = 1.0f; m_iHealth = 0; m_fMaxHealth = 0; @@ -51,26 +61,35 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_LootMatrixID = 0; m_MinCoins = 0; m_MaxCoins = 0; - m_ImmuneStacks = 0; m_DamageReduction = 0; + + m_ImmuneToBasicAttackCount = 0; + m_ImmuneToDamageOverTimeCount = 0; + m_ImmuneToKnockbackCount = 0; + m_ImmuneToInterruptCount = 0; + m_ImmuneToSpeedCount = 0; + m_ImmuneToImaginationGainCount = 0; + m_ImmuneToImaginationLossCount = 0; + m_ImmuneToQuickbuildInterruptCount = 0; + m_ImmuneToPullToPointCount = 0; } DestroyableComponent::~DestroyableComponent() { } void DestroyableComponent::Reinitialize(LOT templateID) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); - int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_BUFF); - int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_COLLECTIBLE); - int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_REBUILD); + int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::BUFF); + int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::COLLECTIBLE); + int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD); int32_t componentID = 0; if (collectibleComponentID > 0) componentID = collectibleComponentID; if (rebuildComponentID > 0) componentID = rebuildComponentID; if (buffComponentID > 0) componentID = buffComponentID; - CDDestructibleComponentTable* destCompTable = CDClientManager::Instance()->GetTable("DestructibleComponent"); + CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable(); std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (componentID > 0) { @@ -87,8 +106,7 @@ void DestroyableComponent::Reinitialize(LOT templateID) { SetIsSmashable(destCompData[0].isSmashable); } - } - else { + } else { SetHealth(1); SetImagination(0); SetArmor(0); @@ -102,89 +120,90 @@ void DestroyableComponent::Reinitialize(LOT templateID) { } void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { - if (bIsInitialUpdate) { - outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now. - } + if (bIsInitialUpdate) { + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToBasicAttackCount); + outBitStream->Write(m_ImmuneToDamageOverTimeCount); + outBitStream->Write(m_ImmuneToKnockbackCount); + outBitStream->Write(m_ImmuneToInterruptCount); + outBitStream->Write(m_ImmuneToSpeedCount); + outBitStream->Write(m_ImmuneToImaginationGainCount); + outBitStream->Write(m_ImmuneToImaginationLossCount); + outBitStream->Write(m_ImmuneToQuickbuildInterruptCount); + outBitStream->Write(m_ImmuneToPullToPointCount); + } - outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); - if (m_DirtyHealth || bIsInitialUpdate) { - outBitStream->Write(m_iHealth); - outBitStream->Write(m_fMaxHealth); - outBitStream->Write(m_iArmor); - outBitStream->Write(m_fMaxArmor); - outBitStream->Write(m_iImagination); - outBitStream->Write(m_fMaxImagination); + outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); + if (m_DirtyHealth || bIsInitialUpdate) { + outBitStream->Write(m_iHealth); + outBitStream->Write(m_fMaxHealth); + outBitStream->Write(m_iArmor); + outBitStream->Write(m_fMaxArmor); + outBitStream->Write(m_iImagination); + outBitStream->Write(m_fMaxImagination); - outBitStream->Write(m_DamageToAbsorb); - outBitStream->Write(IsImmune()); - outBitStream->Write(m_IsGMImmune); - outBitStream->Write(m_IsShielded); + outBitStream->Write(m_DamageToAbsorb); + outBitStream->Write(IsImmune()); + outBitStream->Write(m_IsGMImmune); + outBitStream->Write(m_IsShielded); - outBitStream->Write(m_fMaxHealth); - outBitStream->Write(m_fMaxArmor); - outBitStream->Write(m_fMaxImagination); + outBitStream->Write(m_fMaxHealth); + outBitStream->Write(m_fMaxArmor); + outBitStream->Write(m_fMaxImagination); outBitStream->Write(uint32_t(m_FactionIDs.size())); for (size_t i = 0; i < m_FactionIDs.size(); ++i) { outBitStream->Write(m_FactionIDs[i]); } - outBitStream->Write(m_IsSmashable); + outBitStream->Write(m_IsSmashable); - if (bIsInitialUpdate) { - outBitStream->Write(m_IsDead); - outBitStream->Write(m_IsSmashed); - - if (m_IsSmashable) { - outBitStream->Write(m_HasBricks); - - if (m_ExplodeFactor != 1.0f) { - outBitStream->Write1(); - outBitStream->Write(m_ExplodeFactor); - } else { - outBitStream->Write0(); - } - } - } + if (bIsInitialUpdate) { + outBitStream->Write(m_IsDead); + outBitStream->Write(m_IsSmashed); + if (m_IsSmashable) { + outBitStream->Write(m_HasBricks); + outBitStream->Write(m_ExplodeFactor != 1.0f); + if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor); + } + } m_DirtyHealth = false; - } + } - if (m_DirtyThreatList || bIsInitialUpdate) { - outBitStream->Write1(); - outBitStream->Write(m_HasThreats); + outBitStream->Write(m_DirtyThreatList || bIsInitialUpdate); + if (m_DirtyThreatList || bIsInitialUpdate) { + outBitStream->Write(m_HasThreats); m_DirtyThreatList = false; - } else { - outBitStream->Write0(); - } + } } -void DestroyableComponent::LoadFromXML(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); +void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { + tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { - Game::logger->Log("DestroyableComponent", "Failed to find dest tag!\n"); + Game::logger->Log("DestroyableComponent", "Failed to find dest tag!"); return; } auto* buffComponent = m_Parent->GetComponent(); if (buffComponent != nullptr) { - buffComponent->LoadFromXML(doc); + buffComponent->LoadFromXml(doc); } dest->QueryAttribute("hc", &m_iHealth); - dest->QueryAttribute("hm", &m_fMaxHealth); - dest->QueryAttribute("im", &m_fMaxImagination); - dest->QueryAttribute("ic", &m_iImagination); - dest->QueryAttribute("ac", &m_iArmor); - dest->QueryAttribute("am", &m_fMaxArmor); - m_DirtyHealth = true; + dest->QueryAttribute("hm", &m_fMaxHealth); + dest->QueryAttribute("im", &m_fMaxImagination); + dest->QueryAttribute("ic", &m_iImagination); + dest->QueryAttribute("ac", &m_iArmor); + dest->QueryAttribute("am", &m_fMaxArmor); + m_DirtyHealth = true; } void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); + tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { - Game::logger->Log("DestroyableComponent", "Failed to find dest tag!\n"); + Game::logger->Log("DestroyableComponent", "Failed to find dest tag!"); return; } @@ -195,11 +214,11 @@ void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) { } dest->SetAttribute("hc", m_iHealth); - dest->SetAttribute("hm", m_fMaxHealth); - dest->SetAttribute("im", m_fMaxImagination); - dest->SetAttribute("ic", m_iImagination); - dest->SetAttribute("ac", m_iArmor); - dest->SetAttribute("am", m_fMaxArmor); + dest->SetAttribute("hm", m_fMaxHealth); + dest->SetAttribute("im", m_fMaxImagination); + dest->SetAttribute("ic", m_iImagination); + dest->SetAttribute("ac", m_iArmor); + dest->SetAttribute("am", m_fMaxArmor); } void DestroyableComponent::SetHealth(int32_t value) { @@ -207,7 +226,7 @@ void DestroyableComponent::SetHealth(int32_t value) { auto* characterComponent = m_Parent->GetComponent(); if (characterComponent != nullptr) { - characterComponent->TrackHealthDelta(value - m_iHealth); + characterComponent->TrackHealthDelta(value - m_iHealth); } m_iHealth = value; @@ -234,27 +253,25 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) { AMFArrayValue args; args.InsertValue("amount", amount); args.InsertValue("type", type); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - delete amount; - delete type; + GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); } EntityManager::Instance()->SerializeEntity(m_Parent); } void DestroyableComponent::SetArmor(int32_t value) { - m_DirtyHealth = true; + m_DirtyHealth = true; // If Destroyable Component already has zero armor do not trigger the passive ability again. bool hadArmor = m_iArmor > 0; - - auto* characterComponent = m_Parent->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->TrackArmorDelta(value - m_iArmor); - } - m_iArmor = value; + auto* characterComponent = m_Parent->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->TrackArmorDelta(value - m_iArmor); + } + + m_iArmor = value; auto* inventroyComponent = m_Parent->GetComponent(); if (m_iArmor == 0 && inventroyComponent != nullptr && hadArmor) { @@ -263,8 +280,8 @@ void DestroyableComponent::SetArmor(int32_t value) { } void DestroyableComponent::SetMaxArmor(float value, bool playAnim) { - m_DirtyHealth = true; - m_fMaxArmor = value; + m_DirtyHealth = true; + m_fMaxArmor = value; if (m_iArmor > m_fMaxArmor) { m_iArmor = m_fMaxArmor; @@ -283,23 +300,20 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) { args.InsertValue("type", type); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - - delete amount; - delete type; } EntityManager::Instance()->SerializeEntity(m_Parent); } void DestroyableComponent::SetImagination(int32_t value) { - m_DirtyHealth = true; + m_DirtyHealth = true; - auto* characterComponent = m_Parent->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->TrackImaginationDelta(value - m_iImagination); - } + auto* characterComponent = m_Parent->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->TrackImaginationDelta(value - m_iImagination); + } - m_iImagination = value; + m_iImagination = value; auto* inventroyComponent = m_Parent->GetComponent(); if (m_iImagination == 0 && inventroyComponent != nullptr) { @@ -308,10 +322,10 @@ void DestroyableComponent::SetImagination(int32_t value) { } void DestroyableComponent::SetMaxImagination(float value, bool playAnim) { - m_DirtyHealth = true; + m_DirtyHealth = true; // Used for playAnim if opted in for. int32_t difference = static_cast(std::abs(m_fMaxImagination - value)); - m_fMaxImagination = value; + m_fMaxImagination = value; if (m_iImagination > m_fMaxImagination) { m_iImagination = m_fMaxImagination; @@ -328,40 +342,33 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) { AMFArrayValue args; args.InsertValue("amount", amount); args.InsertValue("type", type); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - delete amount; - delete type; + GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); } EntityManager::Instance()->SerializeEntity(m_Parent); } -void DestroyableComponent::SetDamageToAbsorb(int32_t value) -{ +void DestroyableComponent::SetDamageToAbsorb(int32_t value) { m_DirtyHealth = true; m_DamageToAbsorb = value; } -void DestroyableComponent::SetDamageReduction(int32_t value) -{ +void DestroyableComponent::SetDamageReduction(int32_t value) { m_DirtyHealth = true; m_DamageReduction = value; } -void DestroyableComponent::SetIsImmune(bool value) -{ +void DestroyableComponent::SetIsImmune(bool value) { m_DirtyHealth = true; - m_ImmuneStacks = value ? 1 : 0; + m_ImmuneToBasicAttackCount = value ? 1 : 0; } -void DestroyableComponent::SetIsGMImmune(bool value) -{ +void DestroyableComponent::SetIsGMImmune(bool value) { m_DirtyHealth = true; m_IsGMImmune = value; } -void DestroyableComponent::SetIsShielded(bool value) -{ +void DestroyableComponent::SetIsShielded(bool value) { m_DirtyHealth = true; m_IsShielded = value; } @@ -372,12 +379,12 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore return; } - m_FactionIDs.push_back(factionID); - m_DirtyHealth = true; + m_FactionIDs.push_back(factionID); + m_DirtyHealth = true; auto query = CDClientDatabase::CreatePreppedStmt( "SELECT enemyList FROM Factions WHERE faction = ?;"); - query.bind(1, (int) factionID); + query.bind(1, (int)factionID); auto result = query.execQuery(); @@ -397,13 +404,11 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore auto exclude = std::find(m_FactionIDs.begin(), m_FactionIDs.end(), id) != m_FactionIDs.end(); - if (!exclude) - { + if (!exclude) { exclude = std::find(m_EnemyFactionIDs.begin(), m_EnemyFactionIDs.end(), id) != m_EnemyFactionIDs.end(); } - if (exclude) - { + if (exclude) { continue; } @@ -413,69 +418,64 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore result.finalize(); } -bool DestroyableComponent::IsEnemy (const Entity* other) const { - const auto* otherDestroyableComponent = other->GetComponent(); - if (otherDestroyableComponent != nullptr) { - for (const auto enemyFaction : m_EnemyFactionIDs) { - for (const auto otherFaction : otherDestroyableComponent->GetFactionIDs()) { - if (enemyFaction == otherFaction) - return true; - } - } - } +bool DestroyableComponent::IsEnemy(const Entity* other) const { + const auto* otherDestroyableComponent = other->GetComponent(); + if (otherDestroyableComponent != nullptr) { + for (const auto enemyFaction : m_EnemyFactionIDs) { + for (const auto otherFaction : otherDestroyableComponent->GetFactionIDs()) { + if (enemyFaction == otherFaction) + return true; + } + } + } - return false; + return false; } -bool DestroyableComponent::IsFriend (const Entity* other) const { - const auto* otherDestroyableComponent = other->GetComponent(); - if (otherDestroyableComponent != nullptr) { - for (const auto enemyFaction : m_EnemyFactionIDs) { - for (const auto otherFaction : otherDestroyableComponent->GetFactionIDs()) { - if (enemyFaction == otherFaction) - return false; - } - } +bool DestroyableComponent::IsFriend(const Entity* other) const { + const auto* otherDestroyableComponent = other->GetComponent(); + if (otherDestroyableComponent != nullptr) { + for (const auto enemyFaction : m_EnemyFactionIDs) { + for (const auto otherFaction : otherDestroyableComponent->GetFactionIDs()) { + if (enemyFaction == otherFaction) + return false; + } + } - return true; - } + return true; + } - return false; + return false; } -void DestroyableComponent::AddEnemyFaction(int32_t factionID) -{ +void DestroyableComponent::AddEnemyFaction(int32_t factionID) { m_EnemyFactionIDs.push_back(factionID); } void DestroyableComponent::SetIsSmashable(bool value) { - m_DirtyHealth = true; - m_IsSmashable = value; - //m_HasBricks = value; + m_DirtyHealth = true; + m_IsSmashable = value; } -void DestroyableComponent::SetAttacksToBlock(const uint32_t value) -{ +void DestroyableComponent::SetAttacksToBlock(const uint32_t value) { m_AttacksToBlock = value; } -bool DestroyableComponent::IsImmune() const -{ - return m_ImmuneStacks > 0 || m_IsGMImmune; +bool DestroyableComponent::IsImmune() const { + return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0; } -bool DestroyableComponent::IsKnockbackImmune() const -{ +bool DestroyableComponent::IsKnockbackImmune() const { auto* characterComponent = m_Parent->GetComponent(); auto* inventoryComponent = m_Parent->GetComponent(); - if (characterComponent != nullptr && inventoryComponent != nullptr && characterComponent->GetCurrentActivity() == eGameActivities::ACTIVITY_QUICKBUILDING) { + if (characterComponent != nullptr && inventoryComponent != nullptr && characterComponent->GetCurrentActivity() == eGameActivity::QUICKBUILDING) { const auto hasPassive = inventoryComponent->HasAnyPassive({ - ItemSetPassiveAbilityID::EngineerRank2, ItemSetPassiveAbilityID::EngineerRank3, - ItemSetPassiveAbilityID::SummonerRank2, ItemSetPassiveAbilityID::SummonerRank3, - ItemSetPassiveAbilityID::InventorRank2, ItemSetPassiveAbilityID::InventorRank3, - }, 5); + eItemSetPassiveAbilityID::EngineerRank2, eItemSetPassiveAbilityID::EngineerRank3, + eItemSetPassiveAbilityID::SummonerRank2, eItemSetPassiveAbilityID::SummonerRank3, + eItemSetPassiveAbilityID::InventorRank2, eItemSetPassiveAbilityID::InventorRank3, + }, 5); if (hasPassive) { return true; @@ -485,52 +485,43 @@ bool DestroyableComponent::IsKnockbackImmune() const return IsImmune() || m_IsShielded || m_AttacksToBlock > 0; } -bool DestroyableComponent::HasFaction(int32_t factionID) const -{ +bool DestroyableComponent::HasFaction(int32_t factionID) const { return std::find(m_FactionIDs.begin(), m_FactionIDs.end(), factionID) != m_FactionIDs.end(); } -LWOOBJID DestroyableComponent::GetKillerID() const -{ +LWOOBJID DestroyableComponent::GetKillerID() const { return m_KillerID; } -Entity* DestroyableComponent::GetKiller() const -{ +Entity* DestroyableComponent::GetKiller() const { return EntityManager::Instance()->GetEntity(m_KillerID); } -bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignoreFactions, const bool targetEnemy, const bool targetFriend) const -{ +bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignoreFactions, const bool targetEnemy, const bool targetFriend) const { auto* targetEntity = EntityManager::Instance()->GetEntity(target); - if (targetEntity == nullptr) - { - Game::logger->Log("DestroyableComponent", "Invalid entity for checking validity (%llu)!\n", target); + if (targetEntity == nullptr) { + Game::logger->Log("DestroyableComponent", "Invalid entity for checking validity (%llu)!", target); return false; } auto* targetDestroyable = targetEntity->GetComponent(); - if (targetDestroyable == nullptr) - { + if (targetDestroyable == nullptr) { return false; } auto* targetQuickbuild = targetEntity->GetComponent(); - if (targetQuickbuild != nullptr) - { + if (targetQuickbuild != nullptr) { const auto state = targetQuickbuild->GetState(); - if (state != REBUILD_COMPLETED) - { + if (state != eRebuildState::COMPLETED) { return false; } } - if (ignoreFactions) - { + if (ignoreFactions) { return true; } @@ -543,8 +534,7 @@ bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignor } -void DestroyableComponent::Heal(const uint32_t health) -{ +void DestroyableComponent::Heal(const uint32_t health) { auto current = static_cast(GetHealth()); const auto max = static_cast(GetMaxHealth()); @@ -558,8 +548,7 @@ void DestroyableComponent::Heal(const uint32_t health) } -void DestroyableComponent::Imagine(const int32_t deltaImagination) -{ +void DestroyableComponent::Imagine(const int32_t deltaImagination) { auto current = static_cast(GetImagination()); const auto max = static_cast(GetMaxImagination()); @@ -567,8 +556,7 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination) current = std::min(current, max); - if (current < 0) - { + if (current < 0) { current = 0; } @@ -578,8 +566,7 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination) } -void DestroyableComponent::Repair(const uint32_t armor) -{ +void DestroyableComponent::Repair(const uint32_t armor) { auto current = static_cast(GetArmor()); const auto max = static_cast(GetMaxArmor()); @@ -593,34 +580,26 @@ void DestroyableComponent::Repair(const uint32_t armor) } -void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32_t skillID, bool echo) -{ - if (GetHealth() <= 0) - { +void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32_t skillID, bool echo) { + if (GetHealth() <= 0) { return; } - if (IsImmune()) - { + if (IsImmune()) { return; } - if (m_AttacksToBlock > 0) - { + if (m_AttacksToBlock > 0) { m_AttacksToBlock--; return; } // If this entity has damage reduction, reduce the damage to a minimum of 1 - if (m_DamageReduction > 0 && damage > 0) - { - if (damage > m_DamageReduction) - { + if (m_DamageReduction > 0 && damage > 0) { + if (damage > m_DamageReduction) { damage -= m_DamageReduction; - } - else - { + } else { damage = 1; } } @@ -648,42 +627,84 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 SetHealth(health); SetIsShielded(absorb > 0); - if (m_Parent->GetLOT() != 1) - { + // Dismount on the possessable hit + auto possessable = m_Parent->GetComponent(); + if (possessable && possessable->GetDepossessOnHit()) { + possessable->Dismount(); + } + + // Dismount on the possessor hit + auto possessor = m_Parent->GetComponent(); + if (possessor) { + auto possessableId = possessor->GetPossessable(); + if (possessableId != LWOOBJID_EMPTY) { + auto possessable = EntityManager::Instance()->GetEntity(possessableId); + if (possessable) { + possessor->Dismount(possessable); + } + } + } + + if (m_Parent->GetLOT() != 1) { echo = true; } - if (echo) - { + if (echo) { EntityManager::Instance()->SerializeEntity(m_Parent); } auto* attacker = EntityManager::Instance()->GetEntity(source); m_Parent->OnHit(attacker); m_Parent->OnHitOrHealResult(attacker, sourceDamage); + NotifySubscribers(attacker, sourceDamage); for (const auto& cb : m_OnHitCallbacks) { - cb(attacker); + cb(attacker); } - if (health != 0) - { + if (health != 0) { auto* combatComponent = m_Parent->GetComponent(); - if (combatComponent != nullptr) - { + if (combatComponent != nullptr) { combatComponent->Taunt(source, sourceDamage * 10); // * 10 is arbatrary } return; } + + //check if hardcore mode is enabled + if (EntityManager::Instance()->GetHardcoreMode()) { + DoHardcoreModeDrops(source); + } + Smash(source, eKillType::VIOLENT, u"", skillID); } -void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) -{ - if (m_iHealth > 0) - { +void DestroyableComponent::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd) { + m_SubscribedScripts.insert(std::make_pair(scriptObjId, scriptToAdd)); + Game::logger->LogDebug("DestroyableComponent", "Added script %llu to entity %llu", scriptObjId, m_Parent->GetObjectID()); + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::Unsubscribe(LWOOBJID scriptObjId) { + auto foundScript = m_SubscribedScripts.find(scriptObjId); + if (foundScript != m_SubscribedScripts.end()) { + m_SubscribedScripts.erase(foundScript); + Game::logger->LogDebug("DestroyableComponent", "Removed script %llu from entity %llu", scriptObjId, m_Parent->GetObjectID()); + } else { + Game::logger->LogDebug("DestroyableComponent", "Tried to remove a script for Entity %llu but script %llu didnt exist", m_Parent->GetObjectID(), scriptObjId); + } + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) { + for (auto script : m_SubscribedScripts) { + script.second->NotifyHitOrHealResult(m_Parent, attacker, damage); + } +} + +void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) { + if (m_iHealth > 0) { SetArmor(0); SetHealth(0); @@ -694,8 +715,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* owner = EntityManager::Instance()->GetEntity(source); - if (owner != nullptr) - { + if (owner != nullptr) { owner = owner->GetOwner(); // If the owner is overwritten, we collect that here auto* team = TeamManager::Instance()->GetTeam(owner->GetObjectID()); @@ -704,19 +724,15 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* inventoryComponent = owner->GetComponent(); - if (inventoryComponent != nullptr && isEnemy) - { - inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed); + if (inventoryComponent != nullptr && isEnemy) { + inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed, m_Parent); } auto* missions = owner->GetComponent(); - if (missions != nullptr) - { - if (team != nullptr && isEnemy) - { - for (const auto memberId : team->members) - { + if (missions != nullptr) { + if (team != nullptr) { + for (const auto memberId : team->members) { auto* member = EntityManager::Instance()->GetEntity(memberId); if (member == nullptr) continue; @@ -725,14 +741,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (memberMissions == nullptr) continue; - memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT()); - memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID); + memberMissions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT()); + memberMissions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID); } - } - else - { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT()); - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID); + } else { + missions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT()); + missions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID); } } } @@ -742,14 +756,11 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType GameMessages::SendDie(m_Parent, source, source, true, killType, deathType, 0, 0, 0, isPlayer, false, 1); //NANI?! - if (!isPlayer) - { - if (owner != nullptr) - { + if (!isPlayer) { + if (owner != nullptr) { auto* team = TeamManager::Instance()->GetTeam(owner->GetObjectID()); - if (team != nullptr && m_Parent->GetComponent() != nullptr) - { + if (team != nullptr && m_Parent->GetComponent() != nullptr) { LWOOBJID specificOwner = LWOOBJID_EMPTY; auto* scriptedActivityComponent = m_Parent->GetComponent(); uint32_t teamSize = team->members.size(); @@ -764,9 +775,8 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* member = EntityManager::Instance()->GetEntity(specificOwner); - if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); - } - else { + if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); + } else { for (const auto memberId : team->members) { // Free for all auto* member = EntityManager::Instance()->GetEntity(memberId); @@ -775,79 +785,105 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); } } - } - else { // drop loot for non team user + } else { // drop loot for non team user LootGenerator::Instance().DropLoot(owner, m_Parent, GetLootMatrixID(), GetMinCoins(), GetMaxCoins()); } } - } - else - { + } else { //Check if this zone allows coin drops - if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) - { + if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) { auto* character = m_Parent->GetCharacter(); uint64_t coinsTotal = character->GetCoins(); + const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; + if (coinsTotal >= minCoinsToLose) { + const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax; + const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent; - if (coinsTotal > 0) - { - uint64_t coinsToLoose = 1; + uint64_t coinsToLose = std::max(static_cast(coinsTotal * coinPercentageToLose), minCoinsToLose); + coinsToLose = std::min(maxCoinsToLose, coinsToLose); - if (coinsTotal >= 200) - { - float hundreth = (coinsTotal / 100.0f); - coinsToLoose = static_cast(hundreth); - } + coinsTotal -= coinsToLose; - if (coinsToLoose > 10000) - { - coinsToLoose = 10000; - } - - coinsTotal -= coinsToLoose; - - LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLoose, coinsToLoose); - character->SetCoins(coinsTotal, eLootSourceType::LOOT_SOURCE_PICKUP); + LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose); + character->SetCoins(coinsTotal, eLootSourceType::PICKUP); } } - Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerDied(zoneControl, m_Parent); - } + Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { + script->OnPlayerDied(zoneControl, m_Parent); + } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); - for (Entity* scriptEntity : scriptedActs) { - if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerDied(scriptEntity, m_Parent); - } - } - } + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (Entity* scriptEntity : scriptedActs) { + if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds + for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { + script->OnPlayerDied(scriptEntity, m_Parent); + } + } + } } m_Parent->Kill(owner); } -void DestroyableComponent::SetFaction(int32_t factionID) { +void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) { m_FactionIDs.clear(); m_EnemyFactionIDs.clear(); - AddFaction(factionID); + AddFaction(factionID, ignoreChecks); } -void DestroyableComponent::PushImmunity(int32_t stacks) -{ - m_ImmuneStacks += stacks; +void DestroyableComponent::SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack, + const bool bImmuneToDamageOverTime, + const bool bImmuneToKnockback, + const bool bImmuneToInterrupt, + const bool bImmuneToSpeed, + const bool bImmuneToImaginationGain, + const bool bImmuneToImaginationLoss, + const bool bImmuneToQuickbuildInterrupt, + const bool bImmuneToPullToPoint) { + + if (state == eStateChangeType::POP) { + if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1; + if (bImmuneToDamageOverTime && m_ImmuneToDamageOverTimeCount > 0) m_ImmuneToDamageOverTimeCount -= 1; + if (bImmuneToKnockback && m_ImmuneToKnockbackCount > 0) m_ImmuneToKnockbackCount -= 1; + if (bImmuneToInterrupt && m_ImmuneToInterruptCount > 0) m_ImmuneToInterruptCount -= 1; + if (bImmuneToSpeed && m_ImmuneToSpeedCount > 0) m_ImmuneToSpeedCount -= 1; + if (bImmuneToImaginationGain && m_ImmuneToImaginationGainCount > 0) m_ImmuneToImaginationGainCount -= 1; + if (bImmuneToImaginationLoss && m_ImmuneToImaginationLossCount > 0) m_ImmuneToImaginationLossCount -= 1; + if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1; + if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1; + + } else if (state == eStateChangeType::PUSH){ + if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1; + if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1; + if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1; + if (bImmuneToInterrupt) m_ImmuneToInterruptCount += 1; + if (bImmuneToSpeed) m_ImmuneToSpeedCount += 1; + if (bImmuneToImaginationGain) m_ImmuneToImaginationGainCount += 1; + if (bImmuneToImaginationLoss) m_ImmuneToImaginationLossCount += 1; + if (bImmuneToQuickbuildInterrupt) m_ImmuneToQuickbuildInterruptCount += 1; + if (bImmuneToPullToPoint) m_ImmuneToPullToPointCount += 1; + } + + GameMessages::SendSetStatusImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), + bImmuneToBasicAttack, + bImmuneToDamageOverTime, + bImmuneToKnockback, + bImmuneToInterrupt, + bImmuneToSpeed, + bImmuneToImaginationGain, + bImmuneToImaginationLoss, + bImmuneToQuickbuildInterrupt, + bImmuneToPullToPoint + ); } -void DestroyableComponent::PopImmunity(int32_t stacks) -{ - m_ImmuneStacks -= stacks; -} - -void DestroyableComponent::FixStats() -{ +void DestroyableComponent::FixStats() { auto* entity = GetParent(); if (entity == nullptr) return; @@ -860,8 +896,7 @@ void DestroyableComponent::FixStats() auto* destroyableComponent = entity->GetComponent(); // If any of the components are nullptr, return - if (skillComponent == nullptr || buffComponent == nullptr || missionComponent == nullptr || inventoryComponent == nullptr || destroyableComponent == nullptr) - { + if (skillComponent == nullptr || buffComponent == nullptr || missionComponent == nullptr || inventoryComponent == nullptr || destroyableComponent == nullptr) { return; } @@ -873,13 +908,11 @@ void DestroyableComponent::FixStats() // Unequip all items auto equipped = inventoryComponent->GetEquippedItems(); - for (auto& equippedItem : equipped) - { + for (auto& equippedItem : equipped) { // Get the item with the item ID auto* item = inventoryComponent->FindItemById(equippedItem.second.id); - if (item == nullptr) - { + if (item == nullptr) { continue; } @@ -893,12 +926,10 @@ void DestroyableComponent::FixStats() int32_t maxImagination = 0; // Go through all completed missions and add the reward stats - for (auto& pair : missionComponent->GetMissions()) - { + for (auto& pair : missionComponent->GetMissions()) { auto* mission = pair.second; - if (!mission->IsComplete()) - { + if (!mission->IsComplete()) { continue; } @@ -918,13 +949,11 @@ void DestroyableComponent::FixStats() buffComponent->ReApplyBuffs(); // Requip all items - for (auto& equippedItem : equipped) - { + for (auto& equippedItem : equipped) { // Get the item with the item ID auto* item = inventoryComponent->FindItemById(equippedItem.second.id); - if (item == nullptr) - { + if (item == nullptr) { continue; } @@ -952,5 +981,77 @@ void DestroyableComponent::FixStats() } void DestroyableComponent::AddOnHitCallback(const std::function& callback) { - m_OnHitCallbacks.push_back(callback); + m_OnHitCallbacks.push_back(callback); +} + +void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){ + //check if this is a player: + if (m_Parent->IsPlayer()) { + //remove hardcore_lose_uscore_on_death_percent from the player's uscore: + auto* character = m_Parent->GetComponent(); + auto uscore = character->GetUScore(); + + auto uscoreToLose = uscore * (EntityManager::Instance()->GetHardcoreLoseUscoreOnDeathPercent() / 100); + character->SetUScore(uscore - uscoreToLose); + + GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::MISSION); + + if (EntityManager::Instance()->GetHardcoreDropinventoryOnDeath()) { + //drop all items from inventory: + auto* inventory = m_Parent->GetComponent(); + if (inventory) { + //get the items inventory: + auto items = inventory->GetInventory(eInventoryType::ITEMS); + if (items){ + auto itemMap = items->GetItems(); + if (!itemMap.empty()){ + for (const auto& item : itemMap) { + //drop the item: + if (!item.second) continue; + // don't drop the thinkng cap + if (item.second->GetLot() == 6086) continue; + GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount()); + item.second->SetCount(0, false, false); + } + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } + } + } + + //get character: + auto* chars = m_Parent->GetCharacter(); + if (chars) { + auto coins = chars->GetCoins(); + + //lose all coins: + chars->SetCoins(0, eLootSourceType::NONE); + + //drop all coins: + GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, coins, m_Parent->GetPosition()); + } + + // Reload the player since we can't normally reduce uscore from the server and we want the UI to update + // do this last so we don't get killed.... again + EntityManager::Instance()->DestructEntity(m_Parent); + EntityManager::Instance()->ConstructEntity(m_Parent); + return; + } + + //award the player some u-score: + auto* player = EntityManager::Instance()->GetEntity(source); + if (player && player->IsPlayer()) { + auto* playerStats = player->GetComponent(); + if (playerStats) { + //get the maximum health from this enemy: + auto maxHealth = GetMaxHealth(); + + int uscore = maxHealth * EntityManager::Instance()->GetHardcoreUscoreEnemiesMultiplier(); + + playerStats->SetUScore(playerStats->GetUScore() + uscore); + GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::MISSION); + + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } } diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index a1f57be4..66c8374d 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -6,6 +6,12 @@ #include "tinyxml2.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" + +namespace CppScripts { + class Script; +}; //! namespace CppScripts +enum class eStateChangeType : uint32_t; /** * Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which @@ -13,542 +19,592 @@ */ class DestroyableComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_DESTROYABLE; - - DestroyableComponent(Entity* parentEntity); - ~DestroyableComponent() override; + static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); - void LoadFromXML(tinyxml2::XMLDocument* doc); - void UpdateXml(tinyxml2::XMLDocument* doc) override; + DestroyableComponent(Entity* parentEntity); + ~DestroyableComponent() override; - /** - * Initializes the component using a different LOT - * @param templateID the ID to use for initialization - */ + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); + void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument* doc) override; + + /** + * Initializes the component using a different LOT + * @param templateID the ID to use for initialization + */ void Reinitialize(LOT templateID); - /** - * Sets the health of this entity. Makes sure this is serialized on the next tick and if this is a character its - * stats will also update. - * @param value the new health value - */ - void SetHealth(int32_t value); + /** + * Sets the health of this entity. Makes sure this is serialized on the next tick and if this is a character its + * stats will also update. + * @param value the new health value + */ + void SetHealth(int32_t value); - /** - * Heals the entity by some delta amount - * @param health the delta amount to heal - */ - void Heal(uint32_t health); + /** + * Heals the entity by some delta amount + * @param health the delta amount to heal + */ + void Heal(uint32_t health); - /** - * Returns the current health of this entity - * @return the current health of this entity - */ - int32_t GetHealth() const { return m_iHealth; } + /** + * Returns the current health of this entity + * @return the current health of this entity + */ + int32_t GetHealth() const { return m_iHealth; } - /** - * Updates the max health this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that - * @param value the max health value to set - * @param playAnim whether or not to play a UI animation indicating the change in max health - */ - void SetMaxHealth(float value, bool playAnim = false); + /** + * Updates the max health this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that + * @param value the max health value to set + * @param playAnim whether or not to play a UI animation indicating the change in max health + */ + void SetMaxHealth(float value, bool playAnim = false); - /** - * Returns the curent max health of this entity - * @return the current max health of this entity - */ - float GetMaxHealth() const { return m_fMaxHealth; } + /** + * Returns the curent max health of this entity + * @return the current max health of this entity + */ + float GetMaxHealth() const { return m_fMaxHealth; } - /** - * Sets the armor for this entity. This also makes sure this change is serialized and if this is a character it also - * updates their stats. - * @param value the armor value to set - */ - void SetArmor(int32_t value); + /** + * Sets the armor for this entity. This also makes sure this change is serialized and if this is a character it also + * updates their stats. + * @param value the armor value to set + */ + void SetArmor(int32_t value); - /** - * Repairs armor of this entity, updating it by a delta amount - * @param armor the amount of armor to repair - */ - void Repair(uint32_t armor); + /** + * Repairs armor of this entity, updating it by a delta amount + * @param armor the amount of armor to repair + */ + void Repair(uint32_t armor); - /** - * Returns the current armor value for the entity - * @return the current armor value for the entity - */ - int32_t GetArmor() const { return m_iArmor; } + /** + * Returns the current armor value for the entity + * @return the current armor value for the entity + */ + int32_t GetArmor() const { return m_iArmor; } - /** - * Updates the max armor this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that - * @param value the max armor value to set - * @param playAnim whether or not to play a UI animation indicating the change in max armor - */ - void SetMaxArmor(float value, bool playAnim = false); + /** + * Updates the max armor this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that + * @param value the max armor value to set + * @param playAnim whether or not to play a UI animation indicating the change in max armor + */ + void SetMaxArmor(float value, bool playAnim = false); - /** - * Returns the current maximum armor this entity can have - * @return the current maximum armor this entity can have - */ - float GetMaxArmor() const { return m_fMaxArmor; } + /** + * Returns the current maximum armor this entity can have + * @return the current maximum armor this entity can have + */ + float GetMaxArmor() const { return m_fMaxArmor; } - /** - * Sets the imagination value for this entity. Ensures that the change is serialized and if this is a character - * their stats will be updated. Can also trigger the assembly passive ability to restore on 0 imag. - * @param value - */ - void SetImagination(int32_t value); + /** + * Sets the imagination value for this entity. Ensures that the change is serialized and if this is a character + * their stats will be updated. Can also trigger the assembly passive ability to restore on 0 imag. + * @param value + */ + void SetImagination(int32_t value); - /** - * Updates the imagination of this entity by a delta amount - * @param deltaImagination the imagination to update - */ - void Imagine(int32_t deltaImagination); + /** + * Updates the imagination of this entity by a delta amount + * @param deltaImagination the imagination to update + */ + void Imagine(int32_t deltaImagination); - /** - * Returns the current imagination value of this entity - * @return the current imagination value of this entity - */ - int32_t GetImagination() const { return m_iImagination; } + /** + * Returns the current imagination value of this entity + * @return the current imagination value of this entity + */ + int32_t GetImagination() const { return m_iImagination; } - /** - * Updates the max imagination this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that - * @param value the max imagination value to set - * @param playAnim whether or not to play a UI animation indicating the change in max imagination - */ - void SetMaxImagination(float value, bool playAnim = false); + /** + * Updates the max imagination this entity has (e.g. what it can heal to), and optionally displays a UI animation indicating that + * @param value the max imagination value to set + * @param playAnim whether or not to play a UI animation indicating the change in max imagination + */ + void SetMaxImagination(float value, bool playAnim = false); - /** - * Returns the current max imagination value - * @return the current max imagination value - */ - float GetMaxImagination() const { return m_fMaxImagination; } + /** + * Returns the current max imagination value + * @return the current max imagination value + */ + float GetMaxImagination() const { return m_fMaxImagination; } - /** - * Sets the damage this entity can absorb before getting hurt, also serializes this change. - * @param value the damage to absorb - */ - void SetDamageToAbsorb(int32_t value); + /** + * Sets the damage this entity can absorb before getting hurt, also serializes this change. + * @param value the damage to absorb + */ + void SetDamageToAbsorb(int32_t value); - /** - * Returns the current damage to absorb - * @return the current damage to absorb - */ - int32_t GetDamageToAbsorb() const { return m_DamageToAbsorb; } + /** + * Returns the current damage to absorb + * @return the current damage to absorb + */ + int32_t GetDamageToAbsorb() const { return m_DamageToAbsorb; } - /** - * Sets the reduced damage value for each attack for this entity, also serializes that change. - * @param value the damage to reduce for each attack - */ - void SetDamageReduction(int32_t value); + /** + * Sets the reduced damage value for each attack for this entity, also serializes that change. + * @param value the damage to reduce for each attack + */ + void SetDamageReduction(int32_t value); - /** - * Returns the current damage reduction value - * @return the current damage reduction value - */ - int32_t GetDamageReduction() const { return m_DamageReduction; } + /** + * Returns the current damage reduction value + * @return the current damage reduction value + */ + int32_t GetDamageReduction() const { return m_DamageReduction; } - /** - * Sets whether or not this entity is immune to attacks - * @param value whether or not this entity is immune to attacks - */ - void SetIsImmune(bool value); + /** + * Sets whether or not this entity is immune to attacks + * @param value whether or not this entity is immune to attacks + */ + void SetIsImmune(bool value); - /** - * Returns whether or not this entity is immune to attacks - * @return whether or not this entity is immune to attacks - */ - bool IsImmune() const; + /** + * Returns whether or not this entity is immune to attacks + * @return whether or not this entity is immune to attacks + */ + bool IsImmune() const; - /** - * Sets if this entity has GM immunity, making it not killable - * @param value the GM immunity of this entity - */ - void SetIsGMImmune(bool value); + /** + * Sets if this entity has GM immunity, making it not killable + * @param value the GM immunity of this entity + */ + void SetIsGMImmune(bool value); - /** - * Returns whether or not this entity has GM immunity - * @return whether or not this entity has GM immunity - */ - bool GetIsGMImmune() const { return m_IsGMImmune; } + /** + * Returns whether or not this entity has GM immunity + * @return whether or not this entity has GM immunity + */ + bool GetIsGMImmune() const { return m_IsGMImmune; } - /** - * Sets whether or not this entity is shielded for a certain amount of damage - * @param value whether or not this entity is shielded for a certain amount of damage - */ - void SetIsShielded(bool value); + /** + * Sets whether or not this entity is shielded for a certain amount of damage + * @param value whether or not this entity is shielded for a certain amount of damage + */ + void SetIsShielded(bool value); - /** - * Returns if this entity is currently shielded from damage - * @return if this entity is currently shielded from damage - */ - bool GetIsShielded() const { return m_IsShielded; } + /** + * Returns if this entity is currently shielded from damage + * @return if this entity is currently shielded from damage + */ + bool GetIsShielded() const { return m_IsShielded; } - /** - * Adds a faction to the faction list of this entity, potentially making more factions friendly. Fetches the info - * from the CDClient. - * @param factionID the faction ID to add - * @param ignoreChecks whether or not to allow factionID -1 - */ - void AddFaction(int32_t factionID, bool ignoreChecks = false); + /** + * Adds a faction to the faction list of this entity, potentially making more factions friendly. Fetches the info + * from the CDClient. + * @param factionID the faction ID to add + * @param ignoreChecks whether or not to allow factionID -1 + */ + void AddFaction(int32_t factionID, bool ignoreChecks = false); - /** - * Adds a faction ID to the enemy list - * @param factionID the faction ID to make an enemy - */ - void AddEnemyFaction(int32_t factionID); + /** + * Adds a faction ID to the enemy list + * @param factionID the faction ID to make an enemy + */ + void AddEnemyFaction(int32_t factionID); - /** - * Sets whether or not this entity can be smashed, does not indicate the smashable glow, which is indicated by - * faction ids - * @param value whether or not this entity is smashable - */ - void SetIsSmashable(bool value); + /** + * Sets whether or not this entity can be smashed, does not indicate the smashable glow, which is indicated by + * faction ids + * @param value whether or not this entity is smashable + */ + void SetIsSmashable(bool value); - /** - * Returns whether or not this entity is smashable - * @return whether or not this entity is smashable - */ - bool GetIsSmashable() const { return m_IsSmashable; } + /** + * Returns whether or not this entity is smashable + * @return whether or not this entity is smashable + */ + bool GetIsSmashable() const { return m_IsSmashable; } - /** - * Returns the current is-dead value, this is mostly unused - * @return the current is-dead value, this is mostly unused - */ - bool GetIsDead() const { return m_IsDead; } + /** + * Returns the current is-dead value, this is mostly unused + * @return the current is-dead value, this is mostly unused + */ + bool GetIsDead() const { return m_IsDead; } - /** - * Returns the current is-smashed value, this is mostly unused - * @return the current is-smashed value, this is mostly unused - */ - bool GetIsSmashed() const { return m_IsSmashed; } + /** + * Returns the current is-smashed value, this is mostly unused + * @return the current is-smashed value, this is mostly unused + */ + bool GetIsSmashed() const { return m_IsSmashed; } - /** - * Sets whether or not this entity has bricks flying out when smashed - * @param value whether or not this entity has bricks flying out when smashed - */ - void SetHasBricks(bool value); + /** + * Sets whether or not this entity has bricks flying out when smashed + * @param value whether or not this entity has bricks flying out when smashed + */ + void SetHasBricks(bool value); - /** - * Returns whether or not this entity has bricks flying out when smashed - * @return whether or not this entity has bricks flying out when smashed - */ - bool GetHasBricks() const { return m_HasBricks; } + /** + * Returns whether or not this entity has bricks flying out when smashed + * @return whether or not this entity has bricks flying out when smashed + */ + bool GetHasBricks() const { return m_HasBricks; } - /** - * Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed - * @param value the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed - */ - void SetExplodeFactor(float value); + /** + * Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed + * @param value the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed + */ + void SetExplodeFactor(float value) { m_ExplodeFactor = value; }; - /** - * Returns the current multiplier for explosions - * @return the current multiplier for explosions - */ - float GetExplodeFactor() const { return m_ExplodeFactor; } + /** + * Returns the current multiplier for explosions + * @return the current multiplier for explosions + */ + float GetExplodeFactor() const { return m_ExplodeFactor; } - /** - * Sets the amount of attacks this entity can block before being able to be damaged again, useful for example for - * shields. - * @param value the amount of attacks this entity can block before being able to be damaged again - */ - void SetAttacksToBlock(uint32_t value); + /** + * Sets the amount of attacks this entity can block before being able to be damaged again, useful for example for + * shields. + * @param value the amount of attacks this entity can block before being able to be damaged again + */ + void SetAttacksToBlock(uint32_t value); - /** - * Returns the current amount of attacks this entity can block - * @return the current amount of attacks this entity can block - */ - uint32_t GetAttacksToBlock() const { return m_AttacksToBlock; } + /** + * Returns the current amount of attacks this entity can block + * @return the current amount of attacks this entity can block + */ + uint32_t GetAttacksToBlock() const { return m_AttacksToBlock; } - /** - * Sets whether or not this enemy currently has threats, NOTE: only here for serialization, has no use internally - * @param value whether or not this enemy currently has threats - */ - void SetHasThreats(bool value); + /** + * Sets whether or not this enemy currently has threats, NOTE: only here for serialization, has no use internally + * @param value whether or not this enemy currently has threats + */ + void SetHasThreats(bool value); - /** - * Returns whether or not this entity currently has threats, NOTE: unused internally - * @return whether or not this entity currently has threats - */ - bool GetHasThreats() const { return m_HasThreats; } + /** + * Returns whether or not this entity currently has threats, NOTE: unused internally + * @return whether or not this entity currently has threats + */ + bool GetHasThreats() const { return m_HasThreats; } - /** - * Returns whether or not this entity is knockback immune, based on whether it's quickbuilding or has assembly gear - * @return whether or not this entity is knockback immune - */ - bool IsKnockbackImmune() const; + /** + * Returns whether or not this entity is knockback immune, based on whether it's quickbuilding or has assembly gear + * @return whether or not this entity is knockback immune + */ + bool IsKnockbackImmune() const; - /** - * Sets the faction ID of this entity, overriding all previously set entries - * @param factionID the faction ID to set - */ - void SetFaction(int32_t factionID); + /** + * Sets the faction ID of this entity, overriding all previously set entries + * @param factionID the faction ID to set + */ + void SetFaction(int32_t factionID, bool ignoreChecks = false); - /** - * Returns whether or not the provided entity is an enemy of this entity - * @param other the entity to check - * @return whether the provided entity is an enemy of this entity or not - */ - bool IsEnemy(const Entity *other) const; + /** + * Returns whether or not the provided entity is an enemy of this entity + * @param other the entity to check + * @return whether the provided entity is an enemy of this entity or not + */ + bool IsEnemy(const Entity* other) const; - /** - * Returns whether or not the provided entity is a friend of this entity - * @param other the entity to check - * @return whether or not the provided entity is a friend of this entity - */ - bool IsFriend(const Entity *other) const; + /** + * Returns whether or not the provided entity is a friend of this entity + * @param other the entity to check + * @return whether or not the provided entity is a friend of this entity + */ + bool IsFriend(const Entity* other) const; - /** - * Returns all the faction IDs that this entity considers a friend - * @return all the faction IDs that this entity considers a friend - */ - const std::vector& GetFactionIDs() const { return m_FactionIDs; } + /** + * Returns all the faction IDs that this entity considers a friend + * @return all the faction IDs that this entity considers a friend + */ + const std::vector& GetFactionIDs() const { return m_FactionIDs; } - /** - * Returns all the faction IDs that this entity considers an enemy - * @return all the faction IDs that this entity considers an enemy - */ - const std::vector& GetEnemyFactionsIDs() const { return m_EnemyFactionIDs; } + /** + * Returns all the faction IDs that this entity considers an enemy + * @return all the faction IDs that this entity considers an enemy + */ + const std::vector& GetEnemyFactionsIDs() const { return m_EnemyFactionIDs; } - /** - * Returns whether the provided faction is a friendly faction - * @param factionID the faction ID to check - * @return whether the provided faction is a friendly faction - */ - bool HasFaction(int32_t factionID) const; + /** + * Returns whether the provided faction is a friendly faction + * @param factionID the faction ID to check + * @return whether the provided faction is a friendly faction + */ + bool HasFaction(int32_t factionID) const; - /** - * Sets the minimum amount of coins this entity drops when smashed - * @param minCoins the minimum amount of coins this entity drops when smashed - */ + /** + * Sets the minimum amount of coins this entity drops when smashed + * @param minCoins the minimum amount of coins this entity drops when smashed + */ void SetMinCoins(uint32_t minCoins) { m_MinCoins = minCoins; } - /** - * Returns the minimum amount of coins this entity drops when smashed - * @return the minimum amount of coins this entity drops when smashed - */ + /** + * Returns the minimum amount of coins this entity drops when smashed + * @return the minimum amount of coins this entity drops when smashed + */ uint32_t GetMinCoins() const { return m_MinCoins; } - /** - * Sets the maximum amount of coins this entity drops when smashed - * @param maxCoins the maximum amount of coins this entity drops when smashed - */ + /** + * Sets the maximum amount of coins this entity drops when smashed + * @param maxCoins the maximum amount of coins this entity drops when smashed + */ void SetMaxCoins(uint32_t maxCoins) { m_MaxCoins = maxCoins; } - /** - * Returns the maximum amount of coins this entity drops when smashed - * @return the maximum amount of coins this entity drops when smashed - */ + /** + * Returns the maximum amount of coins this entity drops when smashed + * @return the maximum amount of coins this entity drops when smashed + */ uint32_t GetMaxCoins() const { return m_MaxCoins; } - /** - * Sets the loot matrix ID that will be used to determine what items to drop when this entity is smashed - * @param lootMatrixID the loot matrix ID to set - */ + /** + * Sets the loot matrix ID that will be used to determine what items to drop when this entity is smashed + * @param lootMatrixID the loot matrix ID to set + */ void SetLootMatrixID(uint32_t lootMatrixID) { m_LootMatrixID = lootMatrixID; } - /** - * Returns the current loot matrix ID that will be used to determine loot drops when this entity is smashed - * @return the current loot matrix ID - */ + /** + * Returns the current loot matrix ID that will be used to determine loot drops when this entity is smashed + * @return the current loot matrix ID + */ uint32_t GetLootMatrixID() const { return m_LootMatrixID; } - /** - * Returns the ID of the entity that killed this entity, if any - * @return the ID of the entity that killed this entity, if any - */ - LWOOBJID GetKillerID() const; + /** + * Returns the ID of the entity that killed this entity, if any + * @return the ID of the entity that killed this entity, if any + */ + LWOOBJID GetKillerID() const; - /** - * Returns the entity that killed this entity, if any - * @return the entity that killed this entity, if any - */ - Entity* GetKiller() const; + /** + * Returns the entity that killed this entity, if any + * @return the entity that killed this entity, if any + */ + Entity* GetKiller() const; - /** - * Checks if the target ID is a valid enemy of this entity - * @param target the target ID to check for - * @param ignoreFactions whether or not check for the factions, e.g. just return true if the entity cannot be smashed - * @return if the target ID is a valid enemy - */ - bool CheckValidity(LWOOBJID target, bool ignoreFactions = false, bool targetEnemy = true, bool targetFriend = false) const; + /** + * Checks if the target ID is a valid enemy of this entity + * @param target the target ID to check for + * @param ignoreFactions whether or not check for the factions, e.g. just return true if the entity cannot be smashed + * @return if the target ID is a valid enemy + */ + bool CheckValidity(LWOOBJID target, bool ignoreFactions = false, bool targetEnemy = true, bool targetFriend = false) const; - /** - * Attempt to damage this entity, handles everything from health and armor to absorption, immunity and callbacks. - * @param damage the damage to attempt to apply - * @param source the attacker that caused this damage - * @param skillID the skill that damaged this entity - * @param echo whether or not to serialize the damage - */ + /** + * Attempt to damage this entity, handles everything from health and armor to absorption, immunity and callbacks. + * @param damage the damage to attempt to apply + * @param source the attacker that caused this damage + * @param skillID the skill that damaged this entity + * @param echo whether or not to serialize the damage + */ void Damage(uint32_t damage, LWOOBJID source, uint32_t skillID = 0, bool echo = true); - /** - * Smashes this entity, notifying all clients - * @param source the source that smashed this entity - * @param skillID the skill that killed this entity - * @param killType the way this entity was killed, determines if a client animation is played - * @param deathType the animation to play when killed - */ - void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0); + /** + * Smashes this entity, notifying all clients + * @param source the source that smashed this entity + * @param skillID the skill that killed this entity + * @param killType the way this entity was killed, determines if a client animation is played + * @param deathType the animation to play when killed + */ + void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0); - /** - * Pushes a layer of immunity to this entity, making it immune for longer - * @param stacks the amount of immunity to add - */ - void PushImmunity(int32_t stacks = 1); + /** + * Push or Pop a layer of status immunity to this entity + */ + void SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack = false, + const bool bImmuneToDamageOverTime = false, + const bool bImmuneToKnockback = false, + const bool bImmuneToInterrupt = false, + const bool bImmuneToSpeed = false, + const bool bImmuneToImaginationGain = false, + const bool bImmuneToImaginationLoss = false, + const bool bImmuneToQuickbuildInterrupt = false, + const bool bImmuneToPullToPoint = false + ); - /** - * Pops layers of immunity, making it immune for less longer - * @param stacks the number of layers of immunity to remove - */ - void PopImmunity(int32_t stacks = 1); + // Getters for status immunities + const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;}; + const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;}; + const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;}; + const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;}; + const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;}; + const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;}; + const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;}; + const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;}; + const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;}; - /** - * Utility to reset all stats to the default stats based on items and completed missions - */ + /** + * Utility to reset all stats to the default stats based on items and completed missions + */ void FixStats(); - /** - * Adds a callback that is called when this entity is hit by some other entity - * @param callback the callback to add - */ + /** + * Adds a callback that is called when this entity is hit by some other entity + * @param callback the callback to add + */ void AddOnHitCallback(const std::function& callback); + /** + * Pushes a faction back to the list of factions. + * @param value Faction to add to list. + * + * This method should only be used for testing. Use AddFaction(int32_t, bool) for adding a faction properly. + */ + void AddFactionNoLookup(int32_t faction) { m_FactionIDs.push_back(faction); }; + + /** + * Notify subscribed scripts of Damage actions. + * + * @param attacker The attacking Entity + * @param damage The amount of damage that was done + */ + void NotifySubscribers(Entity* attacker, uint32_t damage); + + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd); + void Unsubscribe(LWOOBJID scriptObjId); + + // handle hardcode mode drops + void DoHardcoreModeDrops(const LWOOBJID source); + private: - /** - * Whether or not the health should be serialized - */ - bool m_DirtyHealth; + /** + * Whether or not the health should be serialized + */ + bool m_DirtyHealth; - /** - * The health of the entity - */ - int32_t m_iHealth; + /** + * The health of the entity + */ + int32_t m_iHealth; - /** - * The max health of the entity - */ - float m_fMaxHealth; + /** + * The max health of the entity + */ + float m_fMaxHealth; - /** - * The armor of the entity - */ - int32_t m_iArmor; + /** + * The armor of the entity + */ + int32_t m_iArmor; - /** - * The max armor of the entity - */ - float m_fMaxArmor; + /** + * The max armor of the entity + */ + float m_fMaxArmor; - /** - * The imagination of the entity - */ - int32_t m_iImagination; + /** + * The imagination of the entity + */ + int32_t m_iImagination; - /** - * The max imagination of the entity - */ - float m_fMaxImagination; + /** + * The max imagination of the entity + */ + float m_fMaxImagination; - /** - * The damage this entity can absord before being able to be damaged again - */ - int32_t m_DamageToAbsorb; + /** + * The damage this entity can absord before being able to be damaged again + */ + int32_t m_DamageToAbsorb; - /** - * Whether this entity currently has GM immunity, making it unsmashable - */ - bool m_IsGMImmune; + /** + * Whether this entity currently has GM immunity, making it unsmashable + */ + bool m_IsGMImmune; - /** - * Whether this entity is currently shielded from other attacks - */ - bool m_IsShielded; + /** + * Whether this entity is currently shielded from other attacks + */ + bool m_IsShielded; - /** - * The number of attacks this entity can block before being able to be attacked again - */ - uint32_t m_AttacksToBlock; + /** + * The number of attacks this entity can block before being able to be attacked again + */ + uint32_t m_AttacksToBlock; - /** - * The layers of immunity this entity has left - */ - int32_t m_ImmuneStacks; + /** + * The amount of damage that should be reduced from every attack + */ + int32_t m_DamageReduction; - /** - * The amount of damage that should be reduced from every attack - */ - int32_t m_DamageReduction; + /** + * The faction IDs this entity considers friendly + */ + std::vector m_FactionIDs; - /** - * The faction IDs this entity considers friendly - */ - std::vector m_FactionIDs; + /** + * The faction IDs this entity considers hostile + */ + std::vector m_EnemyFactionIDs; - /** - * The faction IDs this entity considers hostile - */ - std::vector m_EnemyFactionIDs; + /** + * Whether this entity is smasahble, mostly unused + */ + bool m_IsSmashable; - /** - * Whether this entity is smasahble, mostly unused - */ - bool m_IsSmashable; + /** + * Whether this entity is dead. Unused, here for serialization + */ + bool m_IsDead; - /** - * Whether this entity is dead. Unused, here for serialization - */ - bool m_IsDead; + /** + * Whether this entity is smashed. Unused, here for serialization + */ + bool m_IsSmashed; - /** - * Whether this entity is smashed. Unused, here for serialization - */ - bool m_IsSmashed; + /** + * Whether this entity has bricks flying out when smashed (causes the client to look up the files) + */ + bool m_HasBricks; - /** - * Whether this entity has bricks flying out when smashed (causes the client to look up the files) - */ - bool m_HasBricks; + /** + * The rate at which bricks fly out when smashed + */ + float m_ExplodeFactor; - /** - * The rate at which bricks fly out when smashed - */ - float m_ExplodeFactor; + /** + * Whether the list of potential enemies has changed + */ + bool m_DirtyThreatList; - /** - * Whether the list of potential enemies has changed - */ - bool m_DirtyThreatList; + /** + * Whether the entity has threats. Unused: here for serialization + */ + bool m_HasThreats; - /** - * Whether the entity has threats. Unused: here for serialization - */ - bool m_HasThreats; - - /** - * The loot matrix that will be used to drop items when the entity is smashed - */ + /** + * The loot matrix that will be used to drop items when the entity is smashed + */ uint32_t m_LootMatrixID; - /** - * The min amount of coins that will drop when this entity is smashed - */ + /** + * The min amount of coins that will drop when this entity is smashed + */ uint32_t m_MinCoins; - /** - * The max amount of coins that will drop when this entity is smashed - */ + /** + * The max amount of coins that will drop when this entity is smashed + */ uint32_t m_MaxCoins; - /** - * The ID of the entity that smashed this entity, if any - */ - LWOOBJID m_KillerID; + /** + * The ID of the entity that smashed this entity, if any + */ + LWOOBJID m_KillerID; - /** - * The list of callbacks that will be called when this entity gets hit - */ - std::vector> m_OnHitCallbacks; + /** + * The list of callbacks that will be called when this entity gets hit + */ + std::vector> m_OnHitCallbacks; + + /** + * The list of scripts subscribed to this components actions + */ + std::map m_SubscribedScripts; + + /** + * status immunity counters + */ + uint32_t m_ImmuneToBasicAttackCount; + uint32_t m_ImmuneToDamageOverTimeCount; + uint32_t m_ImmuneToKnockbackCount; + uint32_t m_ImmuneToInterruptCount; + uint32_t m_ImmuneToSpeedCount; + uint32_t m_ImmuneToImaginationGainCount; + uint32_t m_ImmuneToImaginationLossCount; + uint32_t m_ImmuneToQuickbuildInterruptCount; + uint32_t m_ImmuneToPullToPointCount; }; #endif // DESTROYABLECOMPONENT_H diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 8ae6e93f..907356ce 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -25,9 +25,20 @@ #include "PropertyManagementComponent.h" #include "DestroyableComponent.h" #include "dConfig.h" +#include "eItemType.h" +#include "eUnequippableActiveType.h" +#include "CppScripts.h" +#include "eMissionTaskType.h" +#include "eStateChangeType.h" +#include "eUseItemResponse.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) -{ +#include "CDComponentsRegistryTable.h" +#include "CDInventoryComponentTable.h" +#include "CDScriptComponentTable.h" +#include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" + +InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -36,8 +47,7 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto lot = parent->GetLOT(); - if (lot == 1) - { + if (lot == 1) { LoadXml(document); CheckProxyIntegrity(); @@ -45,18 +55,16 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do return; } - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - const auto componentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_INVENTORY); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + const auto componentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::INVENTORY); - auto* inventoryComponentTable = CDClientManager::Instance()->GetTable("InventoryComponent"); + auto* inventoryComponentTable = CDClientManager::Instance().GetTable(); auto items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; }); auto slot = 0u; - for (const auto& item : items) - { - if (!item.equip || !Inventory::IsValidItem(item.itemid)) - { + for (const auto& item : items) { + if (!item.equip || !Inventory::IsValidItem(item.itemid)) { continue; } @@ -65,23 +73,39 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto& info = Inventory::FindItemComponent(item.itemid); UpdateSlot(info.equipLocation, { id, static_cast(item.itemid), item.count, slot++ }); + + // Equip this items proxies. + auto subItems = info.subItems; + + subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end()); + + if (!subItems.empty()) { + const auto subItemsSplit = GeneralUtils::SplitString(subItems, ','); + + for (auto proxyLotAsString : subItemsSplit) { + const auto proxyLOT = static_cast(std::stoi(proxyLotAsString)); + + const auto& proxyInfo = Inventory::FindItemComponent(proxyLOT); + const LWOOBJID proxyId = ObjectIDManager::Instance()->GenerateObjectID(); + + // Use item.count since we equip item.count number of the item this is a requested proxy of + UpdateSlot(proxyInfo.equipLocation, { proxyId, proxyLOT, item.count, slot++ }); + } + } } } -Inventory* InventoryComponent::GetInventory(const eInventoryType type) -{ +Inventory* InventoryComponent::GetInventory(const eInventoryType type) { const auto index = m_Inventories.find(type); - if (index != m_Inventories.end()) - { + if (index != m_Inventories.end()) { return index->second; } // Create new empty inventory uint32_t size = 240u; - switch (type) - { + switch (type) { case eInventoryType::ITEMS: size = 20u; break; @@ -103,29 +127,24 @@ Inventory* InventoryComponent::GetInventory(const eInventoryType type) return inventory; } -const std::map& InventoryComponent::GetInventories() const -{ +const std::map& InventoryComponent::GetInventories() const { return m_Inventories; } -uint32_t InventoryComponent::GetLotCount(const LOT lot) const -{ +uint32_t InventoryComponent::GetLotCount(const LOT lot) const { uint32_t count = 0; - for (const auto& inventory : m_Inventories) - { + for (const auto& inventory : m_Inventories) { count += inventory.second->GetLotCount(lot); } return count; } -uint32_t InventoryComponent::GetLotCountNonTransfer(LOT lot) const -{ +uint32_t InventoryComponent::GetLotCountNonTransfer(LOT lot) const { uint32_t count = 0; - for (const auto& inventory : m_Inventories) - { + for (const auto& inventory : m_Inventories) { if (IsTransferInventory(inventory.second->GetType())) continue; count += inventory.second->GetLotCount(lot); @@ -134,8 +153,7 @@ uint32_t InventoryComponent::GetLotCountNonTransfer(LOT lot) const return count; } -const EquipmentMap& InventoryComponent::GetEquippedItems() const -{ +const EquipmentMap& InventoryComponent::GetEquippedItems() const { return m_Equipped; } @@ -152,50 +170,42 @@ void InventoryComponent::AddItem( const eInventoryType inventorySourceType, const int32_t sourceType, const bool bound, - int32_t preferredSlot) -{ - if (count == 0) - { - Game::logger->Log("InventoryComponent", "Attempted to add 0 of item (%i) to the inventory!\n", lot); + int32_t preferredSlot) { + if (count == 0) { + Game::logger->Log("InventoryComponent", "Attempted to add 0 of item (%i) to the inventory!", lot); return; } - if (!Inventory::IsValidItem(lot)) - { - if (lot > 0) - { - Game::logger->Log("InventoryComponent", "Attempted to add invalid item (%i) to the inventory!\n", lot); + if (!Inventory::IsValidItem(lot)) { + if (lot > 0) { + Game::logger->Log("InventoryComponent", "Attempted to add invalid item (%i) to the inventory!", lot); } return; } - if (inventoryType == INVALID) - { + if (inventoryType == INVALID) { inventoryType = Inventory::FindInventoryTypeForLot(lot); } - auto* missions = static_cast(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missions = static_cast(this->m_Parent->GetComponent(eReplicaComponentType::MISSION)); auto* inventory = GetInventory(inventoryType); - if (!config.empty() || bound) - { + if (!config.empty() || bound) { const auto slot = preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot) ? preferredSlot : inventory->FindEmptySlot(); - if (slot == -1) - { - Game::logger->Log("InventoryComponent", "Failed to find empty slot for inventory (%i)!\n", inventoryType); + if (slot == -1) { + Game::logger->Log("InventoryComponent", "Failed to find empty slot for inventory (%i)!", inventoryType); return; } auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType); - if (missions != nullptr && !IsTransferInventory(inventoryType)) - { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); + if (missions != nullptr && !IsTransferInventory(inventoryType)) { + missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); } return; @@ -209,73 +219,63 @@ void InventoryComponent::AddItem( auto stack = static_cast(info.stackSize); + bool isBrick = inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1); + // info.itemType of 1 is item type brick - if (inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1)) - { - stack = 999; - } - else if (stack == 0) - { + if (isBrick) { + stack = UINT32_MAX; + } else if (stack == 0) { stack = 1; } auto* existing = FindItemByLot(lot, inventoryType); - if (existing != nullptr) - { + if (existing != nullptr) { const auto delta = std::min(left, stack - existing->GetCount()); left -= delta; existing->SetCount(existing->GetCount() + delta, false, true, showFlyingLoot, lootSourceType); - if (isModMoveAndEquip) - { + if (isModMoveAndEquip) { existing->Equip(); isModMoveAndEquip = false; } } - while (left > 0) - { + // If we have some leftover and we aren't bricks, make a new stack + while (left > 0 && (!isBrick || (isBrick && !existing))) { const auto size = std::min(left, stack); left -= size; int32_t slot; - if (preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot)) - { + if (preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot)) { slot = preferredSlot; preferredSlot = -1; - } - else - { + } else { slot = inventory->FindEmptySlot(); } - if (slot == -1) - { + if (slot == -1) { auto* player = dynamic_cast(GetParent()); - if (player == nullptr) - { + if (player == nullptr) { return; } outOfSpace += size; - switch (sourceType) - { + switch (sourceType) { case 0: player->SendMail(LWOOBJID_EMPTY, "Darkflame Universe", "Lost Reward", "You received an item and didn't have room for it.", lot, size); break; case 1: - for (size_t i = 0; i < size; i++) - { + for (size_t i = 0; i < size; i++) { GameMessages::SendDropClientLoot(this->m_Parent, this->m_Parent->GetObjectID(), lot, 0, this->m_Parent->GetPosition(), 1); } @@ -292,41 +292,34 @@ void InventoryComponent::AddItem( isModMoveAndEquip = false; } - if (missions != nullptr && !IsTransferInventory(inventoryType)) - { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); + if (missions != nullptr && !IsTransferInventory(inventoryType)) { + missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); } } -void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInventoryType inventoryType, const bool ignoreBound) -{ - if (count == 0) - { - Game::logger->Log("InventoryComponent", "Attempted to remove 0 of item (%i) from the inventory!\n", lot); +void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInventoryType inventoryType, const bool ignoreBound) { + if (count == 0) { + Game::logger->Log("InventoryComponent", "Attempted to remove 0 of item (%i) from the inventory!", lot); return; } - if (inventoryType == INVALID) - { + if (inventoryType == INVALID) { inventoryType = Inventory::FindInventoryTypeForLot(lot); } auto* inventory = GetInventory(inventoryType); - if (inventory == nullptr) - { + if (inventory == nullptr) { return; } auto left = std::min(count, inventory->GetLotCount(lot)); - while (left > 0) - { + while (left > 0) { auto* item = FindItemByLot(lot, inventoryType, false, ignoreBound); - if (item == nullptr) - { + if (item == nullptr) { break; } @@ -338,10 +331,8 @@ void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInvent } } -void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType inventory, const uint32_t count, const bool showFlyingLot, bool isModMoveAndEquip, const bool ignoreEquipped, const int32_t preferredSlot) -{ - if (item == nullptr) - { +void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType inventory, const uint32_t count, const bool showFlyingLot, bool isModMoveAndEquip, const bool ignoreEquipped, const int32_t preferredSlot) { + if (item == nullptr) { return; } @@ -349,18 +340,16 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in const auto lot = item->GetLot(); - if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP)) - { + const auto subkey = item->GetSubKey(); + + if (subkey == LWOOBJID_EMPTY && item->GetConfig().empty() && (!item->GetBound() || (item->GetBound() && item->GetInfo().isBOP))) { auto left = std::min(count, origin->GetLotCount(lot)); - while (left > 0) - { - if (item == nullptr) - { + while (left > 0) { + if (item == nullptr) { item = origin->FindItemByLot(lot, false); - if (item == nullptr) - { + if (item == nullptr) { break; } } @@ -369,44 +358,37 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in left -= delta; - AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, {}, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, false, preferredSlot); + AddItem(lot, delta, eLootSourceType::NONE, inventory, {}, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, false, preferredSlot); item->SetCount(item->GetCount() - delta, false, false); isModMoveAndEquip = false; } - } - else - { + } else { std::vector config; - for (auto* const data : item->GetConfig()) - { + for (auto* const data : item->GetConfig()) { config.push_back(data->Copy()); } const auto delta = std::min(item->GetCount(), count); - AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, item->GetBound(), preferredSlot); + AddItem(lot, delta, eLootSourceType::NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, subkey, origin->GetType(), 0, item->GetBound(), preferredSlot); item->SetCount(item->GetCount() - delta, false, false); } auto* missionComponent = m_Parent->GetComponent(); - if (missionComponent != nullptr) - { - if (IsTransferInventory(inventory)) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", -static_cast(count)); + if (missionComponent != nullptr) { + if (IsTransferInventory(inventory)) { + missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", -static_cast(count)); } } } -void InventoryComponent::MoveStack(Item* item, const eInventoryType inventory, const uint32_t slot) -{ - if (inventory != INVALID && item->GetInventory()->GetType() != inventory) - { +void InventoryComponent::MoveStack(Item* item, const eInventoryType inventory, const uint32_t slot) { + if (inventory != INVALID && item->GetInventory()->GetType() != inventory) { auto* newInventory = GetInventory(inventory); item->SetInventory(newInventory); @@ -415,14 +397,11 @@ void InventoryComponent::MoveStack(Item* item, const eInventoryType inventory, c item->SetSlot(slot); } -Item* InventoryComponent::FindItemById(const LWOOBJID id) const -{ - for (const auto& inventory : m_Inventories) - { +Item* InventoryComponent::FindItemById(const LWOOBJID id) const { + for (const auto& inventory : m_Inventories) { auto* item = inventory.second->FindItemById(id); - if (item != nullptr) - { + if (item != nullptr) { return item; } } @@ -430,10 +409,8 @@ Item* InventoryComponent::FindItemById(const LWOOBJID id) const return nullptr; } -Item* InventoryComponent::FindItemByLot(const LOT lot, eInventoryType inventoryType, const bool ignoreEquipped, const bool ignoreBound) -{ - if (inventoryType == INVALID) - { +Item* InventoryComponent::FindItemByLot(const LOT lot, eInventoryType inventoryType, const bool ignoreEquipped, const bool ignoreBound) { + if (inventoryType == INVALID) { inventoryType = Inventory::FindInventoryTypeForLot(lot); } @@ -442,47 +419,37 @@ Item* InventoryComponent::FindItemByLot(const LOT lot, eInventoryType inventoryT return inventory->FindItemByLot(lot, ignoreEquipped, ignoreBound); } -Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType) -{ - if (inventoryType == INVALID) - { - for (const auto& inventory : m_Inventories) - { +Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType) { + if (inventoryType == INVALID) { + for (const auto& inventory : m_Inventories) { auto* item = inventory.second->FindItemBySubKey(id); - if (item != nullptr) - { + if (item != nullptr) { return item; } } return nullptr; - } - else - { + } else { return GetInventory(inventoryType)->FindItemBySubKey(id); } } -bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& loot) -{ - std::unordered_map spaceOffset {}; +bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& loot) { + std::unordered_map spaceOffset{}; uint32_t slotsNeeded = 0; - for (const auto& pair : loot) - { + for (const auto& pair : loot) { const auto inventoryType = Inventory::FindInventoryTypeForLot(pair.first); - if (inventoryType == BRICKS) - { + if (inventoryType == BRICKS) { continue; } auto* inventory = GetInventory(inventoryType); - if (inventory == nullptr) - { + if (inventory == nullptr) { return false; } @@ -494,8 +461,7 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& auto* partial = inventory->FindItemByLot(pair.first); - if (partial != nullptr && partial->GetCount() < stack) - { + if (partial != nullptr && partial->GetCount() < stack) { left -= stack - partial->GetCount(); } @@ -505,16 +471,14 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& auto freeSpace = inventory->GetEmptySlots() - (offsetIter == spaceOffset.end() ? 0 : offsetIter->second); - if (requiredSlots > freeSpace) - { + if (requiredSlots > freeSpace) { slotsNeeded += requiredSlots - freeSpace; } spaceOffset[inventoryType] = offsetIter == spaceOffset.end() ? requiredSlots : offsetIter->second + requiredSlots; } - if (slotsNeeded > 0) - { + if (slotsNeeded > 0) { GameMessages::SendNotifyNotEnoughInvSpace(m_Parent->GetObjectID(), slotsNeeded, ITEMS, m_Parent->GetSystemAddress()); return false; @@ -523,24 +487,21 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& return true; } -void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) -{ +void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { LoadPetXml(document); auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); - if (inventoryElement == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'inv' xml element!\n"); + if (inventoryElement == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'inv' xml element!"); return; } auto* bags = inventoryElement->FirstChildElement("bag"); - if (bags == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!\n"); + if (bags == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!"); return; } @@ -549,8 +510,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) auto* bag = bags->FirstChildElement(); - while (bag != nullptr) - { + while (bag != nullptr) { unsigned int type; unsigned int size; @@ -566,34 +526,30 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) auto* items = inventoryElement->FirstChildElement("items"); - if (items == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!\n"); + if (items == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!"); return; } bag = items->FirstChildElement(); - while (bag != nullptr) - { + while (bag != nullptr) { unsigned int type; bag->QueryAttribute("t", &type); auto* inventory = GetInventory(static_cast(type)); - if (inventory == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find inventory (%i)!\n", type); + if (inventory == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find inventory (%i)!", type); return; } auto* itemElement = bag->FirstChildElement(); - while (itemElement != nullptr) - { + while (itemElement != nullptr) { LWOOBJID id; LOT lot; bool equipped; @@ -620,8 +576,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) auto* extraInfo = itemElement->FirstChildElement("x"); - if (extraInfo) - { + if (extraInfo) { std::string modInfo = extraInfo->Attribute("ma"); LDFBaseData* moduleAssembly = new LDFData(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1))); @@ -631,8 +586,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey); - if (equipped) - { + if (equipped) { const auto info = Inventory::FindItemComponent(lot); UpdateSlot(info.equipLocation, { item->GetId(), item->GetLot(), item->GetCount(), item->GetSlot() }); @@ -646,59 +600,52 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) bag = bag->NextSiblingElement(); } - for (const auto inventory : m_Inventories) - { + for (const auto inventory : m_Inventories) { const auto itemCount = inventory.second->GetItems().size(); - if (inventory.second->GetSize() < itemCount) - { + if (inventory.second->GetSize() < itemCount) { inventory.second->SetSize(itemCount); } } } -void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) -{ +void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { UpdatePetXml(document); auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); - if (inventoryElement == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'inv' xml element!\n"); + if (inventoryElement == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'inv' xml element!"); return; } - std::vector inventories; + std::vector inventoriesToSave; - for (const auto& pair : this->m_Inventories) - { + // Need to prevent some transfer inventories from being saved + for (const auto& pair : this->m_Inventories) { auto* inventory = pair.second; - if (inventory->GetType() == VENDOR_BUYBACK) - { + if (inventory->GetType() == VENDOR_BUYBACK || inventory->GetType() == eInventoryType::MODELS_IN_BBB) { continue; } - inventories.push_back(inventory); + inventoriesToSave.push_back(inventory); } inventoryElement->SetAttribute("csl", m_Consumable); auto* bags = inventoryElement->FirstChildElement("bag"); - if (bags == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!\n"); + if (bags == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'bags' xml element!"); return; } bags->DeleteChildren(); - for (const auto* inventory : inventories) - { + for (const auto* inventory : inventoriesToSave) { auto* bag = document->NewElement("b"); bag->SetAttribute("t", inventory->GetType()); @@ -709,19 +656,16 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) auto* items = inventoryElement->FirstChildElement("items"); - if (items == nullptr) - { - Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!\n"); + if (items == nullptr) { + Game::logger->Log("InventoryComponent", "Failed to find 'items' xml element!"); return; } items->DeleteChildren(); - for (auto* inventory : inventories) - { - if (inventory->GetSize() == 0) - { + for (auto* inventory : inventoriesToSave) { + if (inventory->GetSize() == 0) { continue; } @@ -729,8 +673,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) bagElement->SetAttribute("t", inventory->GetType()); - for (const auto& pair : inventory->GetItems()) - { + for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; auto* itemElement = document->NewElement("i"); @@ -747,10 +690,8 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) itemElement->SetAttribute("parent", item->GetParent()); // End custom xml - for (auto* data : item->GetConfig()) - { - if (data->GetKey() != u"assemblyPartLOTs") - { + for (auto* data : item->GetConfig()) { + if (data->GetKey() != u"assemblyPartLOTs") { continue; } @@ -768,35 +709,31 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) } } -void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate, unsigned& flags) -{ - if (bIsInitialUpdate || m_Dirty) - { +void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate, unsigned& flags) { + if (bIsInitialUpdate || m_Dirty) { outBitStream->Write(true); outBitStream->Write(m_Equipped.size()); - for (const auto& pair : m_Equipped) - { + for (const auto& pair : m_Equipped) { const auto item = pair.second; - if (bIsInitialUpdate) - { + if (bIsInitialUpdate) { AddItemSkills(item.lot); } outBitStream->Write(item.id); - outBitStream->Write(item.lot); + outBitStream->Write(item.lot); - outBitStream->Write0(); + outBitStream->Write0(); - outBitStream->Write(item.count > 0); - if (item.count > 0) outBitStream->Write(item.count); + outBitStream->Write(item.count > 0); + if (item.count > 0) outBitStream->Write(item.count); - outBitStream->Write(item.slot != 0); - if (item.slot != 0) outBitStream->Write(item.slot); + outBitStream->Write(item.slot != 0); + if (item.slot != 0) outBitStream->Write(item.slot); - outBitStream->Write0(); + outBitStream->Write0(); bool flag = !item.config.empty(); outBitStream->Write(flag); @@ -818,39 +755,32 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b outBitStream->Write(0); // Don't compress outBitStream->Write(ldfStream); } - + outBitStream->Write1(); } m_Dirty = false; - } - else - { + } else { outBitStream->Write(false); } outBitStream->Write(false); } -void InventoryComponent::ResetFlags() -{ +void InventoryComponent::ResetFlags() { m_Dirty = false; } -void InventoryComponent::Update(float deltaTime) -{ - for (auto* set : m_Itemsets) - { +void InventoryComponent::Update(float deltaTime) { + for (auto* set : m_Itemsets) { set->Update(deltaTime); } } -void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem item, bool keepCurrent) -{ +void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem item, bool keepCurrent) { const auto index = m_Equipped.find(location); - if (index != m_Equipped.end()) - { + if (index != m_Equipped.end()) { if (keepCurrent) { m_Equipped.insert_or_assign(location + std::to_string(m_Equipped.size()), item); @@ -861,8 +791,7 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it auto* old = FindItemById(index->second.id); - if (old != nullptr) - { + if (old != nullptr) { UnEquipItem(old); } } @@ -872,10 +801,8 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it m_Dirty = true; } -void InventoryComponent::RemoveSlot(const std::string& location) -{ - if (m_Equipped.find(location) == m_Equipped.end()) - { +void InventoryComponent::RemoveSlot(const std::string& location) { + if (m_Equipped.find(location) == m_Equipped.end()) { return; } @@ -884,41 +811,31 @@ void InventoryComponent::RemoveSlot(const std::string& location) m_Dirty = true; } -void InventoryComponent::EquipItem(Item* item, const bool skipChecks) -{ - if (!Inventory::IsValidItem(item->GetLot())) - { - return; - } +void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { + if (!Inventory::IsValidItem(item->GetLot())) return; - // Temp items should be equippable but other transfer items shouldn't be (for example the instruments in RB) + // Temp items should be equippable but other transfer items shouldn't be (for example the instruments in RB) if (item->IsEquipped() - || (item->GetInventory()->GetType() != TEMP_ITEMS && IsTransferInventory(item->GetInventory()->GetType())) - || IsPet(item->GetSubKey())) { + || (item->GetInventory()->GetType() != TEMP_ITEMS && IsTransferInventory(item->GetInventory()->GetType())) + || IsPet(item->GetSubKey())) { return; } auto* character = m_Parent->GetCharacter(); - if (character != nullptr && !skipChecks) - { + if (character != nullptr && !skipChecks) { // Hacky proximity rocket - if (item->GetLot() == 6416) - { - const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_ROCKET_LAUNCH); + if (item->GetLot() == 6416) { + const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCH); const auto position = m_Parent->GetPosition(); - for (auto* lauchPad : rocketLauchPads) - { + for (auto* lauchPad : rocketLauchPads) { if (Vector3::DistanceSquared(lauchPad->GetPosition(), position) > 13 * 13) continue; auto* characterComponent = m_Parent->GetComponent(); - if (characterComponent != nullptr) - { - characterComponent->SetLastRocketItemID(item->GetId()); - } + if (characterComponent != nullptr) characterComponent->SetLastRocketItemID(item->GetId()); lauchPad->OnUse(m_Parent); @@ -931,109 +848,12 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) const auto building = character->GetBuildMode(); const auto type = static_cast(item->GetInfo().itemType); - - if (item->GetLot() == 8092 && m_Parent->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && hasCarEquipped == false) - { - auto startPosition = m_Parent->GetPosition(); - auto startRotation = NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X); - auto angles = startRotation.GetEulerAngles(); - angles.y -= PI; - startRotation = NiQuaternion::FromEulerAngles(angles); - GameMessages::SendTeleport(m_Parent->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true); + if (!building && (item->GetLot() == 6086 || type == eItemType::LOOT_MODEL || type == eItemType::VEHICLE)) return; - EntityInfo info {}; - info.lot = 8092; - info.pos = startPosition; - info.rot = startRotation; - info.spawnerID = m_Parent->GetObjectID(); - - auto* carEntity = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); - m_Parent->AddChild(carEntity); - - auto *destroyableComponent = carEntity->GetComponent(); - - // Setup the vehicle stats. - if (destroyableComponent != nullptr) { - destroyableComponent->SetIsSmashable(false); - destroyableComponent->SetIsImmune(true); - } - // #108 - auto* possessableComponent = carEntity->GetComponent(); - - if (possessableComponent != nullptr) - { - previousPossessableID = possessableComponent->GetPossessor(); - possessableComponent->SetPossessor(m_Parent->GetObjectID()); - } - - auto* moduleAssemblyComponent = carEntity->GetComponent(); - - if (moduleAssemblyComponent != nullptr) - { - moduleAssemblyComponent->SetSubKey(item->GetSubKey()); - moduleAssemblyComponent->SetUseOptionalParts(false); - - for (auto* config : item->GetConfig()) - { - if (config->GetKey() == u"assemblyPartLOTs") - { - moduleAssemblyComponent->SetAssemblyPartsLOTs(GeneralUtils::ASCIIToUTF16(config->GetValueAsString())); - } - } - } - // #107 - auto* possessorComponent = m_Parent->GetComponent(); - - if (possessorComponent) possessorComponent->SetPossessable(carEntity->GetObjectID()); - - auto* characterComponent = m_Parent->GetComponent(); - - if (characterComponent) characterComponent->SetIsRacing(true); - - EntityManager::Instance()->ConstructEntity(carEntity); - EntityManager::Instance()->SerializeEntity(m_Parent); - GameMessages::SendSetJetPackMode(m_Parent, false); - - GameMessages::SendNotifyVehicleOfRacingObject(carEntity->GetObjectID(), m_Parent->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendRacingPlayerLoaded(LWOOBJID_EMPTY, m_Parent->GetObjectID(), carEntity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendVehicleUnlockInput(carEntity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendTeleport(m_Parent->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true); - GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true); - EntityManager::Instance()->SerializeEntity(m_Parent); - - hasCarEquipped = true; - equippedCarEntity = carEntity; - return; - } else if (item->GetLot() == 8092 && m_Parent->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && hasCarEquipped == true) - { - GameMessages::SendNotifyRacingClient(LWOOBJID_EMPTY, 3, 0, LWOOBJID_EMPTY, u"", m_Parent->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - auto player = dynamic_cast(m_Parent); - player->SendToZone(player->GetCharacter()->GetZoneID()); - equippedCarEntity->Kill(); - hasCarEquipped = false; - equippedCarEntity = nullptr; - return; - } - - if (!building) - { - if (item->GetLot() == 6086) - { - return; - } - - if (type == ITEM_TYPE_LOOT_MODEL || type == ITEM_TYPE_VEHICLE) - { - return; - } - } - - if (type != ITEM_TYPE_LOOT_MODEL && type != ITEM_TYPE_MODEL) - { - if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) - { + if (type != eItemType::LOOT_MODEL && type != eItemType::MODEL) { + if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) { return; } } @@ -1043,115 +863,211 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) CheckItemSet(lot); - for (auto* set : m_Itemsets) - { + for (auto* set : m_Itemsets) { set->OnEquip(lot); } - if (item->GetInfo().isBOE) - { - item->SetBound(true); - } + if (item->GetInfo().isBOE) item->SetBound(true); GenerateProxies(item); - + UpdateSlot(item->GetInfo().equipLocation, { item->GetId(), item->GetLot(), item->GetCount(), item->GetSlot(), item->GetConfig() }); ApplyBuff(item); - + AddItemSkills(item->GetLot()); + EquipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); } -void InventoryComponent::UnEquipItem(Item* item) -{ - if (!item->IsEquipped()) - { +void InventoryComponent::UnEquipItem(Item* item) { + if (!item->IsEquipped()) { return; } const auto lot = item->GetLot(); - if (!Inventory::IsValidItem(lot)) - { + if (!Inventory::IsValidItem(lot)) { return; } CheckItemSet(lot); - for (auto* set : m_Itemsets) - { + for (auto* set : m_Itemsets) { set->OnUnEquip(lot); } RemoveBuff(item); - + RemoveItemSkills(item->GetLot()); RemoveSlot(item->GetInfo().equipLocation); PurgeProxies(item); + UnequipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); // Trigger property event - if (PropertyManagementComponent::Instance() != nullptr && item->GetCount() > 0 && Inventory::FindInventoryTypeForLot(item->GetLot()) == MODELS) - { + if (PropertyManagementComponent::Instance() != nullptr && item->GetCount() > 0 && Inventory::FindInventoryTypeForLot(item->GetLot()) == MODELS) { PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); } } -void InventoryComponent::ApplyBuff(Item* item) const -{ + +void InventoryComponent::EquipScripts(Item* equippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId()); + } +} + +void InventoryComponent::UnequipScripts(Item* unequippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId()); + } +} + +void InventoryComponent::HandlePossession(Item* item) { + auto* characterComponent = m_Parent->GetComponent(); + if (!characterComponent) return; + + auto* possessorComponent = m_Parent->GetComponent(); + if (!possessorComponent) return; + + // Don't do anything if we are busy dismounting + if (possessorComponent->GetIsDismounting()) return; + + // Check to see if we are already mounting something + auto* currentlyPossessedEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + auto currentlyPossessedItem = possessorComponent->GetMountItemID(); + + if (currentlyPossessedItem) { + if (currentlyPossessedEntity) possessorComponent->Dismount(currentlyPossessedEntity); + return; + } + + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + + // Set the mount Item ID so that we know what were handling + possessorComponent->SetMountItemID(item->GetId()); + GameMessages::SendSetMountInventoryID(m_Parent, item->GetId(), UNASSIGNED_SYSTEM_ADDRESS); + + // Create entity to mount + auto startRotation = m_Parent->GetRotation(); + + EntityInfo info{}; + info.lot = item->GetLot(); + info.pos = m_Parent->GetPosition(); + info.rot = startRotation; + info.spawnerID = m_Parent->GetObjectID(); + + auto* mount = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); + + // Check to see if the mount is a vehicle, if so, flip it + auto* vehicleComponent = mount->GetComponent(); + if (vehicleComponent) { + auto angles = startRotation.GetEulerAngles(); + // Make it right side up + angles.x -= PI; + // Make it going in the direction of the player + angles.y -= PI; + startRotation = NiQuaternion::FromEulerAngles(angles); + mount->SetRotation(startRotation); + // We're pod racing now + characterComponent->SetIsRacing(true); + } + + // Setup the destroyable stats + auto* destroyableComponent = mount->GetComponent(); + if (destroyableComponent) { + destroyableComponent->SetIsSmashable(false); + destroyableComponent->SetIsImmune(true); + } + + // Mount it + auto* possessableComponent = mount->GetComponent(); + if (possessableComponent) { + possessableComponent->SetIsItemSpawned(true); + possessableComponent->SetPossessor(m_Parent->GetObjectID()); + // Possess it + possessorComponent->SetPossessable(mount->GetObjectID()); + possessorComponent->SetPossessableType(possessableComponent->GetPossessionType()); + } + + GameMessages::SendSetJetPackMode(m_Parent, false); + + // Make it go to the client + EntityManager::Instance()->ConstructEntity(mount); + // Update the possessor + EntityManager::Instance()->SerializeEntity(m_Parent); + + // have to unlock the input so it vehicle can be driven + if (vehicleComponent) GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); + GameMessages::SendMarkInventoryItemAsActive(m_Parent->GetObjectID(), true, eUnequippableActiveType::MOUNT, item->GetId(), m_Parent->GetSystemAddress()); +} + +void InventoryComponent::ApplyBuff(Item* item) const { const auto buffs = FindBuffs(item, true); - for (const auto buff : buffs) - { + for (const auto buff : buffs) { SkillComponent::HandleUnmanaged(buff, m_Parent->GetObjectID()); } } -void InventoryComponent::RemoveBuff(Item* item) const -{ +// TODO Something needs to send the remove buff GameMessage as well when it is unequipping items that would remove buffs. +void InventoryComponent::RemoveBuff(Item* item) const { const auto buffs = FindBuffs(item, false); - for (const auto buff : buffs) - { + for (const auto buff : buffs) { SkillComponent::HandleUnCast(buff, m_Parent->GetObjectID()); } } -void InventoryComponent::PushEquippedItems() -{ +void InventoryComponent::PushEquippedItems() { m_Pushed = m_Equipped; m_Dirty = true; } -void InventoryComponent::PopEquippedItems() -{ +void InventoryComponent::PopEquippedItems() { auto current = m_Equipped; - for (const auto& pair : current) - { + for (const auto& pair : current) { auto* const item = FindItemById(pair.second.id); - if (item == nullptr) - { + if (item == nullptr) { continue; } item->UnEquip(); } - for (const auto& pair : m_Pushed) - { + for (const auto& pair : m_Pushed) { auto* const item = FindItemById(pair.second.id); - if (item == nullptr) - { + if (item == nullptr) { continue; } @@ -1161,7 +1077,7 @@ void InventoryComponent::PopEquippedItems() m_Pushed.clear(); auto destroyableComponent = m_Parent->GetComponent(); - + // Reset stats to full if (destroyableComponent) { destroyableComponent->SetHealth(static_cast(destroyableComponent->GetMaxHealth())); @@ -1174,12 +1090,9 @@ void InventoryComponent::PopEquippedItems() } -bool InventoryComponent::IsEquipped(const LOT lot) const -{ - for (const auto& pair : m_Equipped) - { - if (pair.second.lot == lot) - { +bool InventoryComponent::IsEquipped(const LOT lot) const { + for (const auto& pair : m_Equipped) { + if (pair.second.lot == lot) { return true; } } @@ -1207,17 +1120,14 @@ void InventoryComponent::CheckItemSet(const LOT lot) { bool found = false; // Check if we have the set already - for (auto* itemset : m_Itemsets) - { - if (itemset->GetID() == id) - { + for (auto* itemset : m_Itemsets) { + if (itemset->GetID() == id) { found = true; break; } } - if (!found) - { + if (!found) { auto* set = new ItemSet(id, this); m_Itemsets.push_back(set); @@ -1231,24 +1141,20 @@ void InventoryComponent::CheckItemSet(const LOT lot) { result.finalize(); } -void InventoryComponent::SetConsumable(LOT lot) -{ +void InventoryComponent::SetConsumable(LOT lot) { m_Consumable = lot; } -LOT InventoryComponent::GetConsumable() const -{ +LOT InventoryComponent::GetConsumable() const { return m_Consumable; } -void InventoryComponent::AddItemSkills(const LOT lot) -{ +void InventoryComponent::AddItemSkills(const LOT lot) { const auto info = Inventory::FindItemComponent(lot); const auto slot = FindBehaviorSlot(static_cast(info.itemType)); - if (slot == BehaviorSlot::Invalid) - { + if (slot == BehaviorSlot::Invalid) { return; } @@ -1256,38 +1162,33 @@ void InventoryComponent::AddItemSkills(const LOT lot) const auto skill = FindSkill(lot); - if (skill == 0) - { + if (skill == 0) { return; } - if (index != m_Skills.end()) - { + if (index != m_Skills.end()) { const auto old = index->second; - + GameMessages::SendRemoveSkill(m_Parent, old); } - + GameMessages::SendAddSkill(m_Parent, skill, static_cast(slot)); m_Skills.insert_or_assign(slot, skill); } -void InventoryComponent::RemoveItemSkills(const LOT lot) -{ +void InventoryComponent::RemoveItemSkills(const LOT lot) { const auto info = Inventory::FindItemComponent(lot); const auto slot = FindBehaviorSlot(static_cast(info.itemType)); - if (slot == BehaviorSlot::Invalid) - { + if (slot == BehaviorSlot::Invalid) { return; } const auto index = m_Skills.find(slot); - if (index == m_Skills.end()) - { + if (index == m_Skills.end()) { return; } @@ -1297,34 +1198,27 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) m_Skills.erase(slot); - if (slot == BehaviorSlot::Primary) - { + if (slot == BehaviorSlot::Primary) { m_Skills.insert_or_assign(BehaviorSlot::Primary, 1); GameMessages::SendAddSkill(m_Parent, 1, static_cast(BehaviorSlot::Primary)); } } -void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) -{ - for (auto* set : m_Itemsets) - { - set->TriggerPassiveAbility(trigger); +void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { + for (auto* set : m_Itemsets) { + set->TriggerPassiveAbility(trigger, target); } } -bool InventoryComponent::HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const -{ - for (auto* set : m_Itemsets) - { - if (set->GetEquippedCount() < equipmentRequirement) - { +bool InventoryComponent::HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const { + for (auto* set : m_Itemsets) { + if (set->GetEquippedCount() < equipmentRequirement) { continue; } // Check if the set has any of the passive abilities - if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast(set->GetID())) != passiveIDs.end()) - { + if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast(set->GetID())) != passiveIDs.end()) { return true; } } @@ -1332,26 +1226,21 @@ bool InventoryComponent::HasAnyPassive(const std::vectorGetObjectID()); - if (current != nullptr) - { + if (current != nullptr) { current->Deactivate(); } } -void InventoryComponent::SpawnPet(Item* item) -{ +void InventoryComponent::SpawnPet(Item* item) { auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID()); - if (current != nullptr) - { + if (current != nullptr) { current->Deactivate(); - if (current->GetDatabaseId() == item->GetSubKey()) - { + if (current->GetDatabaseId() == item->GetSubKey()) { return; } } @@ -1360,11 +1249,11 @@ void InventoryComponent::SpawnPet(Item* item) auto destroyableComponent = m_Parent->GetComponent(); if (Game::config->GetValue("pets_take_imagination") == "1" && destroyableComponent && destroyableComponent->GetImagination() <= 0) { - GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), eUseItemResponse::NoImaginationForPet); return; } - EntityInfo info {}; + EntityInfo info{}; info.lot = item->GetLot(); info.pos = m_Parent->GetPosition(); info.rot = NiQuaternion::IDENTITY; @@ -1374,21 +1263,18 @@ void InventoryComponent::SpawnPet(Item* item) auto* petComponent = pet->GetComponent(); - if (petComponent != nullptr) - { + if (petComponent != nullptr) { petComponent->Activate(item); } EntityManager::Instance()->ConstructEntity(pet); } -void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) -{ +void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) { m_Pets.insert_or_assign(id, data); } -const DatabasePet& InventoryComponent::GetDatabasePet(LWOOBJID id) const -{ +const DatabasePet& InventoryComponent::GetDatabasePet(LWOOBJID id) const { const auto& pair = m_Pets.find(id); if (pair == m_Pets.end()) return DATABASE_PET_INVALID; @@ -1396,54 +1282,46 @@ const DatabasePet& InventoryComponent::GetDatabasePet(LWOOBJID id) const return pair->second; } -bool InventoryComponent::IsPet(LWOOBJID id) const -{ +bool InventoryComponent::IsPet(LWOOBJID id) const { const auto& pair = m_Pets.find(id); return pair != m_Pets.end(); } -void InventoryComponent::RemoveDatabasePet(LWOOBJID id) -{ +void InventoryComponent::RemoveDatabasePet(LWOOBJID id) { m_Pets.erase(id); } -BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) -{ +BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) { switch (type) { - case ITEM_TYPE_HAT: + case eItemType::HAT: return BehaviorSlot::Head; - case ITEM_TYPE_NECK: + case eItemType::NECK: return BehaviorSlot::Neck; - case ITEM_TYPE_LEFT_HAND: + case eItemType::LEFT_HAND: return BehaviorSlot::Offhand; - case ITEM_TYPE_RIGHT_HAND: + case eItemType::RIGHT_HAND: return BehaviorSlot::Primary; - case ITEM_TYPE_CONSUMABLE: + case eItemType::CONSUMABLE: return BehaviorSlot::Consumable; default: return BehaviorSlot::Invalid; } } -bool InventoryComponent::IsTransferInventory(eInventoryType type) -{ - return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS; +bool InventoryComponent::IsTransferInventory(eInventoryType type) { + return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS || type == MODELS_IN_BBB; } -uint32_t InventoryComponent::FindSkill(const LOT lot) -{ - auto* table = CDClientManager::Instance()->GetTable("ObjectSkills"); +uint32_t InventoryComponent::FindSkill(const LOT lot) { + auto* table = CDClientManager::Instance().GetTable(); - const auto results = table->Query([=](const CDObjectSkills& entry) - { + const auto results = table->Query([=](const CDObjectSkills& entry) { return entry.objectTemplate == static_cast(lot); - }); + }); - for (const auto& result : results) - { - if (result.castOnType == 0) - { + for (const auto& result : results) { + if (result.castOnType == 0) { return result.skillID; } } @@ -1451,38 +1329,32 @@ uint32_t InventoryComponent::FindSkill(const LOT lot) return 0; } -std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip) const -{ +std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip) const { std::vector buffs; if (item == nullptr) return buffs; - auto* table = CDClientManager::Instance()->GetTable("ObjectSkills"); - auto* behaviors = CDClientManager::Instance()->GetTable("SkillBehavior"); + auto* table = CDClientManager::Instance().GetTable(); + auto* behaviors = CDClientManager::Instance().GetTable(); - const auto results = table->Query([=](const CDObjectSkills& entry) - { + const auto results = table->Query([=](const CDObjectSkills& entry) { return entry.objectTemplate == static_cast(item->GetLot()); - }); + }); - auto* missions = static_cast(m_Parent->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missions = static_cast(m_Parent->GetComponent(eReplicaComponentType::MISSION)); - for (const auto& result : results) - { - if (result.castOnType == 1) - { + for (const auto& result : results) { + if (result.castOnType == 1) { const auto entry = behaviors->GetSkillByID(result.skillID); - if (entry.skillID == 0) - { - Game::logger->Log("InventoryComponent", "Failed to find buff behavior for skill (%i)!\n", result.skillID); + if (entry.skillID == 0) { + Game::logger->Log("InventoryComponent", "Failed to find buff behavior for skill (%i)!", result.skillID); continue; } - if (missions != nullptr && castOnEquip) - { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID); + if (missions != nullptr && castOnEquip) { + missions->Progress(eMissionTaskType::USE_SKILL, result.skillID); } - + // If item is not a proxy, add its buff to the added buffs. if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast(entry.behaviorID)); } @@ -1491,14 +1363,12 @@ std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip return buffs; } -void InventoryComponent::SetNPCItems(const std::vector& items) -{ +void InventoryComponent::SetNPCItems(const std::vector& items) { m_Equipped.clear(); auto slot = 0u; - for (const auto& item : items) - { + for (const auto& item : items) { const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID(); const auto& info = Inventory::FindItemComponent(item); @@ -1509,17 +1379,14 @@ void InventoryComponent::SetNPCItems(const std::vector& items) EntityManager::Instance()->SerializeEntity(m_Parent); } -InventoryComponent::~InventoryComponent() -{ - for (const auto& inventory : m_Inventories) - { +InventoryComponent::~InventoryComponent() { + for (const auto& inventory : m_Inventories) { delete inventory.second; } m_Inventories.clear(); - for (auto* set : m_Itemsets) - { + for (auto* set : m_Itemsets) { delete set; } @@ -1527,14 +1394,12 @@ InventoryComponent::~InventoryComponent() m_Pets.clear(); } -std::vector InventoryComponent::GenerateProxies(Item* parent) -{ +std::vector InventoryComponent::GenerateProxies(Item* parent) { std::vector proxies; auto subItems = parent->GetInfo().subItems; - if (subItems.empty()) - { + if (subItems.empty()) { return proxies; } @@ -1544,22 +1409,16 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) std::string segment; std::vector lots; - while (std::getline(stream, segment, ',')) - { - try - { + while (std::getline(stream, segment, ',')) { + try { lots.push_back(std::stoi(segment)); - } - catch (std::invalid_argument& exception) - { - Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!\n", segment.c_str(), exception.what()); + } catch (std::invalid_argument& exception) { + Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!", segment.c_str(), exception.what()); } } - for (const auto lot : lots) - { - if (!Inventory::IsValidItem(lot)) - { + for (const auto lot : lots) { + if (!Inventory::IsValidItem(lot)) { continue; } @@ -1575,18 +1434,15 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) return proxies; } -std::vector InventoryComponent::FindProxies(const LWOOBJID parent) -{ +std::vector InventoryComponent::FindProxies(const LWOOBJID parent) { auto* inventory = GetInventory(ITEM_SETS); std::vector proxies; - for (const auto& pair : inventory->GetItems()) - { + for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; - if (item->GetParent() == parent) - { + if (item->GetParent() == parent) { proxies.push_back(item); } } @@ -1594,18 +1450,14 @@ std::vector InventoryComponent::FindProxies(const LWOOBJID parent) return proxies; } -bool InventoryComponent::IsValidProxy(const LWOOBJID parent) -{ - for (const auto& pair : m_Inventories) - { +bool InventoryComponent::IsValidProxy(const LWOOBJID parent) { + for (const auto& pair : m_Inventories) { const auto items = pair.second->GetItems(); - for (const auto& candidate : items) - { + for (const auto& candidate : items) { auto* item = candidate.second; - if (item->GetId() == parent) - { + if (item->GetId() == parent) { return true; } } @@ -1614,25 +1466,20 @@ bool InventoryComponent::IsValidProxy(const LWOOBJID parent) return false; } -bool InventoryComponent::IsParentValid(Item* root) -{ - if (root->GetInfo().subItems.empty()) - { +bool InventoryComponent::IsParentValid(Item* root) { + if (root->GetInfo().subItems.empty()) { return true; } const auto id = root->GetId(); - for (const auto& pair : m_Inventories) - { + for (const auto& pair : m_Inventories) { const auto items = pair.second->GetItems(); - for (const auto& candidate : items) - { + for (const auto& candidate : items) { auto* item = candidate.second; - if (item->GetParent() == id) - { + if (item->GetParent() == id) { return true; } } @@ -1641,27 +1488,22 @@ bool InventoryComponent::IsParentValid(Item* root) return false; } -void InventoryComponent::CheckProxyIntegrity() -{ +void InventoryComponent::CheckProxyIntegrity() { std::vector dead; - for (const auto& pair : m_Inventories) - { + for (const auto& pair : m_Inventories) { const auto& items = pair.second->GetItems(); - for (const auto& candidate : items) - { + for (const auto& candidate : items) { auto* item = candidate.second; const auto parent = item->GetParent(); - if (parent == LWOOBJID_EMPTY) - { + if (parent == LWOOBJID_EMPTY) { continue; } - if (IsValidProxy(parent)) - { + if (IsValidProxy(parent)) { continue; } @@ -1669,8 +1511,7 @@ void InventoryComponent::CheckProxyIntegrity() } } - for (auto* item : dead) - { + for (auto* item : dead) { item->RemoveFromInventory(); } @@ -1713,16 +1554,13 @@ void InventoryComponent::CheckProxyIntegrity() */ } -void InventoryComponent::PurgeProxies(Item* item) -{ +void InventoryComponent::PurgeProxies(Item* item) { const auto root = item->GetParent(); - if (root != LWOOBJID_EMPTY) - { + if (root != LWOOBJID_EMPTY) { item = FindItemById(root); - if (item != nullptr) - { + if (item != nullptr) { UnEquipItem(item); } @@ -1731,20 +1569,17 @@ void InventoryComponent::PurgeProxies(Item* item) auto proxies = FindProxies(item->GetId()); - for (auto* proxy : proxies) - { + for (auto* proxy : proxies) { proxy->UnEquip(); proxy->RemoveFromInventory(); } } -void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) -{ +void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); - if (petInventoryElement == nullptr) - { + if (petInventoryElement == nullptr) { m_Pets.clear(); return; @@ -1752,8 +1587,7 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) auto* petElement = petInventoryElement->FirstChildElement(); - while (petElement != nullptr) - { + while (petElement != nullptr) { LWOOBJID id; LOT lot; int32_t moderationStatus; @@ -1774,12 +1608,10 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) } } -void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) -{ +void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); - if (petInventoryElement == nullptr) - { + if (petInventoryElement == nullptr) { petInventoryElement = document->NewElement("pet"); document->FirstChildElement("obj")->LinkEndChild(petInventoryElement); @@ -1787,8 +1619,7 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) petInventoryElement->DeleteChildren(); - for (const auto& pet : m_Pets) - { + for (const auto& pet : m_Pets) { auto* petElement = document->NewElement("p"); petElement->SetAttribute("id", pet.first); diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 1fda5942..801f9f51 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #ifndef INVENTORYCOMPONENT_H #define INVENTORYCOMPONENT_H @@ -17,14 +17,19 @@ #include "DatabasePet.h" #include "Component.h" #include "ItemSetPassiveAbility.h" -#include "ItemSetPassiveAbilityID.h" +#include "eItemSetPassiveAbilityID.h" #include "PossessorComponent.h" +#include "eInventoryType.h" +#include "eReplicaComponentType.h" +#include "eLootSourceType.h" class Entity; class ItemSet; typedef std::map EquipmentMap; +enum class eItemType : int32_t; + /** * Handles the inventory of entity, including the items they possess and have equipped. An entity can have inventories * of different types, each type representing a different group of items, see `eInventoryType` for a list of @@ -33,69 +38,69 @@ typedef std::map EquipmentMap; class InventoryComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_INVENTORY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr); - void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadXml(tinyxml2::XMLDocument* document); - void UpdateXml(tinyxml2::XMLDocument* document) override; - void ResetFlags(); + void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void LoadXml(tinyxml2::XMLDocument* document); + void UpdateXml(tinyxml2::XMLDocument* document) override; + void ResetFlags(); - /** - * Returns an inventory of the specified type, if it exists - * @param type the inventory type to find an inventory for - * @return the inventory of the specified type - */ + /** + * Returns an inventory of the specified type, if it exists + * @param type the inventory type to find an inventory for + * @return the inventory of the specified type + */ Inventory* GetInventory(eInventoryType type); - /** - * Returns all the inventories this entity has, indexed by type - * @return all the inventories this entity has, indexed by type - */ + /** + * Returns all the inventories this entity has, indexed by type + * @return all the inventories this entity has, indexed by type + */ const std::map& GetInventories() const; - /** - * Returns the amount of items this entity possesses of a certain LOT - * @param lot the lot to search for - * @return the amount of items this entity possesses the specified LOT - */ + /** + * Returns the amount of items this entity possesses of a certain LOT + * @param lot the lot to search for + * @return the amount of items this entity possesses the specified LOT + */ uint32_t GetLotCount(LOT lot) const; - /** - * Returns the amount of items this entity possesses of a LOT, given that they're not in a temporary inventory - * (vendor buyback, vault, etc). - * @param lot the lot to search for - * @return the amount of items this entity possesses of the specified lot - */ + /** + * Returns the amount of items this entity possesses of a LOT, given that they're not in a temporary inventory + * (vendor buyback, vault, etc). + * @param lot the lot to search for + * @return the amount of items this entity possesses of the specified lot + */ uint32_t GetLotCountNonTransfer(LOT lot) const; - /** - * Returns the items that are currently equipped by this entity - * @return the items that are currently equipped by this entity - */ + /** + * Returns the items that are currently equipped by this entity + * @return the items that are currently equipped by this entity + */ const EquipmentMap& GetEquippedItems() const; - /** - * Adds an item to the inventory of the entity - * @param lot the lot to add - * @param count the amount of items to add - * @param inventoryType the inventory to add the item to - * @param config optional config for this item, used for example for rockets - * @param parent optional parent of this item, used for proxy items - * @param showFlyingLoot show a client animation if the item is added - * @param isModMoveAndEquip equips the item - * @param subKey optional sub ID of a related object, used by pets - * @param inventorySourceType if the inventory was moved, the source inventory - * @param sourceType the source of the item, used to determine if the item is dropped or mailed if the inventory is full - * @param bound whether this item is bound - * @param preferredSlot the preferred slot to store this item - * @param lootSourceType The source of the loot. Defaults to none. - */ + /** + * Adds an item to the inventory of the entity + * @param lot the lot to add + * @param count the amount of items to add + * @param inventoryType the inventory to add the item to + * @param config optional config for this item, used for example for rockets + * @param parent optional parent of this item, used for proxy items + * @param showFlyingLoot show a client animation if the item is added + * @param isModMoveAndEquip equips the item + * @param subKey optional sub ID of a related object, used by pets + * @param inventorySourceType if the inventory was moved, the source inventory + * @param sourceType the source of the item, used to determine if the item is dropped or mailed if the inventory is full + * @param bound whether this item is bound + * @param preferredSlot the preferred slot to store this item + * @param lootSourceType The source of the loot. Defaults to none. + */ void AddItem( LOT lot, uint32_t count, - eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE, + eLootSourceType lootSourceType = eLootSourceType::NONE, eInventoryType inventoryType = INVALID, const std::vector& config = {}, LWOOBJID parent = LWOOBJID_EMPTY, @@ -108,65 +113,65 @@ public: int32_t preferredSlot = -1 ); - /** - * Removes a LOT from the inventory - * @param lot the lot to remove - * @param count the number of items to remove - * @param inventoryType optional inventory type to remove the item from - * @param ignoreBound ignores bound items - */ + /** + * Removes a LOT from the inventory + * @param lot the lot to remove + * @param count the number of items to remove + * @param inventoryType optional inventory type to remove the item from + * @param ignoreBound ignores bound items + */ void RemoveItem(LOT lot, uint32_t count, eInventoryType inventoryType = INVALID, bool ignoreBound = false); - /** - * Moves an existing item to an inventory of the entity - * @param item the item to add - * @param inventory the inventory to add the item to - * @param count the number of items to add - * @param showFlyingLot displays UI animation to the user - * @param isModMoveAndEquip equips the item - * @param ignoreEquipped does not stack on equipped items - * @param preferredSlot the preferred slot to store the item in - */ + /** + * Moves an existing item to an inventory of the entity + * @param item the item to add + * @param inventory the inventory to add the item to + * @param count the number of items to add + * @param showFlyingLot displays UI animation to the user + * @param isModMoveAndEquip equips the item + * @param ignoreEquipped does not stack on equipped items + * @param preferredSlot the preferred slot to store the item in + */ void MoveItemToInventory(Item* item, eInventoryType inventory, uint32_t count, bool showFlyingLot = true, bool isModMoveAndEquip = false, bool ignoreEquipped = false, int32_t preferredSlot = -1); - /** - * Moves a stack of items to an inventory - * @param item the item to move - * @param inventory the inventory to move the item to - * @param slot the slot in the inventory to move the item to - */ + /** + * Moves a stack of items to an inventory + * @param item the item to move + * @param inventory the inventory to move the item to + * @param slot the slot in the inventory to move the item to + */ void MoveStack(Item* item, eInventoryType inventory, uint32_t slot = 0); - /** - * Returns an item in the inventory by object ID - * @param id the id of the item to find - * @return item in the inventory by object ID - */ + /** + * Returns an item in the inventory by object ID + * @param id the id of the item to find + * @return item in the inventory by object ID + */ Item* FindItemById(LWOOBJID id) const; - /** - * Returns an item in the inventory that matches the specified LOT - * @param lot the lot of the item to find - * @param inventoryType optional inventory to search in - * @param ignoreEquipped ignores items that are equipped - * @param ignoreBound ignores items that are bound - * @return item in the inventory that matches the specified LOT - */ + /** + * Returns an item in the inventory that matches the specified LOT + * @param lot the lot of the item to find + * @param inventoryType optional inventory to search in + * @param ignoreEquipped ignores items that are equipped + * @param ignoreBound ignores items that are bound + * @return item in the inventory that matches the specified LOT + */ Item* FindItemByLot(LOT lot, eInventoryType inventoryType = INVALID, bool ignoreEquipped = false, bool ignoreBound = false); - /** - * Finds an item in the inventory that has the specified subkey, useful for pets - * @param id the subkey to look for - * @param inventoryType optional inventory type to search in - * @return item in the inventory that has the specified subkey - */ + /** + * Finds an item in the inventory that has the specified subkey, useful for pets + * @param id the subkey to look for + * @param inventoryType optional inventory type to search in + * @return item in the inventory that has the specified subkey + */ Item* FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType = INVALID); - /** - * Checks if the entity has enough space for a batch of loot - * @param loot a map of items to add and how many to add - * @return whether the entity has enough space for all the items - */ + /** + * Checks if the entity has enough space for a batch of loot + * @param loot a map of items to add and how many to add + * @return whether the entity has enough space for all the items + */ bool HasSpaceForLoot(const std::unordered_map& loot); /** @@ -177,84 +182,91 @@ public: */ void UpdateSlot(const std::string& location, EquippedItem item, bool keepCurrent = false); - /** - * Removes a slot from the inventory - * @param location the slot to remove - */ + /** + * Removes a slot from the inventory + * @param location the slot to remove + */ void RemoveSlot(const std::string& location); - /** - * Equips the given item, guesses the slot to equip it in - * @param item the item to equip - * @param skipChecks skips checks for equipping cars and rockets (e.g. no special behavior follows) - */ + /** + * Equips the given item, guesses the slot to equip it in + * @param item the item to equip + * @param skipChecks skips checks for equipping cars and rockets (e.g. no special behavior follows) + */ void EquipItem(Item* item, bool skipChecks = false); - /** - * Unequips an item from the inventory - * @param item the item to unequip - */ + /** + * Unequips an item from the inventory + * @param item the item to unequip + */ void UnEquipItem(Item* item); - /** - * Adds a buff related to equipping a lot to the entity - * @param item the item to find buffs for - */ + /** + * Unequips an Item from the inventory + * @param item the Item to unequip + * @return if we were successful + */ + void HandlePossession(Item* item); + + /** + * Adds a buff related to equipping a lot to the entity + * @param item the item to find buffs for + */ void ApplyBuff(Item* item) const; - /** - * Removes buffs related to equipping a lot from the entity - * @param item the item to find buffs for - */ + /** + * Removes buffs related to equipping a lot from the entity + * @param item the item to find buffs for + */ void RemoveBuff(Item* item) const; - /** - * Saves the equipped items into a temp state - */ + /** + * Saves the equipped items into a temp state + */ void PushEquippedItems(); - /** - * Unequips all the temporary items and equips the previous item state - */ + /** + * Unequips all the temporary items and equips the previous item state + */ void PopEquippedItems(); - /** - * Returns if the entity has an item equipped of the given lot - * @param lot to lot to search for - * @return if the entity has an item equipped of the given lot - */ + /** + * Returns if the entity has an item equipped of the given lot + * @param lot to lot to search for + * @return if the entity has an item equipped of the given lot + */ bool IsEquipped(LOT lot) const; - /** - * Checks and ensures that we have loaded the item set that might be related to this item - * @param lot the lot to check the item set for - */ + /** + * Checks and ensures that we have loaded the item set that might be related to this item + * @param lot the lot to check the item set for + */ void CheckItemSet(LOT lot); - /** - * Sets the current consumable lot - * @param lot the lot to set as consumable - */ + /** + * Sets the current consumable lot + * @param lot the lot to set as consumable + */ void SetConsumable(LOT lot); - /** - * Returns the current consumable lot - * @return the current consumable lot - */ + /** + * Returns the current consumable lot + * @return the current consumable lot + */ LOT GetConsumable() const; - /** - * Finds all the buffs related to a lot - * @param item the item to get the buffs for - * @param castOnEquip if true, the skill missions for these buffs will be progressed - * @return the buffs related to the specified lot - */ + /** + * Finds all the buffs related to a lot + * @param item the item to get the buffs for + * @param castOnEquip if true, the skill missions for these buffs will be progressed + * @return the buffs related to the specified lot + */ std::vector FindBuffs(Item* item, bool castOnEquip) const; - /** - * Initializes the equipped items with a list of items - * @param items the items to equip - */ + /** + * Initializes the equipped items with a list of items + * @param items the items to equip + */ void SetNPCItems(const std::vector& items); /** @@ -263,189 +275,203 @@ public: */ void AddItemSkills(LOT lot); - /** - * Removes the skills related to the passed LOT from the currently equipped skills - * @param lot the lot to remove - */ + /** + * Removes the skills related to the passed LOT from the currently equipped skills + * @param lot the lot to remove + */ void RemoveItemSkills(LOT lot); - /** - * Triggers one of the passive abilities from the equipped item set - * @param trigger the trigger to fire - */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + /** + * Triggers one of the passive abilities from the equipped item set + * @param trigger the trigger to fire + */ + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); - /** - * Returns if the entity has any of the passed passive abilities equipped - * @param passiveIDs the IDs to check for - * @param equipmentRequirement the number of equipment required to be allowed to have the ability - * @return if the entity has any of the passed passive abilities equipped - */ - bool HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const; + /** + * Returns if the entity has any of the passed passive abilities equipped + * @param passiveIDs the IDs to check for + * @param equipmentRequirement the number of equipment required to be allowed to have the ability + * @return if the entity has any of the passed passive abilities equipped + */ + bool HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const; - /** - * Despawns the currently active pet, if any - */ + /** + * Despawns the currently active pet, if any + */ void DespawnPet(); - /** - * Spawns the item as a pet (if it is one) - * @param item the pet to spawn - */ + /** + * Spawns the item as a pet (if it is one) + * @param item the pet to spawn + */ void SpawnPet(Item* item); - /** - * Updates the database pet data for an item (e.g. moderation status) - * @param id the id of the pet to find - * @param data the data to store on the pet - */ + /** + * Updates the database pet data for an item (e.g. moderation status) + * @param id the id of the pet to find + * @param data the data to store on the pet + */ void SetDatabasePet(LWOOBJID id, const DatabasePet& data); - /** - * Returns the database pet information for an object - * @param id the object ID to search for - * @return the database pet information for the object that belongs to the passed id - */ + /** + * Returns the database pet information for an object + * @param id the object ID to search for + * @return the database pet information for the object that belongs to the passed id + */ const DatabasePet& GetDatabasePet(LWOOBJID id) const; - /** - * Checks if the provided object ID is in this inventory and is a pet - * @param id the id of the object to check for - * @return if the provided object ID is in this inventory and is a pet - */ + /** + * Checks if the provided object ID is in this inventory and is a pet + * @param id the id of the object to check for + * @return if the provided object ID is in this inventory and is a pet + */ bool IsPet(LWOOBJID id) const; - /** - * Removes pet database information from the item with the specified object id - * @param id the object id to remove pet info for - */ + /** + * Removes pet database information from the item with the specified object id + * @param id the object id to remove pet info for + */ void RemoveDatabasePet(LWOOBJID id); - /** - * Returns the current behavior slot active for the passed item type - * @param type the item type to find the behavior slot for - * @return the current behavior slot active for the passed item type - */ + /** + * Returns the current behavior slot active for the passed item type + * @param type the item type to find the behavior slot for + * @return the current behavior slot active for the passed item type + */ static BehaviorSlot FindBehaviorSlot(eItemType type); - /** - * Checks if the inventory type is a temp inventory - * @param type the inventory type to check - * @return if the inventory type is a temp inventory - */ + /** + * Checks if the inventory type is a temp inventory + * @param type the inventory type to check + * @return if the inventory type is a temp inventory + */ static bool IsTransferInventory(eInventoryType type); - /** - * Finds the skill related to the passed LOT from the ObjectSkills table - * @param lot the lot to find - * @return the skill related to the passed LOT - */ + /** + * Finds the skill related to the passed LOT from the ObjectSkills table + * @param lot the lot to find + * @return the skill related to the passed LOT + */ static uint32_t FindSkill(LOT lot); - + + /** + * Call this when you equip an item. This calls OnFactionTriggerItemEquipped for any scripts found on the items. + * + * @param equippedItem The item script to lookup and call equip on + */ + void EquipScripts(Item* equippedItem); + + /** + * Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items. + * + * @param unequippedItem The item script to lookup and call unequip on + */ + void UnequipScripts(Item* unequippedItem); + ~InventoryComponent() override; - + private: - /** - * All the inventory this entity possesses - */ + /** + * All the inventory this entity possesses + */ std::map m_Inventories; - /** - * The skills that this entity currently has active - */ + /** + * The skills that this entity currently has active + */ std::map m_Skills; - /** - * The pets this entity has, mapped by object ID and pet info - */ + /** + * The pets this entity has, mapped by object ID and pet info + */ std::unordered_map m_Pets; - /** - * Cache of item sets this entity has encountered - */ + /** + * Cache of item sets this entity has encountered + */ std::vector m_Itemsets; - /** - * The LOTs we've checked all the item sets for (for cache reasons) - */ + /** + * The LOTs we've checked all the item sets for (for cache reasons) + */ std::vector m_ItemSetsChecked; - /** - * all the equipped items - */ + /** + * all the equipped items + */ EquipmentMap m_Equipped; - /** - * Clone of the equipped items before unequipping all of them - */ + /** + * Clone of the equipped items before unequipping all of them + */ EquipmentMap m_Pushed; - /** - * If the inventory has changed - */ + /** + * If the inventory has changed + */ bool m_Dirty; - /** - * The currently active consumable - */ + /** + * The currently active consumable + */ LOT m_Consumable; - /** - * Currently has a car equipped - */ - bool hasCarEquipped = false; - Entity* equippedCarEntity = nullptr; - LWOOBJID previousPossessableID = LWOOBJID_EMPTY; - LWOOBJID previousPossessorID = LWOOBJID_EMPTY; - /** - * Creates all the proxy items (subitems) for a parent item - * @param parent the parent item to generate all the subitems for - * @return the proxy items (subitems) for a parent item - */ + /** + * Currently has a car equipped + */ + bool hasCarEquipped = false; + Entity* equippedCarEntity = nullptr; + LWOOBJID previousPossessableID = LWOOBJID_EMPTY; + LWOOBJID previousPossessorID = LWOOBJID_EMPTY; + /** + * Creates all the proxy items (subitems) for a parent item + * @param parent the parent item to generate all the subitems for + * @return the proxy items (subitems) for a parent item + */ std::vector GenerateProxies(Item* parent); - /** - * Finds all the proxy items in this inventory for a given parent item - * @param parent the parent to find proxy items for - * @return the proxy items for the parent - */ + /** + * Finds all the proxy items in this inventory for a given parent item + * @param parent the parent to find proxy items for + * @return the proxy items for the parent + */ std::vector FindProxies(LWOOBJID parent); - /** - * Returns true if the provided LWOOBJID is the parent of this Item. - * @param parent the parent item to check for proxies - * @return if the provided ID is a valid proxy item - */ + /** + * Returns true if the provided LWOOBJID is the parent of this Item. + * @param parent the parent item to check for proxies + * @return if the provided ID is a valid proxy item + */ bool IsValidProxy(LWOOBJID parent); - /** - * Returns if the provided ID is a valid proxy item (e.g. we have children for it) - * @param parent the parent item to check for - * @return if the provided ID is a valid proxy item - */ + /** + * Returns if the provided ID is a valid proxy item (e.g. we have children for it) + * @param parent the parent item to check for + * @return if the provided ID is a valid proxy item + */ bool IsParentValid(Item* root); - /** - * Removes all the proxy items that have a dangling parent - */ + /** + * Removes all the proxy items that have a dangling parent + */ void CheckProxyIntegrity(); - /** - * Removes all the proxy items for a given parent from the inventory - * @param item the item to remove proxy items for - */ + /** + * Removes all the proxy items for a given parent from the inventory + * @param item the item to remove proxy items for + */ void PurgeProxies(Item* item); - /** - * Saves all the pet information stored in inventory items to the database - * @param document the xml doc to save to - */ + /** + * Saves all the pet information stored in inventory items to the database + * @param document the xml doc to save to + */ void LoadPetXml(tinyxml2::XMLDocument* document); - /** - * Loads all the pet information from an xml doc into items - * @param document the xml doc to load from - */ + /** + * Loads all the pet information from an xml doc into items + * @param document the xml doc to load from + */ void UpdatePetXml(tinyxml2::XMLDocument* document); }; diff --git a/dGame/dComponents/LUPExhibitComponent.cpp b/dGame/dComponents/LUPExhibitComponent.cpp index 8c825a30..7b8c85ba 100644 --- a/dGame/dComponents/LUPExhibitComponent.cpp +++ b/dGame/dComponents/LUPExhibitComponent.cpp @@ -2,50 +2,43 @@ #include "EntityManager.h" -LUPExhibitComponent::LUPExhibitComponent(Entity* parent) : Component(parent) -{ - m_Exhibits = { 11121, 11295, 11423, 11979 }; +LUPExhibitComponent::LUPExhibitComponent(Entity* parent) : Component(parent) { + m_Exhibits = { 11121, 11295, 11423, 11979 }; - m_ExhibitIndex = 0; + m_ExhibitIndex = 0; - m_Exhibit = m_Exhibits[m_ExhibitIndex]; + m_Exhibit = m_Exhibits[m_ExhibitIndex]; } -LUPExhibitComponent::~LUPExhibitComponent() -{ - +LUPExhibitComponent::~LUPExhibitComponent() { + } -void LUPExhibitComponent::Update(float deltaTime) -{ - m_UpdateTimer += deltaTime; +void LUPExhibitComponent::Update(float deltaTime) { + m_UpdateTimer += deltaTime; - if (m_UpdateTimer > 20.0f) - { - NextExhibit(); + if (m_UpdateTimer > 20.0f) { + NextExhibit(); - m_UpdateTimer = 0.0f; - } + m_UpdateTimer = 0.0f; + } } -void LUPExhibitComponent::NextExhibit() -{ - m_ExhibitIndex++; +void LUPExhibitComponent::NextExhibit() { + m_ExhibitIndex++; - if (m_ExhibitIndex >= m_Exhibits.size()) - { - m_ExhibitIndex = 0; - } + if (m_ExhibitIndex >= m_Exhibits.size()) { + m_ExhibitIndex = 0; + } - m_Exhibit = m_Exhibits[m_ExhibitIndex]; + m_Exhibit = m_Exhibits[m_ExhibitIndex]; - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); } -void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) -{ - outBitStream->Write1(); // Dirty flag? - outBitStream->Write(m_Exhibit); +void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { + outBitStream->Write1(); // Dirty flag? + outBitStream->Write(m_Exhibit); } diff --git a/dGame/dComponents/LUPExhibitComponent.h b/dGame/dComponents/LUPExhibitComponent.h index b9ecf70a..587d1b2f 100644 --- a/dGame/dComponents/LUPExhibitComponent.h +++ b/dGame/dComponents/LUPExhibitComponent.h @@ -2,6 +2,7 @@ #include "Component.h" #include "Entity.h" +#include "eReplicaComponentType.h" /** * Component that handles the LOT that is shown in the LUP exhibit in the LUP world. Works by setting a timer and @@ -10,35 +11,35 @@ class LUPExhibitComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_EXHIBIT; - - LUPExhibitComponent(Entity* parent); - ~LUPExhibitComponent(); - void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); + static const eReplicaComponentType ComponentType = eReplicaComponentType::EXHIBIT; - /** - * After the timer runs out, this changes the currently exhibited LOT to the next one - */ - void NextExhibit(); + LUPExhibitComponent(Entity* parent); + ~LUPExhibitComponent(); + void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); + + /** + * After the timer runs out, this changes the currently exhibited LOT to the next one + */ + void NextExhibit(); private: - /** - * The LOT that's currently on exhibit - */ - LOT m_Exhibit; + /** + * The LOT that's currently on exhibit + */ + LOT m_Exhibit; - /** - * The time since we've last updated the exhibit - */ - float m_UpdateTimer; + /** + * The time since we've last updated the exhibit + */ + float m_UpdateTimer; - /** - * The list of possible exhibits to show - */ - std::vector m_Exhibits; + /** + * The list of possible exhibits to show + */ + std::vector m_Exhibits; - /** - * The current index in the exhibit list - */ - size_t m_ExhibitIndex; + /** + * The current index in the exhibit list + */ + size_t m_ExhibitIndex; }; diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp new file mode 100644 index 00000000..8163e736 --- /dev/null +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -0,0 +1,89 @@ +#include "LevelProgressionComponent.h" +#include "ControllablePhysicsComponent.h" +#include "InventoryComponent.h" +#include "CharacterComponent.h" +#include "tinyxml2.h" + +#include "CDRewardsTable.h" + +LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) { + m_Parent = parent; + m_Level = 1; + m_SpeedBase = 500.0f; + m_CharacterVersion = eCharacterVersion::LIVE; +} + +void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { + tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); + if (!level) { + Game::logger->Log("LevelProgressionComponent", "Failed to find lvl tag while updating XML!"); + return; + } + level->SetAttribute("l", m_Level); + level->SetAttribute("sb", m_SpeedBase); + level->SetAttribute("cv", static_cast(m_CharacterVersion)); +} + +void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { + tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); + if (!level) { + Game::logger->Log("LevelProgressionComponent", "Failed to find lvl tag while loading XML!"); + return; + } + level->QueryAttribute("l", &m_Level); + level->QueryAttribute("sb", &m_SpeedBase); + uint32_t characterVersion; + level->QueryAttribute("cv", &characterVersion); + m_CharacterVersion = static_cast(characterVersion); +} + +void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(bIsInitialUpdate || m_DirtyLevelInfo); + if (bIsInitialUpdate || m_DirtyLevelInfo) outBitStream->Write(m_Level); + m_DirtyLevelInfo = false; +} + +void LevelProgressionComponent::HandleLevelUp() { + auto* rewardsTable = CDClientManager::Instance().GetTable(); + + const auto& rewards = rewardsTable->GetByLevelID(m_Level); + bool rewardingItem = rewards.size() > 0; + + auto* inventoryComponent = m_Parent->GetComponent(); + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + + if (!inventoryComponent || !controllablePhysicsComponent) return; + // Tell the client we beginning to send level rewards. + if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, rewardingItem); + + for (auto* reward : rewards) { + switch (reward->rewardType) { + case 0: + inventoryComponent->AddItem(reward->value, reward->count, eLootSourceType::LEVEL_REWARD); + break; + case 4: + { + auto* items = inventoryComponent->GetInventory(eInventoryType::ITEMS); + items->SetSize(items->GetSize() + reward->value); + } + break; + case 9: + SetSpeedBase(static_cast(reward->value) ); + controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); + break; + case 11: + case 12: + break; + default: + break; + } + } + // Tell the client we have finished sending level rewards. + if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem); +} + +void LevelProgressionComponent::SetRetroactiveBaseSpeed(){ + if (m_Level >= 20) m_SpeedBase = 525.0f; + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f); +} diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h new file mode 100644 index 00000000..06908a81 --- /dev/null +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -0,0 +1,105 @@ +#pragma once + +#include "Entity.h" +#include "GameMessages.h" +#include "Component.h" +#include "eCharacterVersion.h" +#include "eReplicaComponentType.h" + +/** + * Component that handles level progression and serilization. + * + */ + +class LevelProgressionComponent : public Component { +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::LEVEL_PROGRESSION; + + /** + * Constructor for this component + * @param parent parent that contains this component + */ + LevelProgressionComponent(Entity* parent); + + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + + /** + * Save data from this componennt to character XML + * @param doc the document to write data to + */ + void UpdateXml(tinyxml2::XMLDocument* doc) override; + + /** + * Load base data for this component from character XML + * @param doc the document to read data from + */ + void LoadFromXml(tinyxml2::XMLDocument* doc) override; + + /** + * Gets the current level of the entity + * @return the current level of the entity + */ + const uint32_t GetLevel() const { return m_Level; } + + /** + * Sets the level of the entity + * @param level the level to set + */ + void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; } + + /** + * Gets the current Speed Base of the entity + * @return the current Speed Base of the entity + */ + const uint32_t GetSpeedBase() const { return m_SpeedBase; } + + /** + * Sets the Speed Base of the entity + * @param SpeedBase the Speed Base to set + */ + void SetSpeedBase(uint32_t SpeedBase) { m_SpeedBase = SpeedBase; } + + /** + * Gives the player rewards for the last level that they leveled up from + */ + void HandleLevelUp(); + + /** + * Gets the current Character Version of the entity + * @return the current Character Version of the entity + */ + const eCharacterVersion GetCharacterVersion() const { return m_CharacterVersion; } + + /** + * Sets the Character Version of the entity + * @param CharacterVersion the Character Version to set + */ + void SetCharacterVersion(eCharacterVersion CharacterVersion) { m_CharacterVersion = CharacterVersion; } + + /** + * Set the Base Speed retroactively of the entity + */ + void SetRetroactiveBaseSpeed(); + +private: + /** + * whether the level is dirty + */ + bool m_DirtyLevelInfo = false; + + /** + * Level of the entity + */ + uint32_t m_Level; + + /** + * The base speed of the entity + */ + float m_SpeedBase; + + /** + * The Character format version + */ + eCharacterVersion m_CharacterVersion; + +}; diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index 1b809f48..0ae0f07e 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -17,599 +17,606 @@ #include "dZoneManager.h" #include "Mail.h" #include "MissionPrerequisites.h" +#include "AchievementCacheKey.h" +#include "eMissionState.h" -// MARK: Mission Component + // MARK: Mission Component -std::unordered_map> MissionComponent::m_AchievementCache = {}; +std::unordered_map> MissionComponent::m_AchievementCache = {}; //! Initializer MissionComponent::MissionComponent(Entity* parent) : Component(parent) { + m_LastUsedMissionOrderUID = dZoneManager::Instance()->GetUniqueMissionIdStartingValue(); } //! Destructor MissionComponent::~MissionComponent() { - for (const auto& mission : m_Missions) { - delete mission.second; - } + for (const auto& mission : m_Missions) { + delete mission.second; + } - this->m_Missions.clear(); + this->m_Missions.clear(); } Mission* MissionComponent::GetMission(const uint32_t missionId) const { - if (m_Missions.count(missionId) == 0) { - return nullptr; - } + if (m_Missions.count(missionId) == 0) { + return nullptr; + } - const auto& index = m_Missions.find(missionId); + const auto& index = m_Missions.find(missionId); - if (index == m_Missions.end()) { - return nullptr; - } + if (index == m_Missions.end()) { + return nullptr; + } - return index->second; + return index->second; } -MissionState MissionComponent::GetMissionState(const uint32_t missionId) const { - auto* mission = GetMission(missionId); +eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const { + auto* mission = GetMission(missionId); - if (mission == nullptr) { - return CanAccept(missionId) ? MissionState::MISSION_STATE_AVAILABLE : MissionState::MISSION_STATE_UNKNOWN; - } + if (mission == nullptr) { + return CanAccept(missionId) ? eMissionState::AVAILABLE : eMissionState::UNKNOWN; + } - return mission->GetMissionState(); + return mission->GetMissionState(); } const std::unordered_map& MissionComponent::GetMissions() const { - return m_Missions; + return m_Missions; } bool MissionComponent::CanAccept(const uint32_t missionId) const { - return MissionPrerequisites::CanAccept(missionId, m_Missions); + return MissionPrerequisites::CanAccept(missionId, m_Missions); } void MissionComponent::AcceptMission(const uint32_t missionId, const bool skipChecks) { - if (!skipChecks && !CanAccept(missionId)) { - return; - } + if (!skipChecks && !CanAccept(missionId)) { + return; + } - // If this is a daily mission, it may already be "accepted" - auto* mission = this->GetMission(missionId); + // If this is a daily mission, it may already be "accepted" + auto* mission = this->GetMission(missionId); - if (mission != nullptr) { - if (mission->GetClientInfo().repeatable) { - mission->Accept(); - } + if (mission != nullptr) { + if (mission->GetClientInfo().repeatable) { + mission->Accept(); + if (mission->IsMission()) mission->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); + } - return; - } + return; + } - mission = new Mission(this, missionId); + mission = new Mission(this, missionId); - mission->Accept(); + if (mission->IsMission()) mission->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); - this->m_Missions.insert_or_assign(missionId, mission); + mission->Accept(); - if (missionId == 1728) { - //Needs to send a mail + this->m_Missions.insert_or_assign(missionId, mission); - auto address = m_Parent->GetSystemAddress(); + if (missionId == 1728) { + //Needs to send a mail - Mail::HandleNotificationRequest(address, m_Parent->GetObjectID()); - } + auto address = m_Parent->GetSystemAddress(); + + Mail::HandleNotificationRequest(address, m_Parent->GetObjectID()); + } } void MissionComponent::CompleteMission(const uint32_t missionId, const bool skipChecks, const bool yieldRewards) { - // Get the mission first - auto* mission = this->GetMission(missionId); + // Get the mission first + auto* mission = this->GetMission(missionId); - if (mission == nullptr) { - AcceptMission(missionId, skipChecks); + if (mission == nullptr) { + AcceptMission(missionId, skipChecks); - mission = this->GetMission(missionId); + mission = this->GetMission(missionId); - if (mission == nullptr) { - return; - } - } + if (mission == nullptr) { + return; + } + } - //If this mission is not repeatable, and already completed, we stop here. - if (mission->IsComplete() && !mission->IsRepeatable()) { - return; - } + //If this mission is not repeatable, and already completed, we stop here. + if (mission->IsComplete() && !mission->IsRepeatable()) { + return; + } - mission->Complete(yieldRewards); + mission->Complete(yieldRewards); } void MissionComponent::RemoveMission(uint32_t missionId) { - auto* mission = this->GetMission(missionId); + auto* mission = this->GetMission(missionId); - if (mission == nullptr) { - return; - } + if (mission == nullptr) { + return; + } - delete mission; + delete mission; - m_Missions.erase(missionId); + m_Missions.erase(missionId); } -void MissionComponent::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) { - for (const auto& pair : m_Missions) { - auto* mission = pair.second; +void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) { + for (const auto& pair : m_Missions) { + auto* mission = pair.second; - if (mission->IsAchievement() && ignoreAchievements) continue; + if (mission->IsAchievement() && ignoreAchievements) continue; - if (mission->IsComplete()) continue; + if (mission->IsComplete()) continue; - mission->Progress(type, value, associate, targets, count); - } + mission->Progress(type, value, associate, targets, count); + } - if (count > 0 && !ignoreAchievements) { - LookForAchievements(type, value, true, associate, targets, count); - } + if (count > 0 && !ignoreAchievements) { + LookForAchievements(type, value, true, associate, targets, count); + } } void MissionComponent::ForceProgress(const uint32_t missionId, const uint32_t taskId, const int32_t value, const bool acceptMission) { - auto* mission = GetMission(missionId); + auto* mission = GetMission(missionId); - if (mission == nullptr) { - if (!acceptMission) { - return; - } + if (mission == nullptr) { + if (!acceptMission) { + return; + } - AcceptMission(missionId); + AcceptMission(missionId); - mission = GetMission(missionId); + mission = GetMission(missionId); - if (mission == nullptr) { - return; - } - } + if (mission == nullptr) { + return; + } + } - for (auto* element : mission->GetTasks()) { - if (element->GetClientInfo().uid != taskId) continue; + for (auto* element : mission->GetTasks()) { + if (element->GetClientInfo().uid != taskId) continue; - element->AddProgress(value); - } + element->AddProgress(value); + } - if (!mission->IsComplete()) { - mission->CheckCompletion(); - } + if (!mission->IsComplete()) { + mission->CheckCompletion(); + } } void MissionComponent::ForceProgressTaskType(const uint32_t missionId, const uint32_t taskType, const int32_t value, const bool acceptMission) { - auto* mission = GetMission(missionId); + auto* mission = GetMission(missionId); - if (mission == nullptr) { - if (!acceptMission) { - return; - } + if (mission == nullptr) { + if (!acceptMission) { + return; + } - CDMissions missionInfo; + CDMissions missionInfo; - if (!GetMissionInfo(missionId, missionInfo)) { - return; - } + if (!GetMissionInfo(missionId, missionInfo)) { + return; + } - if (missionInfo.isMission) { - return; - } + if (missionInfo.isMission) { + return; + } - AcceptMission(missionId); + AcceptMission(missionId); - mission = GetMission(missionId); + mission = GetMission(missionId); - if (mission == nullptr) { - return; - } - } + if (mission == nullptr) { + return; + } + } - for (auto* element : mission->GetTasks()) { - if (element->GetType() != static_cast(taskType)) continue; + for (auto* element : mission->GetTasks()) { + if (element->GetType() != static_cast(taskType)) continue; - element->AddProgress(value); - } + element->AddProgress(value); + } - if (!mission->IsComplete()) { - mission->CheckCompletion(); - } + if (!mission->IsComplete()) { + mission->CheckCompletion(); + } } -void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission) -{ - auto* mission = GetMission(missionId); +void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission) { + auto* mission = GetMission(missionId); - if (mission == nullptr) { - if (!acceptMission) { - return; - } + if (mission == nullptr) { + if (!acceptMission) { + return; + } - CDMissions missionInfo; + CDMissions missionInfo; - if (!GetMissionInfo(missionId, missionInfo)) { - return; - } + if (!GetMissionInfo(missionId, missionInfo)) { + return; + } - if (missionInfo.isMission) { - return; - } + if (missionInfo.isMission) { + return; + } - AcceptMission(missionId); + AcceptMission(missionId); - mission = GetMission(missionId); + mission = GetMission(missionId); - if (mission == nullptr) { - return; - } - } + if (mission == nullptr) { + return; + } + } - for (auto* element : mission->GetTasks()) { - if (element->GetType() != static_cast(taskType) || !element->InAllTargets(value)) continue; + for (auto* element : mission->GetTasks()) { + if (element->GetType() != static_cast(taskType) || !element->InAllTargets(value)) continue; - element->AddProgress(1); - } + element->AddProgress(1); + } - if (!mission->IsComplete()) { - mission->CheckCompletion(); - } + if (!mission->IsComplete()) { + mission->CheckCompletion(); + } } bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) { - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionsTable = CDClientManager::Instance().GetTable(); - const auto missions = missionsTable->Query([=](const CDMissions& entry) { - return entry.id == static_cast(missionId); - }); + const auto missions = missionsTable->Query([=](const CDMissions& entry) { + return entry.id == static_cast(missionId); + }); - if (missions.empty()) { - return false; - } + if (missions.empty()) { + return false; + } - result = missions[0]; + result = missions[0]; - return true; + return true; } #define MISSION_NEW_METHOD -bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) { +bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) { #ifdef MISSION_NEW_METHOD - // Query for achievments, using the cache - const auto& result = QueryAchievements(type, value, targets); + // Query for achievments, using the cache + const auto& result = QueryAchievements(type, value, targets); - bool any = false; + bool any = false; - for (const uint32_t missionID : result) { - // Check if we already have this achievement - if (GetMission(missionID) != nullptr) { - continue; - } + for (const uint32_t missionID : result) { + // Check if we already have this achievement + if (GetMission(missionID) != nullptr) { + continue; + } - // Check if we can accept this achievement - if (!MissionPrerequisites::CanAccept(missionID, m_Missions)) { - continue; - } + // Check if we can accept this achievement + if (!MissionPrerequisites::CanAccept(missionID, m_Missions)) { + continue; + } - // Instantiate new mission and accept it - auto* instance = new Mission(this, missionID); + // Instantiate new mission and accept it + auto* instance = new Mission(this, missionID); - m_Missions.insert_or_assign(missionID, instance); + m_Missions.insert_or_assign(missionID, instance); - instance->Accept(); + if (instance->IsMission()) instance->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); - any = true; + instance->Accept(); - if (progress) { - // Progress mission to bring it up to speed - instance->Progress(type, value, associate, targets, count); - } - } + any = true; - return any; + if (progress) { + // Progress mission to bring it up to speed + instance->Progress(type, value, associate, targets, count); + } + } + + return any; #else - auto* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionTasksTable = CDClientManager::Instance().GetTable(); + auto* missionsTable = CDClientManager::Instance().GetTable(); - auto tasks = missionTasksTable->Query([=](const CDMissionTasks& entry) { - return entry.taskType == static_cast(type); - }); + auto tasks = missionTasksTable->Query([=](const CDMissionTasks& entry) { + return entry.taskType == static_cast(type); + }); - auto any = false; + auto any = false; - for (const auto& task : tasks) { - if (GetMission(task.id) != nullptr) { - continue; - } + for (const auto& task : tasks) { + if (GetMission(task.id) != nullptr) { + continue; + } - const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { - return entry.id == static_cast(task.id) && !entry.isMission; - }); + const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { + return entry.id == static_cast(task.id) && !entry.isMission; + }); - if (missionEntries.empty()) { - continue; - } + if (missionEntries.empty()) { + continue; + } - const auto mission = missionEntries[0]; + const auto mission = missionEntries[0]; - if (mission.isMission || !MissionPrerequisites::CanAccept(mission.id, m_Missions)) { - continue; - } + if (mission.isMission || !MissionPrerequisites::CanAccept(mission.id, m_Missions)) { + continue; + } - if (task.target != value && task.targetGroup != targets) { - auto stream = std::istringstream(task.targetGroup); - std::string token; + if (task.target != value && task.targetGroup != targets) { + auto stream = std::istringstream(task.targetGroup); + std::string token; - auto found = false; + auto found = false; - while (std::getline(stream, token, ',')) { - try { - const auto target = std::stoul(token); + while (std::getline(stream, token, ',')) { + try { + const auto target = std::stoul(token); - found = target == value; + found = target == value; - if (found) { - break; - } - } - catch (std::invalid_argument& exception) { - Game::logger->Log("MissionComponent", "Failed to parse target (%s): (%s)!\n", token.c_str(), exception.what()); - } - } + if (found) { + break; + } + } catch (std::invalid_argument& exception) { + Game::logger->Log("MissionComponent", "Failed to parse target (%s): (%s)!", token.c_str(), exception.what()); + } + } - if (!found) { - continue; - } - } + if (!found) { + continue; + } + } - auto* instance = new Mission(this, mission.id); + auto* instance = new Mission(this, mission.id); - m_Missions.insert_or_assign(mission.id, instance); + m_Missions.insert_or_assign(mission.id, instance); - instance->Accept(); + if (instance->IsMission()) instance->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); - any = true; + instance->Accept(); - if (progress) { - instance->Progress(type, value, associate, targets, count); - } - } + any = true; - return any; + if (progress) { + instance->Progress(type, value, associate, targets, count); + } + } + + return any; #endif } -const std::vector& MissionComponent::QueryAchievements(MissionTaskType type, int32_t value, const std::string targets) { - // Create a hash which represent this query for achievements - size_t hash = 0; - GeneralUtils::hash_combine(hash, type); - GeneralUtils::hash_combine(hash, value); - GeneralUtils::hash_combine(hash, targets); +const std::vector& MissionComponent::QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets) { + // Create a hash which represent this query for achievements + AchievementCacheKey toFind; + toFind.SetType(type); + toFind.SetValue(value); + toFind.SetTargets(targets); - const std::unordered_map>::iterator& iter = m_AchievementCache.find(hash); + const auto& iter = m_AchievementCache.find(toFind); - // Check if this query is cached - if (iter != m_AchievementCache.end()) { - return iter->second; - } + // Check if this query is cached + if (iter != m_AchievementCache.end()) { + return iter->second; + } - // Find relevent tables - auto* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + // Find relevent tables + auto* missionTasksTable = CDClientManager::Instance().GetTable(); + auto* missionsTable = CDClientManager::Instance().GetTable(); - std::vector result; + std::vector result; - // Loop through all mission tasks, might cache this task check later - for (const auto& task : missionTasksTable->GetEntries()) { - if (task.taskType != static_cast(type)) { - continue; - } + // Loop through all mission tasks, might cache this task check later + for (const auto& task : missionTasksTable->GetEntries()) { + if (task.taskType != static_cast(type)) { + continue; + } - // Seek the assosicated mission - auto foundMission = false; + // Seek the assosicated mission + auto foundMission = false; - const auto& mission = missionsTable->GetByMissionID(task.id, foundMission); + const auto& mission = missionsTable->GetByMissionID(task.id, foundMission); - if (!foundMission || mission.isMission) { - continue; - } + if (!foundMission || mission.isMission) { + continue; + } - // Compare the easy values - if (task.target == value || task.targetGroup == targets) { - result.push_back(mission.id); + // Compare the easy values + if (task.target == value || task.targetGroup == targets) { + result.push_back(mission.id); - continue; - } + continue; + } - // Compare the target group, array separated by ',' - auto stream = std::istringstream(task.targetGroup); - std::string token; + // Compare the target group, array separated by ',' + auto stream = std::istringstream(task.targetGroup); + std::string token; - while (std::getline(stream, token, ',')) { - try { - if (std::stoi(token) == value) { - result.push_back(mission.id); + while (std::getline(stream, token, ',')) { + try { + if (std::stoi(token) == value) { + result.push_back(mission.id); - continue; - } - } - catch (std::invalid_argument& exception) { - // Ignored - } - } - } - - // Insert into cache - m_AchievementCache.insert_or_assign(hash, result); - - return m_AchievementCache.find(hash)->second; + continue; + } + } catch (std::invalid_argument& exception) { + // Ignored + } + } + } + // Insert into cache + m_AchievementCache.insert_or_assign(toFind, result); + return m_AchievementCache.find(toFind)->second; } bool MissionComponent::RequiresItem(const LOT lot) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT type FROM Objects WHERE id = ?;"); - query.bind(1, (int) lot); + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT type FROM Objects WHERE id = ?;"); + query.bind(1, (int)lot); - auto result = query.execQuery(); + auto result = query.execQuery(); - if (result.eof()) { - return false; - } + if (result.eof()) { + return false; + } - if (!result.fieldIsNull(0)) { - const auto type = std::string(result.getStringField(0)); + if (!result.fieldIsNull(0)) { + const auto type = std::string(result.getStringField(0)); - result.finalize(); + result.finalize(); - if (type == "Powerup") { - return true; - } - } + if (type == "Powerup") { + return true; + } + } - result.finalize(); - - for (const auto& pair : m_Missions) { - auto* mission = pair.second; + result.finalize(); - if (mission->IsComplete()) { - continue; - } + for (const auto& pair : m_Missions) { + auto* mission = pair.second; - for (auto* task : mission->GetTasks()) { - if (task->IsComplete() || task->GetType() != MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { - continue; - } + if (mission->IsComplete()) { + continue; + } - if (!task->InAllTargets(lot)) { - continue; - } + for (auto* task : mission->GetTasks()) { + if (task->IsComplete() || task->GetType() != eMissionTaskType::GATHER) { + continue; + } - return true; - } - } + if (!task->InAllTargets(lot)) { + continue; + } - const auto required = LookForAchievements(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, false); + return true; + } + } - return required; + const auto required = LookForAchievements(eMissionTaskType::GATHER, lot, false); + + return required; } void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; + if (doc == nullptr) return; - auto* mis = doc->FirstChildElement("obj")->FirstChildElement("mis"); + auto* mis = doc->FirstChildElement("obj")->FirstChildElement("mis"); - if (mis == nullptr) return; + if (mis == nullptr) return; - auto* cur = mis->FirstChildElement("cur"); - auto* done = mis->FirstChildElement("done"); + auto* cur = mis->FirstChildElement("cur"); + auto* done = mis->FirstChildElement("done"); - auto* doneM = done->FirstChildElement(); + auto* doneM = done->FirstChildElement(); - while (doneM) { - int missionId; + while (doneM) { + int missionId; - doneM->QueryAttribute("id", &missionId); + doneM->QueryAttribute("id", &missionId); - auto* mission = new Mission(this, missionId); + auto* mission = new Mission(this, missionId); - mission->LoadFromXml(doneM); + mission->LoadFromXml(doneM); - doneM = doneM->NextSiblingElement(); + doneM = doneM->NextSiblingElement(); - m_Missions.insert_or_assign(missionId, mission); - } + m_Missions.insert_or_assign(missionId, mission); + } - auto* currentM = cur->FirstChildElement(); + auto* currentM = cur->FirstChildElement(); - while (currentM) { - int missionId; + uint32_t missionOrder{}; + while (currentM) { + int missionId; - currentM->QueryAttribute("id", &missionId); + currentM->QueryAttribute("id", &missionId); - auto* mission = new Mission(this, missionId); + auto* mission = new Mission(this, missionId); - mission->LoadFromXml(currentM); + mission->LoadFromXml(currentM); - currentM = currentM->NextSiblingElement(); + if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) { + mission->SetUniqueMissionOrderID(missionOrder); + if (missionOrder > m_LastUsedMissionOrderUID) m_LastUsedMissionOrderUID = missionOrder; + } - m_Missions.insert_or_assign(missionId, mission); - } + currentM = currentM->NextSiblingElement(); + + m_Missions.insert_or_assign(missionId, mission); + } } void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; + if (doc == nullptr) return; - auto shouldInsertMis = false; + auto shouldInsertMis = false; - auto* obj = doc->FirstChildElement("obj"); + auto* obj = doc->FirstChildElement("obj"); - auto* mis = obj->FirstChildElement("mis"); + auto* mis = obj->FirstChildElement("mis"); - if (mis == nullptr) { - mis = doc->NewElement("mis"); + if (mis == nullptr) { + mis = doc->NewElement("mis"); - shouldInsertMis = true; - } + shouldInsertMis = true; + } - mis->DeleteChildren(); + mis->DeleteChildren(); - auto* done = doc->NewElement("done"); - auto* cur = doc->NewElement("cur"); + auto* done = doc->NewElement("done"); + auto* cur = doc->NewElement("cur"); - for (const auto& pair : m_Missions) { - auto* mission = pair.second; + for (const auto& pair : m_Missions) { + auto* mission = pair.second; - if (mission) { - const auto complete = mission->IsComplete(); + if (mission) { + const auto complete = mission->IsComplete(); - if (complete) { - auto* m = doc->NewElement("m"); + auto* m = doc->NewElement("m"); - mission->UpdateXml(m); + if (complete) { + mission->UpdateXml(m); - done->LinkEndChild(m); + done->LinkEndChild(m); - continue; - } + continue; + } + if (mission->IsMission()) m->SetAttribute("o", mission->GetUniqueMissionOrderID()); - auto* m = doc->NewElement("m"); + mission->UpdateXml(m); - mission->UpdateXml(m); + cur->LinkEndChild(m); + } + } - cur->LinkEndChild(m); - } - } + mis->InsertFirstChild(done); + mis->InsertEndChild(cur); - mis->InsertFirstChild(done); - mis->InsertEndChild(cur); - - if (shouldInsertMis) { - obj->LinkEndChild(mis); - } + if (shouldInsertMis) { + obj->LinkEndChild(mis); + } } -void MissionComponent::AddCollectible(int32_t collectibleID) -{ - // Check if this collectible is already in the list - if (HasCollectible(collectibleID)) { - return; - } +void MissionComponent::AddCollectible(int32_t collectibleID) { + // Check if this collectible is already in the list + if (HasCollectible(collectibleID)) { + return; + } - m_Collectibles.push_back(collectibleID); + m_Collectibles.push_back(collectibleID); } -bool MissionComponent::HasCollectible(int32_t collectibleID) -{ - return std::find(m_Collectibles.begin(), m_Collectibles.end(), collectibleID) != m_Collectibles.end(); +bool MissionComponent::HasCollectible(int32_t collectibleID) { + return std::find(m_Collectibles.begin(), m_Collectibles.end(), collectibleID) != m_Collectibles.end(); } -bool MissionComponent::HasMission(uint32_t missionId) -{ - return GetMission(missionId) != nullptr; -} \ No newline at end of file +bool MissionComponent::HasMission(uint32_t missionId) { + return GetMission(missionId) != nullptr; +} diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index 13a812d2..eeaaa726 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -16,183 +16,193 @@ #include "CDClientManager.h" #include "CDMissionsTable.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for - * progression of each of the mission task types (see MissionTaskType). - */ +class AchievementCacheKey; + + /** + * The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for + * progression of each of the mission task types (see eMissionTaskType). + */ class MissionComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MISSION; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION; explicit MissionComponent(Entity* parent); - ~MissionComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + ~MissionComponent() override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument* doc) override; - /** - * Returns all the missions for this entity, mapped by mission ID - * @return the missions for this entity, mapped by mission ID - */ - const std::unordered_map& GetMissions() const; + /** + * Returns all the missions for this entity, mapped by mission ID + * @return the missions for this entity, mapped by mission ID + */ + const std::unordered_map& GetMissions() const; - /** - * Returns the mission for the given mission ID, if it exists - * @param missionId the id of the mission to get - * @return the mission for the given mission ID - */ - Mission* GetMission(uint32_t missionId) const; + /** + * Returns the mission for the given mission ID, if it exists + * @param missionId the id of the mission to get + * @return the mission for the given mission ID + */ + Mission* GetMission(uint32_t missionId) const; - /** - * Returns the current state of the entities progression for the mission of the specified ID - * @param missionId the ID of the mission to get the mission state for - * @return the mission state of the mission specified by the ID - */ - MissionState GetMissionState(uint32_t missionId) const; + /** + * Returns the current state of the entities progression for the mission of the specified ID + * @param missionId the ID of the mission to get the mission state for + * @return the mission state of the mission specified by the ID + */ + eMissionState GetMissionState(uint32_t missionId) const; - /** - * Checks if the entity has all the requirements for accepting the mission specified by the ID. - * @param missionId the mission ID to check for if the character may accept it - * @return whether this entity can accept the mission represented by the given mission ID - */ - bool CanAccept(uint32_t missionId) const; + /** + * Checks if the entity has all the requirements for accepting the mission specified by the ID. + * @param missionId the mission ID to check for if the character may accept it + * @return whether this entity can accept the mission represented by the given mission ID + */ + bool CanAccept(uint32_t missionId) const; - /** - * Accepts the mission specified by the ID, if the entity may accept it. Also stores it in the mission inventory. - * @param missionId the ID of the mission to accept - * @param skipChecks skips the checks for the mission prerequisites - */ - void AcceptMission(uint32_t missionId, bool skipChecks = false); + /** + * Accepts the mission specified by the ID, if the entity may accept it. Also stores it in the mission inventory. + * @param missionId the ID of the mission to accept + * @param skipChecks skips the checks for the mission prerequisites + */ + void AcceptMission(uint32_t missionId, bool skipChecks = false); - /** - * Completes the mission specified by the given ID, if the entity has fulfilled all progress requirements. - * @param missionId the ID of the mission to complete - * @param skipChecks skips the checks for having completed all of the mission tasks - * @param yieldRewards whether to yield mission rewards, currently unused - */ - void CompleteMission(uint32_t missionId, bool skipChecks = false, bool yieldRewards = true); + /** + * Completes the mission specified by the given ID, if the entity has fulfilled all progress requirements. + * @param missionId the ID of the mission to complete + * @param skipChecks skips the checks for having completed all of the mission tasks + * @param yieldRewards whether to yield mission rewards, currently unused + */ + void CompleteMission(uint32_t missionId, bool skipChecks = false, bool yieldRewards = true); - /** - * Removes the mission from the entities' mission chain. Not used for normal gameplay but useful for debugging. - * @param missionId the ID of the mission to remove - */ - void RemoveMission(uint32_t missionId); + /** + * Removes the mission from the entities' mission chain. Not used for normal gameplay but useful for debugging. + * @param missionId the ID of the mission to remove + */ + void RemoveMission(uint32_t missionId); - /** - * Attempts to progress mission tasks for a given type using parameters to progress. Note that this function is - * very abstract and different mission tasks require different combinations of parameters. This also progresses - * achievements, which are basically just missions with the isMission flag set to false. - * @param type the type of the mission task to try and progress with - * @param value the value to progress with, could be a LOT for item collection for example - * @param associate an associated entity for the progression, might be an activity host for example - * @param targets optionally multiple target values that could exist for the mission that we wish to progress - * @param count the number to progress by, for example the number of items - * @param ignoreAchievements do not progress achievements - */ - void Progress(MissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false); + /** + * Attempts to progress mission tasks for a given type using parameters to progress. Note that this function is + * very abstract and different mission tasks require different combinations of parameters. This also progresses + * achievements, which are basically just missions with the isMission flag set to false. + * @param type the type of the mission task to try and progress with + * @param value the value to progress with, could be a LOT for item collection for example + * @param associate an associated entity for the progression, might be an activity host for example + * @param targets optionally multiple target values that could exist for the mission that we wish to progress + * @param count the number to progress by, for example the number of items + * @param ignoreAchievements do not progress achievements + */ + void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false); - /** - * Forces progression for a mission and task, ignoring checks - * @param missionId the mission ID to try and progress - * @param taskId the task ID of the task belonging to the mission trying to progress - * @param value the value to progress with - * @param acceptMission accept the mission if it was not already accepted - */ - void ForceProgress(uint32_t missionId, uint32_t taskId, int32_t value, bool acceptMission = true); + /** + * Forces progression for a mission and task, ignoring checks + * @param missionId the mission ID to try and progress + * @param taskId the task ID of the task belonging to the mission trying to progress + * @param value the value to progress with + * @param acceptMission accept the mission if it was not already accepted + */ + void ForceProgress(uint32_t missionId, uint32_t taskId, int32_t value, bool acceptMission = true); - /** - * Forces progress for all tasks of a certain type that belong to the same mission - * @param missionId the mission to progress - * @param taskType the task tyoe to progress - * @param value the value to progress with - * @param acceptMission accept the mission if it wasn't already - */ - void ForceProgressTaskType(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); + /** + * Forces progress for all tasks of a certain type that belong to the same mission + * @param missionId the mission to progress + * @param taskType the task tyoe to progress + * @param value the value to progress with + * @param acceptMission accept the mission if it wasn't already + */ + void ForceProgressTaskType(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); - /** - * Force progresses by checking the value and progressing by 1 - * @param missionId the mission to progress - * @param taskType the task to progress for - * @param value the value to check the mission values before progressing - * @param acceptMission accept the mission if it wasn't already - */ - void ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); + /** + * Force progresses by checking the value and progressing by 1 + * @param missionId the mission to progress + * @param taskType the task to progress for + * @param value the value to check the mission values before progressing + * @param acceptMission accept the mission if it wasn't already + */ + void ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); - /** - * Returns client database mission information for a mission - * @param missionId the ID of the mission to get the info for - * @param result the result to store the information in - * @return true if the information was succesfully retrieved, false otherwise - */ - bool GetMissionInfo(uint32_t missionId, CDMissions& result); + /** + * Returns client database mission information for a mission + * @param missionId the ID of the mission to get the info for + * @param result the result to store the information in + * @return true if the information was succesfully retrieved, false otherwise + */ + bool GetMissionInfo(uint32_t missionId, CDMissions& result); - /** - * Checks if there's any achievements we might be able to accept for the given parameters - * @param type the task type for tasks in the achievement that we wish to progress - * @param value the value to progress by - * @param progress if we can accept the mission, this will apply the progression - * @param associate optional associate related to mission progression - * @param targets optional multiple targets related to mission progression - * @param count the number of values to progress by (differs by task type) - * @return true if a achievement was accepted, false otherwise - */ - bool LookForAchievements(MissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1); + /** + * Checks if there's any achievements we might be able to accept for the given parameters + * @param type the task type for tasks in the achievement that we wish to progress + * @param value the value to progress by + * @param progress if we can accept the mission, this will apply the progression + * @param associate optional associate related to mission progression + * @param targets optional multiple targets related to mission progression + * @param count the number of values to progress by (differs by task type) + * @return true if a achievement was accepted, false otherwise + */ + bool LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1); - /** - * Checks if there's a mission active that requires the collection of the specified LOT - * @param lot the LOT to check for - * @return if there's a mission active that requires the collection of the specified LOT - */ - bool RequiresItem(LOT lot); + /** + * Checks if there's a mission active that requires the collection of the specified LOT + * @param lot the LOT to check for + * @return if there's a mission active that requires the collection of the specified LOT + */ + bool RequiresItem(LOT lot); - /** - * Collects a collectable for the entity, unrendering it for the entity - * @param collectibleID the ID of the collectable to add - */ - void AddCollectible(int32_t collectibleID); + /** + * Collects a collectable for the entity, unrendering it for the entity + * @param collectibleID the ID of the collectable to add + */ + void AddCollectible(int32_t collectibleID); - /** - * Checks if the entity already has a collectible of the specified ID - * @param collectibleID the ID of the collectible to check - * @return if the entity already has a collectible of the specified ID - */ - bool HasCollectible(int32_t collectibleID); + /** + * Checks if the entity already has a collectible of the specified ID + * @param collectibleID the ID of the collectible to check + * @return if the entity already has a collectible of the specified ID + */ + bool HasCollectible(int32_t collectibleID); + + /** + * Checks if the entity has a certain mission in its inventory + * @param missionId the ID of the mission to check + * @return if the entity has a certain mission in its inventory + */ + bool HasMission(uint32_t missionId); - /** - * Checks if the entity has a certain mission in its inventory - * @param missionId the ID of the mission to check - * @return if the entity has a certain mission in its inventory - */ - bool HasMission(uint32_t missionId); - private: - /** - * All the missions owned by this entity, mapped by mission ID - */ - std::unordered_map m_Missions; + /** + * All the missions owned by this entity, mapped by mission ID + */ + std::unordered_map m_Missions; - /** - * All the collectibles currently collected by the entity - */ - std::vector m_Collectibles; + /** + * All the collectibles currently collected by the entity + */ + std::vector m_Collectibles; - /** - * For the given parameters, finds the mission IDs of the achievements that may be unlcoked - * @param type the mission task type to try and progress - * @param value the value to try and progress with - * @param targets optional targets to progress with - * @return list of mission IDs (achievements) that can be progressed for the given parameters - */ - static const std::vector& QueryAchievements(MissionTaskType type, int32_t value, const std::string targets); + /** + * For the given parameters, finds the mission IDs of the achievements that may be unlcoked + * @param type the mission task type to try and progress + * @param value the value to try and progress with + * @param targets optional targets to progress with + * @return list of mission IDs (achievements) that can be progressed for the given parameters + */ + static const std::vector& QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets); - /** - * As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a - * combination of tasks and values, so that they can be easily re-queried later - */ - static std::unordered_map> m_AchievementCache; + /** + * As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a + * combination of tasks and values, so that they can be easily re-queried later + */ + static std::unordered_map> m_AchievementCache; + + /** + * Order of missions in the UI. This value is incremented by 1 + * for each mission the Entity that owns this component accepts. + * In live this value started at 745. + */ + uint32_t m_LastUsedMissionOrderUID = 746U; }; #endif // MISSIONCOMPONENT_H diff --git a/dGame/dComponents/MissionOfferComponent.cpp b/dGame/dComponents/MissionOfferComponent.cpp index 8a9abb57..e4c94ebd 100644 --- a/dGame/dComponents/MissionOfferComponent.cpp +++ b/dGame/dComponents/MissionOfferComponent.cpp @@ -14,225 +14,197 @@ #include "dLogger.h" #include "Game.h" #include "MissionPrerequisites.h" +#include "eMissionState.h" -OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) -{ - this->missionId = missionId; - this->offersMission = offersMission; - this->acceptsMission = acceptsMission; +#include "CDComponentsRegistryTable.h" + +OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { + this->missionId = missionId; + this->offersMission = offersMission; + this->acceptsMission = acceptsMission; } -uint32_t OfferedMission::GetMissionId() const -{ - return this->missionId; +uint32_t OfferedMission::GetMissionId() const { + return this->missionId; } -bool OfferedMission::GetOfferMission() const -{ - return this->offersMission; +bool OfferedMission::GetOfferMission() const { + return this->offersMission; } -bool OfferedMission::GetAcceptMission() const -{ - return this->acceptsMission; +bool OfferedMission::GetAcceptMission() const { + return this->acceptsMission; } //------------------------ MissionOfferComponent below ------------------------ MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); - auto value = compRegistryTable->GetByIDAndType(parentLot, COMPONENT_TYPE_MISSION_OFFER, -1); + auto value = compRegistryTable->GetByIDAndType(parentLot, eReplicaComponentType::MISSION_OFFER, -1); - if (value != -1) { - const uint32_t componentId = value; + if (value != -1) { + const uint32_t componentId = value; - // Now lookup the missions in the MissionNPCComponent table - auto* missionNpcComponentTable = CDClientManager::Instance()->GetTable("MissionNPCComponent"); - - auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) - { - return entry.id == static_cast(componentId); - }); + // Now lookup the missions in the MissionNPCComponent table + auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); - for (auto& mission : missions) - { - auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission); - this->offeredMissions.push_back(offeredMission); - } - } + auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { + return entry.id == static_cast(componentId); + }); + + for (auto& mission : missions) { + auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission); + this->offeredMissions.push_back(offeredMission); + } + } } -MissionOfferComponent::~MissionOfferComponent() -{ - for (auto* mission : this->offeredMissions) { - if (mission) { - delete mission; - mission = nullptr; - } - } - - offeredMissions.clear(); +MissionOfferComponent::~MissionOfferComponent() { + for (auto* mission : this->offeredMissions) { + if (mission) { + delete mission; + mission = nullptr; + } + } + + offeredMissions.clear(); } -void MissionOfferComponent::OnUse(Entity* originator) -{ - OfferMissions(originator); +void MissionOfferComponent::OnUse(Entity* originator) { + OfferMissions(originator); } -void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) -{ - // First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity. - auto* missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - - if (!missionComponent) { - Game::logger->Log("MissionOfferComponent", "Unable to get mission component for Entity %llu\n", entity->GetObjectID()); - return; - } +void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) { + // First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity. + auto* missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); - std::vector offered {}; + if (!missionComponent) { + Game::logger->Log("MissionOfferComponent", "Unable to get mission component for Entity %llu", entity->GetObjectID()); + return; + } - CDMissions info {}; + std::vector offered{}; - if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) - { - return; - } + CDMissions info{}; - for (auto* offeredMission : this->offeredMissions) - { - if (specifiedMissionId > 0) - { - if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) - { - continue; - } - } + if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) { + return; + } - // First, check if we already have the mission - const auto missionId = offeredMission->GetMissionId(); + for (auto* offeredMission : this->offeredMissions) { + if (specifiedMissionId > 0) { + if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) { + continue; + } + } - auto* mission = missionComponent->GetMission(missionId); + // First, check if we already have the mission + const auto missionId = offeredMission->GetMissionId(); - if (mission != nullptr) - { - if (specifiedMissionId <= 0) - { - // Handles the odd case where the offer object should not display the mission again - if (!mission->IsComplete() && mission->GetClientInfo().offer_objectID == m_Parent->GetLOT() && mission->GetClientInfo().target_objectID != m_Parent->GetLOT() && mission->IsFetchMission()) - { - continue; - } - } + auto* mission = missionComponent->GetMission(missionId); - // We have the mission, if it is not complete, offer it - if (mission->IsActive() || mission->IsReadyToComplete()) - { - GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID()); + if (mission != nullptr) { + if (specifiedMissionId <= 0) { + // Handles the odd case where the offer object should not display the mission again + if (!mission->IsComplete() && mission->GetClientInfo().offer_objectID == m_Parent->GetLOT() && mission->GetClientInfo().target_objectID != m_Parent->GetLOT() && mission->IsFetchMission()) { + continue; + } + } - offered.push_back(missionId); + // We have the mission, if it is not complete, offer it + if (mission->IsActive() || mission->IsReadyToComplete()) { + GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID()); - continue; - } - } - - const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions()); + offered.push_back(missionId); - // Mission has not yet been accepted - check the prereqs - if (!canAccept) - continue; + continue; + } + } - if (!Mission::IsValidMission(missionId, info)) - { - continue; - } - - const auto& randomPool = info.randomPool; - const auto isRandom = info.isRandom; - - if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions. - { - continue; - } + const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions()); - if (isRandom && !randomPool.empty()) - { - std::istringstream stream(randomPool); - std::string token; + // Mission has not yet been accepted - check the prereqs + if (!canAccept) + continue; - std::vector randomMissionPool; - - while (std::getline(stream, token, ',')) - { - try - { - const auto value = std::stoul(token); + if (!Mission::IsValidMission(missionId, info)) { + continue; + } - randomMissionPool.push_back(value); - } - catch (std::invalid_argument& exception) - { - Game::logger->Log("MissionOfferComponent", "Failed to parse value (%s): (%s)!\n", token.c_str(), exception.what()); - } - } + const auto& randomPool = info.randomPool; + const auto isRandom = info.isRandom; - if (specifiedMissionId > 0) - { - const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId); + if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions. + { + continue; + } - if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) - { - GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_Parent->GetObjectID()); + if (isRandom && !randomPool.empty()) { + std::istringstream stream(randomPool); + std::string token; - return; - } - } + std::vector randomMissionPool; - std::vector canAcceptPool; + while (std::getline(stream, token, ',')) { + try { + const auto value = std::stoul(token); - for (const auto sample : randomMissionPool) - { - const auto state = missionComponent->GetMissionState(sample); - - if (state == MissionState::MISSION_STATE_ACTIVE || - state == MissionState::MISSION_STATE_COMPLETE_ACTIVE || - state == MissionState::MISSION_STATE_READY_TO_COMPLETE || - state == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE || - sample == specifiedMissionId) - { - mission = missionComponent->GetMission(sample); + randomMissionPool.push_back(value); + } catch (std::invalid_argument& exception) { + Game::logger->Log("MissionOfferComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what()); + } + } - if (mission == nullptr || mission->IsAchievement()) - { - continue; - } + if (specifiedMissionId > 0) { + const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId); - GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_Parent->GetObjectID()); + if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) { + GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_Parent->GetObjectID()); - canAcceptPool.clear(); - - break; - } - - if (std::find(offered.begin(), offered.end(), sample) == offered.end() && MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) - { - canAcceptPool.push_back(sample); - } - } + return; + } + } - // If the mission is already active or we already completed one of them today - if (canAcceptPool.empty()) - continue; + std::vector canAcceptPool; - const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; + for (const auto sample : randomMissionPool) { + const auto state = missionComponent->GetMissionState(sample); - GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_Parent->GetObjectID()); - } - else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) - { - GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID()); - } - } + if (state == eMissionState::ACTIVE || + state == eMissionState::COMPLETE_ACTIVE || + state == eMissionState::READY_TO_COMPLETE || + state == eMissionState::COMPLETE_READY_TO_COMPLETE || + sample == specifiedMissionId) { + mission = missionComponent->GetMission(sample); + + if (mission == nullptr || mission->IsAchievement()) { + continue; + } + + GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_Parent->GetObjectID()); + + canAcceptPool.clear(); + + break; + } + + if (std::find(offered.begin(), offered.end(), sample) == offered.end() && MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) { + canAcceptPool.push_back(sample); + } + } + + // If the mission is already active or we already completed one of them today + if (canAcceptPool.empty()) + continue; + + const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; + + GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_Parent->GetObjectID()); + } else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) { + GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID()); + } + } } diff --git a/dGame/dComponents/MissionOfferComponent.h b/dGame/dComponents/MissionOfferComponent.h index 6719810e..6e22ca05 100644 --- a/dGame/dComponents/MissionOfferComponent.h +++ b/dGame/dComponents/MissionOfferComponent.h @@ -10,6 +10,7 @@ #include "Component.h" #include #include +#include "eReplicaComponentType.h" class Entity; @@ -19,40 +20,40 @@ class Entity; struct OfferedMission { OfferedMission(uint32_t missionId, bool offersMission, bool acceptsMission); - /** - * Returns the ID of the mission - * @return the ID of the mission - */ - uint32_t GetMissionId() const; + /** + * Returns the ID of the mission + * @return the ID of the mission + */ + uint32_t GetMissionId() const; - /** - * Returns if this mission is offered by the entity - * @return true if this mission is offered by the entity, false otherwise - */ - bool GetOfferMission() const; + /** + * Returns if this mission is offered by the entity + * @return true if this mission is offered by the entity, false otherwise + */ + bool GetOfferMission() const; + + /** + * Returns if this mission may be accepted by the entity (currently unused) + * @return true if this mission may be accepted by the entity, false otherwise + */ + bool GetAcceptMission() const; - /** - * Returns if this mission may be accepted by the entity (currently unused) - * @return true if this mission may be accepted by the entity, false otherwise - */ - bool GetAcceptMission() const; - private: - /** - * The ID of the mission - */ - uint32_t missionId; + /** + * The ID of the mission + */ + uint32_t missionId; - /** - * Determines if the mission is offered by the entity - */ - bool offersMission; + /** + * Determines if the mission is offered by the entity + */ + bool offersMission; - /** - * Determines if the mission can be accepted by the entity - */ - bool acceptsMission; + /** + * Determines if the mission can be accepted by the entity + */ + bool acceptsMission; }; /** @@ -60,31 +61,31 @@ private: */ class MissionOfferComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MISSION_OFFER; - - MissionOfferComponent(Entity* parent, LOT parentLot); - ~MissionOfferComponent() override; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER; - /** - * Handles the OnUse event triggered by some entity, determines which missions to show based on what they may - * hand in now and what they may start based on their mission history. - * @param originator the entity that triggered the event - */ - void OnUse(Entity* originator) override; + MissionOfferComponent(Entity* parent, LOT parentLot); + ~MissionOfferComponent() override; - /** - * Offers all the missions an entity can accept to said entity - * @param entity the entity to offer missions to - * @param specifiedMissionId optional mission ID if you wish to offer a specific mission - */ - void OfferMissions(Entity* entity, uint32_t specifiedMissionId = 0); + /** + * Handles the OnUse event triggered by some entity, determines which missions to show based on what they may + * hand in now and what they may start based on their mission history. + * @param originator the entity that triggered the event + */ + void OnUse(Entity* originator) override; + + /** + * Offers all the missions an entity can accept to said entity + * @param entity the entity to offer missions to + * @param specifiedMissionId optional mission ID if you wish to offer a specific mission + */ + void OfferMissions(Entity* entity, uint32_t specifiedMissionId = 0); private: - /** - * The missions this entity has to offer - */ - std::vector offeredMissions; + /** + * The missions this entity has to offer + */ + std::vector offeredMissions; }; #endif // MISSIONOFFERCOMPONENT_H diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index bb8bdfe4..74f614d1 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -1,42 +1,31 @@ #include "ModelComponent.h" #include "Entity.h" -ModelComponent::ModelComponent(uint32_t componentID, Entity* parent) : Component(parent) -{ - m_Position = m_Parent->GetDefaultPosition(); - m_Rotation = m_Parent->GetDefaultRotation(); +ModelComponent::ModelComponent(Entity* parent) : Component(parent) { + m_OriginalPosition = m_Parent->GetDefaultPosition(); + m_OriginalRotation = m_Parent->GetDefaultRotation(); m_userModelID = m_Parent->GetVarAs(u"userModelID"); - - /* - for (auto set : m_Parent->GetInfo().settings) { - if (set && set->GetKey() == u"userModelID") { - m_userModelID = std::stoull(set->GetValueAsString()); - } - } - */ -} - -ModelComponent::~ModelComponent() { } void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - //item component: - outBitStream->Write1(); - outBitStream->Write(m_userModelID); - outBitStream->Write(0); - outBitStream->Write0(); - + // ItemComponent Serialization. Pets do not get this serialization. + if (!m_Parent->HasComponent(eReplicaComponentType::PET)) { + outBitStream->Write1(); + outBitStream->Write(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID()); + outBitStream->Write(0); + outBitStream->Write0(); + } + //actual model component: - outBitStream->Write1(); //yes we are writing model info - outBitStream->Write0(); //?? - outBitStream->Write(2); //model type, always 2 for BBB + outBitStream->Write1(); // Yes we are writing model info + outBitStream->Write0(); // Is pickable + outBitStream->Write(2); // Physics type + outBitStream->Write(m_OriginalPosition); // Original position + outBitStream->Write(m_OriginalRotation); // Original rotation - outBitStream->Write(m_Position); - outBitStream->Write(m_Rotation); - - outBitStream->Write1(); //second data flag, all unknown. Maybe skip? - outBitStream->Write(0); - outBitStream->Write1(); - outBitStream->Write0(); + outBitStream->Write1(); // We are writing behavior info + outBitStream->Write(0); // Number of behaviors + outBitStream->Write1(); // Is this model paused + if (bIsInitialUpdate) outBitStream->Write0(); // We are not writing model editing info } diff --git a/dGame/dComponents/ModelComponent.h b/dGame/dComponents/ModelComponent.h index 3b13bab8..b5224869 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -4,6 +4,7 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -12,51 +13,50 @@ class Entity; */ class ModelComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MODEL; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MODEL; - ModelComponent(uint32_t componentID, Entity* parent); - ~ModelComponent() override; + ModelComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the position of the model - * @return the position of the model - */ - NiPoint3& GetPosition() { return m_Position; } + /** + * Returns the original position of the model + * @return the original position of the model + */ + const NiPoint3& GetPosition() { return m_OriginalPosition; } - /** - * Sets the position of the model - * @param pos the position to set - */ - void SetPosition(const NiPoint3& pos) { m_Position = pos; } + /** + * Sets the original position of the model + * @param pos the original position to set + */ + void SetPosition(const NiPoint3& pos) { m_OriginalPosition = pos; } - /** - * Returns the rotation of the model - * @return the rotation of the model - */ - NiQuaternion& GetRotation() { return m_Rotation; } + /** + * Returns the original rotation of the model + * @return the original rotation of the model + */ + const NiQuaternion& GetRotation() { return m_OriginalRotation; } - /** - * Sets the rotation of the model - * @param rot the rotation to set - */ - void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; } + /** + * Sets the original rotation of the model + * @param rot the original rotation to set + */ + void SetRotation(const NiQuaternion& rot) { m_OriginalRotation = rot; } private: - /** - * The position of the model - */ - NiPoint3 m_Position; + /** + * The original position of the model + */ + NiPoint3 m_OriginalPosition; - /** - * The rotation of the model - */ - NiQuaternion m_Rotation; + /** + * The rotation original of the model + */ + NiQuaternion m_OriginalRotation; - /** - * The ID of the user that made the model - */ - LWOOBJID m_userModelID; -}; \ No newline at end of file + /** + * The ID of the user that made the model + */ + LWOOBJID m_userModelID; +}; diff --git a/dGame/dComponents/ModuleAssemblyComponent.cpp b/dGame/dComponents/ModuleAssemblyComponent.cpp index 0095b68f..8e197f0c 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.cpp +++ b/dGame/dComponents/ModuleAssemblyComponent.cpp @@ -1,84 +1,70 @@ #include "ModuleAssemblyComponent.h" -ModuleAssemblyComponent::ModuleAssemblyComponent(Entity* parent) : Component(parent) -{ - m_SubKey = LWOOBJID_EMPTY; - m_UseOptionalParts = false; - m_AssemblyPartsLOTs = u""; +ModuleAssemblyComponent::ModuleAssemblyComponent(Entity* parent) : Component(parent) { + m_SubKey = LWOOBJID_EMPTY; + m_UseOptionalParts = false; + m_AssemblyPartsLOTs = u""; } -ModuleAssemblyComponent::~ModuleAssemblyComponent() -{ - +ModuleAssemblyComponent::~ModuleAssemblyComponent() { + } -void ModuleAssemblyComponent::SetSubKey(LWOOBJID value) -{ - m_SubKey = value; +void ModuleAssemblyComponent::SetSubKey(LWOOBJID value) { + m_SubKey = value; } -LWOOBJID ModuleAssemblyComponent::GetSubKey() const -{ - return m_SubKey; +LWOOBJID ModuleAssemblyComponent::GetSubKey() const { + return m_SubKey; } -void ModuleAssemblyComponent::SetUseOptionalParts(bool value) -{ - m_UseOptionalParts = value; +void ModuleAssemblyComponent::SetUseOptionalParts(bool value) { + m_UseOptionalParts = value; } -bool ModuleAssemblyComponent::GetUseOptionalParts() const -{ - return m_UseOptionalParts; +bool ModuleAssemblyComponent::GetUseOptionalParts() const { + return m_UseOptionalParts; } -void ModuleAssemblyComponent::SetAssemblyPartsLOTs(const std::u16string& value) -{ - std::u16string val {}; +void ModuleAssemblyComponent::SetAssemblyPartsLOTs(const std::u16string& value) { + std::u16string val{}; - val.reserve(value.size() + 1); + val.reserve(value.size() + 1); - for (auto character : value) - { - if (character == '+') character = ';'; + for (auto character : value) { + if (character == '+') character = ';'; - val.push_back(character); - } + val.push_back(character); + } - val.push_back(';'); - - m_AssemblyPartsLOTs = val; + val.push_back(';'); + + m_AssemblyPartsLOTs = val; } -const std::u16string& ModuleAssemblyComponent::GetAssemblyPartsLOTs() const -{ - return m_AssemblyPartsLOTs; +const std::u16string& ModuleAssemblyComponent::GetAssemblyPartsLOTs() const { + return m_AssemblyPartsLOTs; } -void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - if (bIsInitialUpdate) - { - outBitStream->Write1(); +void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + if (bIsInitialUpdate) { + outBitStream->Write1(); - outBitStream->Write(m_SubKey != LWOOBJID_EMPTY); - if (m_SubKey != LWOOBJID_EMPTY) - { - outBitStream->Write(m_SubKey); - } + outBitStream->Write(m_SubKey != LWOOBJID_EMPTY); + if (m_SubKey != LWOOBJID_EMPTY) { + outBitStream->Write(m_SubKey); + } - outBitStream->Write(m_UseOptionalParts); + outBitStream->Write(m_UseOptionalParts); - outBitStream->Write(static_cast(m_AssemblyPartsLOTs.size())); - for (char16_t character : m_AssemblyPartsLOTs) - { - outBitStream->Write(character); - } - } + outBitStream->Write(static_cast(m_AssemblyPartsLOTs.size())); + for (char16_t character : m_AssemblyPartsLOTs) { + outBitStream->Write(character); + } + } } -void ModuleAssemblyComponent::Update(float deltaTime) -{ - +void ModuleAssemblyComponent::Update(float deltaTime) { + } diff --git a/dGame/dComponents/ModuleAssemblyComponent.h b/dGame/dComponents/ModuleAssemblyComponent.h index 7153f30b..39670c9a 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.h +++ b/dGame/dComponents/ModuleAssemblyComponent.h @@ -3,6 +3,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that belongs to an object that may be modularly built, like cars and rockets. Note that this is not the @@ -11,66 +12,66 @@ */ class ModuleAssemblyComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MODULE_ASSEMBLY; - - ModuleAssemblyComponent(Entity* MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); + static const eReplicaComponentType ComponentType = eReplicaComponentType::MODULE_ASSEMBLY; + + ModuleAssemblyComponent(Entity* parent); ~ModuleAssemblyComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Update(float deltaTime) override; - /** - * Sets the subkey of this entity - * @param value the subkey to set - */ - void SetSubKey(LWOOBJID value); + /** + * Sets the subkey of this entity + * @param value the subkey to set + */ + void SetSubKey(LWOOBJID value); - /** - * Returns the subkey for this entity - * @return the subkey for this entity - */ - LWOOBJID GetSubKey() const; + /** + * Returns the subkey for this entity + * @return the subkey for this entity + */ + LWOOBJID GetSubKey() const; - /** - * Sets the optional parts value - * @param value the value to set - */ - void SetUseOptionalParts(bool value); + /** + * Sets the optional parts value + * @param value the value to set + */ + void SetUseOptionalParts(bool value); - /** - * Returns the optional parts value - * @return the value to set - */ - bool GetUseOptionalParts() const; + /** + * Returns the optional parts value + * @return the value to set + */ + bool GetUseOptionalParts() const; - /** - * Sets the assembly part lots (the subsections of this modular build) - * @param value the assembly part lots to set - */ - void SetAssemblyPartsLOTs(const std::u16string& value); + /** + * Sets the assembly part lots (the subsections of this modular build) + * @param value the assembly part lots to set + */ + void SetAssemblyPartsLOTs(const std::u16string& value); - /** - * Returns the assembly part lots (the subsections of this modular build) - * @return - */ - const std::u16string& GetAssemblyPartsLOTs() const; + /** + * Returns the assembly part lots (the subsections of this modular build) + * @return + */ + const std::u16string& GetAssemblyPartsLOTs() const; private: - /** - * The sub key is the entity that this entity is an instance of. E.g. the item in the inventory. If a car for - * example is to be rendered, this sub key refers to the car item that was used to build this entity. - */ - LWOOBJID m_SubKey; + /** + * The sub key is the entity that this entity is an instance of. E.g. the item in the inventory. If a car for + * example is to be rendered, this sub key refers to the car item that was used to build this entity. + */ + LWOOBJID m_SubKey; - /** - * Whether to use optional parts, currently unused - */ - bool m_UseOptionalParts; + /** + * Whether to use optional parts, currently unused + */ + bool m_UseOptionalParts; - /** - * The sub items that this entity is made of - */ - std::u16string m_AssemblyPartsLOTs; + /** + * The sub items that this entity is made of + */ + std::u16string m_AssemblyPartsLOTs; }; diff --git a/dGame/dComponents/MovementAIComponent.cpp b/dGame/dComponents/MovementAIComponent.cpp index ff7c0cef..278e9106 100644 --- a/dGame/dComponents/MovementAIComponent.cpp +++ b/dGame/dComponents/MovementAIComponent.cpp @@ -1,4 +1,4 @@ -#include "MovementAIComponent.h" +#include "MovementAIComponent.h" #include #include @@ -9,6 +9,10 @@ #include "dpWorld.h" #include "EntityManager.h" #include "SimplePhysicsComponent.h" +#include "CDClientManager.h" + +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" std::map MovementAIComponent::m_PhysicsSpeedCache = {}; @@ -17,8 +21,8 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : m_Done = true; m_BaseCombatAI = nullptr; - - m_BaseCombatAI = reinterpret_cast(m_Parent->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + + m_BaseCombatAI = reinterpret_cast(m_Parent->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); //Try and fix the insane values: if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f; @@ -42,12 +46,11 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : MovementAIComponent::~MovementAIComponent() = default; void MovementAIComponent::Update(const float deltaTime) { - if (m_Interrupted) - { + if (m_Interrupted) { const auto source = GetCurrentWaypoint(); const auto speed = deltaTime * 2.5f; - + NiPoint3 velocity; velocity.x = (m_PullPoint.x - source.x) * speed; @@ -56,21 +59,19 @@ void MovementAIComponent::Update(const float deltaTime) { SetPosition(source + velocity); - if (Vector3::DistanceSquared(GetCurrentPosition(), m_PullPoint) < 2 * 2) - { + if (Vector3::DistanceSquared(GetCurrentPosition(), m_PullPoint) < 2 * 2) { m_Interrupted = false; } return; } - + if (AtFinalWaypoint()) // Are we done? { return; } - if (m_HaltDistance > 0) - { + if (m_HaltDistance > 0) { if (Vector3::DistanceSquared(ApproximateLocation(), GetDestination()) < m_HaltDistance * m_HaltDistance) // Prevent us from hugging the target { Stop(); @@ -79,12 +80,10 @@ void MovementAIComponent::Update(const float deltaTime) { } } - if (m_Timer > 0) - { + if (m_Timer > 0) { m_Timer -= deltaTime; - if (m_Timer > 0) - { + if (m_Timer > 0) { return; } @@ -92,29 +91,26 @@ void MovementAIComponent::Update(const float deltaTime) { } const auto source = GetCurrentWaypoint(); - + SetPosition(source); NiPoint3 velocity = NiPoint3::ZERO; - if (AdvanceWaypointIndex()) // Do we have another waypoint to seek? + if (m_Acceleration > 0 && m_BaseSpeed > 0 && AdvanceWaypointIndex()) // Do we have another waypoint to seek? { m_NextWaypoint = GetCurrentWaypoint(); - if (m_NextWaypoint == source) - { + if (m_NextWaypoint == source) { m_Timer = 0; goto nextAction; } - if (m_CurrentSpeed < m_Speed) - { + if (m_CurrentSpeed < m_Speed) { m_CurrentSpeed += m_Acceleration; } - if (m_CurrentSpeed > m_Speed) - { + if (m_CurrentSpeed > m_Speed) { m_CurrentSpeed = m_Speed; } @@ -125,8 +121,7 @@ void MovementAIComponent::Update(const float deltaTime) { // Normalize the vector const auto length = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z); - if (length > 0) - { + if (length > 0) { velocity.x = (delta.x / length) * speed; velocity.y = (delta.y / length) * speed; velocity.z = (delta.z / length) * speed; @@ -134,80 +129,66 @@ void MovementAIComponent::Update(const float deltaTime) { // Calclute the time it will take to reach the next waypoint with the current speed m_TotalTime = m_Timer = length / speed; - + SetRotation(NiQuaternion::LookAt(source, m_NextWaypoint)); - } - else - { + } else { // Check if there are more waypoints in the queue, if so set our next destination to the next waypoint - if (!m_Queue.empty()) - { + if (!m_Queue.empty()) { SetDestination(m_Queue.top()); m_Queue.pop(); - } - else - { + } else { // We have reached our final waypoint Stop(); return; } } - - nextAction: + +nextAction: SetVelocity(velocity); EntityManager::Instance()->SerializeEntity(m_Parent); } -const MovementAIInfo& MovementAIComponent::GetInfo() const -{ +const MovementAIInfo& MovementAIComponent::GetInfo() const { return m_Info; } -bool MovementAIComponent::AdvanceWaypointIndex() -{ - if (m_PathIndex >= m_CurrentPath.size()) - { +bool MovementAIComponent::AdvanceWaypointIndex() { + if (m_PathIndex >= m_CurrentPath.size()) { return false; } - + m_PathIndex++; return true; } -NiPoint3 MovementAIComponent::GetCurrentWaypoint() const -{ - if (m_PathIndex >= m_CurrentPath.size()) - { +NiPoint3 MovementAIComponent::GetCurrentWaypoint() const { + if (m_PathIndex >= m_CurrentPath.size()) { return GetCurrentPosition(); } return m_CurrentPath[m_PathIndex]; } -NiPoint3 MovementAIComponent::GetNextWaypoint() const -{ +NiPoint3 MovementAIComponent::GetNextWaypoint() const { return m_NextWaypoint; } -NiPoint3 MovementAIComponent::GetCurrentPosition() const -{ +NiPoint3 MovementAIComponent::GetCurrentPosition() const { return m_Parent->GetPosition(); } -NiPoint3 MovementAIComponent::ApproximateLocation() const -{ +NiPoint3 MovementAIComponent::ApproximateLocation() const { auto source = GetCurrentPosition(); - - if (m_Done) - { + + if (m_Done) { return source; } - + auto destination = m_NextWaypoint; auto factor = m_TotalTime > 0 ? (m_TotalTime - m_Timer) / m_TotalTime : 0; @@ -217,27 +198,23 @@ NiPoint3 MovementAIComponent::ApproximateLocation() const auto z = source.z + factor * (destination.z - source.z); NiPoint3 approximation = NiPoint3(x, y, z); - - if (dpWorld::Instance().IsLoaded()) - { - approximation.y = dpWorld::Instance().GetHeightAtPoint(approximation); + + if (dpWorld::Instance().IsLoaded()) { + approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation); } return approximation; } -bool MovementAIComponent::Warp(const NiPoint3& point) -{ +bool MovementAIComponent::Warp(const NiPoint3& point) { Stop(); - + NiPoint3 destination = point; - if (dpWorld::Instance().IsLoaded()) - { - destination.y = dpWorld::Instance().GetHeightAtPoint(point); + if (dpWorld::Instance().IsLoaded()) { + destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(point); - if (std::abs(destination.y - point.y) > 3) - { + if (std::abs(destination.y - point.y) > 3) { return false; } } @@ -249,29 +226,25 @@ bool MovementAIComponent::Warp(const NiPoint3& point) return true; } -float MovementAIComponent::GetTimer() const -{ +float MovementAIComponent::GetTimer() const { return m_Timer; } -bool MovementAIComponent::AtFinalWaypoint() const -{ +bool MovementAIComponent::AtFinalWaypoint() const { return m_Done; } -void MovementAIComponent::Stop() -{ - if (m_Done) - { +void MovementAIComponent::Stop() { + if (m_Done) { return; } SetPosition(ApproximateLocation()); SetVelocity(NiPoint3::ZERO); - + m_TotalTime = m_Timer = 0; - + m_Done = true; m_CurrentPath = {}; @@ -279,24 +252,21 @@ void MovementAIComponent::Stop() m_PathIndex = 0; m_CurrentSpeed = 0; - + EntityManager::Instance()->SerializeEntity(m_Parent); } -void MovementAIComponent::PullToPoint(const NiPoint3& point) -{ +void MovementAIComponent::PullToPoint(const NiPoint3& point) { Stop(); - + m_Interrupted = true; m_PullPoint = point; } -void MovementAIComponent::SetPath(std::vector path) -{ +void MovementAIComponent::SetPath(std::vector path) { std::reverse(path.begin(), path.end()); - for (const auto& point : path) - { + for (const auto& point : path) { m_Queue.push(point); } @@ -305,50 +275,43 @@ void MovementAIComponent::SetPath(std::vector path) m_Queue.pop(); } -float MovementAIComponent::GetBaseSpeed(LOT lot) -{ +float MovementAIComponent::GetBaseSpeed(LOT lot) { // Check if the lot is in the cache const auto& it = m_PhysicsSpeedCache.find(lot); - - if (it != m_PhysicsSpeedCache.end()) - { + + if (it != m_PhysicsSpeedCache.end()) { return it->second; } - - CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable("PhysicsComponent"); + + CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable(); + CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable(); int32_t componentID; CDPhysicsComponent* physicsComponent = nullptr; - componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_CONTROLLABLE_PHYSICS, -1); + componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::CONTROLLABLE_PHYSICS, -1); - if (componentID != -1) - { + if (componentID != -1) { physicsComponent = physicsComponentTable->GetByID(componentID); goto foundComponent; } - componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_SIMPLE_PHYSICS, -1); + componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::SIMPLE_PHYSICS, -1); - if (componentID != -1) - { + if (componentID != -1) { physicsComponent = physicsComponentTable->GetByID(componentID); goto foundComponent; } - foundComponent: +foundComponent: float speed; - if (physicsComponent == nullptr) - { + if (physicsComponent == nullptr) { speed = 8; - } - else - { + } else { speed = physicsComponent->speed; } @@ -357,12 +320,10 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) return speed; } -void MovementAIComponent::SetPosition(const NiPoint3& value) -{ +void MovementAIComponent::SetPosition(const NiPoint3& value) { auto* controllablePhysicsComponent = m_Parent->GetComponent(); - if (controllablePhysicsComponent != nullptr) - { + if (controllablePhysicsComponent != nullptr) { controllablePhysicsComponent->SetPosition(value); return; @@ -370,23 +331,19 @@ void MovementAIComponent::SetPosition(const NiPoint3& value) auto* simplePhysicsComponent = m_Parent->GetComponent(); - if (simplePhysicsComponent != nullptr) - { + if (simplePhysicsComponent != nullptr) { simplePhysicsComponent->SetPosition(value); } } -void MovementAIComponent::SetRotation(const NiQuaternion& value) -{ - if (m_LockRotation) - { +void MovementAIComponent::SetRotation(const NiQuaternion& value) { + if (m_LockRotation) { return; } auto* controllablePhysicsComponent = m_Parent->GetComponent(); - if (controllablePhysicsComponent != nullptr) - { + if (controllablePhysicsComponent != nullptr) { controllablePhysicsComponent->SetRotation(value); return; @@ -394,18 +351,15 @@ void MovementAIComponent::SetRotation(const NiQuaternion& value) auto* simplePhysicsComponent = m_Parent->GetComponent(); - if (simplePhysicsComponent != nullptr) - { + if (simplePhysicsComponent != nullptr) { simplePhysicsComponent->SetRotation(value); } } -void MovementAIComponent::SetVelocity(const NiPoint3& value) -{ +void MovementAIComponent::SetVelocity(const NiPoint3& value) { auto* controllablePhysicsComponent = m_Parent->GetComponent(); - if (controllablePhysicsComponent != nullptr) - { + if (controllablePhysicsComponent != nullptr) { controllablePhysicsComponent->SetVelocity(value); return; @@ -413,19 +367,16 @@ void MovementAIComponent::SetVelocity(const NiPoint3& value) auto* simplePhysicsComponent = m_Parent->GetComponent(); - if (simplePhysicsComponent != nullptr) - { + if (simplePhysicsComponent != nullptr) { simplePhysicsComponent->SetVelocity(value); } } -void MovementAIComponent::SetDestination(const NiPoint3& value) -{ - if (m_Interrupted) - { +void MovementAIComponent::SetDestination(const NiPoint3& value) { + if (m_Interrupted) { return; } - + /*if (Vector3::DistanceSquared(value, GetDestination()) < 2 * 2) { return; @@ -433,19 +384,15 @@ void MovementAIComponent::SetDestination(const NiPoint3& value) const auto location = ApproximateLocation(); - if (!AtFinalWaypoint()) - { + if (!AtFinalWaypoint()) { SetPosition(location); } std::vector computedPath; - - if (dpWorld::Instance().IsLoaded()) - { - computedPath = dpWorld::Instance().GetPath(GetCurrentPosition(), value, m_Info.wanderSpeed); - } - else - { + + if (dpWorld::Instance().IsLoaded()) { + computedPath = dpWorld::Instance().GetNavMesh()->GetPath(GetCurrentPosition(), value, m_Info.wanderSpeed); + } else { // Than take 10 points between the current position and the destination and make that the path auto point = location; @@ -454,8 +401,7 @@ void MovementAIComponent::SetDestination(const NiPoint3& value) auto step = delta / 10; - for (int i = 0; i < 10; i++) - { + for (int i = 0; i < 10; i++) { point = point + step; computedPath.push_back(point); @@ -472,82 +418,68 @@ void MovementAIComponent::SetDestination(const NiPoint3& value) m_CurrentPath.push_back(location); // Simply path - for (auto point : computedPath) - { - if (dpWorld::Instance().IsLoaded()) - { - point.y = dpWorld::Instance().GetHeightAtPoint(point); + for (auto point : computedPath) { + if (dpWorld::Instance().IsLoaded()) { + point.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(point); } m_CurrentPath.push_back(point); } m_CurrentPath.push_back(computedPath[computedPath.size() - 1]); - + m_PathIndex = 0; - + m_TotalTime = m_Timer = 0; - + m_Done = false; } -NiPoint3 MovementAIComponent::GetDestination() const -{ - if (m_CurrentPath.empty()) - { +NiPoint3 MovementAIComponent::GetDestination() const { + if (m_CurrentPath.empty()) { return GetCurrentPosition(); } return m_CurrentPath[m_CurrentPath.size() - 1]; } -void MovementAIComponent::SetSpeed(const float value) -{ +void MovementAIComponent::SetSpeed(const float value) { m_Speed = value; m_Acceleration = value / 5; } -float MovementAIComponent::GetSpeed() const -{ +float MovementAIComponent::GetSpeed() const { return m_Speed; } -void MovementAIComponent::SetAcceleration(const float value) -{ +void MovementAIComponent::SetAcceleration(const float value) { m_Acceleration = value; } -float MovementAIComponent::GetAcceleration() const -{ +float MovementAIComponent::GetAcceleration() const { return m_Acceleration; } -void MovementAIComponent::SetHaltDistance(const float value) -{ +void MovementAIComponent::SetHaltDistance(const float value) { m_HaltDistance = value; } -float MovementAIComponent::GetHaltDistance() const -{ +float MovementAIComponent::GetHaltDistance() const { return m_HaltDistance; } -void MovementAIComponent::SetCurrentSpeed(float value) -{ +void MovementAIComponent::SetCurrentSpeed(float value) { m_CurrentSpeed = value; } -float MovementAIComponent::GetCurrentSpeed() const -{ +float MovementAIComponent::GetCurrentSpeed() const { return m_CurrentSpeed; } -void MovementAIComponent::SetLockRotation(bool value) -{ +void MovementAIComponent::SetLockRotation(bool value) { m_LockRotation = value; } -bool MovementAIComponent::GetLockRotation() const -{ +bool MovementAIComponent::GetLockRotation() const { return m_LockRotation; } diff --git a/dGame/dComponents/MovementAIComponent.h b/dGame/dComponents/MovementAIComponent.h index 032732cc..3c9044aa 100644 --- a/dGame/dComponents/MovementAIComponent.h +++ b/dGame/dComponents/MovementAIComponent.h @@ -13,6 +13,7 @@ #include "Game.h" #include "dLogger.h" #include "Component.h" +#include "eReplicaComponentType.h" #include class ControllablePhysicsComponent; @@ -24,29 +25,29 @@ class BaseCombatAIComponent; struct MovementAIInfo { std::string movementType; - /** - * The radius that the entity can wander in - */ + /** + * The radius that the entity can wander in + */ float wanderRadius; - /** - * The speed at which the entity wanders - */ + /** + * The speed at which the entity wanders + */ float wanderSpeed; - /** - * This is only used for the emotes - */ + /** + * This is only used for the emotes + */ float wanderChance; - /** - * The min amount of delay before wandering - */ + /** + * The min amount of delay before wandering + */ float wanderDelayMin; - /** - * The max amount of delay before wandering - */ + /** + * The max amount of delay before wandering + */ float wanderDelayMax; }; @@ -56,274 +57,274 @@ struct MovementAIInfo { */ class MovementAIComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MOVEMENT_AI; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI; + MovementAIComponent(Entity* parentEntity, MovementAIInfo info); ~MovementAIComponent() override; - + void Update(float deltaTime) override; - /** - * Returns the basic settings that this entity uses to move around - * @return the basic settings that this entity uses to move around - */ + /** + * Returns the basic settings that this entity uses to move around + * @return the basic settings that this entity uses to move around + */ const MovementAIInfo& GetInfo() const; - /** - * Set a destination point for the entity to move towards - * @param value the destination point to move towards - */ + /** + * Set a destination point for the entity to move towards + * @param value the destination point to move towards + */ void SetDestination(const NiPoint3& value); - /** - * Returns the current rotation this entity is moving towards - * @return the current rotation this entity is moving towards - */ + /** + * Returns the current rotation this entity is moving towards + * @return the current rotation this entity is moving towards + */ NiPoint3 GetDestination() const; - /** - * Sets the max speed at which this entity may run - * @param value the speed value to set - */ + /** + * Sets the max speed at which this entity may run + * @param value the speed value to set + */ void SetSpeed(float value); - /** - * Returns the max speed at which this entity may run - * @return the max speed at which this entity may run - */ + /** + * Returns the max speed at which this entity may run + * @return the max speed at which this entity may run + */ float GetSpeed() const; - /** - * Sets how fast the entity will accelerate when not running at full speed - * @param value the acceleration to set - */ + /** + * Sets how fast the entity will accelerate when not running at full speed + * @param value the acceleration to set + */ void SetAcceleration(float value); - /** - * Returns the current speed at which this entity accelerates when not running at full speed - * @return the current speed at which this entity accelerates when not running at full speed - */ + /** + * Returns the current speed at which this entity accelerates when not running at full speed + * @return the current speed at which this entity accelerates when not running at full speed + */ float GetAcceleration() const; - /** - * Sets the halting distance (the distance at which we consider the target to be reached) - * @param value the halting distance to set - */ + /** + * Sets the halting distance (the distance at which we consider the target to be reached) + * @param value the halting distance to set + */ void SetHaltDistance(float value); - /** - * Returns the current halting distance (the distance at which we consider the target to be reached) - * @return the current halting distance - */ + /** + * Returns the current halting distance (the distance at which we consider the target to be reached) + * @return the current halting distance + */ float GetHaltDistance() const; - /** - * Sets the speed the entity is currently running at - * @param value the speed value to set - */ + /** + * Sets the speed the entity is currently running at + * @param value the speed value to set + */ void SetCurrentSpeed(float value); - /** - * Returns the speed the entity is currently running at - * @return the speed the entity is currently running at - */ + /** + * Returns the speed the entity is currently running at + * @return the speed the entity is currently running at + */ float GetCurrentSpeed() const; - /** - * Locks the rotation of this entity in place, depending on the argument - * @param value if true, the entity will be rotationally locked - */ + /** + * Locks the rotation of this entity in place, depending on the argument + * @param value if true, the entity will be rotationally locked + */ void SetLockRotation(bool value); - /** - * Returns whether this entity is currently rotationally locked - * @return true if the entity is rotationally locked, false otherwise - */ + /** + * Returns whether this entity is currently rotationally locked + * @return true if the entity is rotationally locked, false otherwise + */ bool GetLockRotation() const; - /** - * Attempts to update the waypoint index, making the entity move to the next waypoint - * @return true if the waypoint could be increased, false if the entity is at the last waypoint already - */ + /** + * Attempts to update the waypoint index, making the entity move to the next waypoint + * @return true if the waypoint could be increased, false if the entity is at the last waypoint already + */ bool AdvanceWaypointIndex(); - /** - * Returns the waypoint the entity is currently moving towards - * @return the waypoint the entity is currently moving towards - */ + /** + * Returns the waypoint the entity is currently moving towards + * @return the waypoint the entity is currently moving towards + */ NiPoint3 GetCurrentWaypoint() const; - /** - * Returns the waypoint this entity is supposed to move towards next - * @return the waypoint this entity is supposed to move towards next - */ + /** + * Returns the waypoint this entity is supposed to move towards next + * @return the waypoint this entity is supposed to move towards next + */ NiPoint3 GetNextWaypoint() const; - /** - * Returns the current position of this entity - * @return the current position of this entity - */ + /** + * Returns the current position of this entity + * @return the current position of this entity + */ NiPoint3 GetCurrentPosition() const; - /** - * Returns the approximate current location of the entity, including y coordinates - * @return the approximate current location of the entity - */ + /** + * Returns the approximate current location of the entity, including y coordinates + * @return the approximate current location of the entity + */ NiPoint3 ApproximateLocation() const; - /** - * Teleports this entity to a position. If the distance between the provided point and the y it should have - * according to map data, this will not succeed (to avoid teleporting entities into the sky). - * @param point the point to teleport to - * @return true if the warp was successful, false otherwise - */ + /** + * Teleports this entity to a position. If the distance between the provided point and the y it should have + * according to map data, this will not succeed (to avoid teleporting entities into the sky). + * @param point the point to teleport to + * @return true if the warp was successful, false otherwise + */ bool Warp(const NiPoint3& point); - /** - * Returns the time it will take to reach the final waypoint according to the current speed - * @return the time it will take to reach the final waypoint according to the current speed - */ + /** + * Returns the time it will take to reach the final waypoint according to the current speed + * @return the time it will take to reach the final waypoint according to the current speed + */ float GetTimer() const; - /** - * Returns if the entity is at its final waypoint - * @return if the entity is at its final waypoint - */ + /** + * Returns if the entity is at its final waypoint + * @return if the entity is at its final waypoint + */ bool AtFinalWaypoint() const; - /** - * Renders the entity stationary - */ + /** + * Renders the entity stationary + */ void Stop(); - /** - * Stops the current movement and moves the entity to a certain point. Will continue until it's close enough, - * after which its AI is enabled again. - * @param point the point to move towards - */ + /** + * Stops the current movement and moves the entity to a certain point. Will continue until it's close enough, + * after which its AI is enabled again. + * @param point the point to move towards + */ void PullToPoint(const NiPoint3& point); - /** - * Sets a path to follow for the AI - * @param path the path to follow - */ + /** + * Sets a path to follow for the AI + * @param path the path to follow + */ void SetPath(std::vector path); - /** - * Returns the base speed from the DB for a given LOT - * @param lot the lot to check for - * @return the base speed of the lot - */ + /** + * Returns the base speed from the DB for a given LOT + * @param lot the lot to check for + * @return the base speed of the lot + */ static float GetBaseSpeed(LOT lot); private: - /** - * Sets the current position of the entity - * @param value the position to set - */ + /** + * Sets the current position of the entity + * @param value the position to set + */ void SetPosition(const NiPoint3& value); - /** - * Sets the current rotation of the entity - * @param value the rotation to set - */ + /** + * Sets the current rotation of the entity + * @param value the rotation to set + */ void SetRotation(const NiQuaternion& value); - /** - * Sets the current velocity of the entityes - * @param value the velocity to set - */ + /** + * Sets the current velocity of the entityes + * @param value the velocity to set + */ void SetVelocity(const NiPoint3& value); - /** - * Base information regarding the movement information for this entity - */ + /** + * Base information regarding the movement information for this entity + */ MovementAIInfo m_Info; - /** - * The point this entity is moving towards - */ + /** + * The point this entity is moving towards + */ NiPoint3 m_NextWaypoint; - /** - * The max speed this entity may move at - */ + /** + * The max speed this entity may move at + */ float m_Speed; - /** - * The time it will take to reach the next waypoint using the current speed - */ + /** + * The time it will take to reach the next waypoint using the current speed + */ float m_Timer; - /** - * The total time it will take to reach the waypoint form its starting point - */ + /** + * The total time it will take to reach the waypoint form its starting point + */ float m_TotalTime; - /** - * The path this entity is currently traversing - */ + /** + * The path this entity is currently traversing + */ uint32_t m_PathIndex; - /** - * If the entity has reached it last waypoint - */ + /** + * If the entity has reached it last waypoint + */ bool m_Done; - /** - * The speed the entity is currently moving at - */ + /** + * The speed the entity is currently moving at + */ float m_CurrentSpeed; - /** - * The acceleration this entity has when not moving at its top speed yet - */ + /** + * The acceleration this entity has when not moving at its top speed yet + */ float m_Acceleration; - /** - * The distance between the current position and the target waypoint to consider it reached (to not ghost into it). - */ + /** + * The distance between the current position and the target waypoint to consider it reached (to not ghost into it). + */ float m_HaltDistance; - /** - * The base speed this entity has - */ + /** + * The base speed this entity has + */ float m_BaseSpeed; - /** - * If the AI is currently turned of (e.g. when teleporting to some location) - */ + /** + * If the AI is currently turned of (e.g. when teleporting to some location) + */ bool m_Interrupted; - /** - * A position that the entity is currently moving towards while being interrupted - */ + /** + * A position that the entity is currently moving towards while being interrupted + */ NiPoint3 m_PullPoint; - /** - * If the entity is currently rotationally locked - */ + /** + * If the entity is currently rotationally locked + */ bool m_LockRotation; - /** - * Optional direct link to the combat AI component of the parent entity - */ + /** + * Optional direct link to the combat AI component of the parent entity + */ BaseCombatAIComponent* m_BaseCombatAI = nullptr; - /** - * The path the entity is currently following - */ + /** + * The path the entity is currently following + */ std::vector m_CurrentPath; - /** - * Queue of positions to traverse - */ + /** + * Queue of positions to traverse + */ std::stack m_Queue; - /** - * Cache of all lots and their respective speeds - */ + /** + * Cache of all lots and their respective speeds + */ static std::map m_PhysicsSpeedCache; }; diff --git a/dGame/dComponents/MovingPlatformComponent.cpp b/dGame/dComponents/MovingPlatformComponent.cpp index bf3ea9d5..2666c60c 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -12,372 +12,342 @@ #include "GameMessages.h" #include "CppScripts.h" #include "SimplePhysicsComponent.h" +#include "Zone.h" MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) { - mPosition = {}; + mPosition = {}; - mState = MovementPlatformState::Stopped; - mDesiredWaypointIndex = 0; // -1; - mInReverse = false; - mShouldStopAtDesiredWaypoint = false; - - mPercentBetweenPoints = 0.0f; - - mCurrentWaypointIndex = 0; - mNextWaypointIndex = 0; //mCurrentWaypointIndex + 1; - - mIdleTimeElapsed = 0.0f; + mState = eMovementPlatformState::Stopped; + mDesiredWaypointIndex = 0; // -1; + mInReverse = false; + mShouldStopAtDesiredWaypoint = false; + + mPercentBetweenPoints = 0.0f; + + mCurrentWaypointIndex = 0; + mNextWaypointIndex = 0; //mCurrentWaypointIndex + 1; + + mIdleTimeElapsed = 0.0f; } MoverSubComponent::~MoverSubComponent() = default; void MoverSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const { - outBitStream->Write(true); + outBitStream->Write(true); - outBitStream->Write(static_cast(mState)); - outBitStream->Write(mDesiredWaypointIndex); - outBitStream->Write(mShouldStopAtDesiredWaypoint); - outBitStream->Write(mInReverse); - - outBitStream->Write(mPercentBetweenPoints); + outBitStream->Write(static_cast(mState)); + outBitStream->Write(mDesiredWaypointIndex); + outBitStream->Write(mShouldStopAtDesiredWaypoint); + outBitStream->Write(mInReverse); - outBitStream->Write(mPosition.x); - outBitStream->Write(mPosition.y); - outBitStream->Write(mPosition.z); - - outBitStream->Write(mCurrentWaypointIndex); - outBitStream->Write(mNextWaypointIndex); - - outBitStream->Write(mIdleTimeElapsed); - outBitStream->Write(0.0f); // Move time elapsed + outBitStream->Write(mPercentBetweenPoints); + + outBitStream->Write(mPosition.x); + outBitStream->Write(mPosition.y); + outBitStream->Write(mPosition.z); + + outBitStream->Write(mCurrentWaypointIndex); + outBitStream->Write(mNextWaypointIndex); + + outBitStream->Write(mIdleTimeElapsed); + outBitStream->Write(0.0f); // Move time elapsed } //------------- MovingPlatformComponent below -------------- MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const std::string& pathName) : Component(parent) { - m_MoverSubComponentType = eMoverSubComponentType::mover; - m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition()); - m_PathName = GeneralUtils::ASCIIToUTF16(pathName); - m_Path = dZoneManager::Instance()->GetZone()->GetPath(pathName); - m_NoAutoStart = false; + m_MoverSubComponentType = eMoverSubComponentType::mover; + m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition()); + m_PathName = GeneralUtils::ASCIIToUTF16(pathName); + m_Path = dZoneManager::Instance()->GetZone()->GetPath(pathName); + m_NoAutoStart = false; - if (m_Path == nullptr) { - Game::logger->Log("MovingPlatformComponent", "Path not found: %s\n", pathName.c_str()); - } + if (m_Path == nullptr) { + Game::logger->Log("MovingPlatformComponent", "Path not found: %s", pathName.c_str()); + } } MovingPlatformComponent::~MovingPlatformComponent() { - delete static_cast(m_MoverSubComponent); + delete static_cast(m_MoverSubComponent); } void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - // Here we don't serialize the moving platform to let the client simulate the movement - - if (!m_Serialize) - { - outBitStream->Write(false); - outBitStream->Write(false); + // Here we don't serialize the moving platform to let the client simulate the movement - return; - } + if (!m_Serialize) { + outBitStream->Write(false); + outBitStream->Write(false); - outBitStream->Write(true); + return; + } - auto hasPath = !m_PathingStopped && !m_PathName.empty(); - outBitStream->Write(hasPath); + outBitStream->Write(true); - if (hasPath) { - // Is on rail - outBitStream->Write1(); - - outBitStream->Write(static_cast(m_PathName.size())); - for (const auto& c : m_PathName) { - outBitStream->Write(static_cast(c)); - } + auto hasPath = !m_PathingStopped && !m_PathName.empty(); + outBitStream->Write(hasPath); - // Starting point - outBitStream->Write(0); + if (hasPath) { + // Is on rail + outBitStream->Write1(); - // Reverse - outBitStream->Write(false); - } + outBitStream->Write(static_cast(m_PathName.size())); + for (const auto& c : m_PathName) { + outBitStream->Write(static_cast(c)); + } - const auto hasPlatform = m_MoverSubComponent != nullptr; - outBitStream->Write(hasPlatform); + // Starting point + outBitStream->Write(0); - if (hasPlatform) { - auto* mover = static_cast(m_MoverSubComponent); - outBitStream->Write(static_cast(m_MoverSubComponentType)); + // Reverse + outBitStream->Write(false); + } - if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) { - // TODO - } else { - mover->Serialize(outBitStream, bIsInitialUpdate, flags); - } - } + const auto hasPlatform = m_MoverSubComponent != nullptr; + outBitStream->Write(hasPlatform); + + if (hasPlatform) { + auto* mover = static_cast(m_MoverSubComponent); + outBitStream->Write(static_cast(m_MoverSubComponentType)); + + if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) { + // TODO + } else { + mover->Serialize(outBitStream, bIsInitialUpdate, flags); + } + } } void MovingPlatformComponent::OnRebuildInitilized() { - StopPathing(); + StopPathing(); } void MovingPlatformComponent::OnCompleteRebuild() { - if (m_NoAutoStart) - return; + if (m_NoAutoStart) + return; - StartPathing(); + StartPathing(); } -void MovingPlatformComponent::SetMovementState(MovementPlatformState value) -{ - auto* subComponent = static_cast(m_MoverSubComponent); +void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) { + auto* subComponent = static_cast(m_MoverSubComponent); - subComponent->mState = value; + subComponent->mState = value; - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); } -void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) -{ - auto* subComponent = static_cast(m_MoverSubComponent); - - subComponent->mDesiredWaypointIndex = index; - subComponent->mNextWaypointIndex = index; - subComponent->mShouldStopAtDesiredWaypoint = stopAtWaypoint; +void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) { + auto* subComponent = static_cast(m_MoverSubComponent); - StartPathing(); + subComponent->mDesiredWaypointIndex = index; + subComponent->mNextWaypointIndex = index; + subComponent->mShouldStopAtDesiredWaypoint = stopAtWaypoint; + + StartPathing(); } -void MovingPlatformComponent::StartPathing() -{ +void MovingPlatformComponent::StartPathing() { //GameMessages::SendStartPathing(m_Parent); - m_PathingStopped = false; - - auto* subComponent = static_cast(m_MoverSubComponent); - - subComponent->mShouldStopAtDesiredWaypoint = true; - subComponent->mState = MovementPlatformState::Stationary; + m_PathingStopped = false; - NiPoint3 targetPosition; + auto* subComponent = static_cast(m_MoverSubComponent); - if (m_Path != nullptr) { - const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex]; - const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; + subComponent->mShouldStopAtDesiredWaypoint = true; + subComponent->mState = eMovementPlatformState::Stationary; - subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; - subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; + NiPoint3 targetPosition; - targetPosition = nextWaypoint.position; - } - else { - subComponent->mPosition = m_Parent->GetPosition(); - subComponent->mSpeed = 1.0f; - subComponent->mWaitTime = 2.0f; + if (m_Path != nullptr) { + const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex]; + const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; - targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f); - } + subComponent->mPosition = currentWaypoint.position; + subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; - m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] - { - SetMovementState(MovementPlatformState::Moving); - }); + targetPosition = nextWaypoint.position; + } else { + subComponent->mPosition = m_Parent->GetPosition(); + subComponent->mSpeed = 1.0f; + subComponent->mWaitTime = 2.0f; - const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f; + targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f); + } - const auto travelNext = subComponent->mWaitTime + travelTime; + m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { + SetMovementState(eMovementPlatformState::Moving); + }); - m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); - } - }); + const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f; - m_Parent->AddCallbackTimer(travelNext, [this] - { - ContinuePathing(); - }); + const auto travelNext = subComponent->mWaitTime + travelTime; - //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); + m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); + } + }); - EntityManager::Instance()->SerializeEntity(m_Parent); + m_Parent->AddCallbackTimer(travelNext, [this] { + ContinuePathing(); + }); + + //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); + + EntityManager::Instance()->SerializeEntity(m_Parent); } -void MovingPlatformComponent::ContinuePathing() -{ - auto* subComponent = static_cast(m_MoverSubComponent); - - subComponent->mState = MovementPlatformState::Stationary; +void MovingPlatformComponent::ContinuePathing() { + auto* subComponent = static_cast(m_MoverSubComponent); - subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex; + subComponent->mState = eMovementPlatformState::Stationary; - NiPoint3 targetPosition; - uint32_t pathSize; - PathBehavior behavior; + subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex; - if (m_Path != nullptr) { - const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex]; - const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; + NiPoint3 targetPosition; + uint32_t pathSize; + PathBehavior behavior; - subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; - subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2; + if (m_Path != nullptr) { + const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex]; + const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; - pathSize = m_Path->pathWaypoints.size() - 1; + subComponent->mPosition = currentWaypoint.position; + subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2; - behavior = static_cast(m_Path->pathBehavior); + pathSize = m_Path->pathWaypoints.size() - 1; - targetPosition = nextWaypoint.position; - } - else - { - subComponent->mPosition = m_Parent->GetPosition(); - subComponent->mSpeed = 1.0f; - subComponent->mWaitTime = 2.0f; + behavior = static_cast(m_Path->pathBehavior); - targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f); + targetPosition = nextWaypoint.position; + } else { + subComponent->mPosition = m_Parent->GetPosition(); + subComponent->mSpeed = 1.0f; + subComponent->mWaitTime = 2.0f; - pathSize = 1; - behavior = PathBehavior::Loop; - } + targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f); - if (m_Parent->GetLOT() == 9483) - { - behavior = PathBehavior::Bounce; - } - else - { - return; - } + pathSize = 1; + behavior = PathBehavior::Loop; + } - if (subComponent->mCurrentWaypointIndex >= pathSize) - { - subComponent->mCurrentWaypointIndex = pathSize; - switch (behavior) - { - case PathBehavior::Once: - EntityManager::Instance()->SerializeEntity(m_Parent); - return; - - case PathBehavior::Bounce: - subComponent->mInReverse = true; - break; + if (m_Parent->GetLOT() == 9483) { + behavior = PathBehavior::Bounce; + } else { + return; + } - case PathBehavior::Loop: - subComponent->mNextWaypointIndex = 0; - break; - - default: - break; - } - } - else if (subComponent->mCurrentWaypointIndex == 0) - { - subComponent->mInReverse = false; - } + if (subComponent->mCurrentWaypointIndex >= pathSize) { + subComponent->mCurrentWaypointIndex = pathSize; + switch (behavior) { + case PathBehavior::Once: + EntityManager::Instance()->SerializeEntity(m_Parent); + return; - if (subComponent->mInReverse) - { - subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex - 1; - } - else - { - subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex + 1; - } + case PathBehavior::Bounce: + subComponent->mInReverse = true; + break; - /* - subComponent->mNextWaypointIndex = 0; - subComponent->mCurrentWaypointIndex = 1; - */ + case PathBehavior::Loop: + subComponent->mNextWaypointIndex = 0; + break; - //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); + default: + break; + } + } else if (subComponent->mCurrentWaypointIndex == 0) { + subComponent->mInReverse = false; + } - if (subComponent->mCurrentWaypointIndex == subComponent->mDesiredWaypointIndex) - { - // TODO: Send event? - StopPathing(); + if (subComponent->mInReverse) { + subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex - 1; + } else { + subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex + 1; + } - return; - } + /* + subComponent->mNextWaypointIndex = 0; + subComponent->mCurrentWaypointIndex = 1; + */ - m_Parent->CancelCallbackTimers(); + //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); - m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] - { - SetMovementState(MovementPlatformState::Moving); - }); + if (subComponent->mCurrentWaypointIndex == subComponent->mDesiredWaypointIndex) { + // TODO: Send event? + StopPathing(); - auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5; + return; + } - if (m_Parent->GetLOT() == 9483) - { - travelTime += 20; - } + m_Parent->CancelCallbackTimers(); - const auto travelNext = subComponent->mWaitTime + travelTime; + m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { + SetMovementState(eMovementPlatformState::Moving); + }); - m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); - } - }); + auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5; - m_Parent->AddCallbackTimer(travelNext, [this] - { - ContinuePathing(); - }); + if (m_Parent->GetLOT() == 9483) { + travelTime += 20; + } - EntityManager::Instance()->SerializeEntity(m_Parent); + const auto travelNext = subComponent->mWaitTime + travelTime; + + m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); + } + }); + + m_Parent->AddCallbackTimer(travelNext, [this] { + ContinuePathing(); + }); + + EntityManager::Instance()->SerializeEntity(m_Parent); } -void MovingPlatformComponent::StopPathing() -{ - //m_Parent->CancelCallbackTimers(); +void MovingPlatformComponent::StopPathing() { + //m_Parent->CancelCallbackTimers(); - auto* subComponent = static_cast(m_MoverSubComponent); + auto* subComponent = static_cast(m_MoverSubComponent); - m_PathingStopped = true; + m_PathingStopped = true; - subComponent->mState = MovementPlatformState::Stopped; - subComponent->mDesiredWaypointIndex = -1; - subComponent->mShouldStopAtDesiredWaypoint = false; + subComponent->mState = eMovementPlatformState::Stopped; + subComponent->mDesiredWaypointIndex = -1; + subComponent->mShouldStopAtDesiredWaypoint = false; - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); - //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); + //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); } -void MovingPlatformComponent::SetSerialized(bool value) -{ - m_Serialize = value; +void MovingPlatformComponent::SetSerialized(bool value) { + m_Serialize = value; } -bool MovingPlatformComponent::GetNoAutoStart() const -{ - return m_NoAutoStart; +bool MovingPlatformComponent::GetNoAutoStart() const { + return m_NoAutoStart; } -void MovingPlatformComponent::SetNoAutoStart(const bool value) -{ - m_NoAutoStart = value; +void MovingPlatformComponent::SetNoAutoStart(const bool value) { + m_NoAutoStart = value; } -void MovingPlatformComponent::WarpToWaypoint(size_t index) -{ - const auto& waypoint = m_Path->pathWaypoints[index]; +void MovingPlatformComponent::WarpToWaypoint(size_t index) { + const auto& waypoint = m_Path->pathWaypoints[index]; - m_Parent->SetPosition(waypoint.position); - m_Parent->SetRotation(waypoint.rotation); + m_Parent->SetPosition(waypoint.position); + m_Parent->SetRotation(waypoint.rotation); - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); } -size_t MovingPlatformComponent::GetLastWaypointIndex() const -{ - return m_Path->pathWaypoints.size() - 1; +size_t MovingPlatformComponent::GetLastWaypointIndex() const { + return m_Path->pathWaypoints.size() - 1; } -MoverSubComponent* MovingPlatformComponent::GetMoverSubComponent() const -{ - return static_cast(m_MoverSubComponent); +MoverSubComponent* MovingPlatformComponent::GetMoverSubComponent() const { + return static_cast(m_MoverSubComponent); } diff --git a/dGame/dComponents/MovingPlatformComponent.h b/dGame/dComponents/MovingPlatformComponent.h index da377916..9e4c1ecf 100644 --- a/dGame/dComponents/MovingPlatformComponent.h +++ b/dGame/dComponents/MovingPlatformComponent.h @@ -13,27 +13,21 @@ #include "dCommonVars.h" #include "EntityManager.h" #include "Component.h" +#include "eMovementPlatformState.h" +#include "eReplicaComponentType.h" -/** - * Different types of available platforms - */ +class Path; + + /** + * Different types of available platforms + */ enum class eMoverSubComponentType : uint32_t { - mover = 4, + mover = 4, - /** - * Used in NJ - */ - simpleMover = 5, -}; - -/** - * The different types of platform movement state, supposedly a bitmap - */ -enum class MovementPlatformState : uint32_t -{ - Moving = 0b00010, - Stationary = 0b11001, - Stopped = 0b01100 + /** + * Used in NJ + */ + simpleMover = 5, }; /** @@ -41,65 +35,65 @@ enum class MovementPlatformState : uint32_t */ class MoverSubComponent { public: - MoverSubComponent(const NiPoint3& startPos); - ~MoverSubComponent(); - - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const; + MoverSubComponent(const NiPoint3& startPos); + ~MoverSubComponent(); - /** - * The state the platform is currently in - */ - MovementPlatformState mState = MovementPlatformState::Stationary; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const; - /** - * The waypoint this platform currently wants to traverse to - */ - int32_t mDesiredWaypointIndex = 0; + /** + * The state the platform is currently in + */ + eMovementPlatformState mState = eMovementPlatformState::Stationary; - /** - * Whether the platform is currently reversing away from the desired waypoint - */ - bool mInReverse = false; + /** + * The waypoint this platform currently wants to traverse to + */ + int32_t mDesiredWaypointIndex = 0; - /** - * Whether the platform should stop moving when reaching the desired waypoint - */ - bool mShouldStopAtDesiredWaypoint = false; + /** + * Whether the platform is currently reversing away from the desired waypoint + */ + bool mInReverse = false; - /** - * The percentage of the way between the last point and the desired point - */ - float mPercentBetweenPoints = 0; + /** + * Whether the platform should stop moving when reaching the desired waypoint + */ + bool mShouldStopAtDesiredWaypoint = false; - /** - * The current position of the platofrm - */ - NiPoint3 mPosition {}; + /** + * The percentage of the way between the last point and the desired point + */ + float mPercentBetweenPoints = 0; - /** - * The waypoint the platform is (was) at - */ - uint32_t mCurrentWaypointIndex; + /** + * The current position of the platofrm + */ + NiPoint3 mPosition{}; - /** - * The waypoint the platform is attempting to go to - */ - uint32_t mNextWaypointIndex; + /** + * The waypoint the platform is (was) at + */ + uint32_t mCurrentWaypointIndex; - /** - * The timer that handles the time before stopping idling and continue platform movement - */ - float mIdleTimeElapsed = 0; + /** + * The waypoint the platform is attempting to go to + */ + uint32_t mNextWaypointIndex; - /** - * The speed the platform is currently moving at - */ - float mSpeed = 0; + /** + * The timer that handles the time before stopping idling and continue platform movement + */ + float mIdleTimeElapsed = 0; - /** - * The time to wait before continuing movement - */ - float mWaitTime = 0; + /** + * The speed the platform is currently moving at + */ + float mSpeed = 0; + + /** + * The time to wait before continuing movement + */ + float mWaitTime = 0; }; @@ -112,123 +106,123 @@ public: */ class MovingPlatformComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MOVING_PLATFORM; - - MovingPlatformComponent(Entity* parent, const std::string& pathName); - ~MovingPlatformComponent() override; - - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVING_PLATFORM; - /** - * Stops all pathing, called when an entity starts a quick build associated with this platform - */ - void OnRebuildInitilized(); + MovingPlatformComponent(Entity* parent, const std::string& pathName); + ~MovingPlatformComponent() override; - /** - * Starts the pathing, called when an entity completed a quick build associated with this platform - */ - void OnCompleteRebuild(); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Updates the movement state for the moving platform - * @param value the movement state to set - */ - void SetMovementState(MovementPlatformState value); + /** + * Stops all pathing, called when an entity starts a quick build associated with this platform + */ + void OnRebuildInitilized(); - /** - * Instructs the moving platform to go to some waypoint - * @param index the index of the waypoint - * @param stopAtWaypoint determines if the platform should stop at the waypoint - */ - void GotoWaypoint(uint32_t index, bool stopAtWaypoint = true); + /** + * Starts the pathing, called when an entity completed a quick build associated with this platform + */ + void OnCompleteRebuild(); - /** - * Starts the pathing of this platform, setting appropriate waypoints and speeds - */ - void StartPathing(); + /** + * Updates the movement state for the moving platform + * @param value the movement state to set + */ + void SetMovementState(eMovementPlatformState value); - /** - * Continues the path of the platform, after it's been stopped - */ - void ContinuePathing(); + /** + * Instructs the moving platform to go to some waypoint + * @param index the index of the waypoint + * @param stopAtWaypoint determines if the platform should stop at the waypoint + */ + void GotoWaypoint(uint32_t index, bool stopAtWaypoint = true); - /** - * Stops the platform from moving, waiting for it to be activated again. - */ - void StopPathing(); + /** + * Starts the pathing of this platform, setting appropriate waypoints and speeds + */ + void StartPathing(); - /** - * Determines if the entity should be serialized on the next update - * @param value whether to serialize the entity or not - */ - void SetSerialized(bool value); + /** + * Continues the path of the platform, after it's been stopped + */ + void ContinuePathing(); - /** - * Returns if this platform will start automatically after spawn - * @return if this platform will start automatically after spawn - */ - bool GetNoAutoStart() const; + /** + * Stops the platform from moving, waiting for it to be activated again. + */ + void StopPathing(); - /** - * Sets the auto start value for this platform - * @param value the auto start value to set - */ - void SetNoAutoStart(bool value); + /** + * Determines if the entity should be serialized on the next update + * @param value whether to serialize the entity or not + */ + void SetSerialized(bool value); - /** - * Warps the platform to a waypoint index, skipping its current path - * @param index the index to go to - */ - void WarpToWaypoint(size_t index); + /** + * Returns if this platform will start automatically after spawn + * @return if this platform will start automatically after spawn + */ + bool GetNoAutoStart() const; - /** - * Returns the waypoint this platform was previously at - * @return the waypoint this platform was previously at - */ - size_t GetLastWaypointIndex() const; + /** + * Sets the auto start value for this platform + * @param value the auto start value to set + */ + void SetNoAutoStart(bool value); + + /** + * Warps the platform to a waypoint index, skipping its current path + * @param index the index to go to + */ + void WarpToWaypoint(size_t index); + + /** + * Returns the waypoint this platform was previously at + * @return the waypoint this platform was previously at + */ + size_t GetLastWaypointIndex() const; + + /** + * Returns the sub component that actually defines how the platform moves around (speeds, etc). + * @return the sub component that actually defines how the platform moves around + */ + MoverSubComponent* GetMoverSubComponent() const; - /** - * Returns the sub component that actually defines how the platform moves around (speeds, etc). - * @return the sub component that actually defines how the platform moves around - */ - MoverSubComponent* GetMoverSubComponent() const; - private: - /** - * The path this platform is currently on - */ - const Path* m_Path = nullptr; + /** + * The path this platform is currently on + */ + const Path* m_Path = nullptr; - /** - * The name of the path this platform is currently on - */ - std::u16string m_PathName; + /** + * The name of the path this platform is currently on + */ + std::u16string m_PathName; - /** - * Whether the platform has stopped pathing - */ - bool m_PathingStopped = false; + /** + * Whether the platform has stopped pathing + */ + bool m_PathingStopped = false; - /** - * The type of the subcomponent - */ - eMoverSubComponentType m_MoverSubComponentType; + /** + * The type of the subcomponent + */ + eMoverSubComponentType m_MoverSubComponentType; - /** - * The mover sub component that belongs to this platform - */ - void* m_MoverSubComponent; + /** + * The mover sub component that belongs to this platform + */ + void* m_MoverSubComponent; - /** - * Whether the platform shouldn't auto start - */ - bool m_NoAutoStart; + /** + * Whether the platform shouldn't auto start + */ + bool m_NoAutoStart; - /** - * Whether to serialize the entity on the next update - */ - bool m_Serialize = false; + /** + * Whether to serialize the entity on the next update + */ + bool m_Serialize = false; }; #endif // MOVINGPLATFORMCOMPONENT_H diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index d54087aa..774aa92b 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -14,875 +14,797 @@ #include "dpWorld.h" #include "PetDigServer.h" #include "../dWorldServer/ObjectIDManager.h" +#include "eUnequippableActiveType.h" +#include "eTerminateType.h" +#include "ePetTamingNotifyType.h" +#include "eUseItemResponse.h" +#include "ePlayerFlag.h" #include "Game.h" #include "dConfig.h" #include "dChatFilter.h" #include "Database.h" +#include "EntityInfo.h" +#include "eMissionTaskType.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" -std::unordered_map PetComponent::buildCache {}; -std::unordered_map PetComponent::currentActivities {}; -std::unordered_map PetComponent::activePets {}; +std::unordered_map PetComponent::buildCache{}; +std::unordered_map PetComponent::currentActivities{}; +std::unordered_map PetComponent::activePets{}; /** * Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID * while the faction ones could be checked using their respective missions. */ -std::map PetComponent::petFlags = { - { 3050, 801 }, // Elephant - { 3054, 803 }, // Cat - { 3195, 806 }, // Triceratops - { 3254, 807 }, // Terrier - { 3261, 811 }, // Skunk - { 3672, 813 }, // Bunny - { 3994, 814 }, // Crocodile - { 5635, 815 }, // Doberman - { 5636, 816 }, // Buffalo - { 5637, 818 }, // Robot Dog - { 5639, 819 }, // Red Dragon - { 5640, 820 }, // Tortoise - { 5641, 821 }, // Green Dragon - { 5643, 822 }, // Panda, see mission 786 - { 5642, 823 }, // Mantis - { 6720, 824 }, // Warthog - { 3520, 825 }, // Lion, see mission 1318 - { 7638, 826 }, // Goat - { 7694, 827 }, // Crab - { 12294, 829 }, // Reindeer - { 12431, 830 }, // Stegosaurus, see mission 1386 - { 12432, 831 }, // Saber cat, see mission 1389 - { 12433, 832 }, // Gryphon, see mission 1392 - { 12434, 833 }, // Alien, see mission 1188 - // 834: unknown?, see mission 506, 688 - { 16210, 836 }, // Ninjago Earth Dragon, see mission 1836 - { 13067, 838 }, // Skeleton dragon +std::map PetComponent::petFlags = { + { 3050, 801 }, // Elephant + { 3054, 803 }, // Cat + { 3195, 806 }, // Triceratops + { 3254, 807 }, // Terrier + { 3261, 811 }, // Skunk + { 3672, 813 }, // Bunny + { 3994, 814 }, // Crocodile + { 5635, 815 }, // Doberman + { 5636, 816 }, // Buffalo + { 5637, 818 }, // Robot Dog + { 5639, 819 }, // Red Dragon + { 5640, 820 }, // Tortoise + { 5641, 821 }, // Green Dragon + { 5643, 822 }, // Panda, see mission 786 + { 5642, 823 }, // Mantis + { 6720, 824 }, // Warthog + { 3520, 825 }, // Lion, see mission 1318 + { 7638, 826 }, // Goat + { 7694, 827 }, // Crab + { 12294, 829 }, // Reindeer + { 12431, 830 }, // Stegosaurus, see mission 1386 + { 12432, 831 }, // Saber cat, see mission 1389 + { 12433, 832 }, // Gryphon, see mission 1392 + { 12434, 833 }, // Alien, see mission 1188 + // 834: unknown?, see mission 506, 688 + { 16210, 836 }, // Ninjago Earth Dragon, see mission 1836 + { 13067, 838 }, // Skeleton dragon }; -PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(parent) -{ - m_ComponentId = componentId; +PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(parent) { + m_ComponentId = componentId; - m_Interaction = LWOOBJID_EMPTY; - m_Owner = LWOOBJID_EMPTY; - m_ModerationStatus = 0; - m_Tamer = LWOOBJID_EMPTY; - m_ModelId = LWOOBJID_EMPTY; - m_Timer = 0; - m_TimerAway = 0; - m_DatabaseId = LWOOBJID_EMPTY; - m_Status = 67108866; // Tamable - m_Ability = PetAbilityType::Invalid; - m_StartPosition = NiPoint3::ZERO; - m_MovementAI = nullptr; - m_TresureTime = 0; - m_Preconditions = nullptr; + m_Interaction = LWOOBJID_EMPTY; + m_Owner = LWOOBJID_EMPTY; + m_ModerationStatus = 0; + m_Tamer = LWOOBJID_EMPTY; + m_ModelId = LWOOBJID_EMPTY; + m_Timer = 0; + m_TimerAway = 0; + m_DatabaseId = LWOOBJID_EMPTY; + m_Status = 67108866; // Tamable + m_Ability = PetAbilityType::Invalid; + m_StartPosition = NiPoint3::ZERO; + m_MovementAI = nullptr; + m_TresureTime = 0; + m_Preconditions = nullptr; std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar(u"CheckPrecondition")); if (!checkPreconditions.empty()) { SetPreconditions(checkPreconditions); } - // Get the imagination drain rate from the CDClient - auto query = CDClientDatabase::CreatePreppedStmt("SELECT imaginationDrainRate FROM PetComponent WHERE id = ?;"); + // Get the imagination drain rate from the CDClient + auto query = CDClientDatabase::CreatePreppedStmt("SELECT imaginationDrainRate FROM PetComponent WHERE id = ?;"); - query.bind(1, static_cast(componentId)); + query.bind(1, static_cast(componentId)); - auto result = query.execQuery(); + auto result = query.execQuery(); - // Should a result not exist for this pet default to 60 seconds. - if (!result.eof() && !result.fieldIsNull(0)) { - imaginationDrainRate = result.getFloatField(0, 60.0f); - } else { - imaginationDrainRate = 60.0f; - } - result.finalize(); + // Should a result not exist for this pet default to 60 seconds. + if (!result.eof() && !result.fieldIsNull(0)) { + imaginationDrainRate = result.getFloatField(0, 60.0f); + } else { + imaginationDrainRate = 60.0f; + } + result.finalize(); } -void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - const bool tamed = m_Owner != LWOOBJID_EMPTY; +void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + const bool tamed = m_Owner != LWOOBJID_EMPTY; - outBitStream->Write1(); // Always serialize as dirty for now + outBitStream->Write1(); // Always serialize as dirty for now - outBitStream->Write(static_cast(m_Status)); - outBitStream->Write(static_cast(tamed ? m_Ability : PetAbilityType::Invalid)); // Something with the overhead icon? + outBitStream->Write(static_cast(m_Status)); + outBitStream->Write(static_cast(tamed ? m_Ability : PetAbilityType::Invalid)); // Something with the overhead icon? - const bool interacting = m_Interaction != LWOOBJID_EMPTY; + const bool interacting = m_Interaction != LWOOBJID_EMPTY; - outBitStream->Write(interacting); - if (interacting) - { - outBitStream->Write(m_Interaction); - } - - outBitStream->Write(tamed); - if (tamed) - { - outBitStream->Write(m_Owner); - } + outBitStream->Write(interacting); + if (interacting) { + outBitStream->Write(m_Interaction); + } - outBitStream->Write(tamed); - if (tamed) - { - outBitStream->Write(m_ModerationStatus); + outBitStream->Write(tamed); + if (tamed) { + outBitStream->Write(m_Owner); + } - const auto nameData = GeneralUtils::ASCIIToUTF16(m_Name); - const auto ownerNameData = GeneralUtils::ASCIIToUTF16(m_OwnerName); + if (bIsInitialUpdate) { + outBitStream->Write(tamed); + if (tamed) { + outBitStream->Write(m_ModerationStatus); - outBitStream->Write(static_cast(nameData.size())); - for (const auto c : nameData) - { - outBitStream->Write(c); - } + const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); + const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); - outBitStream->Write(static_cast(ownerNameData.size())); - for (const auto c : ownerNameData) - { - outBitStream->Write(c); - } - } + outBitStream->Write(static_cast(nameData.size())); + for (const auto c : nameData) { + outBitStream->Write(c); + } + + outBitStream->Write(static_cast(ownerNameData.size())); + for (const auto c : ownerNameData) { + outBitStream->Write(c); + } + } + } } -void PetComponent::OnUse(Entity* originator) -{ - if (m_Owner != LWOOBJID_EMPTY) - { - return; - } +void PetComponent::OnUse(Entity* originator) { + if (m_Owner != LWOOBJID_EMPTY) { + return; + } - if (m_Tamer != LWOOBJID_EMPTY) - { - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + if (m_Tamer != LWOOBJID_EMPTY) { + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer != nullptr) - { - return; - } - - m_Tamer = LWOOBJID_EMPTY; - } + if (tamer != nullptr) { + return; + } - auto* inventoryComponent = originator->GetComponent(); + m_Tamer = LWOOBJID_EMPTY; + } - if (inventoryComponent == nullptr) - { - return; - } + auto* inventoryComponent = originator->GetComponent(); - if (m_Preconditions != nullptr && !m_Preconditions->Check(originator, true)) { - return; - } + if (inventoryComponent == nullptr) { + return; + } - auto* movementAIComponent = m_Parent->GetComponent(); + if (m_Preconditions != nullptr && !m_Preconditions->Check(originator, true)) { + return; + } - if (movementAIComponent != nullptr) - { - movementAIComponent->Stop(); - } - - inventoryComponent->DespawnPet(); + auto* movementAIComponent = m_Parent->GetComponent(); - const auto& cached = buildCache.find(m_Parent->GetLOT()); - int32_t imaginationCost = 0; + if (movementAIComponent != nullptr) { + movementAIComponent->Stop(); + } - std::string buildFile; + inventoryComponent->DespawnPet(); - if (cached == buildCache.end()) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;"); - query.bind(1, (int) m_Parent->GetLOT()); + const auto& cached = buildCache.find(m_Parent->GetLOT()); + int32_t imaginationCost = 0; - auto result = query.execQuery(); + std::string buildFile; - if (result.eof()) - { - ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet."); + if (cached == buildCache.end()) { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;"); + query.bind(1, (int)m_Parent->GetLOT()); - return; - } + auto result = query.execQuery(); - if (result.fieldIsNull(0)) - { - result.finalize(); + if (result.eof()) { + ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet."); - return; - } + return; + } - auto lxfAsset = std::string(result.getStringField(0)); + if (result.fieldIsNull(0)) { + result.finalize(); - std::vector lxfAssetSplit = GeneralUtils::SplitString(lxfAsset, '\\'); + return; + } - lxfAssetSplit.erase(lxfAssetSplit.begin()); + buildFile = std::string(result.getStringField(0)); - buildFile = "res/BrickModels"; + PetPuzzleData data; + data.buildFile = buildFile; + data.puzzleModelLot = result.getIntField(1); + data.timeLimit = result.getFloatField(2); + data.numValidPieces = result.getIntField(3); + data.imaginationCost = result.getIntField(4); + if (data.timeLimit <= 0) data.timeLimit = 60; + imaginationCost = data.imaginationCost; - for (auto part: lxfAssetSplit) - { - std::transform(part.begin(), part.end(), part.begin(), [](unsigned char c) { - return std::tolower(c); - }); + buildCache[m_Parent->GetLOT()] = data; - buildFile += "/" + part; - } + result.finalize(); + } else { + buildFile = cached->second.buildFile; + imaginationCost = cached->second.imaginationCost; + } - PetPuzzleData data; - data.buildFile = buildFile; - data.puzzleModelLot = result.getIntField(1); - data.timeLimit = result.getFloatField(2); - data.numValidPieces = result.getIntField(3); - data.imaginationCost = result.getIntField(4); - if (data.timeLimit <= 0) data.timeLimit = 60; - imaginationCost = data.imaginationCost; + auto* destroyableComponent = originator->GetComponent(); - buildCache[m_Parent->GetLOT()] = data; + if (destroyableComponent == nullptr) { + return; + } - result.finalize(); - } - else - { - buildFile = cached->second.buildFile; - imaginationCost = cached->second.imaginationCost; - } + auto imagination = destroyableComponent->GetImagination(); - auto* destroyableComponent = originator->GetComponent(); - - if (destroyableComponent == nullptr) - { - return; - } + if (imagination < imaginationCost) { + return; + } - auto imagination = destroyableComponent->GetImagination(); + auto& bricks = BrickDatabase::Instance()->GetBricks(buildFile); - if (imagination < imaginationCost) - { - return; - } + if (bricks.empty()) { + ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet."); + Game::logger->Log("PetComponent", "Couldn't find %s for minigame!", buildFile.c_str()); - auto& bricks = BrickDatabase::Instance()->GetBricks(buildFile); + return; + } - if (bricks.empty()) - { - ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet."); - Game::logger->Log("PetComponent", "Couldn't find %s for minigame!\n", buildFile.c_str()); + auto petPosition = m_Parent->GetPosition(); - return; - } + auto originatorPosition = originator->GetPosition(); - auto petPosition = m_Parent->GetPosition(); + m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition)); - auto originatorPosition = originator->GetPosition(); + float interactionDistance = m_Parent->GetVar(u"interaction_distance"); - m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition)); + if (interactionDistance <= 0) { + interactionDistance = 15; + } - float interactionDistance = m_Parent->GetVar(u"interaction_distance"); + auto position = originatorPosition; - if (interactionDistance <= 0) - { - interactionDistance = 15; - } + NiPoint3 forward = NiQuaternion::LookAt(m_Parent->GetPosition(), originator->GetPosition()).GetForwardVector(); + forward.y = 0; - auto position = originatorPosition; - - NiPoint3 forward = NiQuaternion::LookAt(m_Parent->GetPosition(), originator->GetPosition()).GetForwardVector(); - forward.y = 0; + if (dpWorld::Instance().IsLoaded()) { + NiPoint3 attempt = petPosition + forward * interactionDistance; - if (dpWorld::Instance().IsLoaded()) - { - NiPoint3 attempt = petPosition + forward * interactionDistance; + float y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(attempt); - float y = dpWorld::Instance().GetHeightAtPoint(attempt); + while (std::abs(y - petPosition.y) > 4 && interactionDistance > 10) { + const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector(); - while (std::abs(y - petPosition.y) > 4 && interactionDistance > 10) - { - const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector(); + attempt = originatorPosition + forward * interactionDistance; - attempt = originatorPosition + forward * interactionDistance; - - y = dpWorld::Instance().GetHeightAtPoint(attempt); + y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(attempt); - interactionDistance -= 0.5f; - } + interactionDistance -= 0.5f; + } - position = attempt; - } - else - { - position = petPosition + forward * interactionDistance; - } - + position = attempt; + } else { + position = petPosition + forward * interactionDistance; + } - auto rotation = NiQuaternion::LookAt(position, petPosition); - - GameMessages::SendNotifyPetTamingMinigame( - originator->GetObjectID(), - m_Parent->GetObjectID(), - LWOOBJID_EMPTY, - true, - NOTIFY_TYPE_BEGIN, - petPosition, - position, - rotation, - UNASSIGNED_SYSTEM_ADDRESS - ); - GameMessages::SendNotifyPetTamingMinigame( - m_Parent->GetObjectID(), - LWOOBJID_EMPTY, - originator->GetObjectID(), - true, - NOTIFY_TYPE_BEGIN, - petPosition, - position, - rotation, - UNASSIGNED_SYSTEM_ADDRESS - ); + auto rotation = NiQuaternion::LookAt(position, petPosition); - GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress()); + GameMessages::SendNotifyPetTamingMinigame( + originator->GetObjectID(), + m_Parent->GetObjectID(), + LWOOBJID_EMPTY, + true, + ePetTamingNotifyType::BEGIN, + petPosition, + position, + rotation, + UNASSIGNED_SYSTEM_ADDRESS + ); - m_Tamer = originator->GetObjectID(); - SetStatus(5); + GameMessages::SendNotifyPetTamingMinigame( + m_Parent->GetObjectID(), + LWOOBJID_EMPTY, + originator->GetObjectID(), + true, + ePetTamingNotifyType::BEGIN, + petPosition, + position, + rotation, + UNASSIGNED_SYSTEM_ADDRESS + ); - currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); + GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress()); - // Notify the start of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, originator, NOTIFY_TYPE_BEGIN); - } + m_Tamer = originator->GetObjectID(); + SetStatus(5); + + currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); + + // Notify the start of a pet taming minigame + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN); + } } -void PetComponent::Update(float deltaTime) -{ - if (m_StartPosition == NiPoint3::ZERO) - { - m_StartPosition = m_Parent->GetPosition(); - } +void PetComponent::Update(float deltaTime) { + if (m_StartPosition == NiPoint3::ZERO) { + m_StartPosition = m_Parent->GetPosition(); + } - if (m_Owner == LWOOBJID_EMPTY) - { - if (m_Tamer != LWOOBJID_EMPTY) - { - if (m_Timer > 0) - { - m_Timer -= deltaTime; + if (m_Owner == LWOOBJID_EMPTY) { + if (m_Tamer != LWOOBJID_EMPTY) { + if (m_Timer > 0) { + m_Timer -= deltaTime; - if (m_Timer <= 0) - { - m_Timer = 0; + if (m_Timer <= 0) { + m_Timer = 0; - ClientFailTamingMinigame(); - } - } - } - else - { - if (m_Timer > 0) - { - m_Timer -= deltaTime; + ClientFailTamingMinigame(); + } + } + } else { + if (m_Timer > 0) { + m_Timer -= deltaTime; - if (m_Timer <= 0) - { - Wander(); - EntityManager::Instance()->SerializeEntity(m_Parent); - } - } - else - { - m_Timer = 5; - } - } + if (m_Timer <= 0) { + Wander(); + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } else { + m_Timer = 5; + } + } - return; - } + return; + } - auto* owner = GetOwner(); + auto* owner = GetOwner(); - if (owner == nullptr) - { - m_Parent->Kill(); + if (owner == nullptr) { + m_Parent->Kill(); - return; - } + return; + } - m_MovementAI = m_Parent->GetComponent(); + m_MovementAI = m_Parent->GetComponent(); - if (m_MovementAI == nullptr) - { - return; - } + if (m_MovementAI == nullptr) { + return; + } - if (m_TresureTime > 0) - { - auto* tresure = EntityManager::Instance()->GetEntity(m_Interaction); + if (m_TresureTime > 0) { + auto* tresure = EntityManager::Instance()->GetEntity(m_Interaction); - if (tresure == nullptr) - { - m_TresureTime = 0; + if (tresure == nullptr) { + m_TresureTime = 0; - return; - } + return; + } - m_TresureTime -= deltaTime; - - m_MovementAI->Stop(); + m_TresureTime -= deltaTime; - if (m_TresureTime <= 0) - { - m_Parent->SetOwnerOverride(m_Owner); + m_MovementAI->Stop(); - tresure->Smash(m_Parent->GetObjectID()); + if (m_TresureTime <= 0) { + m_Parent->SetOwnerOverride(m_Owner); - m_Interaction = LWOOBJID_EMPTY; + tresure->Smash(m_Parent->GetObjectID()); - m_TresureTime = 0; - } + m_Interaction = LWOOBJID_EMPTY; - return; - } + m_TresureTime = 0; + } - auto destination = owner->GetPosition(); - NiPoint3 position = m_MovementAI->GetCurrentPosition(); + return; + } - float distanceToOwner = Vector3::DistanceSquared(position, destination); + auto destination = owner->GetPosition(); + NiPoint3 position = m_MovementAI->GetCurrentPosition(); - if (distanceToOwner > 50 * 50 || m_TimerAway > 5) - { - m_MovementAI->Warp(destination); + float distanceToOwner = Vector3::DistanceSquared(position, destination); - m_Timer = 1; - m_TimerAway = 0; + if (distanceToOwner > 50 * 50 || m_TimerAway > 5) { + m_MovementAI->Warp(destination); - return; - } + m_Timer = 1; + m_TimerAway = 0; - if (distanceToOwner > 15 * 15 || std::abs(destination.y - position.y) >= 3) - { - m_TimerAway += deltaTime; - } - else - { - m_TimerAway = 0; - } + return; + } - if (m_Timer > 0) - { - m_Timer -= deltaTime; - - return; - } + if (distanceToOwner > 15 * 15 || std::abs(destination.y - position.y) >= 3) { + m_TimerAway += deltaTime; + } else { + m_TimerAway = 0; + } - SwitchComponent* closestSwitch = SwitchComponent::GetClosestSwitch(position); + if (m_Timer > 0) { + m_Timer -= deltaTime; - float haltDistance = 5; + return; + } - if (closestSwitch != nullptr) - { - if (!closestSwitch->GetActive()) - { - NiPoint3 switchPosition = closestSwitch->GetParentEntity()->GetPosition(); - float distance = Vector3::DistanceSquared(position, switchPosition); - if (distance < 3 * 3) - { - m_Interaction = closestSwitch->GetParentEntity()->GetObjectID(); - closestSwitch->EntityEnter(m_Parent); - } - else if (distance < 20 * 20) - { - haltDistance = 1; + SwitchComponent* closestSwitch = SwitchComponent::GetClosestSwitch(position); - destination = switchPosition; - } - } - } + float haltDistance = 5; - Entity* closestTresure = PetDigServer::GetClosestTresure(position); + if (closestSwitch != nullptr) { + if (!closestSwitch->GetActive()) { + NiPoint3 switchPosition = closestSwitch->GetParentEntity()->GetPosition(); + float distance = Vector3::DistanceSquared(position, switchPosition); + if (distance < 3 * 3) { + m_Interaction = closestSwitch->GetParentEntity()->GetObjectID(); + closestSwitch->EntityEnter(m_Parent); + } else if (distance < 20 * 20) { + haltDistance = 1; - if (closestTresure != nullptr) - { - // Skeleton Dragon Pat special case for bone digging - if (closestTresure->GetLOT() == 12192 && m_Parent->GetLOT() != 13067) - { - goto skipTresure; - } + destination = switchPosition; + } + } + } - NiPoint3 tresurePosition = closestTresure->GetPosition(); - float distance = Vector3::DistanceSquared(position, tresurePosition); - if (distance < 3 * 3) - { - m_Interaction = closestTresure->GetObjectID(); - - Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, 202, true); + Entity* closestTresure = PetDigServer::GetClosestTresure(position); - m_TresureTime = 2; - } - else if (distance < 10 * 10) - { - haltDistance = 1; + if (closestTresure != nullptr) { + // Skeleton Dragon Pat special case for bone digging + if (closestTresure->GetLOT() == 12192 && m_Parent->GetLOT() != 13067) { + goto skipTresure; + } - destination = tresurePosition; - } - } + NiPoint3 tresurePosition = closestTresure->GetPosition(); + float distance = Vector3::DistanceSquared(position, tresurePosition); + if (distance < 3 * 3) { + m_Interaction = closestTresure->GetObjectID(); - skipTresure: + Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, 202, true); - m_MovementAI->SetHaltDistance(haltDistance); - - m_MovementAI->SetSpeed(2.5f); + m_TresureTime = 2; + } else if (distance < 10 * 10) { + haltDistance = 1; - m_MovementAI->SetDestination(destination); + destination = tresurePosition; + } + } - m_Timer = 1; +skipTresure: + + m_MovementAI->SetHaltDistance(haltDistance); + + m_MovementAI->SetSpeed(2.5f); + + m_MovementAI->SetDestination(destination); + + m_Timer = 1; } void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { - if (m_Tamer == LWOOBJID_EMPTY) return; + if (m_Tamer == LWOOBJID_EMPTY) return; - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) { - m_Tamer = LWOOBJID_EMPTY; + if (tamer == nullptr) { + m_Tamer = LWOOBJID_EMPTY; - return; - } + return; + } - const auto& cached = buildCache.find(m_Parent->GetLOT()); + const auto& cached = buildCache.find(m_Parent->GetLOT()); - if (cached == buildCache.end()) return; + if (cached == buildCache.end()) return; - auto* destroyableComponent = tamer->GetComponent(); + auto* destroyableComponent = tamer->GetComponent(); - if (destroyableComponent == nullptr) return; + if (destroyableComponent == nullptr) return; - auto imagination = destroyableComponent->GetImagination(); + auto imagination = destroyableComponent->GetImagination(); - imagination -= cached->second.imaginationCost; + imagination -= cached->second.imaginationCost; - destroyableComponent->SetImagination(imagination); + destroyableComponent->SetImagination(imagination); - EntityManager::Instance()->SerializeEntity(tamer); + EntityManager::Instance()->SerializeEntity(tamer); - if (clientFailed) { - if (imagination < cached->second.imaginationCost) { - ClientFailTamingMinigame(); - } - } else { - m_Timer = 0; - } + if (clientFailed) { + if (imagination < cached->second.imaginationCost) { + ClientFailTamingMinigame(); + } + } else { + m_Timer = 0; + } - if (numBricks == 0) return; + if (numBricks == 0) return; - GameMessages::SendPetTamingTryBuildResult(m_Tamer, !clientFailed, numBricks, tamer->GetSystemAddress()); + GameMessages::SendPetTamingTryBuildResult(m_Tamer, !clientFailed, numBricks, tamer->GetSystemAddress()); } -void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) -{ - if (m_Tamer == LWOOBJID_EMPTY) return; +void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { + if (m_Tamer == LWOOBJID_EMPTY) return; - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) - { - m_Tamer = LWOOBJID_EMPTY; + if (tamer == nullptr) { + m_Tamer = LWOOBJID_EMPTY; - return; - } + return; + } - const auto& cached = buildCache.find(m_Parent->GetLOT()); + const auto& cached = buildCache.find(m_Parent->GetLOT()); - if (cached == buildCache.end()) - { - return; - } + if (cached == buildCache.end()) { + return; + } - GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true); - GameMessages::SendPlayAnimation(tamer, u"rebuild-celebrate"); + GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::SendPlayAnimation(tamer, u"rebuild-celebrate"); - EntityInfo info {}; - info.lot = cached->second.puzzleModelLot; - info.pos = position; - info.rot = NiQuaternion::IDENTITY; - info.spawnerID = tamer->GetObjectID(); + EntityInfo info{}; + info.lot = cached->second.puzzleModelLot; + info.pos = position; + info.rot = NiQuaternion::IDENTITY; + info.spawnerID = tamer->GetObjectID(); - auto* modelEntity = EntityManager::Instance()->CreateEntity(info); - - m_ModelId = modelEntity->GetObjectID(); + auto* modelEntity = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(modelEntity); + m_ModelId = modelEntity->GetObjectID(); - GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); + EntityManager::Instance()->ConstructEntity(modelEntity); - GameMessages::SendPetResponse(m_Tamer, m_Parent->GetObjectID(), 0, 10, 0, tamer->GetSystemAddress()); + GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); - auto* inventoryComponent = tamer->GetComponent(); + GameMessages::SendPetResponse(m_Tamer, m_Parent->GetObjectID(), 0, 10, 0, tamer->GetSystemAddress()); - if (inventoryComponent == nullptr) - { - return; - } + auto* inventoryComponent = tamer->GetComponent(); - LWOOBJID petSubKey = ObjectIDManager::Instance()->GenerateRandomObjectID(); + if (inventoryComponent == nullptr) { + return; + } - petSubKey = GeneralUtils::SetBit(petSubKey, OBJECT_BIT_CHARACTER); - petSubKey = GeneralUtils::SetBit(petSubKey, OBJECT_BIT_PERSISTENT); + LWOOBJID petSubKey = ObjectIDManager::Instance()->GenerateRandomObjectID(); - m_DatabaseId = petSubKey; - - std::string petName = tamer->GetCharacter()->GetName(); - petName += "'s Pet"; + GeneralUtils::SetBit(petSubKey, eObjectBits::CHARACTER); + GeneralUtils::SetBit(petSubKey, eObjectBits::PERSISTENT); - GameMessages::SendAddPetToPlayer(m_Tamer, 0, GeneralUtils::ASCIIToUTF16(petName), petSubKey, m_Parent->GetLOT(), tamer->GetSystemAddress()); - - GameMessages::SendRegisterPetID(m_Tamer, m_Parent->GetObjectID(), tamer->GetSystemAddress()); + m_DatabaseId = petSubKey; - GameMessages::SendRegisterPetDBID(m_Tamer, petSubKey, tamer->GetSystemAddress()); - - inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::LOOT_SOURCE_ACTIVITY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey); - auto* item = inventoryComponent->FindItemBySubKey(petSubKey, MODELS); - - if (item == nullptr) - { - return; - } + std::string petName = tamer->GetCharacter()->GetName(); + petName += "'s Pet"; - DatabasePet databasePet {}; - - databasePet.lot = m_Parent->GetLOT(); - databasePet.moderationState = 1; - databasePet.name = petName; + GameMessages::SendAddPetToPlayer(m_Tamer, 0, GeneralUtils::UTF8ToUTF16(petName), petSubKey, m_Parent->GetLOT(), tamer->GetSystemAddress()); - inventoryComponent->SetDatabasePet(petSubKey, databasePet); + GameMessages::SendRegisterPetID(m_Tamer, m_Parent->GetObjectID(), tamer->GetSystemAddress()); - Activate(item, false, true); + GameMessages::SendRegisterPetDBID(m_Tamer, petSubKey, tamer->GetSystemAddress()); - m_Timer = 0; + inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey); + auto* item = inventoryComponent->FindItemBySubKey(petSubKey, MODELS); - GameMessages::SendNotifyPetTamingMinigame( - m_Tamer, - LWOOBJID_EMPTY, - LWOOBJID_EMPTY, - false, - NOTIFY_TYPE_NAMINGPET, - NiPoint3::ZERO, - NiPoint3::ZERO, - NiQuaternion::IDENTITY, - UNASSIGNED_SYSTEM_ADDRESS - ); + if (item == nullptr) { + return; + } - // Triggers the catch a pet missions - if (petFlags.find(m_Parent->GetLOT()) != petFlags.end()) { - tamer->GetCharacter()->SetPlayerFlag(petFlags.at(m_Parent->GetLOT()), true); - } + DatabasePet databasePet{}; - auto* missionComponent = tamer->GetComponent(); + databasePet.lot = m_Parent->GetLOT(); + databasePet.moderationState = 1; + databasePet.name = petName; - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PET_TAMING, m_Parent->GetLOT()); - } + inventoryComponent->SetDatabasePet(petSubKey, databasePet); - SetStatus(1); + Activate(item, false, true); - auto* characterComponent = tamer->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(PetsTamed); - } + m_Timer = 0; + + GameMessages::SendNotifyPetTamingMinigame( + m_Tamer, + LWOOBJID_EMPTY, + LWOOBJID_EMPTY, + false, + ePetTamingNotifyType::NAMINGPET, + NiPoint3::ZERO, + NiPoint3::ZERO, + NiQuaternion::IDENTITY, + UNASSIGNED_SYSTEM_ADDRESS + ); + + // Triggers the catch a pet missions + if (petFlags.find(m_Parent->GetLOT()) != petFlags.end()) { + tamer->GetCharacter()->SetPlayerFlag(petFlags.at(m_Parent->GetLOT()), true); + } + + auto* missionComponent = tamer->GetComponent(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT()); + } + + SetStatus(1); + + auto* characterComponent = tamer->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(PetsTamed); + } } -void PetComponent::RequestSetPetName(std::u16string name) -{ - if (m_Tamer == LWOOBJID_EMPTY) - { - if (m_Owner != LWOOBJID_EMPTY) - { - auto* owner = GetOwner(); +void PetComponent::RequestSetPetName(std::u16string name) { + if (m_Tamer == LWOOBJID_EMPTY) { + if (m_Owner != LWOOBJID_EMPTY) { + auto* owner = GetOwner(); - m_ModerationStatus = 1; // Pending - m_Name = ""; + m_ModerationStatus = 1; // Pending + m_Name = ""; - //Save our pet's new name to the db: - SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name)); + //Save our pet's new name to the db: + SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name)); - GameMessages::SendSetPetName(m_Owner, GeneralUtils::ASCIIToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress()); - GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress()); - } + GameMessages::SendSetPetName(m_Owner, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress()); + GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress()); + } - return; - } + return; + } - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) - { - m_Tamer = LWOOBJID_EMPTY; + if (tamer == nullptr) { + m_Tamer = LWOOBJID_EMPTY; - return; - } + return; + } - Game::logger->Log("PetComponent", "Got set pet name (%s)\n", GeneralUtils::UTF16ToWTF8(name).c_str()); + Game::logger->Log("PetComponent", "Got set pet name (%s)", GeneralUtils::UTF16ToWTF8(name).c_str()); - auto* inventoryComponent = tamer->GetComponent(); + auto* inventoryComponent = tamer->GetComponent(); - if (inventoryComponent == nullptr) - { - return; - } + if (inventoryComponent == nullptr) { + return; + } - m_ModerationStatus = 1; // Pending - m_Name = ""; + m_ModerationStatus = 1; // Pending + m_Name = ""; - //Save our pet's new name to the db: - SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name)); + //Save our pet's new name to the db: + SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name)); - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); - GameMessages::SendSetPetName(m_Tamer, GeneralUtils::ASCIIToUTF16(m_Name), m_DatabaseId, tamer->GetSystemAddress()); - GameMessages::SendSetPetName(m_Tamer, GeneralUtils::ASCIIToUTF16(m_Name), LWOOBJID_EMPTY, tamer->GetSystemAddress()); - GameMessages::SendPetNameChanged(m_Parent->GetObjectID(), m_ModerationStatus, GeneralUtils::ASCIIToUTF16(m_Name), GeneralUtils::ASCIIToUTF16(m_OwnerName), UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendSetPetNameModerated(m_Tamer, m_DatabaseId, m_ModerationStatus, tamer->GetSystemAddress()); + std::u16string u16name = GeneralUtils::UTF8ToUTF16(m_Name); + std::u16string u16ownerName = GeneralUtils::UTF8ToUTF16(m_OwnerName); + GameMessages::SendSetPetName(m_Tamer, u16name, m_DatabaseId, tamer->GetSystemAddress()); + GameMessages::SendSetPetName(m_Tamer, u16name, LWOOBJID_EMPTY, tamer->GetSystemAddress()); + GameMessages::SendPetNameChanged(m_Parent->GetObjectID(), m_ModerationStatus, u16name, u16ownerName, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendSetPetNameModerated(m_Tamer, m_DatabaseId, m_ModerationStatus, tamer->GetSystemAddress()); - GameMessages::SendNotifyPetTamingMinigame( - m_Tamer, - m_Parent->GetObjectID(), - m_Tamer, - false, - NOTIFY_TYPE_SUCCESS, - NiPoint3::ZERO, - NiPoint3::ZERO, - NiQuaternion::IDENTITY, - UNASSIGNED_SYSTEM_ADDRESS - ); + GameMessages::SendNotifyPetTamingMinigame( + m_Tamer, + m_Parent->GetObjectID(), + m_Tamer, + false, + ePetTamingNotifyType::SUCCESS, + NiPoint3::ZERO, + NiPoint3::ZERO, + NiQuaternion::IDENTITY, + UNASSIGNED_SYSTEM_ADDRESS + ); - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - auto* modelEntity = EntityManager::Instance()->GetEntity(m_ModelId); + auto* modelEntity = EntityManager::Instance()->GetEntity(m_ModelId); - if (modelEntity != nullptr) - { - modelEntity->Smash(m_Tamer); - } + if (modelEntity != nullptr) { + modelEntity->Smash(m_Tamer); + } - currentActivities.erase(m_Tamer); + currentActivities.erase(m_Tamer); - m_Tamer = LWOOBJID_EMPTY; + m_Tamer = LWOOBJID_EMPTY; - // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, NOTIFY_TYPE_SUCCESS); - } + // Notify the end of a pet taming minigame + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::SUCCESS); + } } -void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) -{ - if (m_Tamer == LWOOBJID_EMPTY) return; +void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { + if (m_Tamer == LWOOBJID_EMPTY) return; - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) - { - m_Tamer = LWOOBJID_EMPTY; + if (tamer == nullptr) { + m_Tamer = LWOOBJID_EMPTY; - return; - } + return; + } - GameMessages::SendNotifyPetTamingMinigame( - m_Tamer, - m_Parent->GetObjectID(), - m_Tamer, - false, - NOTIFY_TYPE_QUIT, - NiPoint3::ZERO, - NiPoint3::ZERO, - NiQuaternion::IDENTITY, - UNASSIGNED_SYSTEM_ADDRESS - ); + GameMessages::SendNotifyPetTamingMinigame( + m_Tamer, + m_Parent->GetObjectID(), + m_Tamer, + false, + ePetTamingNotifyType::QUIT, + NiPoint3::ZERO, + NiPoint3::ZERO, + NiQuaternion::IDENTITY, + UNASSIGNED_SYSTEM_ADDRESS + ); - GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); + GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - currentActivities.erase(m_Tamer); + currentActivities.erase(m_Tamer); - SetStatus(67108866); - m_Tamer = LWOOBJID_EMPTY; - m_Timer = 0; - - EntityManager::Instance()->SerializeEntity(m_Parent); + SetStatus(67108866); + m_Tamer = LWOOBJID_EMPTY; + m_Timer = 0; - // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, NOTIFY_TYPE_QUIT); - } + EntityManager::Instance()->SerializeEntity(m_Parent); + + // Notify the end of a pet taming minigame + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::QUIT); + } } -void PetComponent::StartTimer() -{ - const auto& cached = buildCache.find(m_Parent->GetLOT()); +void PetComponent::StartTimer() { + const auto& cached = buildCache.find(m_Parent->GetLOT()); - if (cached == buildCache.end()) - { - return; - } + if (cached == buildCache.end()) { + return; + } - m_Timer = cached->second.timeLimit; + m_Timer = cached->second.timeLimit; } -void PetComponent::ClientFailTamingMinigame() -{ - if (m_Tamer == LWOOBJID_EMPTY) return; +void PetComponent::ClientFailTamingMinigame() { + if (m_Tamer == LWOOBJID_EMPTY) return; - auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); + auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) - { - m_Tamer = LWOOBJID_EMPTY; + if (tamer == nullptr) { + m_Tamer = LWOOBJID_EMPTY; - return; - } + return; + } - GameMessages::SendNotifyPetTamingMinigame( - m_Tamer, - m_Parent->GetObjectID(), - m_Tamer, - false, - NOTIFY_TYPE_FAILED, - NiPoint3::ZERO, - NiPoint3::ZERO, - NiQuaternion::IDENTITY, - UNASSIGNED_SYSTEM_ADDRESS - ); + GameMessages::SendNotifyPetTamingMinigame( + m_Tamer, + m_Parent->GetObjectID(), + m_Tamer, + false, + ePetTamingNotifyType::FAILED, + NiPoint3::ZERO, + NiPoint3::ZERO, + NiQuaternion::IDENTITY, + UNASSIGNED_SYSTEM_ADDRESS + ); - GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); + GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - currentActivities.erase(m_Tamer); + currentActivities.erase(m_Tamer); - SetStatus(67108866); - m_Tamer = LWOOBJID_EMPTY; - m_Timer = 0; - - EntityManager::Instance()->SerializeEntity(m_Parent); + SetStatus(67108866); + m_Tamer = LWOOBJID_EMPTY; + m_Timer = 0; - // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, NOTIFY_TYPE_FAILED); - } + EntityManager::Instance()->SerializeEntity(m_Parent); + + // Notify the end of a pet taming minigame + for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { + script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::FAILED); + } } -void PetComponent::Wander() -{ - m_MovementAI = m_Parent->GetComponent(); +void PetComponent::Wander() { + m_MovementAI = m_Parent->GetComponent(); - if (m_MovementAI == nullptr || !m_MovementAI->AtFinalWaypoint()) { - return; + if (m_MovementAI == nullptr || !m_MovementAI->AtFinalWaypoint()) { + return; } m_MovementAI->SetHaltDistance(0); - + const auto& info = m_MovementAI->GetInfo(); const auto div = static_cast(info.wanderDelayMax); m_Timer = (div == 0 ? 0 : GeneralUtils::GenerateRandomNumber(0, div)) + info.wanderDelayMin; //set a random timer to stay put. - + const float radius = info.wanderRadius * sqrt(static_cast(GeneralUtils::GenerateRandomNumber(0, 1))); //our wander radius + a bit of random range const float theta = ((static_cast(GeneralUtils::GenerateRandomNumber(0, 1)) * 2 * PI)); @@ -896,7 +818,7 @@ void PetComponent::Wander() auto destination = m_StartPosition + delta; if (dpWorld::Instance().IsLoaded()) { - destination.y = dpWorld::Instance().GetHeightAtPoint(destination); + destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination); } if (Vector3::DistanceSquared(destination, m_MovementAI->GetCurrentPosition()) < 2 * 2) { @@ -912,325 +834,294 @@ void PetComponent::Wander() m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / info.wanderSpeed; } -void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) -{ - AddDrainImaginationTimer(item, fromTaming); +void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { + AddDrainImaginationTimer(item, fromTaming); - m_ItemId = item->GetId(); - m_DatabaseId = item->GetSubKey(); - - auto* inventoryComponent = item->GetInventory()->GetComponent(); + m_ItemId = item->GetId(); + m_DatabaseId = item->GetSubKey(); - if (inventoryComponent == nullptr) return; + auto* inventoryComponent = item->GetInventory()->GetComponent(); - inventoryComponent->DespawnPet(); + if (inventoryComponent == nullptr) return; - m_Owner = inventoryComponent->GetParent()->GetObjectID(); + inventoryComponent->DespawnPet(); - auto* owner = GetOwner(); + m_Owner = inventoryComponent->GetParent()->GetObjectID(); - if (owner == nullptr) return; - SetStatus(1); + auto* owner = GetOwner(); - auto databaseData = inventoryComponent->GetDatabasePet(m_DatabaseId); + if (owner == nullptr) return; + SetStatus(1); - m_ModerationStatus = databaseData.moderationState; + auto databaseData = inventoryComponent->GetDatabasePet(m_DatabaseId); - bool updatedModerationStatus = false; + m_ModerationStatus = databaseData.moderationState; - //Load mod status from db: - if (m_ModerationStatus != 2) - { - LoadPetNameFromModeration(); + bool updatedModerationStatus = false; - databaseData.name = m_Name; - databaseData.moderationState = m_ModerationStatus; + //Load mod status from db: + if (m_ModerationStatus != 2) { + LoadPetNameFromModeration(); - inventoryComponent->SetDatabasePet(m_DatabaseId, databaseData); + databaseData.name = m_Name; + databaseData.moderationState = m_ModerationStatus; - updatedModerationStatus = true; - } - else - { - m_Name = databaseData.name; - } + inventoryComponent->SetDatabasePet(m_DatabaseId, databaseData); - m_OwnerName = owner->GetCharacter()->GetName(); + updatedModerationStatus = true; + } else { + m_Name = databaseData.name; + } - if (updatedModerationStatus) - { - GameMessages::SendSetPetName(m_Owner, GeneralUtils::ASCIIToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress()); - GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress()); - } + m_OwnerName = owner->GetCharacter()->GetName(); - GameMessages::SendMarkInventoryItemAsActive(m_Owner, true, 0, m_ItemId, GetOwner()->GetSystemAddress()); + if (updatedModerationStatus) { + GameMessages::SendSetPetName(m_Owner, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress()); + GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress()); + } - activePets[m_Owner] = m_Parent->GetObjectID(); + GameMessages::SendMarkInventoryItemAsActive(m_Owner, true, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress()); - m_Timer = 3; + activePets[m_Owner] = m_Parent->GetObjectID(); - EntityManager::Instance()->SerializeEntity(m_Parent); + m_Timer = 3; - owner->GetCharacter()->SetPlayerFlag(69, true); + EntityManager::Instance()->SerializeEntity(m_Parent); - if (registerPet) - { - GameMessages::SendAddPetToPlayer(m_Owner, 0, GeneralUtils::ASCIIToUTF16(m_Name), m_DatabaseId, m_Parent->GetLOT(), owner->GetSystemAddress()); + owner->GetCharacter()->SetPlayerFlag(ePlayerFlag::FIRST_MANUAL_PET_HIBERNATE, true); - GameMessages::SendRegisterPetID(m_Owner, m_Parent->GetObjectID(), owner->GetSystemAddress()); + if (registerPet) { + GameMessages::SendAddPetToPlayer(m_Owner, 0, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, m_Parent->GetLOT(), owner->GetSystemAddress()); - GameMessages::SendRegisterPetDBID(m_Owner, m_DatabaseId, owner->GetSystemAddress()); - } + GameMessages::SendRegisterPetID(m_Owner, m_Parent->GetObjectID(), owner->GetSystemAddress()); - GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress()); + GameMessages::SendRegisterPetDBID(m_Owner, m_DatabaseId, owner->GetSystemAddress()); + } + + GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress()); } void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { - if (Game::config->GetValue("pets_take_imagination") != "1") return; + if (Game::config->GetValue("pets_take_imagination") != "1") return; - auto playerInventory = item->GetInventory(); - if (!playerInventory) return; + auto playerInventory = item->GetInventory(); + if (!playerInventory) return; - auto playerInventoryComponent = playerInventory->GetComponent(); - if (!playerInventoryComponent) return; + auto playerInventoryComponent = playerInventory->GetComponent(); + if (!playerInventoryComponent) return; - auto playerEntity = playerInventoryComponent->GetParent(); - if (!playerEntity) return; + auto playerEntity = playerInventoryComponent->GetParent(); + if (!playerEntity) return; - auto playerDestroyableComponent = playerEntity->GetComponent(); - if (!playerDestroyableComponent) return; + auto playerDestroyableComponent = playerEntity->GetComponent(); + if (!playerDestroyableComponent) return; - // Drain by 1 when you summon pet or when this method is called, but not when we have just tamed this pet. - if (!fromTaming) playerDestroyableComponent->Imagine(-1); + // Drain by 1 when you summon pet or when this method is called, but not when we have just tamed this pet. + if (!fromTaming) playerDestroyableComponent->Imagine(-1); - // Set this to a variable so when this is called back from the player the timer doesn't fire off. - m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item](){ - if (!playerDestroyableComponent) { - Game::logger->Log("PetComponent", "No petComponent and/or no playerDestroyableComponent\n"); - return; - } - - // If we are out of imagination despawn the pet. - if (playerDestroyableComponent->GetImagination() == 0) { - this->Deactivate(); - auto playerEntity = playerDestroyableComponent->GetParent(); - if (!playerEntity) return; + // Set this to a variable so when this is called back from the player the timer doesn't fire off. + m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item]() { + if (!playerDestroyableComponent) { + Game::logger->Log("PetComponent", "No petComponent and/or no playerDestroyableComponent"); + return; + } - GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); - } + // If we are out of imagination despawn the pet. + if (playerDestroyableComponent->GetImagination() == 0) { + this->Deactivate(); + auto playerEntity = playerDestroyableComponent->GetParent(); + if (!playerEntity) return; - this->AddDrainImaginationTimer(item); - }); + GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), eUseItemResponse::NoImaginationForPet); + } + + this->AddDrainImaginationTimer(item); + }); } -void PetComponent::Deactivate() -{ - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); +void PetComponent::Deactivate() { + GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); - GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, 0, m_ItemId, GetOwner()->GetSystemAddress()); + GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress()); - activePets.erase(m_Owner); + activePets.erase(m_Owner); - m_Parent->Kill(); + m_Parent->Kill(); - auto* owner = GetOwner(); + auto* owner = GetOwner(); - if (owner == nullptr) return; - - GameMessages::SendAddPetToPlayer(m_Owner, 0, u"", LWOOBJID_EMPTY, LOT_NULL, owner->GetSystemAddress()); + if (owner == nullptr) return; - GameMessages::SendRegisterPetID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); + GameMessages::SendAddPetToPlayer(m_Owner, 0, u"", LWOOBJID_EMPTY, LOT_NULL, owner->GetSystemAddress()); - GameMessages::SendRegisterPetDBID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); + GameMessages::SendRegisterPetID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); - GameMessages::SendShowPetActionButton(m_Owner, 0, false, owner->GetSystemAddress()); + GameMessages::SendRegisterPetDBID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); + + GameMessages::SendShowPetActionButton(m_Owner, 0, false, owner->GetSystemAddress()); } -void PetComponent::Release() -{ - auto* inventoryComponent = GetOwner()->GetComponent(); +void PetComponent::Release() { + auto* inventoryComponent = GetOwner()->GetComponent(); - if (inventoryComponent == nullptr) - { - return; - } - - Deactivate(); + if (inventoryComponent == nullptr) { + return; + } - inventoryComponent->RemoveDatabasePet(m_DatabaseId); + Deactivate(); - auto* item = inventoryComponent->FindItemBySubKey(m_DatabaseId); + inventoryComponent->RemoveDatabasePet(m_DatabaseId); - item->SetCount(0, false, false); + auto* item = inventoryComponent->FindItemBySubKey(m_DatabaseId); + + item->SetCount(0, false, false); } -void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey) -{ - auto* owner = GetOwner(); +void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey) { + auto* owner = GetOwner(); - if (owner == nullptr) - { - return; - } + if (owner == nullptr) { + return; + } - if (commandType == 1) { - // Emotes - GameMessages::SendPlayEmote(m_Parent->GetObjectID(), typeId, owner->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - } else if (commandType == 3) { - // Follow me, ??? - } else if (commandType == 6) { - // TODO: Go to player - } + if (commandType == 1) { + // Emotes + GameMessages::SendPlayEmote(m_Parent->GetObjectID(), typeId, owner->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } else if (commandType == 3) { + // Follow me, ??? + } else if (commandType == 6) { + // TODO: Go to player + } - if (owner->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { - ChatPackets::SendSystemMessage(owner->GetSystemAddress(), u"Commmand Type: " + (GeneralUtils::to_u16string(commandType)) + u" - Type Id: " + (GeneralUtils::to_u16string(typeId))); - } + if (owner->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + ChatPackets::SendSystemMessage(owner->GetSystemAddress(), u"Commmand Type: " + (GeneralUtils::to_u16string(commandType)) + u" - Type Id: " + (GeneralUtils::to_u16string(typeId))); + } } -LWOOBJID PetComponent::GetOwnerId() const -{ - return m_Owner; +LWOOBJID PetComponent::GetOwnerId() const { + return m_Owner; } -Entity* PetComponent::GetOwner() const -{ - return EntityManager::Instance()->GetEntity(m_Owner); +Entity* PetComponent::GetOwner() const { + return EntityManager::Instance()->GetEntity(m_Owner); } -LWOOBJID PetComponent::GetDatabaseId() const -{ - return m_DatabaseId; +LWOOBJID PetComponent::GetDatabaseId() const { + return m_DatabaseId; } -LWOOBJID PetComponent::GetInteraction() const -{ - return m_Interaction; +LWOOBJID PetComponent::GetInteraction() const { + return m_Interaction; } -LWOOBJID PetComponent::GetItemId() const -{ - return m_ItemId; +LWOOBJID PetComponent::GetItemId() const { + return m_ItemId; } -uint32_t PetComponent::GetStatus() const -{ - return m_Status; +uint32_t PetComponent::GetStatus() const { + return m_Status; } -PetAbilityType PetComponent::GetAbility() const -{ - return m_Ability; +PetAbilityType PetComponent::GetAbility() const { + return m_Ability; } -void PetComponent::SetInteraction(LWOOBJID value) -{ - m_Interaction = value; +void PetComponent::SetInteraction(LWOOBJID value) { + m_Interaction = value; } -void PetComponent::SetStatus(uint32_t value) -{ - m_Status = value; +void PetComponent::SetStatus(uint32_t value) { + m_Status = value; } -void PetComponent::SetAbility(PetAbilityType value) -{ - m_Ability = value; +void PetComponent::SetAbility(PetAbilityType value) { + m_Ability = value; } -PetComponent* PetComponent::GetTamingPet(LWOOBJID tamer) -{ - const auto& pair = currentActivities.find(tamer); +PetComponent* PetComponent::GetTamingPet(LWOOBJID tamer) { + const auto& pair = currentActivities.find(tamer); - if (pair == currentActivities.end()) - { - return nullptr; - } + if (pair == currentActivities.end()) { + return nullptr; + } - auto* entity = EntityManager::Instance()->GetEntity(pair->second); + auto* entity = EntityManager::Instance()->GetEntity(pair->second); - if (entity == nullptr) - { - currentActivities.erase(tamer); + if (entity == nullptr) { + currentActivities.erase(tamer); - return nullptr; - } + return nullptr; + } - return entity->GetComponent(); + return entity->GetComponent(); } -PetComponent* PetComponent::GetActivePet(LWOOBJID owner) -{ - const auto& pair = activePets.find(owner); +PetComponent* PetComponent::GetActivePet(LWOOBJID owner) { + const auto& pair = activePets.find(owner); - if (pair == activePets.end()) - { - return nullptr; - } + if (pair == activePets.end()) { + return nullptr; + } - auto* entity = EntityManager::Instance()->GetEntity(pair->second); + auto* entity = EntityManager::Instance()->GetEntity(pair->second); - if (entity == nullptr) - { - activePets.erase(owner); - - return nullptr; - } + if (entity == nullptr) { + activePets.erase(owner); - return entity->GetComponent(); + return nullptr; + } + + return entity->GetComponent(); } -Entity* PetComponent::GetParentEntity() const -{ - return m_Parent; +Entity* PetComponent::GetParentEntity() const { + return m_Parent; } -PetComponent::~PetComponent() -{ +PetComponent::~PetComponent() { } void PetComponent::SetPetNameForModeration(const std::string& petName) { - int approved = 1; //default, in mod + int approved = 1; //default, in mod - //Make sure that the name isn't already auto-approved: - if (Game::chatFilter->IsSentenceOkay(petName, 0)) { - approved = 2; //approved - } + //Make sure that the name isn't already auto-approved: + if (Game::chatFilter->IsSentenceOkay(petName, eGameMasterLevel::CIVILIAN).empty()) { + approved = 2; //approved + } - auto deleteStmt = Database::CreatePreppedStmt("DELETE FROM pet_names WHERE id = ? LIMIT 1;"); - deleteStmt->setUInt64(1, m_DatabaseId); + auto deleteStmt = Database::CreatePreppedStmt("DELETE FROM pet_names WHERE id = ? LIMIT 1;"); + deleteStmt->setUInt64(1, m_DatabaseId); - deleteStmt->execute(); + deleteStmt->execute(); - delete deleteStmt; + delete deleteStmt; - //Save to db: - auto stmt = Database::CreatePreppedStmt("INSERT INTO `pet_names` (`id`, `pet_name`, `approved`) VALUES (?, ?, ?);"); - stmt->setUInt64(1, m_DatabaseId); - stmt->setString(2, petName); - stmt->setInt(3, approved); - stmt->execute(); - delete stmt; + //Save to db: + auto stmt = Database::CreatePreppedStmt("INSERT INTO `pet_names` (`id`, `pet_name`, `approved`) VALUES (?, ?, ?);"); + stmt->setUInt64(1, m_DatabaseId); + stmt->setString(2, petName); + stmt->setInt(3, approved); + stmt->execute(); + delete stmt; } void PetComponent::LoadPetNameFromModeration() { - auto stmt = Database::CreatePreppedStmt("SELECT pet_name, approved FROM pet_names WHERE id = ? LIMIT 1;"); - stmt->setUInt64(1, m_DatabaseId); + auto stmt = Database::CreatePreppedStmt("SELECT pet_name, approved FROM pet_names WHERE id = ? LIMIT 1;"); + stmt->setUInt64(1, m_DatabaseId); - auto res = stmt->executeQuery(); - while (res->next()) { - m_ModerationStatus = res->getInt(2); + auto res = stmt->executeQuery(); + while (res->next()) { + m_ModerationStatus = res->getInt(2); - if (m_ModerationStatus == 2) - { - m_Name = res->getString(1); - } - } + if (m_ModerationStatus == 2) { + m_Name = res->getString(1); + } + } - delete res; - delete stmt; + delete res; + delete stmt; } void PetComponent::SetPreconditions(std::string& preconditions) { - m_Preconditions = new PreconditionExpression(preconditions); + m_Preconditions = new PreconditionExpression(preconditions); } diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 913cbc56..b3d089a9 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -4,13 +4,14 @@ #include "MovementAIComponent.h" #include "Component.h" #include "Preconditions.h" +#include "eReplicaComponentType.h" enum class PetAbilityType { - Invalid, - GoToObject, - JumpOnObject, - DigAtPosition + Invalid, + GoToObject, + JumpOnObject, + DigAtPosition }; /** @@ -20,343 +21,343 @@ enum class PetAbilityType class PetComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PET; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PET; - explicit PetComponent(Entity* parentEntity, uint32_t componentId); - ~PetComponent() override; + explicit PetComponent(Entity* parentEntity, uint32_t componentId); + ~PetComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Update(float deltaTime) override; - /** - * Handles an OnUse event from another entity, initializing the pet taming minigame if this pet is untamed. - * @param originator the entity that triggered the event - */ - void OnUse(Entity* originator) override; + /** + * Handles an OnUse event from another entity, initializing the pet taming minigame if this pet is untamed. + * @param originator the entity that triggered the event + */ + void OnUse(Entity* originator) override; - /** - * Attempts to complete the pet minigame by passing a list of bricks to build the minigame model. - * @param bricks the bricks to try to complete the minigame with - * @param clientFailed unused - */ - void TryBuild(uint32_t numBricks, bool clientFailed); + /** + * Attempts to complete the pet minigame by passing a list of bricks to build the minigame model. + * @param bricks the bricks to try to complete the minigame with + * @param clientFailed unused + */ + void TryBuild(uint32_t numBricks, bool clientFailed); - /** - * Handles a notification from the client regarding the completion of the pet minigame, adding the pet to their - * inventory. - * @param position the position to spawn the completed model at - */ - void NotifyTamingBuildSuccess(NiPoint3 position); + /** + * Handles a notification from the client regarding the completion of the pet minigame, adding the pet to their + * inventory. + * @param position the position to spawn the completed model at + */ + void NotifyTamingBuildSuccess(NiPoint3 position); - /** - * Handles the notification of the client to set the name of the pet (indicating that minigame was completed - * successfully). - * @param name the name of the pet to set - */ - void RequestSetPetName(std::u16string name); + /** + * Handles the notification of the client to set the name of the pet (indicating that minigame was completed + * successfully). + * @param name the name of the pet to set + */ + void RequestSetPetName(std::u16string name); - /** - * Handles a notification of the client that the taming entity is leaving the minigame, either voluntary or because - * time ran out. - * @param voluntaryExit whether the client voluntarily exited the minigame - */ - void ClientExitTamingMinigame(bool voluntaryExit); + /** + * Handles a notification of the client that the taming entity is leaving the minigame, either voluntary or because + * time ran out. + * @param voluntaryExit whether the client voluntarily exited the minigame + */ + void ClientExitTamingMinigame(bool voluntaryExit); - /** - * Starts the internal timer for the build limit for building the minigame model - */ - void StartTimer(); + /** + * Starts the internal timer for the build limit for building the minigame model + */ + void StartTimer(); - /** - * Notifies the client that they failed the minigame because time ran out - */ - void ClientFailTamingMinigame(); + /** + * Notifies the client that they failed the minigame because time ran out + */ + void ClientFailTamingMinigame(); - /** - * Makes the pet wander around - */ - void Wander(); + /** + * Makes the pet wander around + */ + void Wander(); - /** - * Spawns a pet from an item in the inventory of an owner - * @param item the item to create the pet from - * @param registerPet notifies the client that the pet was spawned, not necessary if this pet is being tamed - */ - void Activate(Item* item, bool registerPet = true, bool fromTaming = false); + /** + * Spawns a pet from an item in the inventory of an owner + * @param item the item to create the pet from + * @param registerPet notifies the client that the pet was spawned, not necessary if this pet is being tamed + */ + void Activate(Item* item, bool registerPet = true, bool fromTaming = false); - /** - * Despawns the pet - */ - void Deactivate(); + /** + * Despawns the pet + */ + void Deactivate(); - /** - * Removes the pet from the inventory - */ - void Release(); + /** + * Removes the pet from the inventory + */ + void Release(); - /** - * Commands the pet to do an action, actions are still a relative mystery, next to playing emotes - * @param position a position to execute the command at, currently unused - * @param source the source object that triggered the command - * @param commandType the type of the command (see function body for types) - * @param typeId extra information about the command, e.g. the emote to play - * @param overrideObey unused - */ - void Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey); + /** + * Commands the pet to do an action, actions are still a relative mystery, next to playing emotes + * @param position a position to execute the command at, currently unused + * @param source the source object that triggered the command + * @param commandType the type of the command (see function body for types) + * @param typeId extra information about the command, e.g. the emote to play + * @param overrideObey unused + */ + void Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey); - /** - * Returns the ID of the owner of this pet (if any) - * @return the ID of the owner of this pet - */ - LWOOBJID GetOwnerId() const; + /** + * Returns the ID of the owner of this pet (if any) + * @return the ID of the owner of this pet + */ + LWOOBJID GetOwnerId() const; - /** - * Returns the entity that owns this pet (if any) - * @return the entity that owns this pet - */ - Entity* GetOwner() const; + /** + * Returns the entity that owns this pet (if any) + * @return the entity that owns this pet + */ + Entity* GetOwner() const; - /** - * Returns the ID that is stored in the database with regards to this pet, only set for pets that are tamed - * @return the ID that is stored in the database with regards to this pet - */ - LWOOBJID GetDatabaseId() const; + /** + * Returns the ID that is stored in the database with regards to this pet, only set for pets that are tamed + * @return the ID that is stored in the database with regards to this pet + */ + LWOOBJID GetDatabaseId() const; - /** - * Returns the ID of the object that the pet is currently interacting with, could be a treasure chest or a switch - * @return the ID of the object that the pet is currently interacting with - */ - LWOOBJID GetInteraction() const; + /** + * Returns the ID of the object that the pet is currently interacting with, could be a treasure chest or a switch + * @return the ID of the object that the pet is currently interacting with + */ + LWOOBJID GetInteraction() const; - /** - * Sets the ID that the pet is interacting with - * @param value the ID that the pet is interacting with - */ - void SetInteraction(LWOOBJID value); + /** + * Sets the ID that the pet is interacting with + * @param value the ID that the pet is interacting with + */ + void SetInteraction(LWOOBJID value); - /** - * Returns the ID that this pet was spawned from, only set for tamed pets - * @return the ID that this pet was spawned from - */ - LWOOBJID GetItemId() const; + /** + * Returns the ID that this pet was spawned from, only set for tamed pets + * @return the ID that this pet was spawned from + */ + LWOOBJID GetItemId() const; - /** - * Returns the status of this pet, e.g. tamable or tamed. The values here are still a bit of mystery and likely a - * bit map - * @return the status of this pet - */ - uint32_t GetStatus() const; + /** + * Returns the status of this pet, e.g. tamable or tamed. The values here are still a bit of mystery and likely a + * bit map + * @return the status of this pet + */ + uint32_t GetStatus() const; - /** - * Sets the current status of the pet - * @param value the current status of the pet to set - */ - void SetStatus(uint32_t value); + /** + * Sets the current status of the pet + * @param value the current status of the pet to set + */ + void SetStatus(uint32_t value); - /** - * Returns an ability the pet may perform, currently unused - * @return an ability the pet may perform - */ - PetAbilityType GetAbility() const; + /** + * Returns an ability the pet may perform, currently unused + * @return an ability the pet may perform + */ + PetAbilityType GetAbility() const; - /** - * Sets the ability of the pet, currently unused - * @param value the ability to set - */ - void SetAbility(PetAbilityType value); + /** + * Sets the ability of the pet, currently unused + * @param value the ability to set + */ + void SetAbility(PetAbilityType value); - /** - * Sets preconditions for the pet that need to be met before it can be tamed - * @param conditions the preconditions to set - */ - void SetPreconditions(std::string& conditions); + /** + * Sets preconditions for the pet that need to be met before it can be tamed + * @param conditions the preconditions to set + */ + void SetPreconditions(std::string& conditions); - /** - * Returns the entity that this component belongs to - * @return the entity that this component belongs to - */ - Entity* GetParentEntity() const; + /** + * Returns the entity that this component belongs to + * @return the entity that this component belongs to + */ + Entity* GetParentEntity() const; - /** - * Sets the name of the pet to be moderated - * @param petName the name of the pet to set - */ - void SetPetNameForModeration(const std::string& petName); + /** + * Sets the name of the pet to be moderated + * @param petName the name of the pet to set + */ + void SetPetNameForModeration(const std::string& petName); - /** - * Loads the pet name up for moderation along with the moderation status from the database and sets them for this - * pet. - */ - void LoadPetNameFromModeration(); + /** + * Loads the pet name up for moderation along with the moderation status from the database and sets them for this + * pet. + */ + void LoadPetNameFromModeration(); - /** - * Returns the component of the pet some entity is currently taming (if any) - * @param tamer the entity that's currently taming - * @return the pet component of the entity that's being tamed - */ - static PetComponent* GetTamingPet(LWOOBJID tamer); + /** + * Returns the component of the pet some entity is currently taming (if any) + * @param tamer the entity that's currently taming + * @return the pet component of the entity that's being tamed + */ + static PetComponent* GetTamingPet(LWOOBJID tamer); - /** - * Returns the pet that's currently spawned for some entity (if any) - * @param owner the owner of the pet that's spawned - * @return the pet component of the entity that was spawned by the owner - */ - static PetComponent* GetActivePet(LWOOBJID owner); + /** + * Returns the pet that's currently spawned for some entity (if any) + * @param owner the owner of the pet that's spawned + * @return the pet component of the entity that was spawned by the owner + */ + static PetComponent* GetActivePet(LWOOBJID owner); - /** - * Adds the timer to the owner of this pet to drain imagination at the rate - * specified by the parameter imaginationDrainRate - * - * @param item The item that represents this pet in the inventory. - */ - void AddDrainImaginationTimer(Item* item, bool fromTaming = false); + /** + * Adds the timer to the owner of this pet to drain imagination at the rate + * specified by the parameter imaginationDrainRate + * + * @param item The item that represents this pet in the inventory. + */ + void AddDrainImaginationTimer(Item* item, bool fromTaming = false); private: - /** - * Information for the minigame to be completed - */ - struct PetPuzzleData - { - /** - * The LOT of the object that is to be created - */ - LOT puzzleModelLot; + /** + * Information for the minigame to be completed + */ + struct PetPuzzleData + { + /** + * The LOT of the object that is to be created + */ + LOT puzzleModelLot; - /** - * That file that contains the bricks required to build the model - */ - std::string buildFile; + /** + * That file that contains the bricks required to build the model + */ + std::string buildFile; - /** - * The time limit to complete the build - */ - int32_t timeLimit; + /** + * The time limit to complete the build + */ + int32_t timeLimit; - /** - * The imagination cost for the tamer to start the minigame - */ - int32_t imaginationCost; + /** + * The imagination cost for the tamer to start the minigame + */ + int32_t imaginationCost; - /** - * The number of pieces required to complete the minigame - */ - int32_t numValidPieces; - }; + /** + * The number of pieces required to complete the minigame + */ + int32_t numValidPieces; + }; - /** - * Cache of all the pets that are currently spawned, indexed by tamer - */ - static std::unordered_map activePets; + /** + * Cache of all the pets that are currently spawned, indexed by tamer + */ + static std::unordered_map activePets; - /** - * Cache of all the pets that are currently being tamed, indexed by tamer - */ - static std::unordered_map currentActivities; + /** + * Cache of all the pets that are currently being tamed, indexed by tamer + */ + static std::unordered_map currentActivities; - /** - * Cache of all the minigames and their information from the database - */ - static std::unordered_map buildCache; + /** + * Cache of all the minigames and their information from the database + */ + static std::unordered_map buildCache; - /** - * Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet - */ - static std::map petFlags; + /** + * Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet + */ + static std::map petFlags; - /** - * The ID of the component in the pet component table - */ - uint32_t m_ComponentId; + /** + * The ID of the component in the pet component table + */ + uint32_t m_ComponentId; - /** - * The ID of the model that was built to complete the taming minigame for this pet - */ - LWOOBJID m_ModelId; + /** + * The ID of the model that was built to complete the taming minigame for this pet + */ + LWOOBJID m_ModelId; - /** - * The ID of the object that the pet is currently interacting with (e.g. a treasure chest or switch) - */ - LWOOBJID m_Interaction; + /** + * The ID of the object that the pet is currently interacting with (e.g. a treasure chest or switch) + */ + LWOOBJID m_Interaction; - /** - * The ID of the entity that owns this pet - */ - LWOOBJID m_Owner; + /** + * The ID of the entity that owns this pet + */ + LWOOBJID m_Owner; - /** - * The ID of the entity that is currently taming this pet - */ - LWOOBJID m_Tamer; + /** + * The ID of the entity that is currently taming this pet + */ + LWOOBJID m_Tamer; - /** - * The ID under which this pet is stored in the database (if it's tamed) - */ - LWOOBJID m_DatabaseId; + /** + * The ID under which this pet is stored in the database (if it's tamed) + */ + LWOOBJID m_DatabaseId; - /** - * The ID of the item from which this pet was created - */ - LWOOBJID m_ItemId; + /** + * The ID of the item from which this pet was created + */ + LWOOBJID m_ItemId; - /** - * The moderation status for the name of this pet - */ - uint32_t m_ModerationStatus; + /** + * The moderation status for the name of this pet + */ + uint32_t m_ModerationStatus; - /** - * The name of this pet - */ - std::string m_Name; + /** + * The name of this pet + */ + std::string m_Name; - /** - * The name of the owner of this pet - */ - std::string m_OwnerName; + /** + * The name of the owner of this pet + */ + std::string m_OwnerName; - /** - * The current state of the pet (e.g. tamable, tamed, etc). - */ - uint32_t m_Status; + /** + * The current state of the pet (e.g. tamable, tamed, etc). + */ + uint32_t m_Status; - /** - * A currently active ability, mostly unused - */ - PetAbilityType m_Ability; + /** + * A currently active ability, mostly unused + */ + PetAbilityType m_Ability; - /** - * The time an entity has left to complete the minigame - */ - float m_Timer; + /** + * The time an entity has left to complete the minigame + */ + float m_Timer; - /** - * A timer that tracks how long a tamed pet has been to far away from its owner, triggering a teleport after timeout - */ - float m_TimerAway; + /** + * A timer that tracks how long a tamed pet has been to far away from its owner, triggering a teleport after timeout + */ + float m_TimerAway; - /** - * Timer that tracks how long a pet has been digging up some treasure, required to spawn the treasure contents - * on time - */ - float m_TresureTime; + /** + * Timer that tracks how long a pet has been digging up some treasure, required to spawn the treasure contents + * on time + */ + float m_TresureTime; - /** - * The position that this pet was spawned at - */ - NiPoint3 m_StartPosition; + /** + * The position that this pet was spawned at + */ + NiPoint3 m_StartPosition; - /** - * The movement AI component that is related to this pet, required to move it around - */ - MovementAIComponent* m_MovementAI; + /** + * The movement AI component that is related to this pet, required to move it around + */ + MovementAIComponent* m_MovementAI; - /** - * Preconditions that need to be met before an entity can tame this pet - */ - PreconditionExpression* m_Preconditions; + /** + * Preconditions that need to be met before an entity can tame this pet + */ + PreconditionExpression* m_Preconditions; - /** - * The rate at which imagination is drained from the user for having the pet out. - */ - float imaginationDrainRate; -}; \ No newline at end of file + /** + * The rate at which imagination is drained from the user for having the pet out. + */ + float imaginationDrainRate; +}; diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index e1c2e842..e6272aa4 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -14,11 +14,13 @@ #include "EntityManager.h" #include "ControllablePhysicsComponent.h" #include "GameMessages.h" +#include "ePhysicsEffectType.h" #include "CDClientManager.h" #include "CDComponentsRegistryTable.h" #include "CDPhysicsComponentTable.h" #include "dServer.h" +#include "EntityInfo.h" #include "dpWorld.h" #include "dpEntity.h" @@ -27,23 +29,23 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(parent) { m_Position = m_Parent->GetDefaultPosition(); - m_Rotation = m_Parent->GetDefaultRotation(); + m_Rotation = m_Parent->GetDefaultRotation(); m_Scale = m_Parent->GetDefaultScale(); m_dpEntity = nullptr; - - m_EffectInfoDirty = false; + + m_EffectInfoDirty = false; m_PositionInfoDirty = false; - - m_IsPhysicsEffectActive = false; - m_EffectType = 0; - m_DirectionalMultiplier = 0.0f; - - m_MinMax = false; - m_Min = 0; - m_Max = 1; - - m_IsDirectional = false; - m_Direction = NiPoint3(); // * m_DirectionalMultiplier + + m_IsPhysicsEffectActive = false; + m_EffectType = ePhysicsEffectType::PUSH; + m_DirectionalMultiplier = 0.0f; + + m_MinMax = false; + m_Min = 0; + m_Max = 1; + + m_IsDirectional = false; + m_Direction = NiPoint3(); // * m_DirectionalMultiplier if (m_Parent->GetVar(u"create_physics")) { CreatePhysics(); @@ -82,8 +84,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par } // HF - RespawnPoints. Legacy respawn entity. - if (m_Parent->GetLOT() == 4945) - { + if (m_Parent->GetLOT() == 4945) { m_IsRespawnVolume = true; m_RespawnPos = m_Position; m_RespawnRot = m_Rotation; @@ -143,10 +144,10 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par */ if (!m_HasCreatedPhysics) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable(); if (physComp == nullptr) return; @@ -162,63 +163,68 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 640.0f, 20.0f, 640.0f); + } else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { + // Move this down by 13.521004 units so it is still effectively at the same height as before + m_Position = m_Position - NiPoint3::UNIT_Y * 13.521004f; + // TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem... + m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); + } else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { + m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { + } else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { + } else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") - { + } else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") { m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 7.5f); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") - { + } else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") { m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 6.0f); dpWorld::Instance().AddEntity(m_dpEntity); - } - else if (info->physicsAsset == "env\\Ring_Trigger.hkx") - { + } else if (info->physicsAsset == "env\\Ring_Trigger.hkx") { m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f); m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); - } - else { - //Game::logger->Log("PhantomPhysicsComponent", "This one is supposed to have %s\n", info->physicsAsset.c_str()); + } else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") { + m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 4.5f); + m_dpEntity->SetScale(m_Scale); + m_dpEntity->SetRotation(m_Rotation); + m_dpEntity->SetPosition(m_Position); + dpWorld::Instance().AddEntity(m_dpEntity); + } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx"){ + m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); + m_dpEntity->SetScale(m_Scale); + m_dpEntity->SetRotation(m_Rotation); + m_Position.y -= (111.467964f * m_Scale) / 2; + m_dpEntity->SetPosition(m_Position); + dpWorld::Instance().AddEntity(m_dpEntity); + } else { + //Game::logger->Log("PhantomPhysicsComponent", "This one is supposed to have %s", info->physicsAsset.c_str()); //add fallback cube: m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f); @@ -254,15 +260,14 @@ void PhantomPhysicsComponent::CreatePhysics() { x = m_Parent->GetVar(u"primitiveModelValueX"); y = m_Parent->GetVar(u"primitiveModelValueY"); z = m_Parent->GetVar(u"primitiveModelValueZ"); - } - else { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS); + } else { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable(); if (physComp == nullptr) return; - + auto info = physComp->GetByID(componentID); if (info == nullptr) return; @@ -294,7 +299,7 @@ void PhantomPhysicsComponent::CreatePhysics() { if (!m_dpEntity) return; - m_dpEntity->SetPosition({m_Position.x, m_Position.y - (height / 2), m_Position.z}); + m_dpEntity->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z }); dpWorld::Instance().AddEntity(m_dpEntity); @@ -302,9 +307,8 @@ void PhantomPhysicsComponent::CreatePhysics() { } void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write(m_PositionInfoDirty || bIsInitialUpdate); - if (m_PositionInfoDirty || bIsInitialUpdate) - { + outBitStream->Write(m_PositionInfoDirty || bIsInitialUpdate); + if (m_PositionInfoDirty || bIsInitialUpdate) { outBitStream->Write(m_Position.x); outBitStream->Write(m_Position.y); outBitStream->Write(m_Position.z); @@ -315,15 +319,15 @@ void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bI m_PositionInfoDirty = false; } - - outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate); - if (m_EffectInfoDirty || bIsInitialUpdate) { - outBitStream->Write(m_IsPhysicsEffectActive); - - if (m_IsPhysicsEffectActive) { - outBitStream->Write(m_EffectType); - outBitStream->Write(m_DirectionalMultiplier); - + + outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate); + if (m_EffectInfoDirty || bIsInitialUpdate) { + outBitStream->Write(m_IsPhysicsEffectActive); + + if (m_IsPhysicsEffectActive) { + outBitStream->Write(m_EffectType); + outBitStream->Write(m_DirectionalMultiplier); + // forgive me father for i have sinned outBitStream->Write0(); //outBitStream->Write(m_MinMax); @@ -331,21 +335,21 @@ void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bI //outBitStream->Write(m_Min); //outBitStream->Write(m_Max); //} - - outBitStream->Write(m_IsDirectional); - if (m_IsDirectional) { - outBitStream->Write(m_Direction.x); - outBitStream->Write(m_Direction.y); - outBitStream->Write(m_Direction.z); - } - } + + outBitStream->Write(m_IsDirectional); + if (m_IsDirectional) { + outBitStream->Write(m_Direction.x); + outBitStream->Write(m_Direction.y); + outBitStream->Write(m_Direction.z); + } + } m_EffectInfoDirty = false; - } + } } void PhantomPhysicsComponent::ResetFlags() { - m_EffectInfoDirty = false; + m_EffectInfoDirty = false; m_PositionInfoDirty = false; } @@ -375,13 +379,13 @@ void PhantomPhysicsComponent::Update(float deltaTime) { } void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) { - m_Direction = pos; - m_Direction.x *= m_DirectionalMultiplier; - m_Direction.y *= m_DirectionalMultiplier; - m_Direction.z *= m_DirectionalMultiplier; - - m_EffectInfoDirty = true; - m_IsDirectional = true; + m_Direction = pos; + m_Direction.x *= m_DirectionalMultiplier; + m_Direction.y *= m_DirectionalMultiplier; + m_Direction.z *= m_DirectionalMultiplier; + + m_EffectInfoDirty = true; + m_IsDirectional = true; } void PhantomPhysicsComponent::SpawnVertices() { @@ -405,35 +409,35 @@ void PhantomPhysicsComponent::SpawnVertices() { } void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) { - m_DirectionalMultiplier = mul; - m_EffectInfoDirty = true; + m_DirectionalMultiplier = mul; + m_EffectInfoDirty = true; } -void PhantomPhysicsComponent::SetEffectType(uint32_t type) { - m_EffectType = type; - m_EffectInfoDirty = true; +void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) { + m_EffectType = type; + m_EffectInfoDirty = true; } void PhantomPhysicsComponent::SetMin(uint32_t min) { - m_Min = min; - m_MinMax = true; - m_EffectInfoDirty = true; + m_Min = min; + m_MinMax = true; + m_EffectInfoDirty = true; } void PhantomPhysicsComponent::SetMax(uint32_t max) { - m_Max = max; - m_MinMax = true; - m_EffectInfoDirty = true; + m_Max = max; + m_MinMax = true; + m_EffectInfoDirty = true; } void PhantomPhysicsComponent::SetPosition(const NiPoint3& pos) { - m_Position = pos; + m_Position = pos; if (m_dpEntity) m_dpEntity->SetPosition(pos); } void PhantomPhysicsComponent::SetRotation(const NiQuaternion& rot) { - m_Rotation = rot; + m_Rotation = rot; if (m_dpEntity) m_dpEntity->SetRotation(rot); } diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index faf6362f..cc0d1844 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -12,10 +12,12 @@ #include "CppScripts.h" #include "InvalidScript.h" #include "Component.h" +#include "eReplicaComponentType.h" class LDFBaseData; class Entity; class dpEntity; +enum class ePhysicsEffectType : uint32_t ; /** * Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be @@ -25,191 +27,191 @@ class dpEntity; */ class PhantomPhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS; - - PhantomPhysicsComponent(Entity* parent); - ~PhantomPhysicsComponent() override; - void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void ResetFlags(); + static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS; - /** - * Creates the physics shape for this entity based on LDF data - */ + PhantomPhysicsComponent(Entity* parent); + ~PhantomPhysicsComponent() override; + void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void ResetFlags(); + + /** + * Creates the physics shape for this entity based on LDF data + */ void CreatePhysics(); - /** - * Sets the direction this physics object is pointed at - * @param pos the direction to set - */ - void SetDirection(const NiPoint3& pos); + /** + * Sets the direction this physics object is pointed at + * @param pos the direction to set + */ + void SetDirection(const NiPoint3& pos); - /** - * Returns the direction this physics object is pointed at - * @return the direction this physics object is pointed at - */ - const NiPoint3& GetDirection() const { return m_Direction; } + /** + * Returns the direction this physics object is pointed at + * @return the direction this physics object is pointed at + */ + const NiPoint3& GetDirection() const { return m_Direction; } - /** - * Returns the multiplier by which the direction coordinates are multiplied - * @return the multiplier by which the direction coordinates are multiplied - */ - float GetDirectionalMultiplier() const { return m_DirectionalMultiplier; } + /** + * Returns the multiplier by which the direction coordinates are multiplied + * @return the multiplier by which the direction coordinates are multiplied + */ + float GetDirectionalMultiplier() const { return m_DirectionalMultiplier; } - /** - * Sets the multiplier by which direction coordinates are multiplied - * @param mul the multiplier to set - */ - void SetDirectionalMultiplier(float mul); + /** + * Sets the multiplier by which direction coordinates are multiplied + * @param mul the multiplier to set + */ + void SetDirectionalMultiplier(float mul); - /** - * Returns whether or not there's currently an effect active - * @return true if there's an effect active, false otherwise - */ - bool GetPhysicsEffectActive() const { return m_IsPhysicsEffectActive; } + /** + * Returns whether or not there's currently an effect active + * @return true if there's an effect active, false otherwise + */ + bool GetPhysicsEffectActive() const { return m_IsPhysicsEffectActive; } - /** - * Sets whether or not there's a physics effect active - * @param val whether or not there's an effect active - */ - void SetPhysicsEffectActive(bool val) { m_IsPhysicsEffectActive = val; m_EffectInfoDirty = true; } + /** + * Sets whether or not there's a physics effect active + * @param val whether or not there's an effect active + */ + void SetPhysicsEffectActive(bool val) { m_IsPhysicsEffectActive = val; m_EffectInfoDirty = true; } - /** - * Returns the position of this physics object - * @return the position of this physics object - */ - const NiPoint3& GetPosition() const { return m_Position; } + /** + * Returns the position of this physics object + * @return the position of this physics object + */ + const NiPoint3& GetPosition() const { return m_Position; } - /** - * Sets the position of this physics object - * @param pos the position to set - */ - void SetPosition(const NiPoint3& pos); + /** + * Sets the position of this physics object + * @param pos the position to set + */ + void SetPosition(const NiPoint3& pos); - /** - * Returns the rotation of this physics object - * @return the rotation of this physics object - */ - const NiQuaternion& GetRotation() const { return m_Rotation; } + /** + * Returns the rotation of this physics object + * @return the rotation of this physics object + */ + const NiQuaternion& GetRotation() const { return m_Rotation; } - /** - * Sets the rotation of this physics object - * @param rot the rotation to set - */ - void SetRotation(const NiQuaternion& rot); + /** + * Sets the rotation of this physics object + * @param rot the rotation to set + */ + void SetRotation(const NiQuaternion& rot); - /** - * Returns the effect that's currently active, defaults to 0 - * @return the effect that's currently active - */ - uint32_t GetEffectType() const { return m_EffectType; } + /** + * Returns the effect that's currently active, defaults to 0 + * @return the effect that's currently active + */ + ePhysicsEffectType GetEffectType() const { return m_EffectType; } - /** - * Sets the effect that's currently active - * @param type the effect to set - */ - void SetEffectType(uint32_t type); + /** + * Sets the effect that's currently active + * @param type the effect to set + */ + void SetEffectType(ePhysicsEffectType type); - /** - * Returns the Physics entity for the component - * @return Physics entity for the component - */ + /** + * Returns the Physics entity for the component + * @return Physics entity for the component + */ - dpEntity* GetdpEntity() const { return m_dpEntity; } + dpEntity* GetdpEntity() const { return m_dpEntity; } - /** - * Spawns an object at each of the vertices for debugging purposes - */ - void SpawnVertices(); + /** + * Spawns an object at each of the vertices for debugging purposes + */ + void SpawnVertices(); - /** - * Legacy stuff no clue what this does - */ - void SetMin(uint32_t min); + /** + * Legacy stuff no clue what this does + */ + void SetMin(uint32_t min); + + /** + * Legacy stuff no clue what this does + */ + void SetMax(uint32_t max); - /** - * Legacy stuff no clue what this does - */ - void SetMax(uint32_t max); - private: - /** - * The position of the physics object - */ - NiPoint3 m_Position; + /** + * The position of the physics object + */ + NiPoint3 m_Position; - /** - * The rotation of the physics object - */ - NiQuaternion m_Rotation; + /** + * The rotation of the physics object + */ + NiQuaternion m_Rotation; - /** - * A scale to apply to the size of the physics object - */ + /** + * A scale to apply to the size of the physics object + */ float m_Scale; - /** - * Whether or not the position has changed and needs to be serialized - */ - bool m_PositionInfoDirty; + /** + * Whether or not the position has changed and needs to be serialized + */ + bool m_PositionInfoDirty; - /** - * Whether or not the effect has changed and needs to be serialized - */ - bool m_EffectInfoDirty; + /** + * Whether or not the effect has changed and needs to be serialized + */ + bool m_EffectInfoDirty; - /** - * Whether or not there's currently a physics effect active - */ - bool m_IsPhysicsEffectActive; + /** + * Whether or not there's currently a physics effect active + */ + bool m_IsPhysicsEffectActive; - /** - * The physics effect that's currently active, defaults to 0 - */ - uint32_t m_EffectType; + /** + * The physics effect that's currently active, defaults to 0 + */ + ePhysicsEffectType m_EffectType; - /** - * A scaling multiplier to add to the directional vector - */ - float m_DirectionalMultiplier; - - bool m_MinMax; - uint32_t m_Min; - uint32_t m_Max; + /** + * A scaling multiplier to add to the directional vector + */ + float m_DirectionalMultiplier; - /** - * Whether or not this physics object is pointed in some direction - */ - bool m_IsDirectional; + bool m_MinMax; + uint32_t m_Min; + uint32_t m_Max; - /** - * The direction this physics object is pointed in, if any - */ - NiPoint3 m_Direction; + /** + * Whether or not this physics object is pointed in some direction + */ + bool m_IsDirectional; - /** - * The parent entity of this component - */ - dpEntity* m_dpEntity; + /** + * The direction this physics object is pointed in, if any + */ + NiPoint3 m_Direction; - /** - * Whether or not the physics object has been created yet - */ + /** + * The parent entity of this component + */ + dpEntity* m_dpEntity; + + /** + * Whether or not the physics object has been created yet + */ bool m_HasCreatedPhysics = false; - /** - * Whether or not this physics object represents an object that updates the respawn pos of an entity that crosses it - */ + /** + * Whether or not this physics object represents an object that updates the respawn pos of an entity that crosses it + */ bool m_IsRespawnVolume = false; - /** - * If this is a respawn volume, the exact position an entity will respawn - */ + /** + * If this is a respawn volume, the exact position an entity will respawn + */ NiPoint3 m_RespawnPos; - /** - * If this is a respawn volume, the exact rotation an entity will respawn - */ + /** + * If this is a respawn volume, the exact rotation an entity will respawn + */ NiQuaternion m_RespawnRot; -}; \ No newline at end of file +}; diff --git a/dGame/dComponents/PlayerForcedMovementComponent.cpp b/dGame/dComponents/PlayerForcedMovementComponent.cpp new file mode 100644 index 00000000..76993507 --- /dev/null +++ b/dGame/dComponents/PlayerForcedMovementComponent.cpp @@ -0,0 +1,16 @@ +#include "PlayerForcedMovementComponent.h" + +PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : Component(parent) { + m_Parent = parent; +} + +PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {} + +void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(m_DirtyInfo || bIsInitialUpdate); + if (m_DirtyInfo || bIsInitialUpdate) { + outBitStream->Write(m_PlayerOnRail); + outBitStream->Write(m_ShowBillboard); + } + m_DirtyInfo = false; +} diff --git a/dGame/dComponents/PlayerForcedMovementComponent.h b/dGame/dComponents/PlayerForcedMovementComponent.h new file mode 100644 index 00000000..90708c9a --- /dev/null +++ b/dGame/dComponents/PlayerForcedMovementComponent.h @@ -0,0 +1,70 @@ +#pragma once + +#include "Entity.h" +#include "Component.h" +#include "eReplicaComponentType.h" + +/** + * Component that handles player forced movement + * + */ +class PlayerForcedMovementComponent : public Component { +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::PLAYER_FORCED_MOVEMENT; + + /** + * Constructor for this component + * @param parent parent that contains this component + */ + PlayerForcedMovementComponent(Entity* parent); + ~PlayerForcedMovementComponent() override; + + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + + /** + * @brief Set the Player On Rail object + * + * @param value if the player is on a rail + */ + void SetPlayerOnRail(bool value) { m_PlayerOnRail = value; m_DirtyInfo = true; } + + /** + * @brief Set the Show Billboard object + * + * @param value if the billboard should be shown + */ + void SetShowBillboard(bool value) { m_ShowBillboard = value; m_DirtyInfo = true; } + + /** + * @brief Get the Player On Rail object + * + * @return true + * @return false + */ + + /** + * @brief Get the Player On Rail object + * + * @return true + * @return false + */ + bool GetPlayerOnRail() { return m_PlayerOnRail; } + bool GetShowBillboard() { return m_ShowBillboard; } + +private: + /** + * whether the info is dirty + */ + bool m_DirtyInfo = false; + + /** + * whether the player is on a rail + */ + bool m_PlayerOnRail = false; + + /** + * whether the billboard should be showing + */ + bool m_ShowBillboard = false; + +}; diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index d4fd0d62..5c45a6c1 100644 --- a/dGame/dComponents/PossessableComponent.cpp +++ b/dGame/dComponents/PossessableComponent.cpp @@ -1,51 +1,55 @@ #include "PossessableComponent.h" - #include "PossessorComponent.h" #include "EntityManager.h" +#include "Inventory.h" +#include "Item.h" -PossessableComponent::PossessableComponent(Entity* parent) : Component(parent) -{ - m_Possessor = LWOOBJID_EMPTY; +PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) : Component(parent) { + m_Possessor = LWOOBJID_EMPTY; + CDItemComponent item = Inventory::FindItemComponent(m_Parent->GetLOT()); + m_AnimationFlag = static_cast(item.animationFlag); + + // Get the possession Type from the CDClient + auto query = CDClientDatabase::CreatePreppedStmt("SELECT possessionType, depossessOnHit FROM PossessableComponent WHERE id = ?;"); + + query.bind(1, static_cast(componentId)); + + auto result = query.execQuery(); + + // Should a result not exist for this default to attached visible + if (!result.eof()) { + m_PossessionType = static_cast(result.getIntField(0, 1)); // Default to Attached Visible + m_DepossessOnHit = static_cast(result.getIntField(1, 0)); + } else { + m_PossessionType = ePossessionType::ATTACHED_VISIBLE; + m_DepossessOnHit = false; + } + result.finalize(); } -PossessableComponent::~PossessableComponent() -{ - +void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(m_DirtyPossessable || bIsInitialUpdate); + if (m_DirtyPossessable || bIsInitialUpdate) { + m_DirtyPossessable = false; // reset flag + outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); + if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor); + + outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE); + if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream->Write(m_AnimationFlag); + + outBitStream->Write(m_ImmediatelyDepossess); + m_ImmediatelyDepossess = false; // reset flag + } } -void PossessableComponent::SetPossessor(LWOOBJID value) -{ - m_Possessor = value; -} - -LWOOBJID PossessableComponent::GetPossessor() const -{ - return m_Possessor; -} - -void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); - if (m_Possessor != LWOOBJID_EMPTY) - { - outBitStream->Write1(); - outBitStream->Write(m_Possessor); - outBitStream->Write0(); - outBitStream->Write0(); - } -} - -void PossessableComponent::Update(float deltaTime) -{ - +void PossessableComponent::Dismount() { + SetPossessor(LWOOBJID_EMPTY); + if (m_ItemSpawned) m_Parent->ScheduleKillAfterUpdate(); } void PossessableComponent::OnUse(Entity* originator) { - PossessorComponent* possessorComponent; - if (originator->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { - SetPossessor(originator->GetObjectID()); - possessorComponent->SetPossessable(m_Parent->GetObjectID()); - EntityManager::Instance()->SerializeEntity(m_Parent); - EntityManager::Instance()->SerializeEntity(originator); - } + auto* possessor = originator->GetComponent(); + if (possessor) { + possessor->Mount(m_Parent); + } } diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 744ebfc5..2026c11e 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -3,6 +3,10 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "Item.h" +#include "PossessorComponent.h" +#include "eAninmationFlags.h" +#include "eReplicaComponentType.h" /** * Represents an entity that can be controlled by some other entity, generally used by cars to indicate that some @@ -10,37 +14,113 @@ */ class PossessableComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE; - - PossessableComponent(Entity* parentEntity); - ~PossessableComponent() override; + static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSABLE; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + PossessableComponent(Entity* parentEntity, uint32_t componentId); - /** - * Sets the possessor of this entity - * @param value the ID of the possessor to set - */ - void SetPossessor(LWOOBJID value); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the possessor of this entity - * @return the possessor of this entitythe - */ - LWOOBJID GetPossessor() const; + /** + * @brief mounts the Entity + */ + void Mount(); - /** - * Handles an OnUsed event by some other entity, if said entity has a PossessorComponent it becomes the possessor - * of this entity - * @param originator the entity that caused the event to trigger - */ + /** + * @brief dismounts the Entity + */ + void Dismount(); + + /** + * Sets the possessor of this Entity + * @param value the ID of the possessor to set + */ + void SetPossessor(LWOOBJID value) { m_Possessor = value; m_DirtyPossessable = true; }; + + /** + * Returns the possessor of this Entity + * @return the possessor of this Entity + */ + LWOOBJID GetPossessor() const { return m_Possessor; }; + + /** + * Sets the animation Flag of the possessable + * @param value the animation flag to set to + */ + void SetAnimationFlag(eAnimationFlags value) { m_AnimationFlag = value; m_DirtyPossessable = true; }; + + /** + * Returns the possession type of this Entity + * @return the possession type of this Entity + */ + ePossessionType GetPossessionType() const { return m_PossessionType; }; + + /** + * Returns if the Entity should deposses on hit + * @return if the Entity should deposses on hit + */ + bool GetDepossessOnHit() const { return m_DepossessOnHit; }; + + /** + * Forcibly depossess the Entity + */ + void ForceDepossess() { m_ImmediatelyDepossess = true; m_DirtyPossessable = true; }; + + /** + * Set if the parent entity was spawned from an item + * @param value if the parent entity was spawned from an item + */ + void SetIsItemSpawned(bool value) { m_ItemSpawned = value; }; + + /** + * Returns if the parent entity was spawned from an item + * @return if the parent entity was spawned from an item + */ + LWOOBJID GetIsItemSpawned() const { return m_ItemSpawned; }; + + /** + * Handles an OnUsed event by some other entity, if said entity has a Possessor it becomes the possessor + * of this entity + * @param originator the entity that caused the event to trigger + */ void OnUse(Entity* originator) override; private: - /** - * The possessor of this entity, e.g. the entity that controls this entity - */ - LWOOBJID m_Possessor; + /** + * @brief Whether the possessor is dirty + */ + bool m_DirtyPossessable = true; + + /** + * @brief The possessor of this entity, e.g. the entity that controls this entity + */ + LWOOBJID m_Possessor = LWOOBJID_EMPTY; + + /** + * @brief The type of possesstion to use on this entity + */ + ePossessionType m_PossessionType = ePossessionType::NO_POSSESSION; + + /** + * @brief Should the possessable be dismount on hit + */ + bool m_DepossessOnHit = false; + + /** + * @brief What animaiton flag to use + * + */ + eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_NONE; + + /** + * @brief Should this be immediately depossessed + * + */ + bool m_ImmediatelyDepossess = false; + + /** + * @brief Whether the parent entity was spawned from an item + * + */ + bool m_ItemSpawned = false; }; diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index 4ace324b..387b3479 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -1,12 +1,30 @@ #include "PossessorComponent.h" +#include "PossessableComponent.h" +#include "CharacterComponent.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "eUnequippableActiveType.h" +#include "eControlScheme.h" +#include "eStateChangeType.h" PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) { m_Possessable = LWOOBJID_EMPTY; } -PossessorComponent::~PossessorComponent() {} - - +PossessorComponent::~PossessorComponent() { + if (m_Possessable != LWOOBJID_EMPTY) { + auto* mount = EntityManager::Instance()->GetEntity(m_Possessable); + if (mount) { + auto* possessable = mount->GetComponent(); + if (possessable) { + if (possessable->GetIsItemSpawned()) { + GameMessages::SendMarkInventoryItemAsActive(m_Parent->GetObjectID(), false, eUnequippableActiveType::MOUNT, GetMountItemID(), m_Parent->GetSystemAddress()); + } + possessable->Dismount(); + } + } + } +} void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { outBitStream->Write(m_DirtyPossesor || bIsInitialUpdate); @@ -19,3 +37,48 @@ void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit outBitStream->Write(m_PossessableType); } } + +void PossessorComponent::Mount(Entity* mount) { + // Don't do anything if we are busy dismounting + if (GetIsDismounting() || !mount) return; + + GameMessages::SendSetMountInventoryID(m_Parent, mount->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + auto* possessableComponent = mount->GetComponent(); + if (possessableComponent) { + possessableComponent->SetPossessor(m_Parent->GetObjectID()); + SetPossessable(mount->GetObjectID()); + SetPossessableType(possessableComponent->GetPossessionType()); + } + + auto characterComponent = m_Parent->GetComponent(); + if (characterComponent) characterComponent->SetIsRacing(true); + + // GM's to send + GameMessages::SendSetJetPackMode(m_Parent, false); + GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + + EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(mount); +} + +void PossessorComponent::Dismount(Entity* mount, bool forceDismount) { + // Don't do anything if we are busy dismounting + if (GetIsDismounting() || !mount) return; + SetIsDismounting(true); + + if (mount) { + auto* possessableComponent = mount->GetComponent(); + if (possessableComponent) { + possessableComponent->SetPossessor(LWOOBJID_EMPTY); + if (forceDismount) possessableComponent->ForceDepossess(); + } + EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(mount); + + auto characterComponent = m_Parent->GetComponent(); + if (characterComponent) characterComponent->SetIsRacing(false); + } + // Make sure we don't have wacky controls + GameMessages::SendSetPlayerControlScheme(m_Parent, eControlScheme::SCHEME_A); +} diff --git a/dGame/dComponents/PossessorComponent.h b/dGame/dComponents/PossessorComponent.h index f3389274..4456af27 100644 --- a/dGame/dComponents/PossessorComponent.h +++ b/dGame/dComponents/PossessorComponent.h @@ -3,53 +3,113 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" + +// possession types +enum class ePossessionType : uint8_t { + NO_POSSESSION = 0, + ATTACHED_VISIBLE, + NOT_ATTACHED_VISIBLE, + NOT_ATTACHED_NOT_VISIBLE, +}; /** * Represents an entity that can posess other entities. Generally used by players to drive a car. */ class PossessorComponent : public Component { - public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR; +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSOR; - PossessorComponent(Entity* parent); - ~PossessorComponent() override; + PossessorComponent(Entity* parent); + ~PossessorComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Sets the entity that this entity is possessing - * @param value the ID of the entity this ID should posess - */ - void SetPossessable(LWOOBJID value) { m_Possessable = value; m_DirtyPossesor = true; } + /** + * @brief Mounts the entity + * + * @param mount Entity to be mounted + */ + void Mount(Entity* mount); - /** - * Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0 - * @param value the possesible type to set - */ - void SetPossessableType(uint8_t value) { m_PossessableType = value; m_DirtyPossesor = true; } + /** + * @brief Dismounts the entity + * + * @param mount Entity to be dismounted + * @param forceDismount Should we forcibly dismount the entity + */ + void Dismount(Entity* mount, bool forceDismount = false); - /** - * Returns the entity that this entity is currently posessing - * @return the entity that this entity is currently posessing - */ - LWOOBJID GetPossessable() const { return m_Possessable; } + /** + * Sets the ID that this entity is possessing + * @param value The ID that this entity is possessing + */ + void SetPossessable(LWOOBJID value) { m_Possessable = value; m_DirtyPossesor = true; } - private: + /** + * Returns the entity that this entity is currently posessing + * @return The entity that this entity is currently posessing + */ + LWOOBJID GetPossessable() const { return m_Possessable; } - /** - * The ID of the entity this entity is possessing (e.g. the ID of a car) - */ - LWOOBJID m_Possessable; + /** + * Sets if we are busy dismounting + * @param value If we are busy dismounting + */ + void SetIsDismounting(bool value) { m_IsDismounting = value; } - /** - * @brief possessable type - * - */ - uint8_t m_PossessableType; + /** + * Returns if we are busy dismounting + * @return If we are busy dismounting + */ + bool GetIsDismounting() const { return m_IsDismounting; } - /** - * @brief if the possessor is dirty - * - */ - bool m_DirtyPossesor; + /** + * Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0 + * @param value The possesible type to set + */ + void SetPossessableType(ePossessionType value) { m_PossessableType = value; m_DirtyPossesor = true; } + + + /** + * Gets the object ID of the mount item that is being used + * @return The object ID of the mount item that is being used + */ + LWOOBJID GetMountItemID() const { return m_MountItemID; } + + /** + * Sets the object ID of the mount item that is being used + * @param m_MountItemID The object ID of the mount item that is being used + */ + void SetMountItemID(LWOOBJID mountItemID) { m_MountItemID = mountItemID; } + +private: + + /** + * The ID of the entity this entity is possessing (e.g. the ID of a car) + */ + LWOOBJID m_Possessable = LWOOBJID_EMPTY; + + /** + * @brief possessable type + * + */ + ePossessionType m_PossessableType = ePossessionType::NO_POSSESSION; + + /** + * @brief If the possessor is dirty + * + */ + bool m_DirtyPossesor = false; + + /** + * @brief If the possessor is busy dismounting + * + */ + bool m_IsDismounting = false; + + /** + * Mount Item ID + */ + LWOOBJID m_MountItemID = LWOOBJID_EMPTY; }; diff --git a/dGame/dComponents/PropertyComponent.cpp b/dGame/dComponents/PropertyComponent.cpp index cbe8d156..4f8df40c 100644 --- a/dGame/dComponents/PropertyComponent.cpp +++ b/dGame/dComponents/PropertyComponent.cpp @@ -3,7 +3,7 @@ #include "dZoneManager.h" PropertyComponent::PropertyComponent(Entity* parent) : Component(parent) { - m_PropertyName = parent->GetVar(u"propertyName"); + m_PropertyName = parent->GetVar(u"propertyName"); m_PropertyState = new PropertyState(); } diff --git a/dGame/dComponents/PropertyComponent.h b/dGame/dComponents/PropertyComponent.h index 2096a475..41f93677 100644 --- a/dGame/dComponents/PropertyComponent.h +++ b/dGame/dComponents/PropertyComponent.h @@ -9,6 +9,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" struct PropertyState { LWOOBJID ownerID; @@ -21,7 +22,7 @@ struct PropertyState { */ class PropertyComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY; explicit PropertyComponent(Entity* parentEntity); ~PropertyComponent() override; [[nodiscard]] PropertyState* GetPropertyState() const { return m_PropertyState; }; diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index 1d631e88..5da9a3c4 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -11,16 +11,18 @@ #include "CharacterComponent.h" #include "UserManager.h" #include "dLogger.h" +#include "AMFFormat.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" -PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) -{ - this->propertyQueries = {}; +PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) { + this->propertyQueries = {}; - auto table = CDClientManager::Instance()->GetTable("PropertyEntranceComponent"); - const auto& entry = table->GetByID(componentID); + auto table = CDClientManager::Instance().GetTable(); + const auto& entry = table->GetByID(componentID); - this->m_MapID = entry.mapID; - this->m_PropertyName = entry.propertyName; + this->m_MapID = entry.mapID; + this->m_PropertyName = entry.propertyName; } void PropertyEntranceComponent::OnUse(Entity* entity) { @@ -40,310 +42,296 @@ void PropertyEntranceComponent::OnUse(Entity* entity) { args.InsertValue("state", state); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); - - delete state; } -void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) -{ - LWOCLONEID cloneId = 0; +void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) { + LWOCLONEID cloneId = 0; - if (index == -1 && !returnToZone) - { - cloneId = entity->GetCharacter()->GetPropertyCloneID(); - } - else if (index == -1 && returnToZone) - { - cloneId = 0; - } - else if (index >= 0) - { - // Increment index once here because the first index of other player properties is 2 in the propertyQueries cache. - index++; + if (index == -1 && !returnToZone) { + cloneId = entity->GetCharacter()->GetPropertyCloneID(); + } else if (index == -1 && returnToZone) { + cloneId = 0; + } else if (index >= 0) { + // Increment index once here because the first index of other player properties is 2 in the propertyQueries cache. + index++; - const auto& pair = propertyQueries.find(entity->GetObjectID()); + const auto& pair = propertyQueries.find(entity->GetObjectID()); - if (pair == propertyQueries.end()) return; + if (pair == propertyQueries.end()) return; - const auto& query = pair->second; + const auto& query = pair->second; - if (index >= query.size()) return; + if (index >= query.size()) return; - cloneId = query[index].CloneId; - } + cloneId = query[index].CloneId; + } - auto* launcher = m_Parent->GetComponent(); + auto* launcher = m_Parent->GetComponent(); - if (launcher == nullptr) - { - return; - } + if (launcher == nullptr) { + return; + } - launcher->SetSelectedCloneId(entity->GetObjectID(), cloneId); + launcher->SetSelectedCloneId(entity->GetObjectID(), cloneId); - launcher->Launch(entity, launcher->GetTargetZone(), cloneId); + launcher->Launch(entity, launcher->GetTargetZone(), cloneId); } PropertySelectQueryProperty PropertyEntranceComponent::SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId, std::string ownerName, std::string propertyName, std::string propertyDescription, float reputation, bool isBFF, bool isFriend, bool isModeratorApproved, bool isAlt, bool isOwned, uint32_t privacyOption, uint32_t timeLastUpdated, float performanceCost) { - property.CloneId = cloneId; - property.OwnerName = ownerName; - property.Name = propertyName; - property.Description = propertyDescription; - property.Reputation = reputation; - property.IsBestFriend = isBFF; - property.IsFriend = isFriend; - property.IsModeratorApproved = isModeratorApproved; - property.IsAlt = isAlt; - property.IsOwned = isOwned; - property.AccessType = privacyOption; - property.DateLastPublished = timeLastUpdated; - property.PerformanceCost = performanceCost; + property.CloneId = cloneId; + property.OwnerName = ownerName; + property.Name = propertyName; + property.Description = propertyDescription; + property.Reputation = reputation; + property.IsBestFriend = isBFF; + property.IsFriend = isFriend; + property.IsModeratorApproved = isModeratorApproved; + property.IsAlt = isAlt; + property.IsOwned = isOwned; + property.AccessType = privacyOption; + property.DateLastPublished = timeLastUpdated; + property.PerformanceCost = performanceCost; - return property; + return property; } -std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery, bool wantLimits) { - std::string base; - if (customQuery == "") { - base = baseQueryForProperties; - } else { - base = customQuery; - } - std::string orderBy = ""; - if (sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS) { - std::string friendsList = " AND p.owner_id IN ("; +std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery, bool wantLimits) { + std::string base; + if (customQuery == "") { + base = baseQueryForProperties; + } else { + base = customQuery; + } + std::string orderBy = ""; + if (sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS) { + std::string friendsList = " AND p.owner_id IN ("; - auto friendsListQuery = Database::CreatePreppedStmt("SELECT * FROM (SELECT CASE WHEN player_id = ? THEN friend_id WHEN friend_id = ? THEN player_id END AS requested_player FROM friends ) AS fr WHERE requested_player IS NOT NULL ORDER BY requested_player DESC;"); + auto friendsListQuery = Database::CreatePreppedStmt("SELECT * FROM (SELECT CASE WHEN player_id = ? THEN friend_id WHEN friend_id = ? THEN player_id END AS requested_player FROM friends ) AS fr WHERE requested_player IS NOT NULL ORDER BY requested_player DESC;"); - friendsListQuery->setInt64(1, entity->GetObjectID()); - friendsListQuery->setInt64(2, entity->GetObjectID()); + friendsListQuery->setUInt(1, character->GetID()); + friendsListQuery->setUInt(2, character->GetID()); - auto friendsListQueryResult = friendsListQuery->executeQuery(); + auto friendsListQueryResult = friendsListQuery->executeQuery(); - while (friendsListQueryResult->next()) { - auto playerIDToConvert = friendsListQueryResult->getInt64(1); - playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_CHARACTER); - playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_PERSISTENT); - friendsList = friendsList + std::to_string(playerIDToConvert) + ","; - } - // Replace trailing comma with the closing parenthesis. - if (friendsList.at(friendsList.size() - 1) == ',') friendsList.erase(friendsList.size() - 1, 1); - friendsList += ") "; + while (friendsListQueryResult->next()) { + auto playerIDToConvert = friendsListQueryResult->getInt(1); + friendsList = friendsList + std::to_string(playerIDToConvert) + ","; + } + // Replace trailing comma with the closing parenthesis. + if (friendsList.at(friendsList.size() - 1) == ',') friendsList.erase(friendsList.size() - 1, 1); + friendsList += ") "; - // If we have no friends then use a -1 for the query. - if (friendsList.find("()") != std::string::npos) friendsList = " AND p.owner_id IN (-1) "; + // If we have no friends then use a -1 for the query. + if (friendsList.find("()") != std::string::npos) friendsList = " AND p.owner_id IN (-1) "; - orderBy += friendsList + "ORDER BY ci.name ASC "; + orderBy += friendsList + "ORDER BY ci.name ASC "; - delete friendsListQueryResult; - friendsListQueryResult = nullptr; + delete friendsListQueryResult; + friendsListQueryResult = nullptr; - delete friendsListQuery; - friendsListQuery = nullptr; - } - else if (sortMethod == SORT_TYPE_RECENT) { - orderBy = "ORDER BY p.last_updated DESC "; - } - else if (sortMethod == SORT_TYPE_REPUTATION) { - orderBy = "ORDER BY p.reputation DESC, p.last_updated DESC "; - } - else { - orderBy = "ORDER BY p.last_updated DESC "; - } - return base + orderBy + (wantLimits ? "LIMIT ? OFFSET ?;" : ";"); + delete friendsListQuery; + friendsListQuery = nullptr; + } else if (sortMethod == SORT_TYPE_RECENT) { + orderBy = "ORDER BY p.last_updated DESC "; + } else if (sortMethod == SORT_TYPE_REPUTATION) { + orderBy = "ORDER BY p.reputation DESC, p.last_updated DESC "; + } else { + orderBy = "ORDER BY p.last_updated DESC "; + } + return base + orderBy + (wantLimits ? "LIMIT ? OFFSET ?;" : ";"); } -void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, int32_t sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr){ +void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, int32_t sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr) { - std::vector entries {}; - PropertySelectQueryProperty playerEntry {}; + std::vector entries{}; + PropertySelectQueryProperty playerEntry{}; - auto character = entity->GetCharacter(); - if (!character) return; + auto character = entity->GetCharacter(); + if (!character) return; - // Player property goes in index 1 of the vector. This is how the client expects it. - auto playerPropertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE owner_id = ? AND zone_id = ?"); + // Player property goes in index 1 of the vector. This is how the client expects it. + auto playerPropertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE owner_id = ? AND zone_id = ?"); - playerPropertyLookup->setInt(1, character->GetID()); - playerPropertyLookup->setInt(2, this->m_MapID); + playerPropertyLookup->setInt(1, character->GetID()); + playerPropertyLookup->setInt(2, this->m_MapID); - auto playerPropertyLookupResults = playerPropertyLookup->executeQuery(); + auto playerPropertyLookupResults = playerPropertyLookup->executeQuery(); - // If the player has a property this query will have a single result. - if (playerPropertyLookupResults->next()) { - const auto cloneId = playerPropertyLookupResults->getUInt64(4); - const auto propertyName = std::string(playerPropertyLookupResults->getString(5).c_str()); - const auto propertyDescription = std::string(playerPropertyLookupResults->getString(6).c_str()); - const auto privacyOption = playerPropertyLookupResults->getInt(9); - const auto modApproved = playerPropertyLookupResults->getBoolean(10); - const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11); - const auto reputation = playerPropertyLookupResults->getUInt(14); - const auto performanceCost = (float)playerPropertyLookupResults->getDouble(16); + // If the player has a property this query will have a single result. + if (playerPropertyLookupResults->next()) { + const auto cloneId = playerPropertyLookupResults->getUInt64(4); + const auto propertyName = std::string(playerPropertyLookupResults->getString(5).c_str()); + const auto propertyDescription = std::string(playerPropertyLookupResults->getString(6).c_str()); + const auto privacyOption = playerPropertyLookupResults->getInt(9); + const auto modApproved = playerPropertyLookupResults->getBoolean(10); + const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11); + const auto reputation = playerPropertyLookupResults->getUInt(14); + const auto performanceCost = (float)playerPropertyLookupResults->getDouble(16); - playerEntry = SetPropertyValues(playerEntry, cloneId, character->GetName(), propertyName, propertyDescription, reputation, true, true, modApproved, true, true, privacyOption, dateLastUpdated, performanceCost); - } else { - playerEntry = SetPropertyValues(playerEntry, character->GetPropertyCloneID(), character->GetName(), "", "", 0, true, true); - } + playerEntry = SetPropertyValues(playerEntry, cloneId, character->GetName(), propertyName, propertyDescription, reputation, true, true, modApproved, true, true, privacyOption, dateLastUpdated, performanceCost); + } else { + playerEntry = SetPropertyValues(playerEntry, character->GetPropertyCloneID(), character->GetName(), "", "", 0, true, true); + } - delete playerPropertyLookupResults; - playerPropertyLookupResults = nullptr; + delete playerPropertyLookupResults; + playerPropertyLookupResults = nullptr; - delete playerPropertyLookup; - playerPropertyLookup = nullptr; + delete playerPropertyLookup; + playerPropertyLookup = nullptr; - entries.push_back(playerEntry); + entries.push_back(playerEntry); - const auto query = BuildQuery(entity, sortMethod); + const auto query = BuildQuery(entity, sortMethod, character); - auto propertyLookup = Database::CreatePreppedStmt(query); - - const auto searchString = "%" + filterText + "%"; - propertyLookup->setUInt(1, this->m_MapID); - propertyLookup->setString(2, searchString.c_str()); - propertyLookup->setString(3, searchString.c_str()); - propertyLookup->setString(4, searchString.c_str()); - propertyLookup->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? (uint32_t)PropertyPrivacyOption::Friends : (uint32_t)PropertyPrivacyOption::Public); - propertyLookup->setInt(6, numResults); - propertyLookup->setInt(7, startIndex); + auto propertyLookup = Database::CreatePreppedStmt(query); - auto propertyEntry = propertyLookup->executeQuery(); + const auto searchString = "%" + filterText + "%"; + propertyLookup->setUInt(1, this->m_MapID); + propertyLookup->setString(2, searchString.c_str()); + propertyLookup->setString(3, searchString.c_str()); + propertyLookup->setString(4, searchString.c_str()); + propertyLookup->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? (uint32_t)PropertyPrivacyOption::Friends : (uint32_t)PropertyPrivacyOption::Public); + propertyLookup->setInt(6, numResults); + propertyLookup->setInt(7, startIndex); - while (propertyEntry->next()) { - const auto propertyId = propertyEntry->getUInt64(1); - const auto owner = propertyEntry->getInt(2); - const auto cloneId = propertyEntry->getUInt64(4); - const auto propertyNameFromDb = std::string(propertyEntry->getString(5).c_str()); - const auto propertyDescriptionFromDb = std::string(propertyEntry->getString(6).c_str()); - const auto privacyOption = propertyEntry->getInt(9); - const auto modApproved = propertyEntry->getBoolean(10); - const auto dateLastUpdated = propertyEntry->getInt(11); - const float reputation = propertyEntry->getInt(14); - const auto performanceCost = (float)propertyEntry->getDouble(16); + auto propertyEntry = propertyLookup->executeQuery(); - PropertySelectQueryProperty entry{}; + while (propertyEntry->next()) { + const auto propertyId = propertyEntry->getUInt64(1); + const auto owner = propertyEntry->getInt(2); + const auto cloneId = propertyEntry->getUInt64(4); + const auto propertyNameFromDb = std::string(propertyEntry->getString(5).c_str()); + const auto propertyDescriptionFromDb = std::string(propertyEntry->getString(6).c_str()); + const auto privacyOption = propertyEntry->getInt(9); + const auto modApproved = propertyEntry->getBoolean(10); + const auto dateLastUpdated = propertyEntry->getInt(11); + const float reputation = propertyEntry->getInt(14); + const auto performanceCost = (float)propertyEntry->getDouble(16); - std::string ownerName = ""; - bool isOwned = true; - auto nameLookup = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE prop_clone_id = ?;"); + PropertySelectQueryProperty entry{}; - nameLookup->setUInt64(1, cloneId); + std::string ownerName = ""; + bool isOwned = true; + auto nameLookup = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE prop_clone_id = ?;"); - auto nameResult = nameLookup->executeQuery(); + nameLookup->setUInt64(1, cloneId); - if (!nameResult->next()) { - delete nameLookup; - nameLookup = nullptr; + auto nameResult = nameLookup->executeQuery(); - Game::logger->Log("PropertyEntranceComponent", "Failed to find property owner name for %llu!\n", cloneId); + if (!nameResult->next()) { + delete nameLookup; + nameLookup = nullptr; - continue; - } else { - isOwned = cloneId == character->GetPropertyCloneID(); - ownerName = std::string(nameResult->getString(1).c_str()); - } + Game::logger->Log("PropertyEntranceComponent", "Failed to find property owner name for %llu!", cloneId); - delete nameResult; - nameResult = nullptr; + continue; + } else { + isOwned = cloneId == character->GetPropertyCloneID(); + ownerName = std::string(nameResult->getString(1).c_str()); + } - delete nameLookup; - nameLookup = nullptr; + delete nameResult; + nameResult = nullptr; - std::string propertyName = propertyNameFromDb; - std::string propertyDescription = propertyDescriptionFromDb; + delete nameLookup; + nameLookup = nullptr; - bool isBestFriend = false; - bool isFriend = false; + std::string propertyName = propertyNameFromDb; + std::string propertyDescription = propertyDescriptionFromDb; - // Convert owner char id to LWOOBJID - LWOOBJID ownerObjId = owner; - ownerObjId = GeneralUtils::SetBit(ownerObjId, OBJECT_BIT_CHARACTER); - ownerObjId = GeneralUtils::SetBit(ownerObjId, OBJECT_BIT_PERSISTENT); + bool isBestFriend = false; + bool isFriend = false; - // Query to get friend and best friend fields - auto friendCheck = Database::CreatePreppedStmt("SELECT best_friend FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?)"); + // Convert owner char id to LWOOBJID + LWOOBJID ownerObjId = owner; + GeneralUtils::SetBit(ownerObjId, eObjectBits::CHARACTER); + GeneralUtils::SetBit(ownerObjId, eObjectBits::PERSISTENT); - friendCheck->setInt64(1, entity->GetObjectID()); - friendCheck->setInt64(2, ownerObjId); - friendCheck->setInt64(3, ownerObjId); - friendCheck->setInt64(4, entity->GetObjectID()); + // Query to get friend and best friend fields + auto friendCheck = Database::CreatePreppedStmt("SELECT best_friend FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?)"); - auto friendResult = friendCheck->executeQuery(); + friendCheck->setUInt(1, character->GetID()); + friendCheck->setUInt(2, ownerObjId); + friendCheck->setUInt(3, ownerObjId); + friendCheck->setUInt(4, character->GetID()); - // If we got a result than the two players are friends. - if (friendResult->next()) { - isFriend = true; - if (friendResult->getInt(1) == 2) { - isBestFriend = true; - } - } + auto friendResult = friendCheck->executeQuery(); - delete friendCheck; - friendCheck = nullptr; + // If we got a result than the two players are friends. + if (friendResult->next()) { + isFriend = true; + if (friendResult->getInt(1) == 3) { + isBestFriend = true; + } + } - delete friendResult; - friendResult = nullptr; + delete friendCheck; + friendCheck = nullptr; - bool isModeratorApproved = propertyEntry->getBoolean(10); + delete friendResult; + friendResult = nullptr; - if (!isModeratorApproved && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { - propertyName = "[AWAITING APPROVAL]"; - propertyDescription = "[AWAITING APPROVAL]"; - isModeratorApproved = true; - } + bool isModeratorApproved = propertyEntry->getBoolean(10); - bool isAlt = false; - // Query to determine whether this property is an alt character of the entity. - auto isAltQuery = Database::CreatePreppedStmt("SELECT id FROM charinfo where account_id in (SELECT account_id from charinfo WHERE id = ?) AND id = ?;"); + if (!isModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { + propertyName = "[AWAITING APPROVAL]"; + propertyDescription = "[AWAITING APPROVAL]"; + isModeratorApproved = true; + } - isAltQuery->setInt(1, character->GetID()); - isAltQuery->setInt(2, owner); + bool isAlt = false; + // Query to determine whether this property is an alt character of the entity. + auto isAltQuery = Database::CreatePreppedStmt("SELECT id FROM charinfo where account_id in (SELECT account_id from charinfo WHERE id = ?) AND id = ?;"); - auto isAltQueryResults = isAltQuery->executeQuery(); + isAltQuery->setInt(1, character->GetID()); + isAltQuery->setInt(2, owner); - if (isAltQueryResults->next()) { - isAlt = true; - } + auto isAltQueryResults = isAltQuery->executeQuery(); - delete isAltQueryResults; - isAltQueryResults = nullptr; + if (isAltQueryResults->next()) { + isAlt = true; + } - delete isAltQuery; - isAltQuery = nullptr; + delete isAltQueryResults; + isAltQueryResults = nullptr; - entry = SetPropertyValues(entry, cloneId, ownerName, propertyName, propertyDescription, reputation, isBestFriend, isFriend, isModeratorApproved, isAlt, isOwned, privacyOption, dateLastUpdated, performanceCost); + delete isAltQuery; + isAltQuery = nullptr; - entries.push_back(entry); - } + entry = SetPropertyValues(entry, cloneId, ownerName, propertyName, propertyDescription, reputation, isBestFriend, isFriend, isModeratorApproved, isAlt, isOwned, privacyOption, dateLastUpdated, performanceCost); - delete propertyEntry; - propertyEntry = nullptr; + entries.push_back(entry); + } - delete propertyLookup; - propertyLookup = nullptr; + delete propertyEntry; + propertyEntry = nullptr; - propertyQueries[entity->GetObjectID()] = entries; - - // Query here is to figure out whether or not to display the button to go to the next page or not. - int32_t numberOfProperties = 0; + delete propertyLookup; + propertyLookup = nullptr; - auto buttonQuery = BuildQuery(entity, sortMethod, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false); - auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery); + propertyQueries[entity->GetObjectID()] = entries; - propertiesLeft->setUInt(1, this->m_MapID); - propertiesLeft->setString(2, searchString.c_str()); - propertiesLeft->setString(3, searchString.c_str()); - propertiesLeft->setString(4, searchString.c_str()); - propertiesLeft->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? 1 : 2); + // Query here is to figure out whether or not to display the button to go to the next page or not. + int32_t numberOfProperties = 0; - auto result = propertiesLeft->executeQuery(); - result->next(); - numberOfProperties = result->getInt(1); + auto buttonQuery = BuildQuery(entity, sortMethod, character, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false); + auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery); - delete result; - result = nullptr; - - delete propertiesLeft; - propertiesLeft = nullptr; + propertiesLeft->setUInt(1, this->m_MapID); + propertiesLeft->setString(2, searchString.c_str()); + propertiesLeft->setString(3, searchString.c_str()); + propertiesLeft->setString(4, searchString.c_str()); + propertiesLeft->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? 1 : 2); - GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); + auto result = propertiesLeft->executeQuery(); + result->next(); + numberOfProperties = result->getInt(1); + + delete result; + result = nullptr; + + delete propertiesLeft; + propertiesLeft = nullptr; + + GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); } diff --git a/dGame/dComponents/PropertyEntranceComponent.h b/dGame/dComponents/PropertyEntranceComponent.h index a3be38a6..e37d1daa 100644 --- a/dGame/dComponents/PropertyEntranceComponent.h +++ b/dGame/dComponents/PropertyEntranceComponent.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -6,84 +6,85 @@ #include "Entity.h" #include "EntityManager.h" #include "GameMessages.h" +#include "eReplicaComponentType.h" /** * Represents the launch pad that's used to select and browse properties */ class PropertyEntranceComponent : public Component { - public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_ENTRANCE; - explicit PropertyEntranceComponent(uint32_t componentID, Entity* parent); +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_ENTRANCE; + explicit PropertyEntranceComponent(uint32_t componentID, Entity* parent); - /** - * Handles an OnUse request for some other entity, rendering the property browse menu - * @param entity the entity that triggered the event - */ - void OnUse(Entity* entity) override; + /** + * Handles an OnUse request for some other entity, rendering the property browse menu + * @param entity the entity that triggered the event + */ + void OnUse(Entity* entity) override; - /** - * Handles the event triggered when the entity selects a property to visit and makes the entity to there - * @param entity the entity that triggered the event - * @param index the index of the property property - * @param returnToZone whether or not the entity wishes to go back to the launch zone - * @param sysAddr the address to send gamemessage responses to - */ - void OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr); + /** + * Handles the event triggered when the entity selects a property to visit and makes the entity to there + * @param entity the entity that triggered the event + * @param index the index of the property property + * @param returnToZone whether or not the entity wishes to go back to the launch zone + * @param sysAddr the address to send gamemessage responses to + */ + void OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr); - /** - * Handles a request for information on available properties when an entity lands on the property - * @param entity the entity that triggered the event - * @param includeNullAddress unused - * @param includeNullDescription unused - * @param playerOwn only query properties owned by the entity - * @param updateUi unused - * @param numResults unused - * @param lReputationTime unused - * @param sortMethod unused - * @param startIndex the minimum index to start the query off - * @param filterText property names to search for - * @param sysAddr the address to send gamemessage responses to - */ - void OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, int32_t sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr); + /** + * Handles a request for information on available properties when an entity lands on the property + * @param entity the entity that triggered the event + * @param includeNullAddress unused + * @param includeNullDescription unused + * @param playerOwn only query properties owned by the entity + * @param updateUi unused + * @param numResults unused + * @param lReputationTime unused + * @param sortMethod unused + * @param startIndex the minimum index to start the query off + * @param filterText property names to search for + * @param sysAddr the address to send gamemessage responses to + */ + void OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, int32_t sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr); - /** - * Returns the name of this property - * @return the name of this property - */ - [[nodiscard]] std::string GetPropertyName() const { return m_PropertyName; }; + /** + * Returns the name of this property + * @return the name of this property + */ + [[nodiscard]] std::string GetPropertyName() const { return m_PropertyName; }; - /** - * Returns the map ID for this property - * @return the map ID for this property - */ - [[nodiscard]] LWOMAPID GetMapID() const { return m_MapID; }; + /** + * Returns the map ID for this property + * @return the map ID for this property + */ + [[nodiscard]] LWOMAPID GetMapID() const { return m_MapID; }; - PropertySelectQueryProperty SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId = LWOCLONEID_INVALID, std::string ownerName = "", std::string propertyName = "", std::string propertyDescription = "", float reputation = 0, bool isBFF = false, bool isFriend = false, bool isModeratorApproved = false, bool isAlt = false, bool isOwned = false, uint32_t privacyOption = 0, uint32_t timeLastUpdated = 0, float performanceCost = 0.0f); + PropertySelectQueryProperty SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId = LWOCLONEID_INVALID, std::string ownerName = "", std::string propertyName = "", std::string propertyDescription = "", float reputation = 0, bool isBFF = false, bool isFriend = false, bool isModeratorApproved = false, bool isAlt = false, bool isOwned = false, uint32_t privacyOption = 0, uint32_t timeLastUpdated = 0, float performanceCost = 0.0f); - std::string BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery = "", bool wantLimits = true); + std::string BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery = "", bool wantLimits = true); - private: - /** - * Cache of property information that was queried for property launched, indexed by property ID - */ - std::map> propertyQueries; +private: + /** + * Cache of property information that was queried for property launched, indexed by property ID + */ + std::map> propertyQueries; - /** - * The custom name for this property - */ - std::string m_PropertyName; + /** + * The custom name for this property + */ + std::string m_PropertyName; - /** - * The base map ID for this property (Avant Grove, etc). - */ - LWOMAPID m_MapID; + /** + * The base map ID for this property (Avant Grove, etc). + */ + LWOMAPID m_MapID; - enum ePropertySortType : int32_t { - SORT_TYPE_FRIENDS = 0, - SORT_TYPE_REPUTATION = 1, - SORT_TYPE_RECENT = 3, - SORT_TYPE_FEATURED = 5 - }; + enum ePropertySortType : int32_t { + SORT_TYPE_FRIENDS = 0, + SORT_TYPE_REPUTATION = 1, + SORT_TYPE_RECENT = 3, + SORT_TYPE_FEATURED = 5 + }; - std::string baseQueryForProperties = "SELECT p.* FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? "; + std::string baseQueryForProperties = "SELECT p.* FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? "; }; diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index f27ea283..c87d0744 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -1,4 +1,4 @@ -#include "PropertyManagementComponent.h" +#include "PropertyManagementComponent.h" #include @@ -17,14 +17,16 @@ #include "Player.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" +#include "eObjectBits.h" #include #include "CppScripts.h" PropertyManagementComponent* PropertyManagementComponent::instance = nullptr; -PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Component(parent) -{ +PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Component(parent) { this->owner = LWOOBJID_EMPTY; this->templateId = 0; this->propertyId = LWOOBJID_EMPTY; @@ -37,21 +39,20 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo instance = this; const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); - + const auto zoneId = worldId.GetMapID(); const auto cloneId = worldId.GetCloneID(); auto query = CDClientDatabase::CreatePreppedStmt( "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int) zoneId); + query.bind(1, (int)zoneId); auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) - { + if (result.eof() || result.fieldIsNull(0)) { return; } - + templateId = result.getIntField(0); result.finalize(); @@ -63,12 +64,11 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo auto* propertyEntry = propertyLookup->executeQuery(); - if (propertyEntry->next()) - { + if (propertyEntry->next()) { this->propertyId = propertyEntry->getUInt64(1); this->owner = propertyEntry->getUInt64(2); - this->owner = GeneralUtils::SetBit(this->owner, OBJECT_BIT_CHARACTER); - this->owner = GeneralUtils::SetBit(this->owner, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(this->owner, eObjectBits::CHARACTER); + GeneralUtils::SetBit(this->owner, eObjectBits::PERSISTENT); this->clone_Id = propertyEntry->getInt(2); this->propertyName = propertyEntry->getString(5).c_str(); this->propertyDescription = propertyEntry->getString(6).c_str(); @@ -80,77 +80,65 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo this->reputation = propertyEntry->getUInt(14); Load(); - } + } delete propertyLookup; } -LWOOBJID PropertyManagementComponent::GetOwnerId() const -{ +LWOOBJID PropertyManagementComponent::GetOwnerId() const { return owner; } -Entity* PropertyManagementComponent::GetOwner() const -{ +Entity* PropertyManagementComponent::GetOwner() const { return EntityManager::Instance()->GetEntity(owner); } -void PropertyManagementComponent::SetOwner(Entity* value) -{ +void PropertyManagementComponent::SetOwner(Entity* value) { owner = value->GetObjectID(); } -std::vector PropertyManagementComponent::GetPaths() const -{ +std::vector PropertyManagementComponent::GetPaths() const { const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); auto query = CDClientDatabase::CreatePreppedStmt( "SELECT path FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int) zoneId); + query.bind(1, (int)zoneId); auto result = query.execQuery(); - std::vector paths {}; - - if (result.eof()) - { + std::vector paths{}; + + if (result.eof()) { return paths; } std::vector points; - + std::istringstream stream(result.getStringField(0)); std::string token; - while (std::getline(stream, token, ' ')) - { - try - { + while (std::getline(stream, token, ' ')) { + try { auto value = std::stof(token); points.push_back(value); - } - catch (std::invalid_argument& exception) - { - Game::logger->Log("PropertyManagementComponent", "Failed to parse value (%s): (%s)!\n", token.c_str(), exception.what()); + } catch (std::invalid_argument& exception) { + Game::logger->Log("PropertyManagementComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what()); } } - for (auto i = 0u; i < points.size(); i += 3) - { + for (auto i = 0u; i < points.size(); i += 3) { paths.emplace_back(points[i], points[i + 1], points[i + 2]); } return paths; } -PropertyPrivacyOption PropertyManagementComponent::GetPrivacyOption() const -{ +PropertyPrivacyOption PropertyManagementComponent::GetPrivacyOption() const { return privacyOption; } -void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value) -{ +void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value) { if (owner == LWOOBJID_EMPTY) return; if (value == static_cast(3)) // Client sends 3 for private for some reason, but expects 0 in return? @@ -174,8 +162,7 @@ void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value) propertyUpdate->executeUpdate(); } -void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::string description) -{ +void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::string description) { if (owner == LWOOBJID_EMPTY) return; propertyName = name; @@ -193,10 +180,8 @@ void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::s OnQueryPropertyData(GetOwner(), UNASSIGNED_SYSTEM_ADDRESS); } -bool PropertyManagementComponent::Claim(const LWOOBJID playerId) -{ - if (owner != LWOOBJID_EMPTY) - { +bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { + if (owner != LWOOBJID_EMPTY) { return false; } @@ -218,6 +203,16 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) // If we are not on our clone do not allow us to claim the property if (propertyCloneId != playerCloneId) return false; + std::string name = zone->GetZoneName(); + std::string description = ""; + + auto prop_path = zone->GetPath(m_Parent->GetVarAsString(u"propertyName")); + + if (prop_path){ + if (!prop_path->property.displayName.empty()) name = prop_path->property.displayName; + description = prop_path->property.displayDesc; + } + SetOwnerId(playerId); propertyId = ObjectIDManager::GenerateRandomObjectID(); @@ -225,37 +220,34 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) auto* insertion = Database::CreatePreppedStmt( "INSERT INTO properties" "(id, owner_id, template_id, clone_id, name, description, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, zone_id, performance_cost)" - "VALUES (?, ?, ?, ?, ?, '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)" + "VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)" ); insertion->setUInt64(1, propertyId); - insertion->setUInt64(2, (uint32_t) playerId); + insertion->setUInt64(2, (uint32_t)playerId); insertion->setUInt(3, templateId); insertion->setUInt64(4, playerCloneId); - insertion->setString(5, zone->GetZoneName().c_str()); - insertion->setInt(6, propertyZoneId); + insertion->setString(5, name.c_str()); + insertion->setString(6, description.c_str()); + insertion->setInt(7, propertyZoneId); // Try and execute the query, print an error if it fails. - try - { + try { insertion->execute(); - } - catch (sql::SQLException& exception) - { - Game::logger->Log("PropertyManagementComponent", "Failed to execute query: (%s)!\n", exception.what()); + } catch (sql::SQLException& exception) { + Game::logger->Log("PropertyManagementComponent", "Failed to execute query: (%s)!", exception.what()); throw exception; return false; } auto* zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) { - script->OnZonePropertyRented(zoneControlObject, entity); - } + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) { + script->OnZonePropertyRented(zoneControlObject, entity); + } return true; } -void PropertyManagementComponent::OnStartBuilding() -{ +void PropertyManagementComponent::OnStartBuilding() { auto* ownerEntity = GetOwner(); if (ownerEntity == nullptr) return; @@ -264,24 +256,21 @@ void PropertyManagementComponent::OnStartBuilding() LWOMAPID zoneId = 1100; - const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_ENTRANCE); + const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_ENTRANCE); originalPrivacyOption = privacyOption; SetPrivacyOption(PropertyPrivacyOption::Private); // Cant visit player which is building - if (!entrance.empty()) - { + if (!entrance.empty()) { auto* rocketPad = entrance[0]->GetComponent(); - if (rocketPad != nullptr) - { + if (rocketPad != nullptr) { zoneId = rocketPad->GetDefaultZone(); } } - for (auto* player : players) - { + for (auto* player : players) { if (player == ownerEntity) continue; player->SendToZone(zoneId); @@ -292,8 +281,7 @@ void PropertyManagementComponent::OnStartBuilding() if (inventoryComponent) inventoryComponent->PushEquippedItems(); } -void PropertyManagementComponent::OnFinishBuilding() -{ +void PropertyManagementComponent::OnFinishBuilding() { auto* ownerEntity = GetOwner(); if (ownerEntity == nullptr) return; @@ -305,29 +293,25 @@ void PropertyManagementComponent::OnFinishBuilding() Save(); } -void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const NiPoint3 position, NiQuaternion rotation) -{ - Game::logger->Log("PropertyManagementComponent", "Placing model <%f, %f, %f>\n", position.x, position.y, position.z); +void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const NiPoint3 position, NiQuaternion rotation) { + Game::logger->Log("PropertyManagementComponent", "Placing model <%f, %f, %f>", position.x, position.y, position.z); auto* entity = GetOwner(); - if (entity == nullptr) - { + if (entity == nullptr) { return; } auto* inventoryComponent = entity->GetComponent(); - if (inventoryComponent == nullptr) - { + if (inventoryComponent == nullptr) { return; } auto* item = inventoryComponent->FindItemById(id); - if (item == nullptr) - { - Game::logger->Log("PropertyManagementComponent", "Failed to find item with id %d\n", id); + if (item == nullptr) { + Game::logger->Log("PropertyManagementComponent", "Failed to find item with id %d", id); return; } @@ -336,8 +320,7 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N const auto modelLOT = item->GetLot(); - if (rotation != NiQuaternion::IDENTITY) - { + if (rotation != NiQuaternion::IDENTITY) { rotation = { rotation.w, rotation.z, rotation.y, rotation.x }; } @@ -360,120 +343,117 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N if (newEntity != nullptr) { EntityManager::Instance()->ConstructEntity(newEntity); - //Make sure the propMgmt doesn't delete our model after the server dies - //Trying to do this after the entity is constructed. Shouldn't really change anything but - //There was an issue with builds not appearing since it was placed above ConstructEntity. + // Make sure the propMgmt doesn't delete our model after the server dies + // Trying to do this after the entity is constructed. Shouldn't really change anything but + // There was an issue with builds not appearing since it was placed above ConstructEntity. PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), spawnerID); } item->SetCount(item->GetCount() - 1); - //item->UnEquip(); - return; } - + item->SetCount(item->GetCount() - 1); - //item->UnEquip(); auto* node = new SpawnerNode(); node->position = position; node->rotation = rotation; - ObjectIDManager::Instance()->RequestPersistentID([this, node, modelLOT, entity, position, rotation, originalRotation](uint32_t persistentId) - { - SpawnerInfo info{}; + ObjectIDManager::Instance()->RequestPersistentID([this, node, modelLOT, entity, position, rotation, originalRotation](uint32_t persistentId) { + SpawnerInfo info{}; - info.templateID = modelLOT; - info.nodes = { node }; - info.templateScale = 1.0f; - info.activeOnLoad = true; - info.amountMaintained = 1; - info.respawnTime = 10; + info.templateID = modelLOT; + info.nodes = { node }; + info.templateScale = 1.0f; + info.activeOnLoad = true; + info.amountMaintained = 1; + info.respawnTime = 10; - info.emulated = true; - info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); + info.emulated = true; + info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); - LWOOBJID id = static_cast(persistentId) | 1ull << OBJECT_BIT_CLIENT; + info.spawnerID = persistentId; + GeneralUtils::SetBit(info.spawnerID, eObjectBits::CLIENT); - info.spawnerID = id; - - const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info); + const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info); - auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); + auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); - auto* model = spawner->Spawn(); + auto ldfModelBehavior = new LDFData(u"modelBehaviors", 0); + auto userModelID = new LDFData(u"userModelID", info.spawnerID); + auto modelType = new LDFData(u"modelType", 2); + auto propertyObjectID = new LDFData(u"propertyObjectID", true); + auto componentWhitelist = new LDFData(u"componentWhitelist", 1); + info.nodes[0]->config.push_back(componentWhitelist); + info.nodes[0]->config.push_back(ldfModelBehavior); + info.nodes[0]->config.push_back(modelType); + info.nodes[0]->config.push_back(propertyObjectID); + info.nodes[0]->config.push_back(userModelID); - models.insert_or_assign(model->GetObjectID(), spawnerId); + auto* model = spawner->Spawn(); - GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), position, m_Parent->GetObjectID(), 14, originalRotation); + models.insert_or_assign(model->GetObjectID(), spawnerId); - GameMessages::SendUGCEquipPreCreateBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), 0, spawnerId); + GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), position, m_Parent->GetObjectID(), 14, originalRotation); - GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendUGCEquipPreCreateBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), 0, spawnerId); - //item->SetCount(item->GetCount() - 1); + GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS); - EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPlaced(entity); + EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPlaced(entity); }); - // Progress place model missions - auto missionComponent = entity->GetComponent(); - if (missionComponent != nullptr) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL, 0); + // Progress place model missions + auto missionComponent = entity->GetComponent(); + if (missionComponent != nullptr) missionComponent->Progress(eMissionTaskType::PLACE_MODEL, 0); } -void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int deleteReason) -{ - Game::logger->Log("PropertyManagementComponent", "Delete model: (%llu) (%i)\n", id, deleteReason); +void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int deleteReason) { + Game::logger->Log("PropertyManagementComponent", "Delete model: (%llu) (%i)", id, deleteReason); auto* entity = GetOwner(); - if (entity == nullptr) - { + if (entity == nullptr) { return; } auto* inventoryComponent = entity->GetComponent(); - if (inventoryComponent == nullptr) - { + if (inventoryComponent == nullptr) { return; } const auto index = models.find(id); - if (index == models.end()) - { - Game::logger->Log("PropertyManagementComponent", "Failed to find model\n"); + if (index == models.end()) { + Game::logger->Log("PropertyManagementComponent", "Failed to find model"); return; } const auto spawnerId = index->second; - + auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); models.erase(id); - - if (spawner == nullptr) - { - Game::logger->Log("PropertyManagementComponent", "Failed to find spawner\n"); + + if (spawner == nullptr) { + Game::logger->Log("PropertyManagementComponent", "Failed to find spawner"); } auto* model = EntityManager::Instance()->GetEntity(id); - if (model == nullptr) - { - Game::logger->Log("PropertyManagementComponent", "Failed to find model entity\n"); + if (model == nullptr) { + Game::logger->Log("PropertyManagementComponent", "Failed to find model entity"); return; } EntityManager::Instance()->DestructEntity(model); - Game::logger->Log("PropertyManagementComponent", "Deleting model LOT %i\n", model->GetLOT()); + Game::logger->Log("PropertyManagementComponent", "Deleting model LOT %i", model->GetLOT()); - if (model->GetLOT() == 14) - { + if (model->GetLOT() == 14) { //add it to the inv std::vector settings; @@ -496,20 +476,18 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet settings.push_back(propertyObjectID); settings.push_back(modelType); - inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::HIDDEN, settings, LWOOBJID_EMPTY, false, false, spawnerId); + inventoryComponent->AddItem(6662, 1, eLootSourceType::DELETION, eInventoryType::MODELS_IN_BBB, settings, LWOOBJID_EMPTY, false, false, spawnerId); auto* item = inventoryComponent->FindItemBySubKey(spawnerId); if (item == nullptr) { return; } - if (deleteReason == 0) - { + if (deleteReason == 0) { //item->Equip(); } - if (deleteReason == 0 || deleteReason == 2) - { + if (deleteReason == 0 || deleteReason == 2) { GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), item->GetId(), item->GetCount()); } @@ -517,21 +495,18 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY); - if (spawner != nullptr) - { + if (spawner != nullptr) { dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID); - } - else - { - model->Smash(SILENT); + } else { + model->Smash(LWOOBJID_EMPTY, eKillType::SILENT); } item->SetCount(0, true, false, false); return; } - - inventoryComponent->AddItem(model->GetLOT(), 1, eLootSourceType::LOOT_SOURCE_DELETION, INVALID, {}, LWOOBJID_EMPTY, false); + + inventoryComponent->AddItem(model->GetLOT(), 1, eLootSourceType::DELETION, INVALID, {}, LWOOBJID_EMPTY, false); auto* item = inventoryComponent->FindItemByLot(model->GetLOT()); @@ -539,8 +514,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet return; } - switch (deleteReason) - { + switch (deleteReason) { case 0: // Pickup { item->Equip(); @@ -566,28 +540,24 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet } default: { - Game::logger->Log("PropertyManagementComponent", "Invalid delete reason\n"); + Game::logger->Log("PropertyManagementComponent", "Invalid delete reason"); } } - + GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY); - if (spawner != nullptr) - { + if (spawner != nullptr) { dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID); - } - else - { - model->Smash(SILENT); + } else { + model->Smash(LWOOBJID_EMPTY, eKillType::SILENT); } } -void PropertyManagementComponent::UpdateApprovedStatus(const bool value) -{ +void PropertyManagementComponent::UpdateApprovedStatus(const bool value) { if (owner == LWOOBJID_EMPTY) return; - + auto* update = Database::CreatePreppedStmt("UPDATE properties SET mod_approved = ? WHERE id = ?;"); update->setBoolean(1, value); @@ -598,25 +568,22 @@ void PropertyManagementComponent::UpdateApprovedStatus(const bool value) delete update; } -void PropertyManagementComponent::Load() -{ - if (propertyId == LWOOBJID_EMPTY) - { +void PropertyManagementComponent::Load() { + if (propertyId == LWOOBJID_EMPTY) { return; } - + auto* lookup = Database::CreatePreppedStmt("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;"); lookup->setUInt64(1, propertyId); - + auto* lookupResult = lookup->executeQuery(); - while (lookupResult->next()) - { + while (lookupResult->next()) { const LWOOBJID id = lookupResult->getUInt64(1); const LOT lot = lookupResult->getInt(2); - const NiPoint3 position = + const NiPoint3 position = { static_cast(lookupResult->getDouble(3)), static_cast(lookupResult->getDouble(4)), @@ -635,7 +602,7 @@ void PropertyManagementComponent::Load() node->position = position; node->rotation = rotation; - + SpawnerInfo info{}; info.templateID = lot; @@ -655,8 +622,8 @@ void PropertyManagementComponent::Load() //BBB property models need to have extra stuff set for them: if (lot == 14) { LWOOBJID blueprintID = lookupResult->getUInt(10); - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_CHARACTER); - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); LDFBaseData* ldfBlueprintID = new LDFData(u"blueprintid", blueprintID); LDFBaseData* componentWhitelist = new LDFData(u"componentWhitelist", 1); @@ -669,6 +636,18 @@ void PropertyManagementComponent::Load() settings.push_back(modelType); settings.push_back(propertyObjectID); settings.push_back(userModelID); + } else { + auto modelType = new LDFData(u"modelType", 2); + auto userModelID = new LDFData(u"userModelID", id); + auto ldfModelBehavior = new LDFData(u"modelBehaviors", 0); + auto propertyObjectID = new LDFData(u"propertyObjectID", true); + auto componentWhitelist = new LDFData(u"componentWhitelist", 1); + + settings.push_back(componentWhitelist); + settings.push_back(ldfModelBehavior); + settings.push_back(modelType); + settings.push_back(propertyObjectID); + settings.push_back(userModelID); } node->config = settings; @@ -680,34 +659,17 @@ void PropertyManagementComponent::Load() auto* model = spawner->Spawn(); models.insert_or_assign(model->GetObjectID(), spawnerId); - - /* - EntityInfo info; - info.lot = lot; - info.pos = position; - info.rot = rotation; - info.settings = settings; - info.spawnerID = id; - - auto* model = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(model); - - models.insert_or_assign(model->GetObjectID(), id); - */ } delete lookup; } -void PropertyManagementComponent::Save() -{ - if (propertyId == LWOOBJID_EMPTY) - { +void PropertyManagementComponent::Save() { + if (propertyId == LWOOBJID_EMPTY) { return; } - auto* insertion = Database::CreatePreppedStmt("INSERT INTO properties_contents VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + auto* insertion = Database::CreatePreppedStmt("INSERT INTO properties_contents VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); auto* update = Database::CreatePreppedStmt("UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;"); auto* lookup = Database::CreatePreppedStmt("SELECT id FROM properties_contents WHERE property_id = ?;"); auto* remove = Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE id = ?;"); @@ -717,12 +679,11 @@ void PropertyManagementComponent::Save() try { lookupResult = lookup->executeQuery(); } catch (sql::SQLException& ex) { - Game::logger->Log("PropertyManagementComponent", "lookup error %s\n", ex.what()); + Game::logger->Log("PropertyManagementComponent", "lookup error %s", ex.what()); } std::vector present; - while (lookupResult->next()) - { + while (lookupResult->next()) { const auto dbId = lookupResult->getUInt64(1); present.push_back(dbId); @@ -731,25 +692,22 @@ void PropertyManagementComponent::Save() delete lookupResult; std::vector modelIds; - - for (const auto& pair : models) - { + + for (const auto& pair : models) { const auto id = pair.second; modelIds.push_back(id); auto* entity = EntityManager::Instance()->GetEntity(pair.first); - if (entity == nullptr) - { + if (entity == nullptr) { continue; } const auto position = entity->GetPosition(); const auto rotation = entity->GetRotation(); - if (std::find(present.begin(), present.end(), id) == present.end()) - { + if (std::find(present.begin(), present.end(), id) == present.end()) { insertion->setInt64(1, id); insertion->setUInt64(2, propertyId); insertion->setNull(3, 0); @@ -761,14 +719,19 @@ void PropertyManagementComponent::Save() insertion->setDouble(9, rotation.y); insertion->setDouble(10, rotation.z); insertion->setDouble(11, rotation.w); + insertion->setString(12, ("Objects_" + std::to_string(entity->GetLOT()) + "_name").c_str()); // Model name. TODO make this customizable + insertion->setString(13, ""); // Model description. TODO implement this. + insertion->setDouble(14, 0); // behavior 1. TODO implement this. + insertion->setDouble(15, 0); // behavior 2. TODO implement this. + insertion->setDouble(16, 0); // behavior 3. TODO implement this. + insertion->setDouble(17, 0); // behavior 4. TODO implement this. + insertion->setDouble(18, 0); // behavior 5. TODO implement this. try { insertion->execute(); } catch (sql::SQLException& ex) { - Game::logger->Log("PropertyManagementComponent", "Error inserting into properties_contents. Error %s\n", ex.what()); + Game::logger->Log("PropertyManagementComponent", "Error inserting into properties_contents. Error %s", ex.what()); } - } - else - { + } else { update->setDouble(1, position.x); update->setDouble(2, position.y); update->setDouble(3, position.z); @@ -781,15 +744,13 @@ void PropertyManagementComponent::Save() try { update->executeUpdate(); } catch (sql::SQLException& ex) { - Game::logger->Log("PropertyManagementComponent", "Error updating properties_contents. Error: %s\n", ex.what()); + Game::logger->Log("PropertyManagementComponent", "Error updating properties_contents. Error: %s", ex.what()); } } } - for (auto id : present) - { - if (std::find(modelIds.begin(), modelIds.end(), id) != modelIds.end()) - { + for (auto id : present) { + if (std::find(modelIds.begin(), modelIds.end(), id) != modelIds.end()) { continue; } @@ -797,7 +758,7 @@ void PropertyManagementComponent::Save() try { remove->execute(); } catch (sql::SQLException& ex) { - Game::logger->Log("PropertyManagementComponent", "Error removing from properties_contents. Error %s\n", ex.what()); + Game::logger->Log("PropertyManagementComponent", "Error removing from properties_contents. Error %s", ex.what()); } } @@ -812,26 +773,23 @@ void PropertyManagementComponent::Save() delete remove; } -void PropertyManagementComponent::AddModel(LWOOBJID modelId, LWOOBJID spawnerId) -{ +void PropertyManagementComponent::AddModel(LWOOBJID modelId, LWOOBJID spawnerId) { models[modelId] = spawnerId; } -PropertyManagementComponent* PropertyManagementComponent::Instance() -{ +PropertyManagementComponent* PropertyManagementComponent::Instance() { return instance; } -void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr, LWOOBJID author) -{ +void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr, LWOOBJID author) { if (author == LWOOBJID_EMPTY) { author = m_Parent->GetObjectID(); } - const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); - const auto zoneId = worldId.GetMapID(); + const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); + const auto zoneId = worldId.GetMapID(); - Game::logger->Log("Properties", "Getting property info for %d\n", zoneId); + Game::logger->Log("Properties", "Getting property info for %d", zoneId); GameMessages::PropertyDataMessage message = GameMessages::PropertyDataMessage(zoneId); const auto isClaimed = GetOwnerId() != LWOOBJID_EMPTY; @@ -842,7 +800,7 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const std::string description = ""; uint64_t claimed = 0; char privacy = 0; - + if (isClaimed) { const auto cloneId = worldId.GetCloneID(); @@ -901,18 +859,15 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const // send rejection here? } -void PropertyManagementComponent::OnUse(Entity* originator) -{ +void PropertyManagementComponent::OnUse(Entity* originator) { OnQueryPropertyData(originator, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendOpenPropertyManagment(m_Parent->GetObjectID(), originator->GetSystemAddress()); } -void PropertyManagementComponent::SetOwnerId(const LWOOBJID value) -{ +void PropertyManagementComponent::SetOwnerId(const LWOOBJID value) { owner = value; } -const std::map& PropertyManagementComponent::GetModels() const -{ +const std::map& PropertyManagementComponent::GetModels() const { return models; } diff --git a/dGame/dComponents/PropertyManagementComponent.h b/dGame/dComponents/PropertyManagementComponent.h index c03c4949..2ee010a8 100644 --- a/dGame/dComponents/PropertyManagementComponent.h +++ b/dGame/dComponents/PropertyManagementComponent.h @@ -1,28 +1,29 @@ -#pragma once +#pragma once #include #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Information regarding which players may visit this property */ enum class PropertyPrivacyOption { - /** - * Default, only you can visit your property - */ + /** + * Default, only you can visit your property + */ Private = 0, - /** - * Your friends can visit your property - */ - Friends = 1, + /** + * Your friends can visit your property + */ + Friends = 1, - /** - * Requires Mythran approval, everyone can visit your property - */ - Public = 2 + /** + * Requires Mythran approval, everyone can visit your property + */ + Public = 2 }; /** @@ -31,211 +32,211 @@ enum class PropertyPrivacyOption class PropertyManagementComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_MANAGEMENT; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_MANAGEMENT; PropertyManagementComponent(Entity* parent); - static PropertyManagementComponent* Instance(); + static PropertyManagementComponent* Instance(); - /** - * Event handler for when an entity requests information about this property, will send back whether it's owned, etc. - * @param originator the entity that triggered the event - * @param sysAddr the address to send game message responses to - * @param author optional explicit ID for the property, if not set defaults to the originator - */ + /** + * Event handler for when an entity requests information about this property, will send back whether it's owned, etc. + * @param originator the entity that triggered the event + * @param sysAddr the address to send game message responses to + * @param author optional explicit ID for the property, if not set defaults to the originator + */ void OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr, LWOOBJID author = LWOOBJID_EMPTY); - /** - * Handles an OnUse event, telling the client who owns this property, etc. - * @param originator the entity that triggered the event - */ + /** + * Handles an OnUse event, telling the client who owns this property, etc. + * @param originator the entity that triggered the event + */ void OnUse(Entity* originator) override; - /** - * Sets the owner of this property - * @param value the owner to set - */ + /** + * Sets the owner of this property + * @param value the owner to set + */ void SetOwnerId(LWOOBJID value); - /** - * Returns the ID of the owner of this property - * @return the ID of the owner of this property - */ + /** + * Returns the ID of the owner of this property + * @return the ID of the owner of this property + */ LWOOBJID GetOwnerId() const; - /** - * Returns the owner of this property - * @return the owner of this property - */ + /** + * Returns the owner of this property + * @return the owner of this property + */ Entity* GetOwner() const; - /** - * sets the owner of this property - * @param value the owner to set - */ + /** + * sets the owner of this property + * @param value the owner to set + */ void SetOwner(Entity* value); - /** - * Returns the paths that this property has - * @return the paths that this property has - */ + /** + * Returns the paths that this property has + * @return the paths that this property has + */ std::vector GetPaths() const; - /** - * Returns the privacy options for this property - * @return the privacy options for this property - */ + /** + * Returns the privacy options for this property + * @return the privacy options for this property + */ PropertyPrivacyOption GetPrivacyOption() const; - /** - * Updates the privacy option for this property - * @param value the privacy option to set - */ + /** + * Updates the privacy option for this property + * @param value the privacy option to set + */ void SetPrivacyOption(PropertyPrivacyOption value); - /** - * Updates information of this property, saving it to the database - * @param name the name to set for the property - * @param description the description to set for the property - */ + /** + * Updates information of this property, saving it to the database + * @param name the name to set for the property + * @param description the description to set for the property + */ void UpdatePropertyDetails(std::string name, std::string description); - /** - * Makes this property owned by the passed player ID, storing it in the database - * @param playerId the ID of the entity that claimed the property - * - * @return If the claim is successful return true. - */ + /** + * Makes this property owned by the passed player ID, storing it in the database + * @param playerId the ID of the entity that claimed the property + * + * @return If the claim is successful return true. + */ bool Claim(LWOOBJID playerId); - /** - * Event triggered when the owner of the property starts building, will kick other entities out - */ + /** + * Event triggered when the owner of the property starts building, will kick other entities out + */ void OnStartBuilding(); - /** - * Event triggered when the owner of the property finished building, will re-apply this property for moderation - * request. - */ + /** + * Event triggered when the owner of the property finished building, will re-apply this property for moderation + * request. + */ void OnFinishBuilding(); - /** - * Updates the position of a model on the property - * @param id the ID of the model to reposition - * @param position the position to place the model on - * @param rotation the rotation to place the model on - */ + /** + * Updates the position of a model on the property + * @param id the ID of the model to reposition + * @param position the position to place the model on + * @param rotation the rotation to place the model on + */ void UpdateModelPosition(LWOOBJID id, NiPoint3 position, NiQuaternion rotation); - /** - * Deletes a model for a property - * @param id the ID of the model to delete - * @param deleteReason the reason of the deletion, e.g. picked up or destroyed (in case of UGC) - */ + /** + * Deletes a model for a property + * @param id the ID of the model to delete + * @param deleteReason the reason of the deletion, e.g. picked up or destroyed (in case of UGC) + */ void DeleteModel(LWOOBJID id, int deleteReason); - /** - * Updates whether or not this property is approved by a moderator - * @param value true if the property should be approved, false otherwise - */ + /** + * Updates whether or not this property is approved by a moderator + * @param value true if the property should be approved, false otherwise + */ void UpdateApprovedStatus(bool value); - /** - * Loads all the models on this property from the database - */ + /** + * Loads all the models on this property from the database + */ void Load(); - /** - * Saves all the models from this property to the database - */ + /** + * Saves all the models from this property to the database + */ void Save(); - /** - * Adds a model to the cache of models - * @param modelId the ID of the model - * @param spawnerId the ID of the object that spawned the model - */ + /** + * Adds a model to the cache of models + * @param modelId the ID of the model + * @param spawnerId the ID of the object that spawned the model + */ void AddModel(LWOOBJID modelId, LWOOBJID spawnerId); - /** - * Returns all the models on this property, indexed by property ID, containing their spawn objects - * @return all the models on this proeprty - */ + /** + * Returns all the models on this property, indexed by property ID, containing their spawn objects + * @return all the models on this proeprty + */ const std::map& GetModels() const; - - LWOCLONEID GetCloneId() { return clone_Id; }; + + LWOCLONEID GetCloneId() { return clone_Id; }; private: - /** - * This - */ + /** + * This + */ static PropertyManagementComponent* instance; - /** - * The ID of the owner of this property - */ + /** + * The ID of the owner of this property + */ LWOOBJID owner = LWOOBJID_EMPTY; - /** - * The LOT of this console - */ + /** + * The LOT of this console + */ uint32_t templateId = 0; - /** - * The unique ID for this property, if it's owned - */ + /** + * The unique ID for this property, if it's owned + */ LWOOBJID propertyId = LWOOBJID_EMPTY; - /** - * The time since this property was claimed - */ + /** + * The time since this property was claimed + */ uint64_t claimedTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - /** - * The models that are placed on this property - */ + /** + * The models that are placed on this property + */ std::map models = {}; - /** - * The name of this property - */ + /** + * The name of this property + */ std::string propertyName = ""; - /** - * The clone ID of this property - */ + /** + * The clone ID of this property + */ LWOCLONEID clone_Id = 0; - /** - * Whether a moderator was requested - */ - bool moderatorRequested = false; + /** + * Whether a moderator was requested + */ + bool moderatorRequested = false; - /** - * The rejection reason for the property - */ + /** + * The rejection reason for the property + */ std::string rejectionReason = ""; - /** - * The description of this property - */ + /** + * The description of this property + */ std::string propertyDescription = ""; - /** - * The reputation of this property - */ + /** + * The reputation of this property + */ uint32_t reputation = 0; - /** - * The last time this property was updated - */ - uint32_t LastUpdatedTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + /** + * The last time this property was updated + */ + uint32_t LastUpdatedTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - /** - * Determines which players may visit this property - */ + /** + * Determines which players may visit this property + */ PropertyPrivacyOption privacyOption = PropertyPrivacyOption::Private; - /** - * The privacy setting before it was changed, saved to set back after a player finishes building - */ + /** + * The privacy setting before it was changed, saved to set back after a player finishes building + */ PropertyPrivacyOption originalPrivacyOption = PropertyPrivacyOption::Private; }; diff --git a/dGame/dComponents/PropertyVendorComponent.cpp b/dGame/dComponents/PropertyVendorComponent.cpp index 72e8ad64..ed89bfc7 100644 --- a/dGame/dComponents/PropertyVendorComponent.cpp +++ b/dGame/dComponents/PropertyVendorComponent.cpp @@ -1,4 +1,4 @@ -#include "PropertyVendorComponent.h" +#include "PropertyVendorComponent.h" #include "PropertyDataMessage.h" #include "GameMessages.h" @@ -10,19 +10,16 @@ #include "PropertyManagementComponent.h" #include "UserManager.h" -PropertyVendorComponent::PropertyVendorComponent(Entity* parent) : Component(parent) -{ +PropertyVendorComponent::PropertyVendorComponent(Entity* parent) : Component(parent) { } -void PropertyVendorComponent::OnUse(Entity* originator) -{ +void PropertyVendorComponent::OnUse(Entity* originator) { if (PropertyManagementComponent::Instance() == nullptr) return; OnQueryPropertyData(originator, originator->GetSystemAddress()); - if (PropertyManagementComponent::Instance()->GetOwnerId() == LWOOBJID_EMPTY) - { - Game::logger->Log("PropertyVendorComponent", "Property vendor opening!\n"); + if (PropertyManagementComponent::Instance()->GetOwnerId() == LWOOBJID_EMPTY) { + Game::logger->Log("PropertyVendorComponent", "Property vendor opening!"); GameMessages::SendOpenPropertyVendor(m_Parent->GetObjectID(), originator->GetSystemAddress()); @@ -30,19 +27,17 @@ void PropertyVendorComponent::OnUse(Entity* originator) } } -void PropertyVendorComponent::OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr) -{ +void PropertyVendorComponent::OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr) { if (PropertyManagementComponent::Instance() == nullptr) return; PropertyManagementComponent::Instance()->OnQueryPropertyData(originator, sysAddr, m_Parent->GetObjectID()); } -void PropertyVendorComponent::OnBuyFromVendor(Entity* originator, const bool confirmed, const LOT lot, const uint32_t count) -{ +void PropertyVendorComponent::OnBuyFromVendor(Entity* originator, const bool confirmed, const LOT lot, const uint32_t count) { if (PropertyManagementComponent::Instance() == nullptr) return; if (PropertyManagementComponent::Instance()->Claim(originator->GetObjectID()) == false) { - Game::logger->Log("PropertyVendorComponent", "FAILED TO CLAIM PROPERTY. PLAYER ID IS %llu\n", originator->GetObjectID()); + Game::logger->Log("PropertyVendorComponent", "FAILED TO CLAIM PROPERTY. PLAYER ID IS %llu", originator->GetObjectID()); return; } @@ -51,11 +46,11 @@ void PropertyVendorComponent::OnBuyFromVendor(Entity* originator, const bool con auto* controller = dZoneManager::Instance()->GetZoneControlObject(); controller->OnFireEventServerSide(m_Parent, "propertyRented"); - + PropertyManagementComponent::Instance()->SetOwner(originator); - + PropertyManagementComponent::Instance()->OnQueryPropertyData(originator, originator->GetSystemAddress()); - Game::logger->Log("PropertyVendorComponent", "Fired event; (%d) (%i) (%i)\n", confirmed, lot, count); + Game::logger->Log("PropertyVendorComponent", "Fired event; (%d) (%i) (%i)", confirmed, lot, count); } diff --git a/dGame/dComponents/PropertyVendorComponent.h b/dGame/dComponents/PropertyVendorComponent.h index 1a469589..5055b445 100644 --- a/dGame/dComponents/PropertyVendorComponent.h +++ b/dGame/dComponents/PropertyVendorComponent.h @@ -1,7 +1,8 @@ -#pragma once +#pragma once #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * The property guard that stands on a property before it's claimed, allows entities to attempt claiming this property. @@ -9,29 +10,29 @@ class PropertyVendorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_VENDOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_VENDOR; explicit PropertyVendorComponent(Entity* parent); - /** - * Handles a use event from some entity, if the property is cleared this allows the entity to claim it - * @param originator the entity that triggered this event - */ + /** + * Handles a use event from some entity, if the property is cleared this allows the entity to claim it + * @param originator the entity that triggered this event + */ void OnUse(Entity* originator) override; - /** - * Handles a property data query after the property has been claimed, sending information about the property to the - * triggering entity. - * @param originator the entity that triggered the event - * @param sysAddr the system address to send game message response to - */ + /** + * Handles a property data query after the property has been claimed, sending information about the property to the + * triggering entity. + * @param originator the entity that triggered the event + * @param sysAddr the system address to send game message response to + */ void OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr); - /** - * Claims the property - * @param originator the entity that attempted to claim the property - * @param confirmed unused - * @param lot unused - * @param count unused - */ + /** + * Claims the property + * @param originator the entity that attempted to claim the property + * @param confirmed unused + * @param lot unused + * @param count unused + */ void OnBuyFromVendor(Entity* originator, bool confirmed, LOT lot, uint32_t count); }; diff --git a/dGame/dComponents/ProximityMonitorComponent.cpp b/dGame/dComponents/ProximityMonitorComponent.cpp index f2ef9b9a..acc93fde 100644 --- a/dGame/dComponents/ProximityMonitorComponent.cpp +++ b/dGame/dComponents/ProximityMonitorComponent.cpp @@ -27,7 +27,7 @@ ProximityMonitorComponent::~ProximityMonitorComponent() { void ProximityMonitorComponent::SetProximityRadius(float proxRadius, const std::string& name) { dpEntity* en = new dpEntity(m_Parent->GetObjectID(), proxRadius); en->SetPosition(m_Parent->GetPosition()); - + dpWorld::Instance().AddEntity(en); m_ProximitiesData.insert(std::make_pair(name, en)); } diff --git a/dGame/dComponents/ProximityMonitorComponent.h b/dGame/dComponents/ProximityMonitorComponent.h index 11cc7ab3..2f51917d 100644 --- a/dGame/dComponents/ProximityMonitorComponent.h +++ b/dGame/dComponents/ProximityMonitorComponent.h @@ -11,64 +11,65 @@ #include "dpWorld.h" #include "dpEntity.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * Utility component for detecting how close entities are to named proximities for this entity. Allows you to store - * proximity checks for multiple ojects. - */ + /** + * Utility component for detecting how close entities are to named proximities for this entity. Allows you to store + * proximity checks for multiple ojects. + */ class ProximityMonitorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROXIMITY_MONITOR; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROXIMITY_MONITOR; + ProximityMonitorComponent(Entity* parentEntity, int smallRadius = -1, int largeRadius = -1); ~ProximityMonitorComponent() override; - void Update(float deltaTime) override; + void Update(float deltaTime) override; - /** - * Creates an entry to check proximity for, given a name - * @param proxRadius the radius to use for the physics entity we use to detect proximity - * @param name the name of this check - */ + /** + * Creates an entry to check proximity for, given a name + * @param proxRadius the radius to use for the physics entity we use to detect proximity + * @param name the name of this check + */ void SetProximityRadius(float proxRadius, const std::string& name); - /** - * Creates an entry to check proximity for, given a name - * @param entity the physics entity to add to our proximity sensors - * @param name the name of this check - */ + /** + * Creates an entry to check proximity for, given a name + * @param entity the physics entity to add to our proximity sensors + * @param name the name of this check + */ void SetProximityRadius(dpEntity* entity, const std::string& name); - /** - * Returns the last of entities that are used to check proximity, given a name - * @param name the proximity name to retrieve physics objects for - * @return a map of physics entities for this name, indexed by object ID - */ + /** + * Returns the last of entities that are used to check proximity, given a name + * @param name the proximity name to retrieve physics objects for + * @return a map of physics entities for this name, indexed by object ID + */ const std::map& GetProximityObjects(const std::string& name); - /** - * Checks if the passed object is in proximity of the named proximity sensor - * @param name the name of the sensor to check proximity for - * @param objectID the entity to check if they're in proximity - * @return true if the object is in proximity, false otherwise - */ + /** + * Checks if the passed object is in proximity of the named proximity sensor + * @param name the name of the sensor to check proximity for + * @param objectID the entity to check if they're in proximity + * @return true if the object is in proximity, false otherwise + */ bool IsInProximity(const std::string& name, LWOOBJID objectID); - /** - * Returns all the proximity sensors stored on this component, indexed by name - * @return all the proximity sensors stored on this component - */ + /** + * Returns all the proximity sensors stored on this component, indexed by name + * @return all the proximity sensors stored on this component + */ const std::map& GetProximitiesData() const { return m_ProximitiesData; } private: - /** - * All the proximity sensors for this component, indexed by name - */ + /** + * All the proximity sensors for this component, indexed by name + */ std::map m_ProximitiesData = {}; - /** - * Default value for the proximity data - */ + /** + * Default value for the proximity data + */ static const std::map m_EmptyObjectMap; }; diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index d8794114..4a4ead59 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -15,894 +15,876 @@ #include "Player.h" #include "PossessableComponent.h" #include "PossessorComponent.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "Spawner.h" #include "VehiclePhysicsComponent.h" #include "dServer.h" #include "dZoneManager.h" #include "dConfig.h" +#include "Loot.h" +#include "eMissionTaskType.h" +#include "dZoneManager.h" +#include "CDActivitiesTable.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif -RacingControlComponent::RacingControlComponent(Entity *parent) - : Component(parent) { - m_PathName = u"MainPath"; - m_RemainingLaps = 3; - m_LeadingPlayer = LWOOBJID_EMPTY; - m_RaceBestTime = 0; - m_RaceBestLap = 0; - m_Started = false; - m_StartTimer = 0; - m_Loaded = false; - m_LoadedPlayers = 0; - m_LoadTimer = 0; - m_Finished = 0; - m_StartTime = 0; - m_EmptyTimer = 0; - m_SoloRacing = Game::config->GetValue("solo_racing") == "1"; +RacingControlComponent::RacingControlComponent(Entity* parent) + : Component(parent) { + m_PathName = u"MainPath"; + m_RemainingLaps = 3; + m_LeadingPlayer = LWOOBJID_EMPTY; + m_RaceBestTime = 0; + m_RaceBestLap = 0; + m_Started = false; + m_StartTimer = 0; + m_Loaded = false; + m_LoadedPlayers = 0; + m_LoadTimer = 0; + m_Finished = 0; + m_StartTime = 0; + m_EmptyTimer = 0; + m_SoloRacing = Game::config->GetValue("solo_racing") == "1"; - // Select the main world ID as fallback when a player fails to load. + m_MainWorld = 1200; + const auto worldID = Game::server->GetZoneID(); + if (dZoneManager::Instance()->CheckIfAccessibleZone((worldID/10)*10)) m_MainWorld = (worldID/10)*10; - const auto worldID = Game::server->GetZoneID(); - - switch (worldID) { - case 1203: - m_ActivityID = 42; - m_MainWorld = 1200; - break; - - case 1261: - m_ActivityID = 60; - m_MainWorld = 1260; - break; - - case 1303: - m_ActivityID = 39; - m_MainWorld = 1300; - break; - - case 1403: - m_ActivityID = 54; - m_MainWorld = 1400; - break; - - default: - m_ActivityID = 42; - m_MainWorld = 1200; - break; - } + m_ActivityID = 42; + CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.instanceMapID == worldID); }); + for (CDActivities activity : activities) m_ActivityID = activity.ActivityID; } RacingControlComponent::~RacingControlComponent() {} -void RacingControlComponent::OnPlayerLoaded(Entity *player) { - // If the race has already started, send the player back to the main world. - if (m_Loaded) { - auto *playerInstance = dynamic_cast(player); +void RacingControlComponent::OnPlayerLoaded(Entity* player) { + // If the race has already started, send the player back to the main world. + if (m_Loaded) { + auto* playerInstance = dynamic_cast(player); - playerInstance->SendToZone(m_MainWorld); + playerInstance->SendToZone(m_MainWorld); - return; - } + return; + } - const auto objectID = player->GetObjectID(); + const auto objectID = player->GetObjectID(); - m_LoadedPlayers++; + m_LoadedPlayers++; - Game::logger->Log("RacingControlComponent", "Loading player %i\n", - m_LoadedPlayers); + Game::logger->Log("RacingControlComponent", "Loading player %i", + m_LoadedPlayers); - m_LobbyPlayers.push_back(objectID); + m_LobbyPlayers.push_back(objectID); } -void RacingControlComponent::LoadPlayerVehicle(Entity *player, - bool initialLoad) { - // Load the player's vehicle. +void RacingControlComponent::LoadPlayerVehicle(Entity* player, + uint32_t positionNumber, bool initialLoad) { + // Load the player's vehicle. - if (player == nullptr) { - return; - } + if (player == nullptr) { + return; + } - auto *inventoryComponent = player->GetComponent(); + auto* inventoryComponent = player->GetComponent(); - if (inventoryComponent == nullptr) { - return; - } + if (inventoryComponent == nullptr) { + return; + } - // Find the player's vehicle. + // Find the player's vehicle. - auto *item = inventoryComponent->FindItemByLot(8092); + auto* item = inventoryComponent->FindItemByLot(8092); - if (item == nullptr) { - Game::logger->Log("RacingControlComponent", "Failed to find item\n"); + if (item == nullptr) { + Game::logger->Log("RacingControlComponent", "Failed to find item"); - return; - } + return; + } - // Calculate the vehicle's starting position. + // Calculate the vehicle's starting position. - auto *path = dZoneManager::Instance()->GetZone()->GetPath( - GeneralUtils::UTF16ToWTF8(m_PathName)); + auto* path = dZoneManager::Instance()->GetZone()->GetPath( + GeneralUtils::UTF16ToWTF8(m_PathName)); - auto startPosition = path->pathWaypoints[0].position + NiPoint3::UNIT_Y * 3; + auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); + auto startPosition = NiPoint3::ZERO; + auto startRotation = NiQuaternion::IDENTITY; + const std::string placementAsString = std::to_string(positionNumber); + for (auto entity : spawnPointEntities) { + if (!entity) continue; + if (entity->GetVarAsString(u"placement") == placementAsString) { + startPosition = entity->GetPosition(); + startRotation = entity->GetRotation(); + break; + } + } - const auto spacing = 15; + // Make sure the player is at the correct position. - // This sometimes spawns the vehicle out of the map if there are lots of - // players loaded. + GameMessages::SendTeleport(player->GetObjectID(), startPosition, + startRotation, player->GetSystemAddress(), true, + true); - const auto range = m_LoadedPlayers * spacing; + // Spawn the vehicle entity. - startPosition = - startPosition + NiPoint3::UNIT_Z * ((m_LeadingPlayer / 2) + - m_RacingPlayers.size() * spacing); + EntityInfo info{}; + info.lot = 8092; + info.pos = startPosition; + info.rot = startRotation; + info.spawnerID = m_Parent->GetObjectID(); - auto startRotation = - NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X); + auto* carEntity = + EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); - auto angles = startRotation.GetEulerAngles(); + // Make the vehicle a child of the racing controller. + m_Parent->AddChild(carEntity); - angles.y -= M_PI; + auto* destroyableComponent = + carEntity->GetComponent(); - startRotation = NiQuaternion::FromEulerAngles(angles); + // Setup the vehicle stats. + if (destroyableComponent != nullptr) { + destroyableComponent->SetMaxImagination(60); + destroyableComponent->SetImagination(0); + } - Game::logger->Log("RacingControlComponent", - "Start position <%f, %f, %f>, <%f, %f, %f>\n", - startPosition.x, startPosition.y, startPosition.z, - angles.x * (180.0f / M_PI), angles.y * (180.0f / M_PI), - angles.z * (180.0f / M_PI)); + // Setup the vehicle as being possessed by the player. + auto* possessableComponent = + carEntity->GetComponent(); - // Make sure the player is at the correct position. + if (possessableComponent != nullptr) { + possessableComponent->SetPossessor(player->GetObjectID()); + } - GameMessages::SendTeleport(player->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true, - true); + // Load the vehicle's assemblyPartLOTs for display. + auto* moduleAssemblyComponent = + carEntity->GetComponent(); - // Spawn the vehicle entity. + if (moduleAssemblyComponent) { + moduleAssemblyComponent->SetSubKey(item->GetSubKey()); + moduleAssemblyComponent->SetUseOptionalParts(false); - EntityInfo info{}; - info.lot = 8092; - info.pos = startPosition; - info.rot = startRotation; - info.spawnerID = m_Parent->GetObjectID(); + for (auto* config : item->GetConfig()) { + if (config->GetKey() == u"assemblyPartLOTs") { + moduleAssemblyComponent->SetAssemblyPartsLOTs( + GeneralUtils::ASCIIToUTF16(config->GetValueAsString())); + } + } + } - auto *carEntity = - EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); + // Setup the player as possessing the vehicle. + auto* possessorComponent = player->GetComponent(); - // Make the vehicle a child of the racing controller. - m_Parent->AddChild(carEntity); + if (possessorComponent != nullptr) { + possessorComponent->SetPossessable(carEntity->GetObjectID()); + possessorComponent->SetPossessableType(ePossessionType::ATTACHED_VISIBLE); // for racing it's always Attached_Visible + } - auto *destroyableComponent = - carEntity->GetComponent(); + // Set the player's current activity as racing. + auto* characterComponent = player->GetComponent(); - // Setup the vehicle stats. - if (destroyableComponent != nullptr) { - destroyableComponent->SetMaxImagination(60); - destroyableComponent->SetImagination(0); - } + if (characterComponent != nullptr) { + characterComponent->SetIsRacing(true); + } - // Setup the vehicle as being possessed by the player. - auto *possessableComponent = - carEntity->GetComponent(); + // Init the player's racing entry. + if (initialLoad) { + m_RacingPlayers.push_back( + { player->GetObjectID(), + carEntity->GetObjectID(), + static_cast(m_RacingPlayers.size()), + false, + {}, + startPosition, + startRotation, + 0, + 0, + 0, + 0 }); + } - if (possessableComponent != nullptr) { - possessableComponent->SetPossessor(player->GetObjectID()); - } + // Construct and serialize everything when done. - // Load the vehicle's assemblyPartLOTs for display. - auto *moduleAssemblyComponent = - carEntity->GetComponent(); + EntityManager::Instance()->ConstructEntity(carEntity); + EntityManager::Instance()->SerializeEntity(player); + EntityManager::Instance()->SerializeEntity(m_Parent); - if (moduleAssemblyComponent) { - moduleAssemblyComponent->SetSubKey(item->GetSubKey()); - moduleAssemblyComponent->SetUseOptionalParts(false); + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), 0, 0, player->GetObjectID(), startPosition, 1, + UNASSIGNED_SYSTEM_ADDRESS); - for (auto *config : item->GetConfig()) { - if (config->GetKey() == u"assemblyPartLOTs") { - moduleAssemblyComponent->SetAssemblyPartsLOTs( - GeneralUtils::ASCIIToUTF16(config->GetValueAsString())); - } - } - } + const auto playerID = player->GetObjectID(); - // Setup the player as possessing the vehicle. - auto *possessorComponent = player->GetComponent(); + // Reset the player to the start position during downtime, in case something + // went wrong. + m_Parent->AddCallbackTimer(1, [this, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); - if (possessorComponent != nullptr) { - possessorComponent->SetPossessable(carEntity->GetObjectID()); - } + if (player == nullptr) { + return; + } - // Set the player's current activity as racing. - auto *characterComponent = player->GetComponent(); + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), playerID, UNASSIGNED_SYSTEM_ADDRESS); + }); - if (characterComponent != nullptr) { - characterComponent->SetIsRacing(true); - } + GameMessages::SendSetJetPackMode(player, false); - // Init the player's racing entry. - if (initialLoad) { - m_RacingPlayers.push_back( - {player->GetObjectID(), - carEntity->GetObjectID(), - static_cast(m_RacingPlayers.size()), - false, - {}, - startPosition, - startRotation, - 0, - 0, - 0, - 0}); - } + // Set the vehicle's state. + GameMessages::SendNotifyVehicleOfRacingObject(carEntity->GetObjectID(), + m_Parent->GetObjectID(), + UNASSIGNED_SYSTEM_ADDRESS); - // Construct and serialize everything when done. + GameMessages::SendVehicleSetWheelLockState(carEntity->GetObjectID(), false, + initialLoad, + UNASSIGNED_SYSTEM_ADDRESS); - EntityManager::Instance()->ConstructEntity(carEntity); - EntityManager::Instance()->SerializeEntity(player); - EntityManager::Instance()->SerializeEntity(m_Parent); - - GameMessages::SendRacingSetPlayerResetInfo( - m_Parent->GetObjectID(), 0, 0, player->GetObjectID(), startPosition, 1, - UNASSIGNED_SYSTEM_ADDRESS); - - const auto playerID = player->GetObjectID(); - - // Reset the player to the start position during downtime, in case something - // went wrong. - m_Parent->AddCallbackTimer(1, [this, playerID]() { - auto *player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) { - return; - } - - GameMessages::SendRacingResetPlayerToLastReset( - m_Parent->GetObjectID(), playerID, UNASSIGNED_SYSTEM_ADDRESS); - }); - - GameMessages::SendSetJetPackMode(player, false); - - // Set the vehicle's state. - GameMessages::SendNotifyVehicleOfRacingObject(carEntity->GetObjectID(), - m_Parent->GetObjectID(), - UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendVehicleSetWheelLockState(carEntity->GetObjectID(), false, - initialLoad, - UNASSIGNED_SYSTEM_ADDRESS); - - // Make sure everything has the correct position. - GameMessages::SendTeleport(player->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true, - true); - GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true, - true); + // Make sure everything has the correct position. + GameMessages::SendTeleport(player->GetObjectID(), startPosition, + startRotation, player->GetSystemAddress(), true, + true); + GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, + startRotation, player->GetSystemAddress(), true, + true); } -void RacingControlComponent::OnRacingClientReady(Entity *player) { - // Notify the other players that this player is ready. +void RacingControlComponent::OnRacingClientReady(Entity* player) { + // Notify the other players that this player is ready. - for (auto &racingPlayer : m_RacingPlayers) { - if (racingPlayer.playerID != player->GetObjectID()) { - if (racingPlayer.playerLoaded) { - GameMessages::SendRacingPlayerLoaded( - m_Parent->GetObjectID(), racingPlayer.playerID, - racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); - } + for (auto& racingPlayer : m_RacingPlayers) { + if (racingPlayer.playerID != player->GetObjectID()) { + if (racingPlayer.playerLoaded) { + GameMessages::SendRacingPlayerLoaded( + m_Parent->GetObjectID(), racingPlayer.playerID, + racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); + } - continue; - } + continue; + } - racingPlayer.playerLoaded = true; + racingPlayer.playerLoaded = true; - GameMessages::SendRacingPlayerLoaded( - m_Parent->GetObjectID(), racingPlayer.playerID, - racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); - } + GameMessages::SendRacingPlayerLoaded( + m_Parent->GetObjectID(), racingPlayer.playerID, + racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); + } - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); } -void RacingControlComponent::OnRequestDie(Entity *player) { - // Sent by the client when they collide with something which should smash - // them. +void RacingControlComponent::OnRequestDie(Entity* player) { + // Sent by the client when they collide with something which should smash + // them. - for (auto &racingPlayer : m_RacingPlayers) { - if (racingPlayer.playerID != player->GetObjectID()) { - continue; - } + for (auto& racingPlayer : m_RacingPlayers) { + if (racingPlayer.playerID != player->GetObjectID()) { + continue; + } - auto *vehicle = - EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); + auto* vehicle = + EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); - if (vehicle == nullptr) { - return; - } + if (!vehicle) return; - if (!racingPlayer.noSmashOnReload) { - racingPlayer.smashedTimes++; - } + if (!racingPlayer.noSmashOnReload) { + racingPlayer.smashedTimes++; + GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true, + eKillType::VIOLENT, u"", 0, 0, 90.0f, false, true, 0); - // Reset player to last checkpoint - GameMessages::SendRacingSetPlayerResetInfo( - m_Parent->GetObjectID(), racingPlayer.lap, - racingPlayer.respawnIndex, player->GetObjectID(), - racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendRacingResetPlayerToLastReset( - m_Parent->GetObjectID(), racingPlayer.playerID, - UNASSIGNED_SYSTEM_ADDRESS); + auto* destroyableComponent = vehicle->GetComponent(); + uint32_t respawnImagination = 0; + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + // Do not actually change the value yet. Do that on respawn. + if (destroyableComponent) { + respawnImagination = static_cast(ceil(destroyableComponent->GetImagination() / 2.0f / 10.0f)) * 10.0f; + GameMessages::SendSetResurrectRestoreValues(vehicle, -1, -1, respawnImagination); + } - auto *characterComponent = player->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); - } + // Respawn the player in 2 seconds, as was done in live. Not sure if this value is in a setting somewhere else... + vehicle->AddCallbackTimer(2.0f, [=]() { + if (!vehicle || !this->m_Parent) return; + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); - return; - } + GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true); + + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendResurrect(vehicle); + auto* destroyableComponent = vehicle->GetComponent(); + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination); + EntityManager::Instance()->SerializeEntity(vehicle); + }); + + auto* characterComponent = player->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); + } + } else { + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); + } + } } -void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity *player) { - // When the player has respawned. +void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) { + // When the player has respawned. - for (auto &racingPlayer : m_RacingPlayers) { - if (racingPlayer.playerID != player->GetObjectID()) { - continue; - } + for (auto& racingPlayer : m_RacingPlayers) { + if (racingPlayer.playerID != player->GetObjectID()) { + continue; + } - auto *vehicle = - EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); + auto* vehicle = + EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); - if (vehicle == nullptr) { - return; - } + if (vehicle == nullptr) { + return; + } - if (!racingPlayer.noSmashOnReload) { - GameMessages::SendDie(vehicle, LWOOBJID_EMPTY, LWOOBJID_EMPTY, true, - VIOLENT, u"", 0, 0, 0, true, false, 0); + racingPlayer.noSmashOnReload = false; - GameMessages::SendVehicleUnlockInput(racingPlayer.vehicleID, false, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendVehicleSetWheelLockState( - racingPlayer.vehicleID, false, false, - UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendResurrect(vehicle); - } - - racingPlayer.noSmashOnReload = false; - - return; - } + return; + } } -void RacingControlComponent::HandleMessageBoxResponse(Entity *player, - const std::string &id) { - auto *data = GetPlayerData(player->GetObjectID()); +void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t button, const std::string& id) { + auto* data = GetPlayerData(player->GetObjectID()); - if (data == nullptr) { - return; - } + if (data == nullptr) { + return; + } - if (id == "rewardButton") { - if (data->collectedRewards) { - return; - } + if (id == "rewardButton") { + if (data->collectedRewards) { + return; + } - data->collectedRewards = true; + data->collectedRewards = true; - // Calculate the score, different loot depending on player count - const auto score = m_LoadedPlayers * 10 + data->finished; + // Calculate the score, different loot depending on player count + const auto score = m_LoadedPlayers * 10 + data->finished; - LootGenerator::Instance().GiveActivityLoot(player, m_Parent, m_ActivityID, score); + LootGenerator::Instance().GiveActivityLoot(player, m_Parent, m_ActivityID, score); - // Giving rewards - GameMessages::SendNotifyRacingClient( - m_Parent->GetObjectID(), 2, 0, LWOOBJID_EMPTY, u"", - player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + // Giving rewards + GameMessages::SendNotifyRacingClient( + m_Parent->GetObjectID(), 2, 0, LWOOBJID_EMPTY, u"", + player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - auto *missionComponent = player->GetComponent(); + auto* missionComponent = player->GetComponent(); - if (missionComponent == nullptr) return; + if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPETED_IN_RACE); // Progress task for competing in a race - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->smashedTimes, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SAFE_DRIVER); // Finish a race without being smashed. + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::COMPETED_IN_RACE); // Progress task for competing in a race + missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, (LWOOBJID)eRacingTaskParam::SAFE_DRIVER); // Finish a race without being smashed. - // If solo racing is enabled OR if there are 3 players in the race, progress placement tasks. - if(m_SoloRacing || m_LoadedPlayers > 2) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->finished, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FINISH_WITH_PLACEMENT); // Finish in 1st place on a race - if(data->finished == 1) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_WIN_RACE_IN_WORLD); // Finished first place in specific world. - } - if (data->finished == m_LoadedPlayers) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAST_PLACE_FINISH); // Finished first place in specific world. - } - } - } else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") { - auto *vehicle = EntityManager::Instance()->GetEntity(data->vehicleID); + // If solo racing is enabled OR if there are 3 players in the race, progress placement tasks. + if (m_SoloRacing || m_LoadedPlayers > 2) { + missionComponent->Progress(eMissionTaskType::RACING, data->finished, (LWOOBJID)eRacingTaskParam::FINISH_WITH_PLACEMENT); // Finish in 1st place on a race + if (data->finished == 1) { + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks. + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::WIN_RACE_IN_WORLD); // Finished first place in specific world. + } + if (data->finished == m_LoadedPlayers) { + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::LAST_PLACE_FINISH); // Finished first place in specific world. + } + } + } else if ((id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") && button == m_ActivityExitConfirm) { + auto* vehicle = EntityManager::Instance()->GetEntity(data->vehicleID); - if (vehicle == nullptr) { - return; - } + if (vehicle == nullptr) { + return; + } - // Exiting race - GameMessages::SendNotifyRacingClient( - m_Parent->GetObjectID(), 3, 0, LWOOBJID_EMPTY, u"", - player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + // Exiting race + GameMessages::SendNotifyRacingClient( + m_Parent->GetObjectID(), 3, 0, LWOOBJID_EMPTY, u"", + player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - auto *playerInstance = dynamic_cast(player); + auto* playerInstance = dynamic_cast(player); - playerInstance->SendToZone(m_MainWorld); + playerInstance->SendToZone(m_MainWorld); - vehicle->Kill(); - } + vehicle->Kill(); + } } -void RacingControlComponent::Serialize(RakNet::BitStream *outBitStream, - bool bIsInitialUpdate, - unsigned int &flags) { - // BEGIN Scripted Activity +void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, + bool bIsInitialUpdate, + unsigned int& flags) { + // BEGIN Scripted Activity - outBitStream->Write1(); + outBitStream->Write1(); - outBitStream->Write(static_cast(m_RacingPlayers.size())); - for (const auto &player : m_RacingPlayers) { - outBitStream->Write(player.playerID); + outBitStream->Write(static_cast(m_RacingPlayers.size())); + for (const auto& player : m_RacingPlayers) { + outBitStream->Write(player.playerID); - for (int i = 0; i < 10; i++) { - outBitStream->Write(player.data[i]); - } - } + for (int i = 0; i < 10; i++) { + outBitStream->Write(player.data[i]); + } + } - // END Scripted Activity + // END Scripted Activity - outBitStream->Write1(); // Dirty? - outBitStream->Write(static_cast(m_RacingPlayers.size())); + outBitStream->Write1(); // Dirty? + outBitStream->Write(static_cast(m_RacingPlayers.size())); - outBitStream->Write(!m_RacingPlayers.empty()); - if (!m_RacingPlayers.empty()) { - for (const auto &player : m_RacingPlayers) { - outBitStream->Write1(); // Has more date + outBitStream->Write(!m_RacingPlayers.empty()); + if (!m_RacingPlayers.empty()) { + for (const auto& player : m_RacingPlayers) { + outBitStream->Write1(); // Has more date - outBitStream->Write(player.playerID); - outBitStream->Write(player.vehicleID); - outBitStream->Write(player.playerIndex); - outBitStream->Write(player.playerLoaded); - } + outBitStream->Write(player.playerID); + outBitStream->Write(player.vehicleID); + outBitStream->Write(player.playerIndex); + outBitStream->Write(player.playerLoaded); + } - outBitStream->Write0(); // No more data - } + outBitStream->Write0(); // No more data + } - outBitStream->Write(!m_RacingPlayers.empty()); - if (!m_RacingPlayers.empty()) { - for (const auto &player : m_RacingPlayers) { - outBitStream->Write1(); // Has more date + outBitStream->Write(!m_RacingPlayers.empty()); + if (!m_RacingPlayers.empty()) { + for (const auto& player : m_RacingPlayers) { + outBitStream->Write1(); // Has more date - outBitStream->Write(player.playerID); - outBitStream->Write(0); - } + outBitStream->Write(player.playerID); + outBitStream->Write(0); + } - outBitStream->Write0(); // No more data - } + outBitStream->Write0(); // No more data + } - outBitStream->Write1(); // Dirty? + outBitStream->Write1(); // Dirty? - outBitStream->Write(m_RemainingLaps); + outBitStream->Write(m_RemainingLaps); - outBitStream->Write(static_cast(m_PathName.size())); - for (const auto character : m_PathName) { - outBitStream->Write(character); - } + outBitStream->Write(static_cast(m_PathName.size())); + for (const auto character : m_PathName) { + outBitStream->Write(character); + } - outBitStream->Write1(); // ??? - outBitStream->Write1(); // ??? + outBitStream->Write1(); // ??? + outBitStream->Write1(); // ??? - outBitStream->Write(m_LeadingPlayer); - outBitStream->Write(m_RaceBestLap); - outBitStream->Write(m_RaceBestTime); + outBitStream->Write(m_LeadingPlayer); + outBitStream->Write(m_RaceBestLap); + outBitStream->Write(m_RaceBestTime); } -RacingPlayerInfo *RacingControlComponent::GetPlayerData(LWOOBJID playerID) { - for (auto &player : m_RacingPlayers) { - if (player.playerID == playerID) { - return &player; - } - } +RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) { + for (auto& player : m_RacingPlayers) { + if (player.playerID == playerID) { + return &player; + } + } - return nullptr; + return nullptr; } void RacingControlComponent::Update(float deltaTime) { - // This method is a mess. + // This method is a mess. - // Pre-load routine - if (!m_Loaded) { - // Check if any players has disconnected before loading in - for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { - auto *playerEntity = - EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); + // Pre-load routine + if (!m_Loaded) { + // Check if any players has disconnected before loading in + for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { + auto* playerEntity = + EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); - if (playerEntity == nullptr) { - --m_LoadedPlayers; + if (playerEntity == nullptr) { + --m_LoadedPlayers; - m_LobbyPlayers.erase(m_LobbyPlayers.begin() + i); + m_LobbyPlayers.erase(m_LobbyPlayers.begin() + i); - return; - } - } + return; + } + } - if (m_LoadedPlayers >= 2 || (m_LoadedPlayers == 1 && m_SoloRacing)) { - m_LoadTimer += deltaTime; - } else { - m_EmptyTimer += deltaTime; - } + if (m_LoadedPlayers >= 2 || (m_LoadedPlayers == 1 && m_SoloRacing)) { + m_LoadTimer += deltaTime; + } else { + m_EmptyTimer += deltaTime; + } - // If a player happens to be left alone for more then 30 seconds without - // anyone else loading in, send them back to the main world - if (m_EmptyTimer >= 30) { - for (const auto player : m_LobbyPlayers) { - auto *playerEntity = - EntityManager::Instance()->GetEntity(player); + // If a player happens to be left alone for more then 30 seconds without + // anyone else loading in, send them back to the main world + if (m_EmptyTimer >= 30) { + for (const auto player : m_LobbyPlayers) { + auto* playerEntity = + EntityManager::Instance()->GetEntity(player); - if (playerEntity == nullptr) { - continue; - } + if (playerEntity == nullptr) { + continue; + } - auto *playerInstance = dynamic_cast(playerEntity); + auto* playerInstance = dynamic_cast(playerEntity); - playerInstance->SendToZone(m_MainWorld); - } + playerInstance->SendToZone(m_MainWorld); + } - m_LobbyPlayers.clear(); - } + m_LobbyPlayers.clear(); + } - // From the first 2 players loading in the rest have a max of 15 seconds - // to load in, can raise this if it's too low - if (m_LoadTimer >= 15) { - Game::logger->Log("RacingControlComponent", - "Loading all players...\n"); + // From the first 2 players loading in the rest have a max of 15 seconds + // to load in, can raise this if it's too low + if (m_LoadTimer >= 15) { + Game::logger->Log("RacingControlComponent", + "Loading all players..."); - for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { - Game::logger->Log("RacingControlComponent", - "Loading player now!\n"); + for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) { + Game::logger->Log("RacingControlComponent", + "Loading player now!"); - auto *player = - EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); + auto* player = + EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); - if (player == nullptr) { - return; - } - - Game::logger->Log("RacingControlComponent", - "Loading player now NOW!\n"); + if (player == nullptr) { + return; + } + + Game::logger->Log("RacingControlComponent", + "Loading player now NOW!"); - LoadPlayerVehicle(player, true); + LoadPlayerVehicle(player, positionNumber + 1, true); - m_Loaded = true; - } + m_Loaded = true; + } - m_Loaded = true; - } + m_Loaded = true; + } - return; - } + return; + } - // The players who will be participating have loaded - if (!m_Started) { - // Check if anyone has disconnected during this period - for (size_t i = 0; i < m_RacingPlayers.size(); i++) { - auto *playerEntity = EntityManager::Instance()->GetEntity( - m_RacingPlayers[i].playerID); - - if (playerEntity == nullptr) { - m_RacingPlayers.erase(m_RacingPlayers.begin() + i); + // The players who will be participating have loaded + if (!m_Started) { + // Check if anyone has disconnected during this period + for (size_t i = 0; i < m_RacingPlayers.size(); i++) { + auto* playerEntity = EntityManager::Instance()->GetEntity( + m_RacingPlayers[i].playerID); + + if (playerEntity == nullptr) { + m_RacingPlayers.erase(m_RacingPlayers.begin() + i); - --m_LoadedPlayers; + --m_LoadedPlayers; - return; - } - } - - // If less then 2 players are left, send the rest back to the main world - if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) { - for (const auto player : m_LobbyPlayers) { - auto *playerEntity = - EntityManager::Instance()->GetEntity(player); - - if (playerEntity == nullptr) { - continue; - } - - auto *playerInstance = dynamic_cast(playerEntity); - - playerInstance->SendToZone(m_MainWorld); - } - - return; - } - - // Check if all players have send a ready message - - int32_t readyPlayers = 0; - - for (const auto &player : m_RacingPlayers) { - if (player.playerLoaded) { - ++readyPlayers; - } - } + return; + } + } + + // If less then 2 players are left, send the rest back to the main world + if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) { + for (const auto player : m_LobbyPlayers) { + auto* playerEntity = + EntityManager::Instance()->GetEntity(player); + + if (playerEntity == nullptr) { + continue; + } + + auto* playerInstance = dynamic_cast(playerEntity); + + playerInstance->SendToZone(m_MainWorld); + } + + return; + } + + // Check if all players have send a ready message + + int32_t readyPlayers = 0; + + for (const auto& player : m_RacingPlayers) { + if (player.playerLoaded) { + ++readyPlayers; + } + } - if (readyPlayers >= m_LoadedPlayers) { - // Setup for racing - if (m_StartTimer == 0) { - GameMessages::SendNotifyRacingClient( - m_Parent->GetObjectID(), 1, 0, LWOOBJID_EMPTY, u"", - LWOOBJID_EMPTY, UNASSIGNED_SYSTEM_ADDRESS); - - for (const auto &player : m_RacingPlayers) { - auto *vehicle = - EntityManager::Instance()->GetEntity(player.vehicleID); - auto *playerEntity = - EntityManager::Instance()->GetEntity(player.playerID); + if (readyPlayers >= m_LoadedPlayers) { + // Setup for racing + if (m_StartTimer == 0) { + GameMessages::SendNotifyRacingClient( + m_Parent->GetObjectID(), 1, 0, LWOOBJID_EMPTY, u"", + LWOOBJID_EMPTY, UNASSIGNED_SYSTEM_ADDRESS); + + for (const auto& player : m_RacingPlayers) { + auto* vehicle = + EntityManager::Instance()->GetEntity(player.vehicleID); + auto* playerEntity = + EntityManager::Instance()->GetEntity(player.playerID); - if (vehicle != nullptr && playerEntity != nullptr) { - GameMessages::SendTeleport( - player.playerID, player.respawnPosition, - player.respawnRotation, - playerEntity->GetSystemAddress(), true, true); + if (vehicle != nullptr && playerEntity != nullptr) { + GameMessages::SendTeleport( + player.playerID, player.respawnPosition, + player.respawnRotation, + playerEntity->GetSystemAddress(), true, true); - vehicle->SetPosition(player.respawnPosition); - vehicle->SetRotation(player.respawnRotation); + vehicle->SetPosition(player.respawnPosition); + vehicle->SetRotation(player.respawnRotation); - auto *destroyableComponent = - vehicle->GetComponent(); + auto* destroyableComponent = + vehicle->GetComponent(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetImagination(0); - } - - EntityManager::Instance()->SerializeEntity(vehicle); - EntityManager::Instance()->SerializeEntity( - playerEntity); - } - } + if (destroyableComponent != nullptr) { + destroyableComponent->SetImagination(0); + } + + EntityManager::Instance()->SerializeEntity(vehicle); + EntityManager::Instance()->SerializeEntity( + playerEntity); + } + } - // Spawn imagination pickups - auto *minSpawner = dZoneManager::Instance()->GetSpawnersByName( - "ImaginationSpawn_Min")[0]; - auto *medSpawner = dZoneManager::Instance()->GetSpawnersByName( - "ImaginationSpawn_Med")[0]; - auto *maxSpawner = dZoneManager::Instance()->GetSpawnersByName( - "ImaginationSpawn_Max")[0]; - - minSpawner->Activate(); - - if (m_LoadedPlayers > 2) { - medSpawner->Activate(); - } - - if (m_LoadedPlayers > 4) { - maxSpawner->Activate(); - } - - // Reset players to their start location, without smashing them - for (auto &player : m_RacingPlayers) { - auto *vehicleEntity = - EntityManager::Instance()->GetEntity(player.vehicleID); - auto *playerEntity = - EntityManager::Instance()->GetEntity(player.playerID); - - if (vehicleEntity == nullptr || playerEntity == nullptr) { - continue; - } + // Spawn imagination pickups + auto* minSpawner = dZoneManager::Instance()->GetSpawnersByName( + "ImaginationSpawn_Min")[0]; + auto* medSpawner = dZoneManager::Instance()->GetSpawnersByName( + "ImaginationSpawn_Med")[0]; + auto* maxSpawner = dZoneManager::Instance()->GetSpawnersByName( + "ImaginationSpawn_Max")[0]; + + minSpawner->Activate(); + + if (m_LoadedPlayers > 2) { + medSpawner->Activate(); + } + + if (m_LoadedPlayers > 4) { + maxSpawner->Activate(); + } + + // Reset players to their start location, without smashing them + for (auto& player : m_RacingPlayers) { + auto* vehicleEntity = + EntityManager::Instance()->GetEntity(player.vehicleID); + auto* playerEntity = + EntityManager::Instance()->GetEntity(player.playerID); + + if (vehicleEntity == nullptr || playerEntity == nullptr) { + continue; + } - player.noSmashOnReload = true; + player.noSmashOnReload = true; - OnRequestDie(playerEntity); - } - } - // This 6 seconds seems to be hardcoded in the client, start race - // after that amount of time - else if (m_StartTimer >= 6) { - // Activate the players movement - for (auto &player : m_RacingPlayers) { - auto *vehicleEntity = - EntityManager::Instance()->GetEntity(player.vehicleID); - auto *playerEntity = - EntityManager::Instance()->GetEntity(player.playerID); - - if (vehicleEntity == nullptr || playerEntity == nullptr) { - continue; - } - - GameMessages::SendVehicleUnlockInput( - player.vehicleID, false, UNASSIGNED_SYSTEM_ADDRESS); - } - - // Start the race - GameMessages::SendActivityStart(m_Parent->GetObjectID(), - UNASSIGNED_SYSTEM_ADDRESS); - - m_Started = true; - - Game::logger->Log("RacingControlComponent", "Starting race\n"); - - EntityManager::Instance()->SerializeEntity(m_Parent); - - m_StartTime = std::time(nullptr); - } - - m_StartTimer += deltaTime; - } else { - m_StartTimer = 0; - } + OnRequestDie(playerEntity); + } + } + // This 6 seconds seems to be hardcoded in the client, start race + // after that amount of time + else if (m_StartTimer >= 6) { + // Activate the players movement + for (auto& player : m_RacingPlayers) { + auto* vehicleEntity = + EntityManager::Instance()->GetEntity(player.vehicleID); + auto* playerEntity = + EntityManager::Instance()->GetEntity(player.playerID); + + if (vehicleEntity == nullptr || playerEntity == nullptr) { + continue; + } + + GameMessages::SendVehicleUnlockInput( + player.vehicleID, false, UNASSIGNED_SYSTEM_ADDRESS); + } + + // Start the race + GameMessages::SendActivityStart(m_Parent->GetObjectID(), + UNASSIGNED_SYSTEM_ADDRESS); + + m_Started = true; + + Game::logger->Log("RacingControlComponent", "Starting race"); + + EntityManager::Instance()->SerializeEntity(m_Parent); + + m_StartTime = std::time(nullptr); + } + + m_StartTimer += deltaTime; + } else { + m_StartTimer = 0; + } - return; - } + return; + } - // Race routines - auto *path = dZoneManager::Instance()->GetZone()->GetPath( - GeneralUtils::UTF16ToWTF8(m_PathName)); + // Race routines + auto* path = dZoneManager::Instance()->GetZone()->GetPath( + GeneralUtils::UTF16ToWTF8(m_PathName)); - for (auto &player : m_RacingPlayers) { - auto *vehicle = EntityManager::Instance()->GetEntity(player.vehicleID); - auto *playerEntity = - EntityManager::Instance()->GetEntity(player.playerID); + for (auto& player : m_RacingPlayers) { + auto* vehicle = EntityManager::Instance()->GetEntity(player.vehicleID); + auto* playerEntity = + EntityManager::Instance()->GetEntity(player.playerID); - if (vehicle == nullptr || playerEntity == nullptr) { - continue; - } + if (vehicle == nullptr || playerEntity == nullptr) { + continue; + } - const auto vehiclePosition = vehicle->GetPosition(); + const auto vehiclePosition = vehicle->GetPosition(); - // If the player is this far below the map, safe to assume they should - // be smashed by death plane - if (vehiclePosition.y < -500) { - GameMessages::SendDie(vehicle, m_Parent->GetObjectID(), - LWOOBJID_EMPTY, true, VIOLENT, u"", 0, 0, 0, - true, false, 0); + // If the player is this far below the map, safe to assume they should + // be smashed by death plane + if (vehiclePosition.y < -500) { + GameMessages::SendDie(vehicle, m_Parent->GetObjectID(), + LWOOBJID_EMPTY, true, eKillType::VIOLENT, u"", 0, 0, 0, + true, false, 0); - OnRequestDie(playerEntity); + OnRequestDie(playerEntity); - continue; - } + continue; + } - // Loop through all the waypoints and see if the player has reached a - // new checkpoint - uint32_t respawnIndex = 0; - for (const auto &waypoint : path->pathWaypoints) { - if (player.lap == 3) { - break; - } + // Loop through all the waypoints and see if the player has reached a + // new checkpoint + uint32_t respawnIndex = 0; + for (const auto& waypoint : path->pathWaypoints) { + if (player.lap == 3) { + break; + } - if (player.respawnIndex == respawnIndex) { - ++respawnIndex; + if (player.respawnIndex == respawnIndex) { + ++respawnIndex; - continue; - } + continue; + } - const auto &position = waypoint.position; + const auto& position = waypoint.position; - if (std::abs((int)respawnIndex - (int)player.respawnIndex) > 10 && - player.respawnIndex != path->pathWaypoints.size() - 1) { - ++respawnIndex; + if (std::abs((int)respawnIndex - (int)player.respawnIndex) > 10 && + player.respawnIndex != path->pathWaypoints.size() - 1) { + ++respawnIndex; - continue; - } + continue; + } - if (Vector3::DistanceSquared(position, vehiclePosition) > 50 * 50) { - ++respawnIndex; + if (Vector3::DistanceSquared(position, vehiclePosition) > 50 * 50) { + ++respawnIndex; - continue; - } + continue; + } - // Only go upwards, except if we've lapped - // Not sure how we are supposed to check if they've reach a - // checkpoint, within 50 units seems safe - if (!(respawnIndex > player.respawnIndex || - player.respawnIndex == path->pathWaypoints.size() - 1)) { - ++respawnIndex; + // Only go upwards, except if we've lapped + // Not sure how we are supposed to check if they've reach a + // checkpoint, within 50 units seems safe + if (!(respawnIndex > player.respawnIndex || + player.respawnIndex == path->pathWaypoints.size() - 1)) { + ++respawnIndex; - continue; - } + continue; + } - // Some offset up to make they don't fall through the terrain on a - // respawn, seems to fix itself to the track anyhow - player.respawnPosition = position + NiPoint3::UNIT_Y * 5; - player.respawnRotation = vehicle->GetRotation(); - player.respawnIndex = respawnIndex; + // Some offset up to make they don't fall through the terrain on a + // respawn, seems to fix itself to the track anyhow + player.respawnPosition = position + NiPoint3::UNIT_Y * 5; + player.respawnRotation = vehicle->GetRotation(); + player.respawnIndex = respawnIndex; - // Reached the start point, lapped - if (respawnIndex == 0) { - time_t lapTime = std::time(nullptr) - (player.lap == 1 ? m_StartTime : player.lapTime); + // Reached the start point, lapped + if (respawnIndex == 0) { + time_t lapTime = std::time(nullptr) - (player.lap == 0 ? m_StartTime : player.lapTime); - // Cheating check - if (lapTime < 40) { - continue; - } + // Cheating check + if (lapTime < 40) { + continue; + } - player.lap++; + player.lap++; - player.lapTime = std::time(nullptr); + player.lapTime = std::time(nullptr); - if (player.bestLapTime == 0 || player.bestLapTime > lapTime) { - player.bestLapTime = lapTime; + if (player.bestLapTime == 0 || player.bestLapTime > lapTime) { + player.bestLapTime = lapTime; - Game::logger->Log("RacingControlComponent", - "Best lap time (%llu)\n", lapTime); - } + Game::logger->Log("RacingControlComponent", + "Best lap time (%llu)", lapTime); + } - auto *missionComponent = - playerEntity->GetComponent(); + auto* missionComponent = + playerEntity->GetComponent(); - if (missionComponent != nullptr) { + if (missionComponent != nullptr) { - // Progress lap time tasks - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (lapTime)*1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAP_TIME); + // Progress lap time tasks + missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, (LWOOBJID)eRacingTaskParam::LAP_TIME); - if (player.lap == 3) { - m_Finished++; - player.finished = m_Finished; + if (player.lap == 3) { + m_Finished++; + player.finished = m_Finished; - const auto raceTime = - (std::time(nullptr) - m_StartTime); + const auto raceTime = + (std::time(nullptr) - m_StartTime); - player.raceTime = raceTime; + player.raceTime = raceTime; - Game::logger->Log("RacingControlComponent", - "Completed time %llu, %llu\n", - raceTime, raceTime * 1000); + Game::logger->Log("RacingControlComponent", + "Completed time %llu, %llu", + raceTime, raceTime * 1000); - // Entire race time - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (raceTime)*1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_TOTAL_TRACK_TIME); + // Entire race time + missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME); - auto *characterComponent = playerEntity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->TrackRaceCompleted(m_Finished == 1); - } + auto* characterComponent = playerEntity->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->TrackRaceCompleted(m_Finished == 1); + } - // TODO: Figure out how to update the GUI leaderboard. - } - } + // TODO: Figure out how to update the GUI leaderboard. + } + } - Game::logger->Log("RacingControlComponent", - "Lapped (%i) in (%llu)\n", player.lap, - lapTime); - } + Game::logger->Log("RacingControlComponent", + "Lapped (%i) in (%llu)", player.lap, + lapTime); + } - Game::logger->Log("RacingControlComponent", - "Reached point (%i)/(%i)\n", player.respawnIndex, - path->pathWaypoints.size()); + Game::logger->Log("RacingControlComponent", + "Reached point (%i)/(%i)", player.respawnIndex, + path->pathWaypoints.size()); - break; - } - } + break; + } + } } std::string RacingControlComponent::FormatTimeString(time_t time) { - int32_t min = time / 60; - time -= min * 60; - int32_t sec = time; + int32_t min = time / 60; + time -= min * 60; + int32_t sec = time; - std::string minText; - std::string secText; + std::string minText; + std::string secText; - if (min <= 0) { - minText = "0"; - } else { - minText = std::to_string(min); - } + if (min <= 0) { + minText = "0"; + } else { + minText = std::to_string(min); + } - if (sec <= 0) { - secText = "00"; - } else if (sec <= 9) { - secText = "0" + std::to_string(sec); - } else { - secText = std::to_string(sec); - } + if (sec <= 0) { + secText = "00"; + } else if (sec <= 9) { + secText = "0" + std::to_string(sec); + } else { + secText = std::to_string(sec); + } - return minText + ":" + secText + ".00"; + return minText + ":" + secText + ".00"; } diff --git a/dGame/dComponents/RacingControlComponent.h b/dGame/dComponents/RacingControlComponent.h index 63d5b2e4..a81121e1 100644 --- a/dGame/dComponents/RacingControlComponent.h +++ b/dGame/dComponents/RacingControlComponent.h @@ -7,96 +7,97 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * Information for each player in the race - */ + /** + * Information for each player in the race + */ struct RacingPlayerInfo { - /** - * The ID of the player - */ - LWOOBJID playerID; + /** + * The ID of the player + */ + LWOOBJID playerID; - /** - * The ID of the car the player is driving - */ - LWOOBJID vehicleID; + /** + * The ID of the car the player is driving + */ + LWOOBJID vehicleID; - /** - * The index of this player in the list of players - */ - uint32_t playerIndex; + /** + * The index of this player in the list of players + */ + uint32_t playerIndex; - /** - * Whether the player has finished loading or not - */ - bool playerLoaded; + /** + * Whether the player has finished loading or not + */ + bool playerLoaded; - /** - * Scripted activity component score - */ - float data[10] {}; + /** + * Scripted activity component score + */ + float data[10]{}; - /** - * Point that the player will respawn at if they smash their car - */ - NiPoint3 respawnPosition; + /** + * Point that the player will respawn at if they smash their car + */ + NiPoint3 respawnPosition; - /** - * Rotation that the player will respawn at if they smash their car - */ - NiQuaternion respawnRotation; + /** + * Rotation that the player will respawn at if they smash their car + */ + NiQuaternion respawnRotation; - /** - * The index in the respawn point the player is now at - */ - uint32_t respawnIndex; + /** + * The index in the respawn point the player is now at + */ + uint32_t respawnIndex; - /** - * The number of laps the player has completed - */ - uint32_t lap; + /** + * The number of laps the player has completed + */ + uint32_t lap; - /** - * Whether or not the player has finished the race - */ - uint32_t finished; + /** + * Whether or not the player has finished the race + */ + uint32_t finished; - /** - * Unused - */ - uint16_t reachedPoints; + /** + * Unused + */ + uint16_t reachedPoints; - /** - * The fastest lap time of the player - */ - time_t bestLapTime = 0; + /** + * The fastest lap time of the player + */ + time_t bestLapTime = 0; - /** - * The current lap time of the player - */ - time_t lapTime = 0; + /** + * The current lap time of the player + */ + time_t lapTime = 0; - /** - * The number of times this player smashed their car - */ - uint32_t smashedTimes = 0; + /** + * The number of times this player smashed their car + */ + uint32_t smashedTimes = 0; - /** - * Whether or not the player should be smashed if the game is reloaded - */ - bool noSmashOnReload = false; + /** + * Whether or not the player should be smashed if the game is reloaded + */ + bool noSmashOnReload = false; - /** - * Whether or not this player has collected their rewards from completing the race - */ - bool collectedRewards = false; + /** + * Whether or not this player has collected their rewards from completing the race + */ + bool collectedRewards = false; - /** - * Unused - */ - time_t raceTime = 0; + /** + * Unused + */ + time_t raceTime = 0; }; /** @@ -104,145 +105,150 @@ struct RacingPlayerInfo { */ class RacingControlComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_RACING_CONTROL; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::RACING_CONTROL; + RacingControlComponent(Entity* parentEntity); ~RacingControlComponent(); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Update(float deltaTime); - /** - * Invoked when a player loads into the zone. - */ - void OnPlayerLoaded(Entity* player); + /** + * Invoked when a player loads into the zone. + */ + void OnPlayerLoaded(Entity* player); - /** - * Initalize the player's vehicle. - * - * @param player The player who's vehicle to initialize. - * @param initialLoad Is this the first time the player is loading in this race? - */ - void LoadPlayerVehicle(Entity* player, bool initialLoad = false); + /** + * Initalize the player's vehicle. + * + * @param player The player who's vehicle to initialize. + * @param initialLoad Is this the first time the player is loading in this race? + */ + void LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad = false); - /** - * Invoked when the client says it has loaded in. - */ - void OnRacingClientReady(Entity* player); + /** + * Invoked when the client says it has loaded in. + */ + void OnRacingClientReady(Entity* player); - /** - * Invoked when the client says it should be smashed. - */ - void OnRequestDie(Entity* player); + /** + * Invoked when the client says it should be smashed. + */ + void OnRequestDie(Entity* player); - /** - * Invoked when the player has finished respawning. - */ - void OnRacingPlayerInfoResetFinished(Entity* player); + /** + * Invoked when the player has finished respawning. + */ + void OnRacingPlayerInfoResetFinished(Entity* player); - /** - * Invoked when the player responds to the GUI. - */ - void HandleMessageBoxResponse(Entity* player, const std::string& id); + /** + * Invoked when the player responds to the GUI. + */ + void HandleMessageBoxResponse(Entity* player, int32_t button, const std::string& id); - /** - * Get the racing data from a player's LWOOBJID. - */ - RacingPlayerInfo* GetPlayerData(LWOOBJID playerID); + /** + * Get the racing data from a player's LWOOBJID. + */ + RacingPlayerInfo* GetPlayerData(LWOOBJID playerID); - /** - * Formats a time to a string, currently unused - * @param time the time to format - * @return the time formatted as string - */ - static std::string FormatTimeString(time_t time); + /** + * Formats a time to a string, currently unused + * @param time the time to format + * @return the time formatted as string + */ + static std::string FormatTimeString(time_t time); private: - /** - * The players that are currently racing - */ - std::vector m_RacingPlayers; + /** + * The players that are currently racing + */ + std::vector m_RacingPlayers; - /** - * The paths that are followed for the camera scenes - */ - std::u16string m_PathName; + /** + * The paths that are followed for the camera scenes + */ + std::u16string m_PathName; - /** - * The ID of the activity for participating in this race - */ - uint32_t m_ActivityID; + /** + * The ID of the activity for participating in this race + */ + uint32_t m_ActivityID; - /** - * The world the players return to when they finish the race - */ - uint32_t m_MainWorld; + /** + * The world the players return to when they finish the race + */ + uint32_t m_MainWorld; - /** - * The number of laps that are remaining for the winning player - */ - uint16_t m_RemainingLaps; + /** + * The number of laps that are remaining for the winning player + */ + uint16_t m_RemainingLaps; - /** - * The ID of the player that's currently winning the race - */ - LWOOBJID m_LeadingPlayer; + /** + * The ID of the player that's currently winning the race + */ + LWOOBJID m_LeadingPlayer; - /** - * The overall best lap from all the players - */ - float m_RaceBestLap; + /** + * The overall best lap from all the players + */ + float m_RaceBestLap; - /** - * The overall best time from all the players - */ - float m_RaceBestTime; + /** + * The overall best time from all the players + */ + float m_RaceBestTime; - /** - * Whether or not the race has started - */ - bool m_Started; + /** + * Whether or not the race has started + */ + bool m_Started; - /** - * The time left until the race will start - */ - float m_StartTimer; + /** + * The time left until the race will start + */ + float m_StartTimer; - /** - * The time left for loading the players - */ - float m_LoadTimer; + /** + * The time left for loading the players + */ + float m_LoadTimer; - /** - * Whether or not all players have loaded - */ - bool m_Loaded; + /** + * Whether or not all players have loaded + */ + bool m_Loaded; - /** - * The number of loaded players - */ - uint32_t m_LoadedPlayers; + /** + * The number of loaded players + */ + uint32_t m_LoadedPlayers; - /** - * All the players that are in the lobby, loaded or not - */ - std::vector m_LobbyPlayers; + /** + * All the players that are in the lobby, loaded or not + */ + std::vector m_LobbyPlayers; - /** - * The number of players that have finished the race - */ - uint32_t m_Finished; + /** + * The number of players that have finished the race + */ + uint32_t m_Finished; - /** - * The time the race was started - */ - time_t m_StartTime; + /** + * The time the race was started + */ + time_t m_StartTime; - /** - * Timer for tracking how long a player was alone in this race - */ - float m_EmptyTimer; + /** + * Timer for tracking how long a player was alone in this race + */ + float m_EmptyTimer; - bool m_SoloRacing; + bool m_SoloRacing; + + /** + * Value for message box response to know if we are exiting the race via the activity dialogue + */ + const int32_t m_ActivityExitConfirm = 1; }; diff --git a/dGame/dComponents/RailActivatorComponent.cpp b/dGame/dComponents/RailActivatorComponent.cpp index 9cdc93f1..e4091046 100644 --- a/dGame/dComponents/RailActivatorComponent.cpp +++ b/dGame/dComponents/RailActivatorComponent.cpp @@ -7,160 +7,151 @@ #include "RebuildComponent.h" #include "Game.h" #include "dLogger.h" +#include "eStateChangeType.h" -RailActivatorComponent::RailActivatorComponent(Entity *parent, int32_t componentID) : Component(parent) { - m_ComponentID = componentID; - const auto tableData = CDClientManager::Instance() - ->GetTable("RailActivatorComponent")->GetEntryByID(componentID); +RailActivatorComponent::RailActivatorComponent(Entity* parent, int32_t componentID) : Component(parent) { + m_ComponentID = componentID; + const auto tableData = CDClientManager::Instance().GetTable()->GetEntryByID(componentID);; - m_Path = parent->GetVar(u"rail_path"); - m_PathDirection = parent->GetVar(u"rail_path_direction"); - m_PathStart = parent->GetVar(u"rail_path_start"); + m_Path = parent->GetVar(u"rail_path"); + m_PathDirection = parent->GetVar(u"rail_path_direction"); + m_PathStart = parent->GetVar(u"rail_path_start"); - m_StartSound = tableData.startSound; - m_loopSound = tableData.loopSound; - m_StopSound = tableData.stopSound; + m_StartSound = tableData.startSound; + m_loopSound = tableData.loopSound; + m_StopSound = tableData.stopSound; - m_StartAnimation = tableData.startAnimation; - m_LoopAnimation = tableData.loopAnimation; - m_StopAnimation = tableData.stopAnimation; + m_StartAnimation = tableData.startAnimation; + m_LoopAnimation = tableData.loopAnimation; + m_StopAnimation = tableData.stopAnimation; - m_StartEffect = tableData.startEffectID; - m_LoopEffect = tableData.loopEffectID; - m_StopEffect = tableData.stopEffectID; + m_StartEffect = tableData.startEffectID; + m_LoopEffect = tableData.loopEffectID; + m_StopEffect = tableData.stopEffectID; - m_DamageImmune = parent->GetVar(u"rail_activator_damage_immune"); - m_NoAggro = parent->GetVar(u"rail_no_aggro"); - m_NotifyArrived = parent->GetVar(u"rail_notify_activator_arrived"); - m_ShowNameBillboard = parent->GetVar(u"rail_show_name_billboard"); - m_UseDB = parent->GetVar(u"rail_use_db"); - m_CameraLocked = tableData.cameraLocked; - m_CollisionEnabled = tableData.playerCollision; + m_DamageImmune = parent->GetVar(u"rail_activator_damage_immune"); + m_NoAggro = parent->GetVar(u"rail_no_aggro"); + m_NotifyArrived = parent->GetVar(u"rail_notify_activator_arrived"); + m_ShowNameBillboard = parent->GetVar(u"rail_show_name_billboard"); + m_UseDB = parent->GetVar(u"rail_use_db"); + m_CameraLocked = tableData.cameraLocked; + m_CollisionEnabled = tableData.playerCollision; } RailActivatorComponent::~RailActivatorComponent() = default; -void RailActivatorComponent::OnUse(Entity *originator) { - auto* rebuildComponent = m_Parent->GetComponent(); - if (rebuildComponent != nullptr && rebuildComponent->GetState() != REBUILD_COMPLETED) - return; +void RailActivatorComponent::OnUse(Entity* originator) { + auto* rebuildComponent = m_Parent->GetComponent(); + if (rebuildComponent != nullptr && rebuildComponent->GetState() != eRebuildState::COMPLETED) + return; - if (rebuildComponent != nullptr) { - // Don't want it to be destroyed while a player is using it - rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 10.0f); - } + if (rebuildComponent != nullptr) { + // Don't want it to be destroyed while a player is using it + rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 10.0f); + } - m_EntitiesOnRail.push_back(originator->GetObjectID()); + m_EntitiesOnRail.push_back(originator->GetObjectID()); - // Start the initial effects - if (!m_StartEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StartEffect.first, m_StartEffect.second, - std::to_string(m_StartEffect.first)); - } + // Start the initial effects + if (!m_StartEffect.second.empty()) { + GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StartEffect.first, m_StartEffect.second, + std::to_string(m_StartEffect.first)); + } - if (!m_StartAnimation.empty()) { - GameMessages::SendPlayAnimation(originator, m_StartAnimation); - } + if (!m_StartAnimation.empty()) { + GameMessages::SendPlayAnimation(originator, m_StartAnimation); + } - float animationLength; - - if (m_StartAnimation == u"whirlwind-rail-up-earth") - { - animationLength = 1.5f; - } - else if (m_StartAnimation == u"whirlwind-rail-up-lightning") - { - animationLength = 0.5f; - } - else if (m_StartAnimation == u"whirlwind-rail-up-ice") - { - animationLength = 0.5f; - } - else if (m_StartAnimation == u"whirlwind-rail-up-fire") - { - animationLength = 0.5f; - } - else - { - animationLength = 0.5f; - } + float animationLength; - const auto originatorID = originator->GetObjectID(); + if (m_StartAnimation == u"whirlwind-rail-up-earth") { + animationLength = 1.5f; + } else if (m_StartAnimation == u"whirlwind-rail-up-lightning") { + animationLength = 0.5f; + } else if (m_StartAnimation == u"whirlwind-rail-up-ice") { + animationLength = 0.5f; + } else if (m_StartAnimation == u"whirlwind-rail-up-fire") { + animationLength = 0.5f; + } else { + animationLength = 0.5f; + } - m_Parent->AddCallbackTimer(animationLength, [originatorID, this] () { - auto* originator = EntityManager::Instance()->GetEntity(originatorID); + const auto originatorID = originator->GetObjectID(); - if (originator == nullptr) { - return; - } + m_Parent->AddCallbackTimer(animationLength, [originatorID, this]() { + auto* originator = EntityManager::Instance()->GetEntity(originatorID); - GameMessages::SendStartRailMovement(originator->GetObjectID(), m_Path, m_StartSound, - m_loopSound, m_StopSound, originator->GetSystemAddress(), - m_PathStart, m_PathDirection, m_DamageImmune, m_NoAggro, m_NotifyArrived, - m_ShowNameBillboard, m_CameraLocked, m_CollisionEnabled, m_UseDB, m_ComponentID, - m_Parent->GetObjectID()); - }); + if (originator == nullptr) { + return; + } + + GameMessages::SendStartRailMovement(originator->GetObjectID(), m_Path, m_StartSound, + m_loopSound, m_StopSound, originator->GetSystemAddress(), + m_PathStart, m_PathDirection, m_DamageImmune, m_NoAggro, m_NotifyArrived, + m_ShowNameBillboard, m_CameraLocked, m_CollisionEnabled, m_UseDB, m_ComponentID, + m_Parent->GetObjectID()); + }); } -void RailActivatorComponent::OnRailMovementReady(Entity *originator) const { - // Stun the originator - GameMessages::SendSetStunned(originator->GetObjectID(), PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); +void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { + // Stun the originator + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); - if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { - // Stop the initial effects - if (!m_StartEffect.second.empty()) { - GameMessages::SendStopFXEffect(originator, false, std::to_string(m_StartEffect.first)); - } + if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { + // Stop the initial effects + if (!m_StartEffect.second.empty()) { + GameMessages::SendStopFXEffect(originator, false, std::to_string(m_StartEffect.first)); + } - // Start the looping effects - if (!m_LoopEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_LoopEffect.first, m_LoopEffect.second, - std::to_string(m_LoopEffect.first)); - } + // Start the looping effects + if (!m_LoopEffect.second.empty()) { + GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_LoopEffect.first, m_LoopEffect.second, + std::to_string(m_LoopEffect.first)); + } - if (!m_LoopAnimation.empty()) { - GameMessages::SendPlayAnimation(originator, m_LoopAnimation); - } + if (!m_LoopAnimation.empty()) { + GameMessages::SendPlayAnimation(originator, m_LoopAnimation); + } - GameMessages::SendSetRailMovement(originator->GetObjectID(), m_PathDirection, m_Path, m_PathStart, - originator->GetSystemAddress(), m_ComponentID, - m_Parent->GetObjectID()); - } + GameMessages::SendSetRailMovement(originator->GetObjectID(), m_PathDirection, m_Path, m_PathStart, + originator->GetSystemAddress(), m_ComponentID, + m_Parent->GetObjectID()); + } } -void RailActivatorComponent::OnCancelRailMovement(Entity *originator) { - // Remove the stun from the originator - GameMessages::SendSetStunned(originator->GetObjectID(), POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); +void RailActivatorComponent::OnCancelRailMovement(Entity* originator) { + // Remove the stun from the originator + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); - auto* rebuildComponent = m_Parent->GetComponent(); + auto* rebuildComponent = m_Parent->GetComponent(); - if (rebuildComponent != nullptr) { - // Set back reset time - rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() - 10.0f); - } + if (rebuildComponent != nullptr) { + // Set back reset time + rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() - 10.0f); + } - if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { - // Stop the looping effects - if (!m_LoopEffect.second.empty()) { - GameMessages::SendStopFXEffect(originator, false, std::to_string(m_LoopEffect.first)); - } + if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { + // Stop the looping effects + if (!m_LoopEffect.second.empty()) { + GameMessages::SendStopFXEffect(originator, false, std::to_string(m_LoopEffect.first)); + } - // Start the end effects - if (!m_StopEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StopEffect.first, m_StopEffect.second, - std::to_string(m_StopEffect.first)); - } + // Start the end effects + if (!m_StopEffect.second.empty()) { + GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StopEffect.first, m_StopEffect.second, + std::to_string(m_StopEffect.first)); + } - if (!m_StopAnimation.empty()) { - GameMessages::SendPlayAnimation(originator, m_StopAnimation); - } + if (!m_StopAnimation.empty()) { + GameMessages::SendPlayAnimation(originator, m_StopAnimation); + } - // Remove the player after they've signalled they're done railing - m_EntitiesOnRail.erase(std::remove(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), - originator->GetObjectID()),m_EntitiesOnRail.end()); - } + // Remove the player after they've signalled they're done railing + m_EntitiesOnRail.erase(std::remove(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), + originator->GetObjectID()), m_EntitiesOnRail.end()); + } } diff --git a/dGame/dComponents/RailActivatorComponent.h b/dGame/dComponents/RailActivatorComponent.h index 82607dcf..5d625d2a 100644 --- a/dGame/dComponents/RailActivatorComponent.h +++ b/dGame/dComponents/RailActivatorComponent.h @@ -4,6 +4,7 @@ #include #include "dCommonVars.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles the traveling using rails, e.g. the ninjago posts that can be used to travel using Spinjitzu. @@ -11,134 +12,134 @@ */ class RailActivatorComponent final : public Component { public: - explicit RailActivatorComponent(Entity* parent, int32_t componentID); - ~RailActivatorComponent() override; + explicit RailActivatorComponent(Entity* parent, int32_t componentID); + ~RailActivatorComponent() override; - static const uint32_t ComponentType = COMPONENT_TYPE_RAIL_ACTIVATOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::RAIL_ACTIVATOR; - /** - * Handles the OnUse event from some entity, initiates the rail movement - * @param originator the entity that triggered the event - */ - void OnUse(Entity *originator) override; + /** + * Handles the OnUse event from some entity, initiates the rail movement + * @param originator the entity that triggered the event + */ + void OnUse(Entity* originator) override; - /** - * Event handler that's called when some entity has played the start animation for rail movement and now wants to - * start the actual movement. - * @param originator the entity that triggered the event - */ - void OnRailMovementReady(Entity* originator) const; + /** + * Event handler that's called when some entity has played the start animation for rail movement and now wants to + * start the actual movement. + * @param originator the entity that triggered the event + */ + void OnRailMovementReady(Entity* originator) const; - /** - * Event handler that's called when some entity has finished traversing the rail and wants to end its interaction - * with it - * @param originator the entity that triggered the event - */ - void OnCancelRailMovement(Entity* originator); + /** + * Event handler that's called when some entity has finished traversing the rail and wants to end its interaction + * with it + * @param originator the entity that triggered the event + */ + void OnCancelRailMovement(Entity* originator); private: - /** - * The ID of this component in the components database - */ - int32_t m_ComponentID; + /** + * The ID of this component in the components database + */ + int32_t m_ComponentID; - /** - * The entities that are currently traversing the rail - */ - std::vector m_EntitiesOnRail {}; + /** + * The entities that are currently traversing the rail + */ + std::vector m_EntitiesOnRail{}; - /** - * The path the entities will follow when traversing the rail - */ - std::u16string m_Path; + /** + * The path the entities will follow when traversing the rail + */ + std::u16string m_Path; - /** - * The index of the path that is the start - */ - uint32_t m_PathStart; + /** + * The index of the path that is the start + */ + uint32_t m_PathStart; - /** - * The direction on the path - */ - bool m_PathDirection; + /** + * The direction on the path + */ + bool m_PathDirection; - /** - * The animation that plays when starting the rail - */ - std::u16string m_StartAnimation; + /** + * The animation that plays when starting the rail + */ + std::u16string m_StartAnimation; - /** - * The animation that plays during the rail - */ - std::u16string m_LoopAnimation; + /** + * The animation that plays during the rail + */ + std::u16string m_LoopAnimation; - /** - * The animation that plays after the rail - */ - std::u16string m_StopAnimation; + /** + * The animation that plays after the rail + */ + std::u16string m_StopAnimation; - /** - * The sound that plays at the start of the rail - */ - std::u16string m_StartSound; + /** + * The sound that plays at the start of the rail + */ + std::u16string m_StartSound; - /** - * The sound that plays during the rail - */ - std::u16string m_loopSound; + /** + * The sound that plays during the rail + */ + std::u16string m_loopSound; - /** - * The sound that plays at the end of the rail - */ - std::u16string m_StopSound; + /** + * The sound that plays at the end of the rail + */ + std::u16string m_StopSound; - /** - * The effects that play at the start of the rail - */ - std::pair m_StartEffect; + /** + * The effects that play at the start of the rail + */ + std::pair m_StartEffect; - /** - * The effects that play during the rail - */ - std::pair m_LoopEffect; + /** + * The effects that play during the rail + */ + std::pair m_LoopEffect; - /** - * The effects that play at the end of the rail - */ - std::pair m_StopEffect; + /** + * The effects that play at the end of the rail + */ + std::pair m_StopEffect; - /** - * Client flag - */ - bool m_DamageImmune; + /** + * Client flag + */ + bool m_DamageImmune; - /** - * Client flag - */ - bool m_NoAggro; + /** + * Client flag + */ + bool m_NoAggro; - /** - * Client flag - */ - bool m_UseDB; + /** + * Client flag + */ + bool m_UseDB; - /** - * Client flag - */ - bool m_CameraLocked; + /** + * Client flag + */ + bool m_CameraLocked; - /** - * Client flag - */ - bool m_CollisionEnabled; + /** + * Client flag + */ + bool m_CollisionEnabled; - /** - * Client flag, notifies the server when the player finished the rail - */ - bool m_NotifyArrived; + /** + * Client flag, notifies the server when the player finished the rail + */ + bool m_NotifyArrived; - /** - * Client flag - */ - bool m_ShowNameBillboard; + /** + * Client flag + */ + bool m_ShowNameBillboard; }; diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 603a18cc..fcf2738c 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -7,33 +7,38 @@ #include "dLogger.h" #include "CharacterComponent.h" #include "MissionComponent.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eTriggerEventType.h" +#include "eQuickBuildFailReason.h" +#include "eTerminateType.h" +#include "eGameActivity.h" #include "dServer.h" #include "PacketUtils.h" #include "Spawner.h" #include "MovingPlatformComponent.h" #include "Preconditions.h" +#include "Loot.h" +#include "TeamManager.h" #include "CppScripts.h" RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) { std::u16string checkPreconditions = entity->GetVar(u"CheckPrecondition"); - if (!checkPreconditions.empty()) - { + if (!checkPreconditions.empty()) { m_Precondition = new PreconditionExpression(GeneralUtils::UTF16ToWTF8(checkPreconditions)); } // Should a setting that has the build activator position exist, fetch that setting here and parse it for position. // It is assumed that the user who sets this setting uses the correct character delimiter (character 31 or in hex 0x1F) auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 0x1F); - if (positionAsVector.size() == 3 && + if (positionAsVector.size() == 3 && GeneralUtils::TryParse(positionAsVector[0], m_ActivatorPosition.x) && - GeneralUtils::TryParse(positionAsVector[1], m_ActivatorPosition.y) && + GeneralUtils::TryParse(positionAsVector[1], m_ActivatorPosition.y) && GeneralUtils::TryParse(positionAsVector[2], m_ActivatorPosition.z)) { } else { - Game::logger->Log("RebuildComponent", "Failed to find activator position for lot %i. Defaulting to parents position.\n", m_Parent->GetLOT()); + Game::logger->Log("RebuildComponent", "Failed to find activator position for lot %i. Defaulting to parents position.", m_Parent->GetLOT()); m_ActivatorPosition = m_Parent->GetPosition(); } @@ -45,14 +50,14 @@ RebuildComponent::~RebuildComponent() { Entity* builder = GetBuilder(); if (builder) { - CancelRebuild(builder, eFailReason::REASON_BUILD_ENDED, true); + CancelRebuild(builder, eQuickBuildFailReason::BUILD_ENDED, true); } - + DespawnActivator(); } void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (m_Parent->GetComponent(COMPONENT_TYPE_DESTROYABLE) == nullptr) { + if (m_Parent->GetComponent(eReplicaComponentType::DESTROYABLE) == nullptr) { if (bIsInitialUpdate) { outBitStream->Write(false); } @@ -61,10 +66,10 @@ void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitia outBitStream->Write(false); } - // If build state is completed and we've already serialized once in the completed state, + // If build state is completed and we've already serialized once in the completed state, // don't serializing this component anymore as this will cause the build to jump again. // If state changes, serialization will begin again. - if (!m_StateDirty && m_State == REBUILD_COMPLETED) { + if (!m_StateDirty && m_State == eRebuildState::COMPLETED) { outBitStream->Write0(); outBitStream->Write0(); return; @@ -81,19 +86,18 @@ void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitia for (int i = 0; i < 10; i++) { outBitStream->Write(0.0f); } - } - else { + } else { outBitStream->Write((uint32_t)0); } // END Scripted Activity outBitStream->Write1(); - outBitStream->Write(m_State); + outBitStream->Write(m_State); outBitStream->Write(m_ShowResetEffect); outBitStream->Write(m_Activator != nullptr); - + outBitStream->Write(m_Timer); outBitStream->Write(m_TimerIncomplete); @@ -119,7 +123,7 @@ void RebuildComponent::Update(float deltaTime) { }*/ switch (m_State) { - case REBUILD_OPEN: { + case eRebuildState::OPEN: { SpawnActivator(); m_TimeBeforeDrain = 0; @@ -146,37 +150,36 @@ void RebuildComponent::Update(float deltaTime) { } } } - + break; } - case REBUILD_COMPLETED: { + case eRebuildState::COMPLETED: { m_Timer += deltaTime; // For reset times < 0 this has to be handled manually if (m_ResetTime > 0) { - if (m_Timer >= m_ResetTime - 4.0f) { - if (!m_ShowResetEffect) { - m_ShowResetEffect = true; + if (m_Timer >= m_ResetTime - 4.0f) { + if (!m_ShowResetEffect) { + m_ShowResetEffect = true; - EntityManager::Instance()->SerializeEntity(m_Parent); - } - } + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } - if (m_Timer >= m_ResetTime) { + if (m_Timer >= m_ResetTime) { - GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true); + GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true); - ResetRebuild(false); - } + ResetRebuild(false); + } } break; } - case REBUILD_BUILDING: + case eRebuildState::BUILDING: { Entity* builder = GetBuilder(); - if (builder == nullptr) - { + if (builder == nullptr) { ResetRebuild(false); return; @@ -201,7 +204,7 @@ void RebuildComponent::Update(float deltaTime) { ++m_DrainedImagination; if (newImagination == 0 && m_DrainedImagination < m_TakeImagination) { - CancelRebuild(builder, eFailReason::REASON_OUT_OF_IMAGINATION, true); + CancelRebuild(builder, eQuickBuildFailReason::OUT_OF_IMAGINATION, true); break; } @@ -213,32 +216,33 @@ void RebuildComponent::Update(float deltaTime) { break; } - case REBUILD_INCOMPLETE: { + case eRebuildState::INCOMPLETE: { m_TimerIncomplete += deltaTime; // For reset times < 0 this has to be handled manually if (m_TimeBeforeSmash > 0) { - if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) { - m_ShowResetEffect = true; + if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) { + m_ShowResetEffect = true; - EntityManager::Instance()->SerializeEntity(m_Parent); - } + EntityManager::Instance()->SerializeEntity(m_Parent); + } - if (m_TimerIncomplete >= m_TimeBeforeSmash) { + if (m_TimerIncomplete >= m_TimeBeforeSmash) { m_Builder = LWOOBJID_EMPTY; - GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true); + GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true); - ResetRebuild(false); - } + ResetRebuild(false); + } } break; } + case eRebuildState::RESETTING: break; } } void RebuildComponent::OnUse(Entity* originator) { - if (GetBuilder() != nullptr || m_State == REBUILD_COMPLETED) { + if (GetBuilder() != nullptr || m_State == eRebuildState::COMPLETED) { return; } @@ -272,7 +276,7 @@ void RebuildComponent::SpawnActivator() { void RebuildComponent::DespawnActivator() { if (m_Activator) { EntityManager::Instance()->DestructEntity(m_Activator); - + m_Activator->ScheduleKillAfterUpdate(); m_Activator = nullptr; @@ -281,8 +285,7 @@ void RebuildComponent::DespawnActivator() { } } -Entity* RebuildComponent::GetActivator() -{ +Entity* RebuildComponent::GetActivator() { return EntityManager::Instance()->GetEntity(m_ActivatorId); } @@ -345,14 +348,13 @@ void RebuildComponent::SetActivatorPosition(NiPoint3 value) { } void RebuildComponent::SetResetTime(float value) { - m_ResetTime = value; + m_ResetTime = value; } void RebuildComponent::SetCompleteTime(float value) { if (value < 0) { m_CompleteTime = 4.5f; - } - else { + } else { m_CompleteTime = value; } } @@ -384,8 +386,7 @@ void RebuildComponent::SetPostImaginationCost(int value) { void RebuildComponent::SetTimeBeforeSmash(float value) { if (value < 0) { m_TimeBeforeSmash = 10.0f; - } - else { + } else { m_TimeBeforeSmash = value; } } @@ -395,18 +396,18 @@ void RebuildComponent::SetRepositionPlayer(bool value) { } void RebuildComponent::StartRebuild(Entity* user) { - if (m_State == eRebuildState::REBUILD_OPEN || m_State == eRebuildState::REBUILD_COMPLETED || m_State == eRebuildState::REBUILD_INCOMPLETE) { + if (m_State == eRebuildState::OPEN || m_State == eRebuildState::COMPLETED || m_State == eRebuildState::INCOMPLETE) { m_Builder = user->GetObjectID(); auto* character = user->GetComponent(); - character->SetCurrentActivity(eGameActivities::ACTIVITY_QUICKBUILDING); + character->SetCurrentActivity(eGameActivity::QUICKBUILDING); EntityManager::Instance()->SerializeEntity(user); - GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_BUILDING, user->GetObjectID()); - GameMessages::SendEnableRebuild(m_Parent, true, false, false, eFailReason::REASON_NOT_GIVEN, 0.0f, user->GetObjectID()); + GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::BUILDING, user->GetObjectID()); + GameMessages::SendEnableRebuild(m_Parent, true, false, false, eQuickBuildFailReason::NOT_GIVEN, 0.0f, user->GetObjectID()); - m_State = eRebuildState::REBUILD_BUILDING; + m_State = eRebuildState::BUILDING; m_StateDirty = true; EntityManager::Instance()->SerializeEntity(m_Parent); @@ -419,11 +420,11 @@ void RebuildComponent::StartRebuild(Entity* user) { script->OnRebuildStart(m_Parent, user); } - // Notify scripts and possible subscribers - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) - script->OnRebuildNotifyState(m_Parent, m_State); - for (const auto& cb : m_RebuildStateCallbacks) - cb(m_State); + // Notify scripts and possible subscribers + for (auto* script : CppScripts::GetEntityScripts(m_Parent)) + script->OnRebuildNotifyState(m_Parent, m_State); + for (const auto& cb : m_RebuildStateCallbacks) + cb(m_State); } } @@ -431,25 +432,25 @@ void RebuildComponent::CompleteRebuild(Entity* user) { if (user == nullptr) { return; } - + auto* characterComponent = user->GetComponent(); if (characterComponent != nullptr) { - characterComponent->SetCurrentActivity(eGameActivities::ACTIVITY_NONE); - characterComponent->TrackRebuildComplete(); + characterComponent->SetCurrentActivity(eGameActivity::NONE); + characterComponent->TrackRebuildComplete(); } else { - Game::logger->Log("RebuildComponent", "Some user tried to finish the rebuild but they didn't have a character somehow.\n"); + Game::logger->Log("RebuildComponent", "Some user tried to finish the rebuild but they didn't have a character somehow."); return; } EntityManager::Instance()->SerializeEntity(user); - GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_COMPLETED, user->GetObjectID()); + GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::COMPLETED, user->GetObjectID()); GameMessages::SendPlayFXEffect(m_Parent, 507, u"create", "BrickFadeUpVisCompleteEffect", LWOOBJID_EMPTY, 0.4f, 1.0f, true); - GameMessages::SendEnableRebuild(m_Parent, false, false, true, eFailReason::REASON_NOT_GIVEN, m_ResetTime, user->GetObjectID()); + GameMessages::SendEnableRebuild(m_Parent, false, false, true, eQuickBuildFailReason::NOT_GIVEN, m_ResetTime, user->GetObjectID()); GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - - m_State = eRebuildState::REBUILD_COMPLETED; + + m_State = eRebuildState::COMPLETED; m_StateDirty = true; m_Timer = 0.0f; m_DrainedImagination = 0; @@ -465,17 +466,25 @@ void RebuildComponent::CompleteRebuild(Entity* user) { DespawnActivator(); - // Set owner override so that entities smashed by this quickbuild will result in the builder getting rewards. + // Set owner override so that entities smashed by this quickbuild will result in the builder getting rewards. m_Parent->SetOwnerOverride(user->GetObjectID()); auto* builder = GetBuilder(); - if (builder != nullptr) { - auto* missionComponent = builder->GetComponent(); - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); + if (builder) { + auto* team = TeamManager::Instance()->GetTeam(builder->GetObjectID()); + if (team) { + for (const auto memberId : team->members) { // progress missions for all team members + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) { + auto* missionComponent = member->GetComponent(); + if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId); + } + } + } else{ + auto* missionComponent = builder->GetComponent(); + if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId); } - LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1); } @@ -487,9 +496,11 @@ void RebuildComponent::CompleteRebuild(Entity* user) { // Notify subscribers for (const auto& callback : m_RebuildStateCallbacks) - callback(m_State); + callback(m_State); for (const auto& callback : m_RebuildCompleteCallbacks) - callback(user); + callback(user); + + m_Parent->TriggerEvent(eTriggerEventType::REBUILD_COMPLETE, user); auto* movingPlatform = m_Parent->GetComponent(); if (movingPlatform != nullptr) { @@ -512,48 +523,47 @@ void RebuildComponent::CompleteRebuild(Entity* user) { void RebuildComponent::ResetRebuild(bool failed) { Entity* builder = GetBuilder(); - if (m_State == eRebuildState::REBUILD_BUILDING && builder) { - GameMessages::SendEnableRebuild(m_Parent, false, false, failed, eFailReason::REASON_NOT_GIVEN, m_ResetTime, builder->GetObjectID()); + if (m_State == eRebuildState::BUILDING && builder) { + GameMessages::SendEnableRebuild(m_Parent, false, false, failed, eQuickBuildFailReason::NOT_GIVEN, m_ResetTime, builder->GetObjectID()); if (failed) { GameMessages::SendPlayAnimation(builder, u"rebuild-fail"); } } - GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_RESETTING, LWOOBJID_EMPTY); + GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::RESETTING, LWOOBJID_EMPTY); - m_State = eRebuildState::REBUILD_RESETTING; + m_State = eRebuildState::RESETTING; m_StateDirty = true; m_Timer = 0.0f; m_TimerIncomplete = 0.0f; m_ShowResetEffect = false; m_DrainedImagination = 0; - + EntityManager::Instance()->SerializeEntity(m_Parent); // Notify scripts and possible subscribers for (auto* script : CppScripts::GetEntityScripts(m_Parent)) script->OnRebuildNotifyState(m_Parent, m_State); for (const auto& cb : m_RebuildStateCallbacks) - cb(m_State); + cb(m_State); m_Parent->ScheduleKillAfterUpdate(); - if (m_Activator) - { + if (m_Activator) { m_Activator->ScheduleKillAfterUpdate(); } } -void RebuildComponent::CancelRebuild(Entity* entity, eFailReason failReason, bool skipChecks) { - if (m_State != eRebuildState::REBUILD_COMPLETED || skipChecks) { +void RebuildComponent::CancelRebuild(Entity* entity, eQuickBuildFailReason failReason, bool skipChecks) { + if (m_State != eRebuildState::COMPLETED || skipChecks) { m_Builder = LWOOBJID_EMPTY; const auto entityID = entity != nullptr ? entity->GetObjectID() : LWOOBJID_EMPTY; // Notify the client that a state has changed - GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_INCOMPLETE, entityID); + GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::INCOMPLETE, entityID); GameMessages::SendEnableRebuild(m_Parent, false, true, false, failReason, m_Timer, entityID); // Now terminate any interaction with the rebuild @@ -561,14 +571,14 @@ void RebuildComponent::CancelRebuild(Entity* entity, eFailReason failReason, boo GameMessages::SendTerminateInteraction(m_Parent->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); // Now update the component itself - m_State = eRebuildState::REBUILD_INCOMPLETE; + m_State = eRebuildState::INCOMPLETE; m_StateDirty = true; - // Notify scripts and possible subscribers - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) - script->OnRebuildNotifyState(m_Parent, m_State); - for (const auto& cb : m_RebuildStateCallbacks) - cb(m_State); + // Notify scripts and possible subscribers + for (auto* script : CppScripts::GetEntityScripts(m_Parent)) + script->OnRebuildNotifyState(m_Parent, m_State); + for (const auto& cb : m_RebuildStateCallbacks) + cb(m_State); EntityManager::Instance()->SerializeEntity(m_Parent); } @@ -579,15 +589,15 @@ void RebuildComponent::CancelRebuild(Entity* entity, eFailReason failReason, boo CharacterComponent* characterComponent = entity->GetComponent(); if (characterComponent) { - characterComponent->SetCurrentActivity(eGameActivities::ACTIVITY_NONE); + characterComponent->SetCurrentActivity(eGameActivity::NONE); EntityManager::Instance()->SerializeEntity(entity); } } void RebuildComponent::AddRebuildCompleteCallback(const std::function& callback) { - m_RebuildCompleteCallbacks.push_back(callback); + m_RebuildCompleteCallbacks.push_back(callback); } void RebuildComponent::AddRebuildStateCallback(const std::function& callback) { - m_RebuildStateCallbacks.push_back(callback); + m_RebuildStateCallbacks.push_back(callback); } diff --git a/dGame/dComponents/RebuildComponent.h b/dGame/dComponents/RebuildComponent.h index 72c57bb0..09dd0465 100644 --- a/dGame/dComponents/RebuildComponent.h +++ b/dGame/dComponents/RebuildComponent.h @@ -9,8 +9,11 @@ #include "ScriptedActivityComponent.h" #include "Preconditions.h" #include "Component.h" +#include "eReplicaComponentType.h" +#include "eRebuildState.h" class Entity; +enum class eQuickBuildFailReason : uint32_t; /** * Component that handles entities that can be built into other entities using the quick build mechanic. Generally @@ -19,343 +22,343 @@ class Entity; */ class RebuildComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_REBUILD; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::QUICK_BUILD; + RebuildComponent(Entity* entity); ~RebuildComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); void Update(float deltaTime) override; - /** - * Handles a OnUse event from some entity, initiating the quick build - * @param originator the entity that triggered the event - */ + /** + * Handles a OnUse event from some entity, initiating the quick build + * @param originator the entity that triggered the event + */ void OnUse(Entity* originator) override; - /** - * Spawns the activator that can be used to initiate the rebuild - */ + /** + * Spawns the activator that can be used to initiate the rebuild + */ void SpawnActivator(); - /** - * Despawns the activiator that can be used to initiate the rebuild - */ + /** + * Despawns the activiator that can be used to initiate the rebuild + */ void DespawnActivator(); - /** - * Returns the entity that acts as the activator for this rebuild - * @return the entity that acts as the activator for this rebuild - */ + /** + * Returns the entity that acts as the activator for this rebuild + * @return the entity that acts as the activator for this rebuild + */ Entity* GetActivator(); - /** - * Returns the spawn position of the activator for this rebuild, if any - * @return the spawn position of the activator for this rebuild, if any - */ + /** + * Returns the spawn position of the activator for this rebuild, if any + * @return the spawn position of the activator for this rebuild, if any + */ NiPoint3 GetActivatorPosition(); - /** - * Sets the spawn position for the activator of this rebuild - * @param value the spawn position to set for the activator - */ + /** + * Sets the spawn position for the activator of this rebuild + * @param value the spawn position to set for the activator + */ void SetActivatorPosition(NiPoint3 value); - /** - * Returns the time it takes for the rebuild to reset after being built - * @return the time it takes for the rebuild to reset after being built - */ + /** + * Returns the time it takes for the rebuild to reset after being built + * @return the time it takes for the rebuild to reset after being built + */ float GetResetTime(); - /** - * Sets the time it takes for the rebuild to reset after being built - * @param value the reset time to set - */ - void SetResetTime(float value); + /** + * Sets the time it takes for the rebuild to reset after being built + * @param value the reset time to set + */ + void SetResetTime(float value); - /** - * Returns the time it takes to complete the rebuild - * @return the time it takes to complete the rebuild - */ + /** + * Returns the time it takes to complete the rebuild + * @return the time it takes to complete the rebuild + */ float GetCompleteTime(); - /** - * Sets the time it takes to complete the rebuild - * @param value the completion time to set - */ - void SetCompleteTime(float value); + /** + * Sets the time it takes to complete the rebuild + * @param value the completion time to set + */ + void SetCompleteTime(float value); - /** - * Returns the imagination that's taken when completing the rebuild - * @return the imagination that's taken when completing the rebuild - */ + /** + * Returns the imagination that's taken when completing the rebuild + * @return the imagination that's taken when completing the rebuild + */ int GetTakeImagination(); - /** - * Sets the imagination that's taken when completing the rebuild - * @param value the imagination deduction to set - */ - void SetTakeImagination(int value); + /** + * Sets the imagination that's taken when completing the rebuild + * @param value the imagination deduction to set + */ + void SetTakeImagination(int value); - /** - * Returns if the rebuild can be interrupted, currently unused - * @return if the rebuild can be interrupted - */ + /** + * Returns if the rebuild can be interrupted, currently unused + * @return if the rebuild can be interrupted + */ bool GetInterruptible(); - /** - * Sets whether or not the rebuild can be interrupted, currently unused - * @param value true if the rebuild may be interrupted, false otherwise - */ - void SetInterruptible(bool value); + /** + * Sets whether or not the rebuild can be interrupted, currently unused + * @param value true if the rebuild may be interrupted, false otherwise + */ + void SetInterruptible(bool value); - /** - * Returns whether or not this entity contains a built-in activator - * @return whether or not this entity contains a built-in activator - */ + /** + * Returns whether or not this entity contains a built-in activator + * @return whether or not this entity contains a built-in activator + */ bool GetSelfActivator(); - /** - * Sets whether or not this entity contains a built-in activator. If set to false this will spawn activators on - * each new rebuild. - * @param value whether or not this entity contains a built-in activator - */ - void SetSelfActivator(bool value); + /** + * Sets whether or not this entity contains a built-in activator. If set to false this will spawn activators on + * each new rebuild. + * @param value whether or not this entity contains a built-in activator + */ + void SetSelfActivator(bool value); - /** - * Currently unused - */ + /** + * Currently unused + */ std::vector GetCustomModules(); - /** - * Currently unused - */ - void SetCustomModules(std::vector value); + /** + * Currently unused + */ + void SetCustomModules(std::vector value); - /** - * Returns the activity ID for participating in this rebuild - * @return the activity ID for participating in this rebuild - */ + /** + * Returns the activity ID for participating in this rebuild + * @return the activity ID for participating in this rebuild + */ int GetActivityId(); - /** - * Sets the activity ID for participating in this rebuild - * @param value the activity ID to set - */ - void SetActivityId(int value); + /** + * Sets the activity ID for participating in this rebuild + * @param value the activity ID to set + */ + void SetActivityId(int value); - /** - * Currently unused - */ + /** + * Currently unused + */ int GetPostImaginationCost(); - /** - * Currently unused - */ - void SetPostImaginationCost(int value); + /** + * Currently unused + */ + void SetPostImaginationCost(int value); - /** - * Returns the time it takes for an incomplete rebuild to be smashed automatically - * @return the time it takes for an incomplete rebuild to be smashed automatically - */ + /** + * Returns the time it takes for an incomplete rebuild to be smashed automatically + * @return the time it takes for an incomplete rebuild to be smashed automatically + */ float GetTimeBeforeSmash(); - /** - * Sets the time it takes for an incomplete rebuild to be smashed automatically - * @param value the time to set - */ - void SetTimeBeforeSmash(float value); + /** + * Sets the time it takes for an incomplete rebuild to be smashed automatically + * @param value the time to set + */ + void SetTimeBeforeSmash(float value); - /** - * Returns the current rebuild state - * @return the current rebuild state - */ + /** + * Returns the current rebuild state + * @return the current rebuild state + */ eRebuildState GetState(); - /** - * Returns the player that is currently building this rebuild - * @return the player that is currently building this rebuild - */ + /** + * Returns the player that is currently building this rebuild + * @return the player that is currently building this rebuild + */ Entity* GetBuilder() const; - /** - * Returns whether or not the player is repositioned when initiating the rebuild - * @return whether or not the player is repositioned when initiating the rebuild - */ + /** + * Returns whether or not the player is repositioned when initiating the rebuild + * @return whether or not the player is repositioned when initiating the rebuild + */ bool GetRepositionPlayer() const; - /** - * Sets whether or not the player is repositioned when initiating the rebuild - * @param value whether or not the player is repositioned when initiating the rebuild - */ + /** + * Sets whether or not the player is repositioned when initiating the rebuild + * @param value whether or not the player is repositioned when initiating the rebuild + */ void SetRepositionPlayer(bool value); - /** - * Adds a callback that is called when the rebuild is completed - * @param callback the callback to add - */ + /** + * Adds a callback that is called when the rebuild is completed + * @param callback the callback to add + */ void AddRebuildCompleteCallback(const std::function& callback); - /** - * Adds a callback when the rebuild state is updated - * @param callback the callback to add - */ + /** + * Adds a callback when the rebuild state is updated + * @param callback the callback to add + */ void AddRebuildStateCallback(const std::function& callback); - /** - * Resets the rebuild - * @param failed whether or not the player failed to complete the rebuild, triggers an extra animation - */ - void ResetRebuild(bool failed); + /** + * Resets the rebuild + * @param failed whether or not the player failed to complete the rebuild, triggers an extra animation + */ + void ResetRebuild(bool failed); - /** - * Cancels the rebuild if it wasn't completed - * @param builder the player that's currently building - * @param failReason the reason the rebuild was cancelled - * @param skipChecks whether or not to skip the check for the rebuild not being completed - */ - void CancelRebuild(Entity* builder, eFailReason failReason, bool skipChecks = false); + /** + * Cancels the rebuild if it wasn't completed + * @param builder the player that's currently building + * @param failReason the reason the rebuild was cancelled + * @param skipChecks whether or not to skip the check for the rebuild not being completed + */ + void CancelRebuild(Entity* builder, eQuickBuildFailReason failReason, bool skipChecks = false); private: - /** - * Whether or not the quickbuild state has been changed since we last serialized it. - */ - bool m_StateDirty = true; - - /** - * The state the rebuild is currently in - */ - eRebuildState m_State = eRebuildState::REBUILD_OPEN; + /** + * Whether or not the quickbuild state has been changed since we last serialized it. + */ + bool m_StateDirty = true; - /** - * The time that has passed since initiating the rebuild - */ + /** + * The state the rebuild is currently in + */ + eRebuildState m_State = eRebuildState::OPEN; + + /** + * The time that has passed since initiating the rebuild + */ float m_Timer = 0; - /** - * The time that has passed before completing the rebuild - */ + /** + * The time that has passed before completing the rebuild + */ float m_TimerIncomplete = 0; - /** - * The position that the rebuild activator is spawned at - */ + /** + * The position that the rebuild activator is spawned at + */ NiPoint3 m_ActivatorPosition = NiPoint3::ZERO; - /** - * The entity that represents the rebuild activator - */ + /** + * The entity that represents the rebuild activator + */ Entity* m_Activator = nullptr; - /** - * The ID of the entity that represents the rebuild activator - */ + /** + * The ID of the entity that represents the rebuild activator + */ LWOOBJID m_ActivatorId = LWOOBJID_EMPTY; - /** - * Triggers the blinking that indicates that the rebuild is resetting - */ + /** + * Triggers the blinking that indicates that the rebuild is resetting + */ bool m_ShowResetEffect = false; - /** - * Currently unused - */ + /** + * Currently unused + */ float m_Taken = 0; - /** - * The callbacks that are called when the rebuild is completed - */ - std::vector> m_RebuildCompleteCallbacks {}; + /** + * The callbacks that are called when the rebuild is completed + */ + std::vector> m_RebuildCompleteCallbacks{}; - /** - * The callbacks that are called when the rebuild state is updated - */ - std::vector> m_RebuildStateCallbacks {}; + /** + * The callbacks that are called when the rebuild state is updated + */ + std::vector> m_RebuildStateCallbacks{}; - /** - * The time it takes for the rebuild to reset after being completed - */ + /** + * The time it takes for the rebuild to reset after being completed + */ float m_ResetTime = 0; - /** - * The time it takes to complete the rebuild - */ + /** + * The time it takes to complete the rebuild + */ float m_CompleteTime = 0; - /** - * The imagination that's deducted when compeleting the rebuild - */ + /** + * The imagination that's deducted when compeleting the rebuild + */ int m_TakeImagination = 0; - /** - * Currently unused - */ + /** + * Currently unused + */ bool m_Interruptible = false; - /** - * Whether or not this rebuild entity also has an activator attached. If not a new one will be spawned - */ + /** + * Whether or not this rebuild entity also has an activator attached. If not a new one will be spawned + */ bool m_SelfActivator = false; - /** - * Currently unused - */ - std::vector m_CustomModules {}; + /** + * Currently unused + */ + std::vector m_CustomModules{}; - /** - * The activity ID that players partake in when doing this rebuild - */ + /** + * The activity ID that players partake in when doing this rebuild + */ int m_ActivityId = 0; - /** - * Currently unused - */ + /** + * Currently unused + */ int m_PostImaginationCost = 0; - /** - * The time it takes for the rebuild to reset when it's not completed yet - */ + /** + * The time it takes for the rebuild to reset when it's not completed yet + */ float m_TimeBeforeSmash = 0; - /** - * The time it takes to drain imagination - */ + /** + * The time it takes to drain imagination + */ float m_TimeBeforeDrain = 0; - /** - * The amount of imagination that was drained when building this rebuild - */ + /** + * The amount of imagination that was drained when building this rebuild + */ int m_DrainedImagination = 0; - /** - * Whether to reposition the player or not when building - */ + /** + * Whether to reposition the player or not when building + */ bool m_RepositionPlayer = true; - /** - * Currently unused - */ + /** + * Currently unused + */ float m_SoftTimer = 0; - /** - * The ID of the entity that's currently building the rebuild - */ + /** + * The ID of the entity that's currently building the rebuild + */ LWOOBJID m_Builder = LWOOBJID_EMPTY; - /** - * Preconditions to be met before being able to start the rebuild - */ + /** + * Preconditions to be met before being able to start the rebuild + */ PreconditionExpression* m_Precondition = nullptr; - /** - * Starts the rebuild for a certain entity - * @param user the entity to start the rebuild - */ + /** + * Starts the rebuild for a certain entity + * @param user the entity to start the rebuild + */ void StartRebuild(Entity* user); - /** - * Completes the rebuild for an entity, dropping loot and despawning the activator - * @param user the entity that completed the rebuild - */ + /** + * Completes the rebuild for an entity, dropping loot and despawning the activator + * @param user the entity that completed the rebuild + */ void CompleteRebuild(Entity* user); }; diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index faec4ab6..ee42acba 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -12,226 +12,215 @@ #include "Game.h" #include "dLogger.h" -std::unordered_map RenderComponent::m_DurationCache {}; +std::unordered_map RenderComponent::m_DurationCache{}; RenderComponent::RenderComponent(Entity* parent) : Component(parent) { - m_Effects = std::vector(); + m_Effects = std::vector(); - return; + return; - /* - auto* table = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + /* + auto* table = CDClientManager::Instance().GetTable(); - const auto entry = table->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_RENDER); + const auto entry = table->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::RENDER); std::stringstream query; - query << "SELECT effect1, effect2, effect3, effect4, effect5, effect6 FROM RenderComponent WHERE id = " << std::to_string(entry) << ";"; + query << "SELECT effect1, effect2, effect3, effect4, effect5, effect6 FROM RenderComponent WHERE id = " << std::to_string(entry) << ";"; - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = CDClientDatabase::ExecuteQuery(query.str()); + + if (result.eof()) + { + return; + } - if (result.eof()) - { - return; - } - for (auto i = 0; i < 6; ++i) - { + { if (result.fieldIsNull(i)) { continue; } - - const auto id = result.getIntField(i); + + const auto id = result.getIntField(i); if (id <= 0) { continue; } - - query.clear(); - query << "SELECT effectType, effectName FROM BehaviorEffect WHERE effectID = " << std::to_string(id) << ";"; + query.clear(); - auto effectResult = CDClientDatabase::ExecuteQuery(query.str()); + query << "SELECT effectType, effectName FROM BehaviorEffect WHERE effectID = " << std::to_string(id) << ";"; - while (!effectResult.eof()) - { - const auto type = effectResult.fieldIsNull(0) ? "" : std::string(effectResult.getStringField(0)); - - const auto name = effectResult.fieldIsNull(1) ? "" : std::string(effectResult.getStringField(1)); + auto effectResult = CDClientDatabase::ExecuteQuery(query.str()); - auto* effect = new Effect(); + while (!effectResult.eof()) + { + const auto type = effectResult.fieldIsNull(0) ? "" : std::string(effectResult.getStringField(0)); - effect->name = name; - effect->type = GeneralUtils::ASCIIToUTF16(type); - effect->scale = 1; - effect->effectID = id; - effect->secondary = LWOOBJID_EMPTY; - - m_Effects.push_back(effect); - - effectResult.nextRow(); - } - } + const auto name = effectResult.fieldIsNull(1) ? "" : std::string(effectResult.getStringField(1)); + + auto* effect = new Effect(); + + effect->name = name; + effect->type = GeneralUtils::ASCIIToUTF16(type); + effect->scale = 1; + effect->effectID = id; + effect->secondary = LWOOBJID_EMPTY; + + m_Effects.push_back(effect); + + effectResult.nextRow(); + } + } result.finalize(); - */ + */ } RenderComponent::~RenderComponent() { - for (Effect* eff : m_Effects) { - if (eff) { - delete eff; - eff = nullptr; - } - } - - m_Effects.clear(); + for (Effect* eff : m_Effects) { + if (eff) { + delete eff; + eff = nullptr; + } + } + + m_Effects.clear(); } void RenderComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (!bIsInitialUpdate) return; - - outBitStream->Write(m_Effects.size()); - - for (Effect* eff : m_Effects) { - // Check that the effect is non-null - assert(eff); + if (!bIsInitialUpdate) return; - outBitStream->Write(eff->name.size()); - for (const auto& value : eff->name) - outBitStream->Write(value); + outBitStream->Write(m_Effects.size()); - outBitStream->Write(eff->effectID); + for (Effect* eff : m_Effects) { + // Check that the effect is non-null + assert(eff); - outBitStream->Write(eff->type.size()); - for (const auto& value : eff->type) - outBitStream->Write(value); + outBitStream->Write(eff->name.size()); + for (const auto& value : eff->name) + outBitStream->Write(value); - outBitStream->Write(eff->scale); - outBitStream->Write(eff->secondary); - } + outBitStream->Write(eff->effectID); + + outBitStream->Write(eff->type.size()); + for (const auto& value : eff->type) + outBitStream->Write(value); + + outBitStream->Write(eff->scale); + outBitStream->Write(eff->secondary); + } } Effect* RenderComponent::AddEffect(const int32_t effectId, const std::string& name, const std::u16string& type) { - auto* eff = new Effect(); - - eff->effectID = effectId; - - eff->name = name; - - eff->type = type; - - m_Effects.push_back(eff); + auto* eff = new Effect(); - return eff; + eff->effectID = effectId; + + eff->name = name; + + eff->type = type; + + m_Effects.push_back(eff); + + return eff; } void RenderComponent::RemoveEffect(const std::string& name) { - uint32_t index = -1; + uint32_t index = -1; - for (auto i = 0u; i < m_Effects.size(); ++i) - { - auto* eff = m_Effects[i]; + for (auto i = 0u; i < m_Effects.size(); ++i) { + auto* eff = m_Effects[i]; - if (eff->name == name) - { - index = i; + if (eff->name == name) { + index = i; - delete eff; + delete eff; - break; - } - } + break; + } + } - if (index == -1) - { + if (index == -1) { return; } - - m_Effects.erase(m_Effects.begin() + index);} -void RenderComponent::Update(const float deltaTime) -{ - std::vector dead; - - for (auto* effect : m_Effects) - { - if (effect->time == 0) - { - continue; // Skip persistent effects - } - - const auto result = effect->time - deltaTime; - - if (result <= 0) - { - dead.push_back(effect); - - continue; - } - - effect->time = result; - } - - for (auto* effect : dead) - { -// StopEffect(effect->name); - } + m_Effects.erase(m_Effects.begin() + index); } -void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& effectType, const std::string& name, const LWOOBJID secondary, const float priority, const float scale, const bool serialize) -{ - RemoveEffect(name); - - GameMessages::SendPlayFXEffect(m_Parent, effectId, effectType, name, secondary, priority, scale, serialize); +void RenderComponent::Update(const float deltaTime) { + std::vector dead; - auto* effect = AddEffect(effectId, name, effectType); + for (auto* effect : m_Effects) { + if (effect->time == 0) { + continue; // Skip persistent effects + } - const auto& pair = m_DurationCache.find(effectId); + const auto result = effect->time - deltaTime; - if (pair != m_DurationCache.end()) - { - effect->time = pair->second; + if (result <= 0) { + dead.push_back(effect); - return; - } + continue; + } - const std::string effectType_str = GeneralUtils::UTF16ToWTF8(effectType); + effect->time = result; + } - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT animation_length FROM Animations WHERE animation_type IN (SELECT animationName FROM BehaviorEffect WHERE effectID = ? AND effectType = ?);"); - query.bind(1, effectId); - query.bind(2, effectType_str.c_str()); + for (auto* effect : dead) { + // StopEffect(effect->name); + } +} - auto result = query.execQuery(); +void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& effectType, const std::string& name, const LWOOBJID secondary, const float priority, const float scale, const bool serialize) { + RemoveEffect(name); - if (result.eof() || result.fieldIsNull(0)) { - result.finalize(); + GameMessages::SendPlayFXEffect(m_Parent, effectId, effectType, name, secondary, priority, scale, serialize); - m_DurationCache[effectId] = 0; + auto* effect = AddEffect(effectId, name, effectType); - effect->time = 0; // Persistent effect - - return; - } + const auto& pair = m_DurationCache.find(effectId); + + if (pair != m_DurationCache.end()) { + effect->time = pair->second; + + return; + } + + const std::string effectType_str = GeneralUtils::UTF16ToWTF8(effectType); + + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT animation_length FROM Animations WHERE animation_type IN (SELECT animationName FROM BehaviorEffect WHERE effectID = ? AND effectType = ?);"); + query.bind(1, effectId); + query.bind(2, effectType_str.c_str()); + + auto result = query.execQuery(); + + if (result.eof() || result.fieldIsNull(0)) { + result.finalize(); + + m_DurationCache[effectId] = 0; + + effect->time = 0; // Persistent effect + + return; + } + + effect->time = static_cast(result.getFloatField(0)); - effect->time = static_cast(result.getFloatField(0)); - result.finalize(); - - m_DurationCache[effectId] = effect->time; + + m_DurationCache[effectId] = effect->time; } -void RenderComponent::StopEffect(const std::string& name, const bool killImmediate) -{ - GameMessages::SendStopFXEffect(m_Parent, killImmediate, name); +void RenderComponent::StopEffect(const std::string& name, const bool killImmediate) { + GameMessages::SendStopFXEffect(m_Parent, killImmediate, name); - RemoveEffect(name); + RemoveEffect(name); } -std::vector& RenderComponent::GetEffects() -{ - return m_Effects; +std::vector& RenderComponent::GetEffects() { + return m_Effects; } diff --git a/dGame/dComponents/RenderComponent.h b/dGame/dComponents/RenderComponent.h index 5107ae7b..de8b2907 100644 --- a/dGame/dComponents/RenderComponent.h +++ b/dGame/dComponents/RenderComponent.h @@ -8,6 +8,7 @@ #include "AMFFormat.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -18,35 +19,35 @@ class Entity; struct Effect { Effect() { scale = 1.0f; } - /** - * The ID of the effect - */ - int32_t effectID = 0; + /** + * The ID of the effect + */ + int32_t effectID = 0; - /** - * The name of the effect - */ - std::string name = ""; + /** + * The name of the effect + */ + std::string name = ""; - /** - * The type of the effect - */ - std::u16string type = u""; + /** + * The type of the effect + */ + std::u16string type = u""; - /** - * How scaled (enlarged) the effect is - */ - float scale = 1.0f; + /** + * How scaled (enlarged) the effect is + */ + float scale = 1.0f; - /** - * Some related entity that casted the effect - */ - uint64_t secondary = 0; + /** + * Some related entity that casted the effect + */ + uint64_t secondary = 0; - /** - * The time that this effect plays for - */ - float time = 0; + /** + * The time that this effect plays for + */ + float time = 0; }; /** @@ -55,65 +56,65 @@ struct Effect { */ class RenderComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_RENDER; - - RenderComponent(Entity* entity); - ~RenderComponent() override; - - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + static const eReplicaComponentType ComponentType = eReplicaComponentType::RENDER; - /** - * Adds an effect to this entity, if successful the effect is returned - * @param effectId the ID of the effect - * @param name the name of the effect - * @param type the type of the effect - * @return if successful, the effect that was created - */ - Effect* AddEffect(int32_t effectId, const std::string& name, const std::u16string& type); + RenderComponent(Entity* entity); + ~RenderComponent() override; - /** - * Removes an effect for this entity - * @param name the name of the effect to remove - */ - void RemoveEffect(const std::string& name); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Update(float deltaTime) override; - /** - * Plays an effect, removes any effects under this name and plays the one according to these params - * @param effectId the ID of the effect - * @param effectType the type of the effect - * @param name the name of the effect - * @param secondary some entity that cast the effect - * @param priority effect priority (determines if the client will play it over other effects) - * @param scale effect scale - * @param serialize whether to serialize the change or not - */ - void PlayEffect(int32_t effectId, const std::u16string& effectType, const std::string& name, LWOOBJID secondary = LWOOBJID_EMPTY, float priority = 1, float scale = 1, bool serialize = true); + /** + * Adds an effect to this entity, if successful the effect is returned + * @param effectId the ID of the effect + * @param name the name of the effect + * @param type the type of the effect + * @return if successful, the effect that was created + */ + Effect* AddEffect(int32_t effectId, const std::string& name, const std::u16string& type); - /** - * Removes and stops the effect for a certain name - * @param name name of the effect to stop - * @param killImmediate whether ot not to immediately stop playing the effect or phase it out - */ - void StopEffect(const std::string& name, bool killImmediate = true); + /** + * Removes an effect for this entity + * @param name the name of the effect to remove + */ + void RemoveEffect(const std::string& name); + + /** + * Plays an effect, removes any effects under this name and plays the one according to these params + * @param effectId the ID of the effect + * @param effectType the type of the effect + * @param name the name of the effect + * @param secondary some entity that cast the effect + * @param priority effect priority (determines if the client will play it over other effects) + * @param scale effect scale + * @param serialize whether to serialize the change or not + */ + void PlayEffect(int32_t effectId, const std::u16string& effectType, const std::string& name, LWOOBJID secondary = LWOOBJID_EMPTY, float priority = 1, float scale = 1, bool serialize = true); + + /** + * Removes and stops the effect for a certain name + * @param name name of the effect to stop + * @param killImmediate whether ot not to immediately stop playing the effect or phase it out + */ + void StopEffect(const std::string& name, bool killImmediate = true); + + /** + * Returns the list of currently active effects + * @return + */ + std::vector& GetEffects(); - /** - * Returns the list of currently active effects - * @return - */ - std::vector& GetEffects(); - private: - /** - * List of currently active effects - */ - std::vector m_Effects; + /** + * List of currently active effects + */ + std::vector m_Effects; - /** - * Cache of queries that look for the length of each effect, indexed by effect ID - */ - static std::unordered_map m_DurationCache; + /** + * Cache of queries that look for the length of each effect, indexed by effect ID + */ + static std::unordered_map m_DurationCache; }; #endif // RENDERCOMPONENT_H diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp index 7a656d31..babd1974 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp @@ -7,27 +7,26 @@ #include "Entity.h" RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : Component(parent) { - m_Position = m_Parent->GetDefaultPosition(); - m_Rotation = m_Parent->GetDefaultRotation(); - m_IsDirty = true; + m_Position = m_Parent->GetDefaultPosition(); + m_Rotation = m_Parent->GetDefaultRotation(); + m_IsDirty = true; } RigidbodyPhantomPhysicsComponent::~RigidbodyPhantomPhysicsComponent() { } void RigidbodyPhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write(m_IsDirty || bIsInitialUpdate); - if (m_IsDirty || bIsInitialUpdate) - { - outBitStream->Write(m_Position.x); - outBitStream->Write(m_Position.y); - outBitStream->Write(m_Position.z); - - outBitStream->Write(m_Rotation.x); - outBitStream->Write(m_Rotation.y); - outBitStream->Write(m_Rotation.z); - outBitStream->Write(m_Rotation.w); + outBitStream->Write(m_IsDirty || bIsInitialUpdate); + if (m_IsDirty || bIsInitialUpdate) { + outBitStream->Write(m_Position.x); + outBitStream->Write(m_Position.y); + outBitStream->Write(m_Position.z); - m_IsDirty = false; - } + outBitStream->Write(m_Rotation.x); + outBitStream->Write(m_Rotation.y); + outBitStream->Write(m_Rotation.z); + outBitStream->Write(m_Rotation.w); + + m_IsDirty = false; + } } diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h index e3ef45c2..480f9b81 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h @@ -11,60 +11,61 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the - * bananas that fall from trees in GF. - */ + /** + * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the + * bananas that fall from trees in GF. + */ class RigidbodyPhantomPhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS; - - RigidbodyPhantomPhysicsComponent(Entity* parent); - ~RigidbodyPhantomPhysicsComponent() override; - - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS; - /** - * Returns the position of this entity - * @return the position of this entity - */ - NiPoint3& GetPosition() { return m_Position; } + RigidbodyPhantomPhysicsComponent(Entity* parent); + ~RigidbodyPhantomPhysicsComponent() override; - /** - * Sets the position of this entity - * @param pos the position to set - */ - void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; } + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the rotation of this entity - * @return the rotation of this entity - */ - NiQuaternion& GetRotation() { return m_Rotation; } + /** + * Returns the position of this entity + * @return the position of this entity + */ + NiPoint3& GetPosition() { return m_Position; } - /** - * Sets the rotation for this entity - * @param rot the rotation to tset - */ - void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; } + /** + * Sets the position of this entity + * @param pos the position to set + */ + void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; } + + /** + * Returns the rotation of this entity + * @return the rotation of this entity + */ + NiQuaternion& GetRotation() { return m_Rotation; } + + /** + * Sets the rotation for this entity + * @param rot the rotation to tset + */ + void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; } private: - /** - * The position of this entity - */ - NiPoint3 m_Position; + /** + * The position of this entity + */ + NiPoint3 m_Position; - /** - * The rotation of this entity - */ - NiQuaternion m_Rotation; + /** + * The rotation of this entity + */ + NiQuaternion m_Rotation; - /** - * Whether or not the component should be serialized - */ - bool m_IsDirty; + /** + * Whether or not the component should be serialized + */ + bool m_IsDirty; }; #endif // RIGIDBODYPHANTOMPHYSICS_H diff --git a/dGame/dComponents/RocketLaunchLupComponent.h b/dGame/dComponents/RocketLaunchLupComponent.h index ce915d70..226fa1b2 100644 --- a/dGame/dComponents/RocketLaunchLupComponent.h +++ b/dGame/dComponents/RocketLaunchLupComponent.h @@ -3,6 +3,7 @@ #include "Entity.h" #include "GameMessages.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles the LUP/WBL rocket launchpad that can be interacted with to travel to WBL worlds. @@ -10,7 +11,7 @@ */ class RocketLaunchLupComponent : public Component { public: - static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_ROCKET_LAUNCH_LUP; + static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH_LUP; /** * Constructor for this component, builds the m_LUPWorlds vector @@ -35,5 +36,5 @@ private: /** * vector of the LUP World Zone IDs, built from CDServer's LUPZoneIDs table */ - std::vector m_LUPWorlds {}; + std::vector m_LUPWorlds{}; }; diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.cpp b/dGame/dComponents/RocketLaunchpadControlComponent.cpp index 357fb2d0..3cac9e42 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -15,8 +15,10 @@ #include "PropertyEntranceComponent.h" #include "RocketLaunchLupComponent.h" #include "dServer.h" -#include "dMessageIdentifiers.h" #include "PacketUtils.h" +#include "eObjectWorldState.h" +#include "eConnectionType.h" +#include "eMasterMessageType.h" RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, int rocketId) : Component(parent) { auto query = CDClientDatabase::CreatePreppedStmt( @@ -25,8 +27,7 @@ RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, auto result = query.execQuery(); - if (!result.eof() && !result.fieldIsNull(0)) - { + if (!result.eof() && !result.fieldIsNull(0)) { m_TargetZone = result.getIntField(0); m_DefaultZone = result.getIntField(1); m_TargetScene = result.getStringField(2); @@ -44,8 +45,7 @@ RocketLaunchpadControlComponent::~RocketLaunchpadControlComponent() { void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, LWOCLONEID cloneId) { auto zone = mapId == LWOMAPID_INVALID ? m_TargetZone : mapId; - if (zone == 0) - { + if (zone == 0) { return; } @@ -57,7 +57,7 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, auto* rocket = characterComponent->GetRocket(originator); if (!rocket) { - Game::logger->Log("RocketLaunchpadControlComponent", "Unable to find rocket!\n"); + Game::logger->Log("RocketLaunchpadControlComponent", "Unable to find rocket!"); return; } @@ -67,8 +67,7 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, // Achievement unlocked: "All zones unlocked" if (!m_AltLandingScene.empty() && m_AltPrecondition->Check(originator)) { character->SetTargetScene(m_AltLandingScene); - } - else { + } else { character->SetTargetScene(m_TargetScene); } @@ -79,8 +78,8 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, SetSelectedMapId(originator->GetObjectID(), zone); GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID()); - - GameMessages::SendChangeObjectWorldState(rocket->GetId(), WORLDSTATE_ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendChangeObjectWorldState(rocket->GetId(), eObjectWorldState::ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); EntityManager::Instance()->SerializeEntity(originator); } @@ -112,13 +111,11 @@ void RocketLaunchpadControlComponent::OnProximityUpdate(Entity* entering, std::s // Proximity rockets are handled by item equipment } -void RocketLaunchpadControlComponent::SetSelectedMapId(LWOOBJID player, LWOMAPID mapID) -{ +void RocketLaunchpadControlComponent::SetSelectedMapId(LWOOBJID player, LWOMAPID mapID) { m_SelectedMapIds[player] = mapID; } -LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) const -{ +LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) const { const auto index = m_SelectedMapIds.find(player); if (index == m_SelectedMapIds.end()) return 0; @@ -126,13 +123,11 @@ LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) cons return index->second; } -void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId) -{ +void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId) { m_SelectedCloneIds[player] = cloneId; } -LWOCLONEID RocketLaunchpadControlComponent::GetSelectedCloneId(LWOOBJID player) const -{ +LWOCLONEID RocketLaunchpadControlComponent::GetSelectedCloneId(LWOOBJID player) const { const auto index = m_SelectedCloneIds.find(player); if (index == m_SelectedCloneIds.end()) return 0; @@ -142,18 +137,16 @@ LWOCLONEID RocketLaunchpadControlComponent::GetSelectedCloneId(LWOOBJID player) void RocketLaunchpadControlComponent::TellMasterToPrepZone(int zoneID) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_PREP_ZONE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PREP_ZONE); bitStream.Write(zoneID); Game::server->SendToMaster(&bitStream); } -LWOMAPID RocketLaunchpadControlComponent::GetTargetZone() const -{ +LWOMAPID RocketLaunchpadControlComponent::GetTargetZone() const { return m_TargetZone; } -LWOMAPID RocketLaunchpadControlComponent::GetDefaultZone() const -{ +LWOMAPID RocketLaunchpadControlComponent::GetDefaultZone() const { return m_DefaultZone; } diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.h b/dGame/dComponents/RocketLaunchpadControlComponent.h index 7fdf4b32..84cff22d 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.h +++ b/dGame/dComponents/RocketLaunchpadControlComponent.h @@ -9,6 +9,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" class PreconditionExpression; @@ -17,115 +18,115 @@ class PreconditionExpression; */ class RocketLaunchpadControlComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_ROCKET_LAUNCH; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH; + RocketLaunchpadControlComponent(Entity* parent, int rocketId); ~RocketLaunchpadControlComponent() override; - /** - * Launches some entity to another world - * @param originator the entity to launch - * @param mapId the world to go to - * @param cloneId the clone ID (for properties) - */ + /** + * Launches some entity to another world + * @param originator the entity to launch + * @param mapId the world to go to + * @param cloneId the clone ID (for properties) + */ void Launch(Entity* originator, LWOMAPID mapId = LWOMAPID_INVALID, LWOCLONEID cloneId = LWOCLONEID_INVALID); - /** - * Handles an OnUse event from some entity, preparing it for launch to some other world - * @param originator the entity that triggered the event - */ + /** + * Handles an OnUse event from some entity, preparing it for launch to some other world + * @param originator the entity that triggered the event + */ void OnUse(Entity* originator) override; - /** - * Currently unused - */ + /** + * Currently unused + */ void OnProximityUpdate(Entity* entering, std::string name, std::string status); - /** - * Sets the map ID that a player will go to - * @param player the entity to set the map ID for - * @param cloneId the map ID of the property to set - */ + /** + * Sets the map ID that a player will go to + * @param player the entity to set the map ID for + * @param cloneId the map ID of the property to set + */ void SetSelectedMapId(LWOOBJID player, LWOMAPID cloneId); - /** - * Returns the map ID that a player will go to - * @param player the player to find the map ID for - * @return the map ID that a player will go to - */ + /** + * Returns the map ID that a player will go to + * @param player the player to find the map ID for + * @return the map ID that a player will go to + */ LWOMAPID GetSelectedMapId(LWOOBJID player) const; - /** - * Sets the clone ID that a player will go to (for properties) - * @param player the entity to set the clone ID for - * @param cloneId the clone ID of the property to set - */ + /** + * Sets the clone ID that a player will go to (for properties) + * @param player the entity to set the clone ID for + * @param cloneId the clone ID of the property to set + */ void SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId); - /** - * Returns the clone ID that a player will go to (for properties) - * @param player the player to find the clone ID for - * @return the clone ID that a player will go to - */ + /** + * Returns the clone ID that a player will go to (for properties) + * @param player the player to find the clone ID for + * @return the clone ID that a player will go to + */ LWOCLONEID GetSelectedCloneId(LWOOBJID player) const; - /** - * Returns the zone that this rocket launchpad points to by default - * @return the zone that this rocket launchpad points to by default - */ + /** + * Returns the zone that this rocket launchpad points to by default + * @return the zone that this rocket launchpad points to by default + */ LWOMAPID GetTargetZone() const; - /** - * Currently unused - */ + /** + * Currently unused + */ LWOMAPID GetDefaultZone() const; private: - /** - * All the players that are in the proximity of the rocket launchpad - */ + /** + * All the players that are in the proximity of the rocket launchpad + */ std::map m_PlayersInRadius = {}; - /** - * The map that the launchpad goes to - */ + /** + * The map that the launchpad goes to + */ LWOMAPID m_TargetZone; - /** - * Currently unused - */ + /** + * Currently unused + */ LWOMAPID m_DefaultZone; - /** - * The clone IDs selected for each player to go to (for properies) - */ + /** + * The clone IDs selected for each player to go to (for properies) + */ std::map m_SelectedCloneIds = {}; - /** - * The map IDs selected for each player to go to - */ + /** + * The map IDs selected for each player to go to + */ std::map m_SelectedMapIds = {}; - /** - * The scene that plays when the player lands - */ + /** + * The scene that plays when the player lands + */ std::string m_TargetScene; - /** - * Alternative landing scene that plays if the alternative precondition is met - */ + /** + * Alternative landing scene that plays if the alternative precondition is met + */ std::string m_AltLandingScene; - /** - * Some precondition that needs to be met to trigger the alternative landing scene - */ + /** + * Some precondition that needs to be met to trigger the alternative landing scene + */ PreconditionExpression* m_AltPrecondition; - /** - * Notifies the master server to prepare some world for a player to be able to travel to it - * @param zoneID the ID of the zone to prepare - */ + /** + * Notifies the master server to prepare some world for a player to be able to travel to it + * @param zoneID the ID of the zone to prepare + */ void TellMasterToPrepZone(int zoneID); }; diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index 4d62fb0b..555332f4 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -16,31 +16,39 @@ #include "GeneralUtils.h" #include "dZoneManager.h" #include "dConfig.h" +#include "InventoryComponent.h" #include "DestroyableComponent.h" +#include "Loot.h" +#include "eMissionTaskType.h" +#include "eMatchUpdate.h" +#include "eConnectionType.h" +#include "eChatInternalMessageType.h" -ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) -{ - CDActivitiesTable* activitiesTable = CDClientManager::Instance()->GetTable("Activities"); - std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == activityID); }); +#include "CDCurrencyTableTable.h" +#include "CDActivityRewardsTable.h" +#include "CDActivitiesTable.h" +#include "LeaderboardManager.h" + +ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) { + m_ActivityID = activityID; + CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); }); for (CDActivities activity : activities) { m_ActivityInfo = activity; + if (static_cast(activity.leaderboardType) == LeaderboardType::Racing && Game::config->GetValue("solo_racing") == "1") { + m_ActivityInfo.minTeamSize = 1; + m_ActivityInfo.minTeams = 1; + } - const auto mapID = m_ActivityInfo.instanceMapID; - - if ((mapID == 1203 || mapID == 1261 || mapID == 1303 || mapID == 1403) && Game::config->GetValue("solo_racing") == "1") { - m_ActivityInfo.minTeamSize = 1; - m_ActivityInfo.minTeams = 1; - } - - const auto& transferOverride = parent->GetVar(u"transferZoneID"); - if (!transferOverride.empty()) { - m_ActivityInfo.instanceMapID = std::stoi(GeneralUtils::UTF16ToWTF8(transferOverride)); + const auto& transferOverride = parent->GetVar(u"transferZoneID"); + if (!transferOverride.empty()) { + m_ActivityInfo.instanceMapID = std::stoi(GeneralUtils::UTF16ToWTF8(transferOverride)); // TODO: LU devs made me do it (for some reason cannon cove instancer is marked to go to GF survival) // NOTE: 1301 is GF survival if (m_ActivityInfo.instanceMapID == 1301) { - m_ActivityInfo.instanceMapID = 1302; + m_ActivityInfo.instanceMapID = 1302; } } } @@ -49,7 +57,7 @@ ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activit if (destroyableComponent) { // check for LMIs and set the loot LMIs - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) {return (entry.LootMatrixIndex == destroyableComponent->GetLootMatrixID()); }); uint32_t startingLMI = 0; @@ -75,30 +83,45 @@ ScriptedActivityComponent::~ScriptedActivityComponent() = default; void ScriptedActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const { - outBitStream->Write(true); - outBitStream->Write(m_ActivityPlayers.size()); + outBitStream->Write(true); + outBitStream->Write(m_ActivityPlayers.size()); - if (!m_ActivityPlayers.empty()) { - for (const auto& activityPlayer : m_ActivityPlayers) { + if (!m_ActivityPlayers.empty()) { + for (const auto& activityPlayer : m_ActivityPlayers) { - outBitStream->Write(activityPlayer->playerID); - for (const auto& activityValue : activityPlayer->values) { - outBitStream->Write(activityValue); - } - } - } + outBitStream->Write(activityPlayer->playerID); + for (const auto& activityValue : activityPlayer->values) { + outBitStream->Write(activityValue); + } + } + } +} + +void ScriptedActivityComponent::ReloadConfig() { + CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); }); + for (auto activity : activities) { + auto mapID = m_ActivityInfo.instanceMapID; + if ((mapID == 1203 || mapID == 1261 || mapID == 1303 || mapID == 1403) && Game::config->GetValue("solo_racing") == "1") { + m_ActivityInfo.minTeamSize = 1; + m_ActivityInfo.minTeams = 1; + } else { + m_ActivityInfo.minTeamSize = activity.minTeamSize; + m_ActivityInfo.minTeams = activity.minTeams; + } + } } void ScriptedActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) { - if (m_ActivityInfo.ActivityID == 103) { - return; - } + if (m_ActivityInfo.ActivityID == 103) { + return; + } - if (id == "LobbyExit") { - PlayerLeave(player->GetObjectID()); - } else if (id == "PlayButton") { - PlayerJoin(player); - } + if (id == "LobbyExit") { + PlayerLeave(player->GetObjectID()); + } else if (id == "PlayButton") { + PlayerJoin(player); + } } void ScriptedActivityComponent::PlayerJoin(Entity* player) { @@ -108,68 +131,67 @@ void ScriptedActivityComponent::PlayerJoin(Entity* player) { // If we have a lobby, queue the player and allow others to join, otherwise spin up an instance on the spot if (HasLobby()) { - PlayerJoinLobby(player); + PlayerJoinLobby(player); } else if (!IsPlayedBy(player)) { - auto* instance = NewInstance(); - instance->AddParticipant(player); + auto* instance = NewInstance(); + instance->AddParticipant(player); } EntityManager::Instance()->SerializeEntity(m_Parent); } void ScriptedActivityComponent::PlayerJoinLobby(Entity* player) { - if (!m_Parent->HasComponent(COMPONENT_TYPE_REBUILD)) - GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby - LobbyPlayer* newLobbyPlayer = new LobbyPlayer(); - newLobbyPlayer->entityID = player->GetObjectID(); - Lobby* playerLobby = nullptr; + if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD)) + GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby + LobbyPlayer* newLobbyPlayer = new LobbyPlayer(); + newLobbyPlayer->entityID = player->GetObjectID(); + Lobby* playerLobby = nullptr; - auto* character = player->GetCharacter(); - if (character != nullptr) - character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZone()->GetWorldID()); + auto* character = player->GetCharacter(); + if (character != nullptr) + character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZone()->GetWorldID()); - for (Lobby* lobby : m_Queue) { - if (lobby->players.size() < m_ActivityInfo.maxTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() < m_ActivityInfo.maxTeams) { - // If an empty slot in an existing lobby is found - lobby->players.push_back(newLobbyPlayer); - playerLobby = lobby; + for (Lobby* lobby : m_Queue) { + if (lobby->players.size() < m_ActivityInfo.maxTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() < m_ActivityInfo.maxTeams) { + // If an empty slot in an existing lobby is found + lobby->players.push_back(newLobbyPlayer); + playerLobby = lobby; - // Update the joining player on players already in the lobby, and update players already in the lobby on the joining player - std::string matchUpdateJoined = "player=9:" + std::to_string(player->GetObjectID()) + "\nplayerName=0:" + player->GetCharacter()->GetName(); - for (LobbyPlayer* joinedPlayer : lobby->players) { - auto* entity = joinedPlayer->GetEntity(); + // Update the joining player on players already in the lobby, and update players already in the lobby on the joining player + std::string matchUpdateJoined = "player=9:" + std::to_string(player->GetObjectID()) + "\nplayerName=0:" + player->GetCharacter()->GetName(); + for (LobbyPlayer* joinedPlayer : lobby->players) { + auto* entity = joinedPlayer->GetEntity(); - if (entity == nullptr) - { - continue; - } + if (entity == nullptr) { + continue; + } - std::string matchUpdate = "player=9:" + std::to_string(entity->GetObjectID()) + "\nplayerName=0:" + entity->GetCharacter()->GetName(); - GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchUpdate, eMatchUpdate::MATCH_UPDATE_PLAYER_JOINED); - PlayerReady(entity, joinedPlayer->ready); - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateJoined, eMatchUpdate::MATCH_UPDATE_PLAYER_JOINED); - } - } - } + std::string matchUpdate = "player=9:" + std::to_string(entity->GetObjectID()) + "\nplayerName=0:" + entity->GetCharacter()->GetName(); + GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchUpdate, eMatchUpdate::PLAYER_ADDED); + PlayerReady(entity, joinedPlayer->ready); + GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateJoined, eMatchUpdate::PLAYER_ADDED); + } + } + } - if (!playerLobby) { - // If all lobbies are full - playerLobby = new Lobby(); - playerLobby->players.push_back(newLobbyPlayer); - playerLobby->timer = m_ActivityInfo.waitTime / 1000; - m_Queue.push_back(playerLobby); - } + if (!playerLobby) { + // If all lobbies are full + playerLobby = new Lobby(); + playerLobby->players.push_back(newLobbyPlayer); + playerLobby->timer = m_ActivityInfo.waitTime / 1000; + m_Queue.push_back(playerLobby); + } - if (m_ActivityInfo.maxTeamSize != 1 && playerLobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && playerLobby->players.size() >= m_ActivityInfo.minTeams) { - // Update the joining player on the match timer - std::string matchTimerUpdate = "time=3:" + std::to_string(playerLobby->timer); - GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::MATCH_UPDATE_TIME); - } + if (m_ActivityInfo.maxTeamSize != 1 && playerLobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && playerLobby->players.size() >= m_ActivityInfo.minTeams) { + // Update the joining player on the match timer + std::string matchTimerUpdate = "time=3:" + std::to_string(playerLobby->timer); + GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_READY); + } } void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { - // Removes the player from a lobby and notifies the others, not applicable for non-lobby instances + // Removes the player from a lobby and notifies the others, not applicable for non-lobby instances for (Lobby* lobby : m_Queue) { for (int i = 0; i < lobby->players.size(); ++i) { if (lobby->players[i]->entityID == playerID) { @@ -179,13 +201,13 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { if (entity == nullptr) continue; - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateLeft, eMatchUpdate::MATCH_UPDATE_PLAYER_LEFT); + GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateLeft, eMatchUpdate::PLAYER_REMOVED); } delete lobby->players[i]; lobby->players[i] = nullptr; lobby->players.erase(lobby->players.begin() + i); - + return; } } @@ -193,8 +215,8 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { } void ScriptedActivityComponent::Update(float deltaTime) { - - // Ticks all the lobbies, not applicable for non-instance activities + std::vector lobbiesToRemove{}; + // Ticks all the lobbies, not applicable for non-instance activities for (Lobby* lobby : m_Queue) { for (LobbyPlayer* player : lobby->players) { auto* entity = player->GetEntity(); @@ -204,9 +226,14 @@ void ScriptedActivityComponent::Update(float deltaTime) { } } + if (lobby->players.empty()) { + lobbiesToRemove.push_back(lobby); + continue; + } + // Update the match time for all players if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize - || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) { + || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) { if (lobby->timer == m_ActivityInfo.waitTime / 1000) { for (LobbyPlayer* joinedPlayer : lobby->players) { auto* entity = joinedPlayer->GetEntity(); @@ -215,7 +242,7 @@ void ScriptedActivityComponent::Update(float deltaTime) { continue; std::string matchTimerUpdate = "time=3:" + std::to_string(lobby->timer); - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::MATCH_UPDATE_TIME); + GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_READY); } } @@ -240,20 +267,24 @@ void ScriptedActivityComponent::Update(float deltaTime) { if (entity == nullptr) continue; - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::MATCH_UPDATE_TIME_START_DELAY); + GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate, eMatchUpdate::PHASE_WAIT_START); } } // The timer has elapsed, start the instance if (lobby->timer <= 0.0f) { - Game::logger->Log("ScriptedActivityComponent", "Setting up instance.\n"); - + Game::logger->Log("ScriptedActivityComponent", "Setting up instance."); ActivityInstance* instance = NewInstance(); LoadPlayersIntoInstance(instance, lobby->players); - RemoveLobby(lobby); instance->StartZone(); + lobbiesToRemove.push_back(lobby); } } + + while (!lobbiesToRemove.empty()) { + RemoveLobby(lobbiesToRemove.front()); + lobbiesToRemove.erase(lobbiesToRemove.begin()); + } } void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) { @@ -266,25 +297,25 @@ void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) { } bool ScriptedActivityComponent::HasLobby() const { - // If the player is not in the world he has to be, create a lobby for the transfer - return m_ActivityInfo.instanceMapID != UINT_MAX && m_ActivityInfo.instanceMapID != Game::server->GetZoneID(); + // If the player is not in the world he has to be, create a lobby for the transfer + return m_ActivityInfo.instanceMapID != UINT_MAX && m_ActivityInfo.instanceMapID != Game::server->GetZoneID(); } bool ScriptedActivityComponent::IsValidActivity(Entity* player) { - // Makes it so that scripted activities with an unimplemented map cannot be joined - /*if (player->GetGMLevel() < GAME_MASTER_LEVEL_DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { - if (m_Parent->GetLOT() == 4860) { - auto* missionComponent = player->GetComponent(); - missionComponent->CompleteMission(229); - } + // Makes it so that scripted activities with an unimplemented map cannot be joined + /*if (player->GetGMLevel() < eGameMasterLevel::DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { + if (m_Parent->GetLOT() == 4860) { + auto* missionComponent = player->GetComponent(); + missionComponent->CompleteMission(229); + } - ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Sorry, this activity is not ready."); - static_cast(player)->SendToZone(dZoneManager::Instance()->GetZone()->GetWorldID()); // Gets them out of this stuck state + ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Sorry, this activity is not ready."); + static_cast(player)->SendToZone(dZoneManager::Instance()->GetZone()->GetWorldID()); // Gets them out of this stuck state - return false; - }*/ + return false; + }*/ - return true; + return true; } bool ScriptedActivityComponent::PlayerIsInQueue(Entity* player) { @@ -298,25 +329,25 @@ bool ScriptedActivityComponent::PlayerIsInQueue(Entity* player) { } bool ScriptedActivityComponent::IsPlayedBy(Entity* player) const { - for (const auto* instance : this->m_Instances) { - for (const auto* instancePlayer : instance->GetParticipants()) { - if (instancePlayer != nullptr && instancePlayer->GetObjectID() == player->GetObjectID()) - return true; - } - } + for (const auto* instance : this->m_Instances) { + for (const auto* instancePlayer : instance->GetParticipants()) { + if (instancePlayer != nullptr && instancePlayer->GetObjectID() == player->GetObjectID()) + return true; + } + } - return false; + return false; } bool ScriptedActivityComponent::IsPlayedBy(LWOOBJID playerID) const { - for (const auto* instance : this->m_Instances) { - for (const auto* instancePlayer : instance->GetParticipants()) { - if (instancePlayer != nullptr && instancePlayer->GetObjectID() == playerID) - return true; - } - } + for (const auto* instance : this->m_Instances) { + for (const auto* instancePlayer : instance->GetParticipants()) { + if (instancePlayer != nullptr && instancePlayer->GetObjectID() == playerID) + return true; + } + } - return false; + return false; } bool ScriptedActivityComponent::TakeCost(Entity* player) const { @@ -344,8 +375,8 @@ void ScriptedActivityComponent::PlayerReady(Entity* player, bool bReady) { // Update players in lobby on player being ready std::string matchReadyUpdate = "player=9:" + std::to_string(player->GetObjectID()); - eMatchUpdate readyStatus = eMatchUpdate::MATCH_UPDATE_PLAYER_READY; - if (!bReady) readyStatus = eMatchUpdate::MATCH_UPDATE_PLAYER_UNREADY; + eMatchUpdate readyStatus = eMatchUpdate::PLAYER_READY; + if (!bReady) readyStatus = eMatchUpdate::PLAYER_NOT_READY; for (LobbyPlayer* otherPlayer : lobby->players) { auto* entity = otherPlayer->GetEntity(); if (entity == nullptr) @@ -365,14 +396,14 @@ ActivityInstance* ScriptedActivityComponent::NewInstance() { } void ScriptedActivityComponent::LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector& lobby) const { - for (LobbyPlayer* player : lobby) { - auto* entity = player->GetEntity(); - if (entity == nullptr || !TakeCost(entity)) { - continue; - } + for (LobbyPlayer* player : lobby) { + auto* entity = player->GetEntity(); + if (entity == nullptr || !TakeCost(entity)) { + continue; + } - instance->AddParticipant(entity); - } + instance->AddParticipant(entity); + } } const std::vector& ScriptedActivityComponent::GetInstances() const { @@ -380,14 +411,14 @@ const std::vector& ScriptedActivityComponent::GetInstances() } ActivityInstance* ScriptedActivityComponent::GetInstance(const LWOOBJID playerID) { - for (const auto* instance : GetInstances()) { - for (const auto* participant : instance->GetParticipants()) { - if (participant->GetObjectID() == playerID) - return const_cast(instance); - } - } + for (const auto* instance : GetInstances()) { + for (const auto* participant : instance->GetParticipants()) { + if (participant->GetObjectID() == playerID) + return const_cast(instance); + } + } - return nullptr; + return nullptr; } void ScriptedActivityComponent::ClearInstances() { @@ -397,12 +428,9 @@ void ScriptedActivityComponent::ClearInstances() { m_Instances.clear(); } -ActivityPlayer* ScriptedActivityComponent::GetActivityPlayerData(LWOOBJID playerID) -{ - for (auto* activityData : m_ActivityPlayers) - { - if (activityData->playerID == playerID) - { +ActivityPlayer* ScriptedActivityComponent::GetActivityPlayerData(LWOOBJID playerID) { + for (auto* activityData : m_ActivityPlayers) { + if (activityData->playerID == playerID) { return activityData; } } @@ -410,89 +438,85 @@ ActivityPlayer* ScriptedActivityComponent::GetActivityPlayerData(LWOOBJID player return nullptr; } -void ScriptedActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) -{ - for (size_t i = 0; i < m_ActivityPlayers.size(); i++) - { - if (m_ActivityPlayers[i]->playerID == playerID) - { +void ScriptedActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) { + for (size_t i = 0; i < m_ActivityPlayers.size(); i++) { + if (m_ActivityPlayers[i]->playerID == playerID) { delete m_ActivityPlayers[i]; m_ActivityPlayers[i] = nullptr; m_ActivityPlayers.erase(m_ActivityPlayers.begin() + i); - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); return; } } } -ActivityPlayer* ScriptedActivityComponent::AddActivityPlayerData(LWOOBJID playerID) -{ +ActivityPlayer* ScriptedActivityComponent::AddActivityPlayerData(LWOOBJID playerID) { auto* data = GetActivityPlayerData(playerID); if (data != nullptr) - return data; + return data; - m_ActivityPlayers.push_back(new ActivityPlayer{playerID, {}}); - EntityManager::Instance()->SerializeEntity(m_Parent); + m_ActivityPlayers.push_back(new ActivityPlayer{ playerID, {} }); + EntityManager::Instance()->SerializeEntity(m_Parent); return GetActivityPlayerData(playerID); } float_t ScriptedActivityComponent::GetActivityValue(LWOOBJID playerID, uint32_t index) { - auto value = -1.0f; + auto value = -1.0f; - auto* data = GetActivityPlayerData(playerID); - if (data != nullptr) { - value = data->values[std::min(index, (uint32_t) 9)]; - } + auto* data = GetActivityPlayerData(playerID); + if (data != nullptr) { + value = data->values[std::min(index, (uint32_t)9)]; + } - return value; + return value; } void ScriptedActivityComponent::SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value) { - auto* data = AddActivityPlayerData(playerID); - if (data != nullptr) { - data->values[std::min(index, (uint32_t) 9)] = value; - } + auto* data = AddActivityPlayerData(playerID); + if (data != nullptr) { + data->values[std::min(index, (uint32_t)9)] = value; + } - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); } void ScriptedActivityComponent::PlayerRemove(LWOOBJID playerID) { - for (auto* instance : GetInstances()) { - auto participants = instance->GetParticipants(); - for (const auto* participant : participants) { - if (participant != nullptr && participant->GetObjectID() == playerID) { - instance->RemoveParticipant(participant); - RemoveActivityPlayerData(playerID); + for (auto* instance : GetInstances()) { + auto participants = instance->GetParticipants(); + for (const auto* participant : participants) { + if (participant != nullptr && participant->GetObjectID() == playerID) { + instance->RemoveParticipant(participant); + RemoveActivityPlayerData(playerID); - // If the instance is empty after the delete of the participant, delete the instance too - if (instance->GetParticipants().empty()) { - m_Instances.erase(std::find(m_Instances.begin(), m_Instances.end(), instance)); - delete instance; - } - return; - } - } - } + // If the instance is empty after the delete of the participant, delete the instance too + if (instance->GetParticipants().empty()) { + m_Instances.erase(std::find(m_Instances.begin(), m_Instances.end(), instance)); + delete instance; + } + return; + } + } + } } void ActivityInstance::StartZone() { if (m_Participants.empty()) - return; + return; const auto& participants = GetParticipants(); if (participants.empty()) - return; + return; auto* leader = participants[0]; LWOZONEID zoneId = LWOZONEID(m_ActivityInfo.instanceMapID, 0, leader->GetCharacter()->GetPropertyCloneID()); // only make a team if we have more than one participant - if (participants.size() > 1){ + if (participants.size() > 1) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_CREATE_TEAM); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::CREATE_TEAM); bitStream.Write(leader->GetObjectID()); bitStream.Write(m_Participants.size()); @@ -515,7 +539,7 @@ void ActivityInstance::StartZone() { if (player == nullptr) return; - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", player->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", player->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (player->GetCharacter()) { player->GetCharacter()->SetZoneID(zoneID); player->GetCharacter()->SetZoneInstance(zoneInstance); @@ -524,27 +548,27 @@ void ActivityInstance::StartZone() { WorldPackets::SendTransferToWorld(player->GetSystemAddress(), serverIP, serverPort, mythranShift); return; - }); + }); } - + m_NextZoneCloneID++; } void ActivityInstance::RewardParticipant(Entity* participant) { auto* missionComponent = participant->GetComponent(); if (missionComponent) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityInfo.ActivityID); + missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityInfo.ActivityID); } // First, get the activity data - auto* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + auto* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); }); if (!activityRewards.empty()) { uint32_t minCoins = 0; uint32_t maxCoins = 0; - auto* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + auto* currencyTableTable = CDClientManager::Instance().GetTable(); std::vector currencyTable = currencyTableTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == activityRewards[0].CurrencyIndex && entry.npcminlevel == 1); }); if (!currencyTable.empty()) { @@ -565,31 +589,31 @@ std::vector ActivityInstance::GetParticipants() const { if (entity != nullptr) entities.push_back(entity); } - + return entities; } void ActivityInstance::AddParticipant(Entity* participant) { const auto id = participant->GetObjectID(); if (std::count(m_Participants.begin(), m_Participants.end(), id)) - return; + return; m_Participants.push_back(id); } -void ActivityInstance::RemoveParticipant(const Entity *participant) { - const auto loadedParticipant = std::find(m_Participants.begin(), m_Participants.end(), participant->GetObjectID()); - if (loadedParticipant != m_Participants.end()) { - m_Participants.erase(loadedParticipant); - } +void ActivityInstance::RemoveParticipant(const Entity* participant) { + const auto loadedParticipant = std::find(m_Participants.begin(), m_Participants.end(), participant->GetObjectID()); + if (loadedParticipant != m_Participants.end()) { + m_Participants.erase(loadedParticipant); + } } uint32_t ActivityInstance::GetScore() const { - return score; + return score; } void ActivityInstance::SetScore(uint32_t score) { - this->score = score; + this->score = score; } Entity* LobbyPlayer::GetEntity() const { diff --git a/dGame/dComponents/ScriptedActivityComponent.h b/dGame/dComponents/ScriptedActivityComponent.h index 8d79df8b..1d49a62d 100644 --- a/dGame/dComponents/ScriptedActivityComponent.h +++ b/dGame/dComponents/ScriptedActivityComponent.h @@ -11,83 +11,86 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" -/** - * Represents an instance of an activity, having participants and score - */ +#include "CDActivitiesTable.h" + + /** + * Represents an instance of an activity, having participants and score + */ class ActivityInstance { public: ActivityInstance(Entity* parent, CDActivities activityInfo) { m_Parent = parent; m_ActivityInfo = activityInfo; }; //~ActivityInstance(); - /** - * Adds an entity to this activity - * @param participant the entity to add - */ + /** + * Adds an entity to this activity + * @param participant the entity to add + */ void AddParticipant(Entity* participant); - /** - * Removes all the participants from this activity - */ + /** + * Removes all the participants from this activity + */ void ClearParticipants() { m_Participants.clear(); }; - /** - * Starts the instance world for this activity and sends all participants there - */ + /** + * Starts the instance world for this activity and sends all participants there + */ void StartZone(); - /** - * Gives the rewards for completing this activity to some participant - * @param participant the participant to give rewards to - */ + /** + * Gives the rewards for completing this activity to some participant + * @param participant the participant to give rewards to + */ void RewardParticipant(Entity* participant); - /** - * Removes a participant from this activity - * @param participant the participant to remove - */ + /** + * Removes a participant from this activity + * @param participant the participant to remove + */ void RemoveParticipant(const Entity* participant); - /** - * Returns all the participants of this activity - * @return all the participants of this activity - */ + /** + * Returns all the participants of this activity + * @return all the participants of this activity + */ std::vector GetParticipants() const; - /** - * Currently unused - */ + /** + * Currently unused + */ uint32_t GetScore() const; - /** - * Currently unused - */ + /** + * Currently unused + */ void SetScore(uint32_t score); private: - /** - * Currently unused - */ - uint32_t score = 0; + /** + * Currently unused + */ + uint32_t score = 0; - /** - * The instance ID of this activity - */ + /** + * The instance ID of this activity + */ uint32_t m_NextZoneCloneID = 0; - /** - * The database information for this activity - */ + /** + * The database information for this activity + */ CDActivities m_ActivityInfo; - /** - * The entity that owns this activity (the entity that has the ScriptedActivityComponent) - */ + /** + * The entity that owns this activity (the entity that has the ScriptedActivityComponent) + */ Entity* m_Parent; - /** - * All the participants of this activity - */ + /** + * All the participants of this activity + */ std::vector m_Participants; }; @@ -96,20 +99,20 @@ private: */ struct LobbyPlayer { - /** - * The ID of the entity that is in the lobby - */ + /** + * The ID of the entity that is in the lobby + */ LWOOBJID entityID; - /** - * Whether or not the entity is ready - */ + /** + * Whether or not the entity is ready + */ bool ready = false; - /** - * Returns the entity that is in the lobby - * @return the entity that is in the lobby - */ + /** + * Returns the entity that is in the lobby + * @return the entity that is in the lobby + */ Entity* GetEntity() const; }; @@ -118,14 +121,14 @@ struct LobbyPlayer { */ struct Lobby { - /** - * The lobby of players - */ + /** + * The lobby of players + */ std::vector players; - /** - * The timer that determines when the activity should start - */ + /** + * The timer that determines when the activity should start + */ float timer; }; @@ -134,14 +137,14 @@ struct Lobby { */ struct ActivityPlayer { - /** - * The entity that the score is tracked for - */ + /** + * The entity that the score is tracked for + */ LWOOBJID playerID; - /** - * The list of score for this entity - */ + /** + * The list of score for this entity + */ float values[10]; }; @@ -153,214 +156,226 @@ struct ActivityPlayer { */ class ScriptedActivityComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPTED_ACTIVITY; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::SCRIPTED_ACTIVITY; + ScriptedActivityComponent(Entity* parent, int activityID); ~ScriptedActivityComponent() override; - void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const; + void Update(float deltaTime) override; + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const; - /** - * Makes some entity join the minigame, if it's a lobbied one, the entity will be placed in the lobby - * @param player the entity to join the game - */ + /** + * Makes some entity join the minigame, if it's a lobbied one, the entity will be placed in the lobby + * @param player the entity to join the game + */ void PlayerJoin(Entity* player); - /** - * Makes an entity join the lobby for this minigame, if it exists - * @param player the entity to join - */ + /** + * Makes an entity join the lobby for this minigame, if it exists + * @param player the entity to join + */ void PlayerJoinLobby(Entity* player); - /** - * Makes the player leave the lobby - * @param playerID the entity to leave the lobby - */ + /** + * Makes the player leave the lobby + * @param playerID the entity to leave the lobby + */ void PlayerLeave(LWOOBJID playerID); - /** - * Removes the entity from the minigame (and its score) - * @param playerID the entity to remove from the minigame - */ + /** + * Removes the entity from the minigame (and its score) + * @param playerID the entity to remove from the minigame + */ void PlayerRemove(LWOOBJID playerID); - /** - * Adds all the players to an instance of some activity - * @param instance the instance to load the players into - * @param lobby the players to load into the instance - */ + /** + * Adds all the players to an instance of some activity + * @param instance the instance to load the players into + * @param lobby the players to load into the instance + */ void LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector& lobby) const; - /** - * Removes a lobby from the activity manager - * @param lobby the lobby to remove - */ + /** + * Removes a lobby from the activity manager + * @param lobby the lobby to remove + */ void RemoveLobby(Lobby* lobby); - /** - * Marks a player as (un)ready in a lobby - * @param player the entity to mark - * @param bReady true if the entity is ready, false otherwise - */ + /** + * Marks a player as (un)ready in a lobby + * @param player the entity to mark + * @param bReady true if the entity is ready, false otherwise + */ void PlayerReady(Entity* player, bool bReady); - /** - * Returns the ID of this activity - * @return the ID of this activity - */ + /** + * Returns the ID of this activity + * @return the ID of this activity + */ int GetActivityID() { return m_ActivityInfo.ActivityID; } - /** - * Returns if this activity has a lobby, e.g. if it needs to instance players to some other map - * @return true if this activity has a lobby, false otherwise - */ - bool HasLobby() const; + /** + * Returns if this activity has a lobby, e.g. if it needs to instance players to some other map + * @return true if this activity has a lobby, false otherwise + */ + bool HasLobby() const; - /** - * Checks if a player is currently waiting in a lobby - * @param player the entity to check for - * @return true if the entity is waiting in a lobby, false otherwise - */ + /** + * Checks if a player is currently waiting in a lobby + * @param player the entity to check for + * @return true if the entity is waiting in a lobby, false otherwise + */ bool PlayerIsInQueue(Entity* player); - /** - * Checks if an entity is currently playing this activity - * @param player the entity to check - * @return true if the entity is playing this lobby, false otherwise - */ + /** + * Checks if an entity is currently playing this activity + * @param player the entity to check + * @return true if the entity is playing this lobby, false otherwise + */ bool IsPlayedBy(Entity* player) const; - /** - * Checks if an entity is currently playing this activity - * @param playerID the entity to check - * @return true if the entity is playing this lobby, false otherwise - */ - bool IsPlayedBy(LWOOBJID playerID) const; + /** + * Checks if an entity is currently playing this activity + * @param playerID the entity to check + * @return true if the entity is playing this lobby, false otherwise + */ + bool IsPlayedBy(LWOOBJID playerID) const; - /** - * Legacy: used to check for unimplemented maps, gladly, this now just returns true :) - */ + /** + * Legacy: used to check for unimplemented maps, gladly, this now just returns true :) + */ bool IsValidActivity(Entity* player); - /** - * Removes the cost of the activity (e.g. green imaginate) for the entity that plays this activity - * @param player the entity to take cost for - * @return true if the cost was successfully deducted, false otherwise - */ + /** + * Removes the cost of the activity (e.g. green imaginate) for the entity that plays this activity + * @param player the entity to take cost for + * @return true if the cost was successfully deducted, false otherwise + */ bool TakeCost(Entity* player) const; - /** - * Handles any response from a player clicking on a lobby / instance menu - * @param player the entity that clicked - * @param id the message that was passed - */ + /** + * Handles any response from a player clicking on a lobby / instance menu + * @param player the entity that clicked + * @param id the message that was passed + */ void HandleMessageBoxResponse(Entity* player, const std::string& id); - /** - * Creates a new instance for this activity - * @return a new instance for this activity - */ + /** + * Creates a new instance for this activity + * @return a new instance for this activity + */ ActivityInstance* NewInstance(); - /** - * Returns all the currently active instances of this activity - * @return all the currently active instances of this activity - */ + /** + * Returns all the currently active instances of this activity + * @return all the currently active instances of this activity + */ const std::vector& GetInstances() const; - /** - * Returns the instance that some entity is currently playing in - * @param playerID the entity to check for - * @return if any, the instance that the entity is currently in - */ + /** + * Returns the instance that some entity is currently playing in + * @param playerID the entity to check for + * @return if any, the instance that the entity is currently in + */ ActivityInstance* GetInstance(const LWOOBJID playerID); - /** - * Removes all the instances - */ + /** + * @brief Reloads the config settings for this component + * + */ + void ReloadConfig(); + + /** + * Removes all the instances + */ void ClearInstances(); - /** - * Returns all the score for the players that are currently playing this activity - * @return - */ + /** + * Returns all the score for the players that are currently playing this activity + * @return + */ std::vector GetActivityPlayers() { return m_ActivityPlayers; }; - /** - * Returns activity data for a specific entity (e.g. score and such). - * @param playerID the entity to get data for - * @return the activity data (score) for the passed player in this activity, if it exists - */ + /** + * Returns activity data for a specific entity (e.g. score and such). + * @param playerID the entity to get data for + * @return the activity data (score) for the passed player in this activity, if it exists + */ ActivityPlayer* GetActivityPlayerData(LWOOBJID playerID); - /** - * Sets some score value for an entity - * @param playerID the entity to set score for - * @param index the score index to set - * @param value the value to set in for that index - */ + /** + * Sets some score value for an entity + * @param playerID the entity to set score for + * @param index the score index to set + * @param value the value to set in for that index + */ void SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value); - /** - * Returns activity score for the passed parameters - * @param playerID the entity to get score for - * @param index the index to get score for - * @return activity score for the passed parameters - */ + /** + * Returns activity score for the passed parameters + * @param playerID the entity to get score for + * @param index the index to get score for + * @return activity score for the passed parameters + */ float_t GetActivityValue(LWOOBJID playerID, uint32_t index); - /** - * Removes activity score tracking for some entity - * @param playerID the entity to remove score for - */ + /** + * Removes activity score tracking for some entity + * @param playerID the entity to remove score for + */ void RemoveActivityPlayerData(LWOOBJID playerID); - /** - * Adds activity score tracking for some entity - * @param playerID the entity to add the activity score for - * @return the created entry - */ + /** + * Adds activity score tracking for some entity + * @param playerID the entity to add the activity score for + * @return the created entry + */ ActivityPlayer* AddActivityPlayerData(LWOOBJID playerID); - /** - * Sets the mapID that this activity points to - * @param mapID the map ID to set - */ + /** + * Sets the mapID that this activity points to + * @param mapID the map ID to set + */ void SetInstanceMapID(uint32_t mapID) { m_ActivityInfo.instanceMapID = mapID; }; - /** - * Returns the LMI that this activity points to for a team size - * @param teamSize the team size to get the LMI for - * @return the LMI that this activity points to for a team size - */ - uint32_t GetLootMatrixForTeamSize(uint32_t teamSize) { return m_ActivityLootMatrices[teamSize]; } + /** + * Returns the LMI that this activity points to for a team size + * @param teamSize the team size to get the LMI for + * @return the LMI that this activity points to for a team size + */ + uint32_t GetLootMatrixForTeamSize(uint32_t teamSize) { return m_ActivityLootMatrices[teamSize]; } private: - /** - * The database information for this activity - */ + /** + * The database information for this activity + */ CDActivities m_ActivityInfo; - /** - * All the active instances of this activity - */ + /** + * All the active instances of this activity + */ std::vector m_Instances; - /** - * The current lobbies for this activity - */ + /** + * The current lobbies for this activity + */ std::vector m_Queue; - /** - * All the activity score for the players in this activity - */ + /** + * All the activity score for the players in this activity + */ std::vector m_ActivityPlayers; - /** - * LMIs for team sizes - */ - std::unordered_map m_ActivityLootMatrices; + /** + * LMIs for team sizes + */ + std::unordered_map m_ActivityLootMatrices; + + /** + * The activity id + * + */ + int32_t m_ActivityID; }; #endif // SCRIPTEDACTIVITYCOMPONENT_H diff --git a/dGame/dComponents/ShootingGalleryComponent.cpp b/dGame/dComponents/ShootingGalleryComponent.cpp index f0fac7f4..d5e12b28 100644 --- a/dGame/dComponents/ShootingGalleryComponent.cpp +++ b/dGame/dComponents/ShootingGalleryComponent.cpp @@ -2,66 +2,64 @@ #include "EntityManager.h" #include "ScriptedActivityComponent.h" -ShootingGalleryComponent::ShootingGalleryComponent(Entity *parent) : Component(parent) { +ShootingGalleryComponent::ShootingGalleryComponent(Entity* parent) : Component(parent) { } ShootingGalleryComponent::~ShootingGalleryComponent() = default; -void ShootingGalleryComponent::SetStaticParams(const StaticShootingGalleryParams ¶ms) { - m_StaticParams = params; +void ShootingGalleryComponent::SetStaticParams(const StaticShootingGalleryParams& params) { + m_StaticParams = params; } -void ShootingGalleryComponent::SetDynamicParams(const DynamicShootingGalleryParams ¶ms) { - m_DynamicParams = params; - m_Dirty = true; - EntityManager::Instance()->SerializeEntity(m_Parent); +void ShootingGalleryComponent::SetDynamicParams(const DynamicShootingGalleryParams& params) { + m_DynamicParams = params; + m_Dirty = true; + EntityManager::Instance()->SerializeEntity(m_Parent); } -void ShootingGalleryComponent::Serialize(RakNet::BitStream *outBitStream, bool isInitialUpdate, uint32_t& flags) const { - // Start ScriptedActivityComponent - outBitStream->Write(true); - if (m_CurrentPlayerID == LWOOBJID_EMPTY) { - outBitStream->Write(0); - } - else { - outBitStream->Write(1); - for (size_t i = 0; i < 10; i++) - { - outBitStream->Write(0.0f); - } - - } - // End ScriptedActivityComponent +void ShootingGalleryComponent::Serialize(RakNet::BitStream* outBitStream, bool isInitialUpdate, uint32_t& flags) const { + // Start ScriptedActivityComponent + outBitStream->Write(true); + if (m_CurrentPlayerID == LWOOBJID_EMPTY) { + outBitStream->Write(0); + } else { + outBitStream->Write(1); + for (size_t i = 0; i < 10; i++) { + outBitStream->Write(0.0f); + } - if (isInitialUpdate) { - outBitStream->Write(m_StaticParams.cameraPosition.GetX()); - outBitStream->Write(m_StaticParams.cameraPosition.GetY()); - outBitStream->Write(m_StaticParams.cameraPosition.GetZ()); + } + // End ScriptedActivityComponent - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetX()); - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetY()); - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetZ()); - } + if (isInitialUpdate) { + outBitStream->Write(m_StaticParams.cameraPosition.GetX()); + outBitStream->Write(m_StaticParams.cameraPosition.GetY()); + outBitStream->Write(m_StaticParams.cameraPosition.GetZ()); - outBitStream->Write(m_Dirty || isInitialUpdate); - if (m_Dirty || isInitialUpdate) { - outBitStream->Write(m_DynamicParams.cannonVelocity); - outBitStream->Write(m_DynamicParams.cannonRefireRate); - outBitStream->Write(m_DynamicParams.cannonMinDistance); + outBitStream->Write(m_StaticParams.cameraLookatPosition.GetX()); + outBitStream->Write(m_StaticParams.cameraLookatPosition.GetY()); + outBitStream->Write(m_StaticParams.cameraLookatPosition.GetZ()); + } - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetX()); - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetY()); - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetZ()); + outBitStream->Write(m_Dirty || isInitialUpdate); + if (m_Dirty || isInitialUpdate) { + outBitStream->Write(m_DynamicParams.cannonVelocity); + outBitStream->Write(m_DynamicParams.cannonRefireRate); + outBitStream->Write(m_DynamicParams.cannonMinDistance); - outBitStream->Write(m_DynamicParams.cannonAngle); + outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetX()); + outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetY()); + outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetZ()); - outBitStream->Write(m_DynamicParams.facing.GetX()); - outBitStream->Write(m_DynamicParams.facing.GetY()); - outBitStream->Write(m_DynamicParams.facing.GetZ()); + outBitStream->Write(m_DynamicParams.cannonAngle); - outBitStream->Write(m_CurrentPlayerID); - outBitStream->Write(m_DynamicParams.cannonTimeout); - outBitStream->Write(m_DynamicParams.cannonFOV); - } + outBitStream->Write(m_DynamicParams.facing.GetX()); + outBitStream->Write(m_DynamicParams.facing.GetY()); + outBitStream->Write(m_DynamicParams.facing.GetZ()); + + outBitStream->Write(m_CurrentPlayerID); + outBitStream->Write(m_DynamicParams.cannonTimeout); + outBitStream->Write(m_DynamicParams.cannonFOV); + } } diff --git a/dGame/dComponents/ShootingGalleryComponent.h b/dGame/dComponents/ShootingGalleryComponent.h index 323bf88f..c31575f1 100644 --- a/dGame/dComponents/ShootingGalleryComponent.h +++ b/dGame/dComponents/ShootingGalleryComponent.h @@ -3,51 +3,52 @@ #include "NiPoint3.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Parameters for the shooting gallery that change during playtime */ struct DynamicShootingGalleryParams { - /** - * The distance from the camera to the barrel - */ - Vector3 cameraBarrelOffset; + /** + * The distance from the camera to the barrel + */ + Vector3 cameraBarrelOffset; - /** - * The area the barrel is looking at - */ - Vector3 facing; + /** + * The area the barrel is looking at + */ + Vector3 facing; - /** - * The velocity of the cannonballs - */ - double_t cannonVelocity; + /** + * The velocity of the cannonballs + */ + double_t cannonVelocity; - /** - * The max firerate of the cannon - */ - double_t cannonRefireRate; + /** + * The max firerate of the cannon + */ + double_t cannonRefireRate; - /** - * The min distance the cannonballs traverse - */ - double_t cannonMinDistance; + /** + * The min distance the cannonballs traverse + */ + double_t cannonMinDistance; - /** - * The angle at which the cannon is shooting - */ - float_t cannonAngle; + /** + * The angle at which the cannon is shooting + */ + float_t cannonAngle; - /** - * The timeout between cannon shots - */ - float_t cannonTimeout; + /** + * The timeout between cannon shots + */ + float_t cannonTimeout; - /** - * The FOV while in the canon - */ - float_t cannonFOV; + /** + * The FOV while in the canon + */ + float_t cannonFOV; }; /** @@ -55,15 +56,15 @@ struct DynamicShootingGalleryParams { */ struct StaticShootingGalleryParams { - /** - * The position of the camera - */ - Vector3 cameraPosition; + /** + * The position of the camera + */ + Vector3 cameraPosition; - /** - * The position that the camera is looking at - */ - Vector3 cameraLookatPosition; + /** + * The position that the camera is looking at + */ + Vector3 cameraLookatPosition; }; /** @@ -72,66 +73,66 @@ struct StaticShootingGalleryParams { */ class ShootingGalleryComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SHOOTING_GALLERY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY; - explicit ShootingGalleryComponent(Entity* parent); - ~ShootingGalleryComponent(); - void Serialize(RakNet::BitStream* outBitStream, bool isInitialUpdate, uint32_t& flags) const; + explicit ShootingGalleryComponent(Entity* parent); + ~ShootingGalleryComponent(); + void Serialize(RakNet::BitStream* outBitStream, bool isInitialUpdate, uint32_t& flags) const; - /** - * Returns the static params for the shooting gallery - * @return the static params for the shooting gallery - */ - const StaticShootingGalleryParams& GetStaticParams() const { return m_StaticParams; }; + /** + * Returns the static params for the shooting gallery + * @return the static params for the shooting gallery + */ + const StaticShootingGalleryParams& GetStaticParams() const { return m_StaticParams; }; - /** - * Sets the static parameters for the shooting gallery, see `StaticShootingGalleryParams` - * @param params the params to set - */ - void SetStaticParams(const StaticShootingGalleryParams& params); + /** + * Sets the static parameters for the shooting gallery, see `StaticShootingGalleryParams` + * @param params the params to set + */ + void SetStaticParams(const StaticShootingGalleryParams& params); - /** - * Returns the dynamic params for the shooting gallery - * @return the dynamic params for the shooting gallery - */ - const DynamicShootingGalleryParams& GetDynamicParams() const { return m_DynamicParams; }; + /** + * Returns the dynamic params for the shooting gallery + * @return the dynamic params for the shooting gallery + */ + const DynamicShootingGalleryParams& GetDynamicParams() const { return m_DynamicParams; }; - /** - * Sets the mutable params for the shooting gallery, see `DynamicShootingGalleryParams` - * @param params the params to set - */ - void SetDynamicParams(const DynamicShootingGalleryParams& params); + /** + * Sets the mutable params for the shooting gallery, see `DynamicShootingGalleryParams` + * @param params the params to set + */ + void SetDynamicParams(const DynamicShootingGalleryParams& params); - /** - * Sets the entity that's currently playing the shooting gallery - * @param playerID the entity to set - */ - void SetCurrentPlayerID(LWOOBJID playerID) { m_CurrentPlayerID = playerID; m_Dirty = true; }; + /** + * Sets the entity that's currently playing the shooting gallery + * @param playerID the entity to set + */ + void SetCurrentPlayerID(LWOOBJID playerID) { m_CurrentPlayerID = playerID; m_Dirty = true; }; - /** - * Returns the player that's currently playing the shooting gallery - * @return the player that's currently playing the shooting gallery - */ - LWOOBJID GetCurrentPlayerID() const { return m_CurrentPlayerID; }; + /** + * Returns the player that's currently playing the shooting gallery + * @return the player that's currently playing the shooting gallery + */ + LWOOBJID GetCurrentPlayerID() const { return m_CurrentPlayerID; }; private: - /** - * The player that's currently playing the shooting gallery - */ - LWOOBJID m_CurrentPlayerID = LWOOBJID_EMPTY; + /** + * The player that's currently playing the shooting gallery + */ + LWOOBJID m_CurrentPlayerID = LWOOBJID_EMPTY; - /** - * The static parameters for the shooting gallery, see `StaticShootingGalleryParams` - */ - StaticShootingGalleryParams m_StaticParams {}; + /** + * The static parameters for the shooting gallery, see `StaticShootingGalleryParams` + */ + StaticShootingGalleryParams m_StaticParams{}; - /** - * The dynamic params for the shooting gallery, see `DynamicShootingGalleryParams` - */ - DynamicShootingGalleryParams m_DynamicParams {}; + /** + * The dynamic params for the shooting gallery, see `DynamicShootingGalleryParams` + */ + DynamicShootingGalleryParams m_DynamicParams{}; - /** - * Whether or not the component should be serialized - */ - bool m_Dirty = false; + /** + * Whether or not the component should be serialized + */ + bool m_Dirty = false; }; diff --git a/dGame/dComponents/SimplePhysicsComponent.cpp b/dGame/dComponents/SimplePhysicsComponent.cpp index c9a42971..54a2e616 100644 --- a/dGame/dComponents/SimplePhysicsComponent.cpp +++ b/dGame/dComponents/SimplePhysicsComponent.cpp @@ -14,70 +14,65 @@ #include "Entity.h" SimplePhysicsComponent::SimplePhysicsComponent(uint32_t componentID, Entity* parent) : Component(parent) { - m_Position = m_Parent->GetDefaultPosition(); - m_Rotation = m_Parent->GetDefaultRotation(); - m_IsDirty = true; + m_Position = m_Parent->GetDefaultPosition(); + m_Rotation = m_Parent->GetDefaultRotation(); + m_IsDirty = true; - const auto& climbable_type = m_Parent->GetVar(u"climbable"); - if (climbable_type == u"wall") { - SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL); - } else if (climbable_type == u"ladder") { - SetClimbableType(eClimbableType::CLIMBABLE_TYPE_LADDER); - } else if (climbable_type == u"wallstick") { - SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL_STICK); - } else { - SetClimbableType(eClimbableType::CLIMBABLE_TYPE_NOT); - } + const auto& climbable_type = m_Parent->GetVar(u"climbable"); + if (climbable_type == u"wall") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL); + } else if (climbable_type == u"ladder") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_LADDER); + } else if (climbable_type == u"wallstick") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL_STICK); + } else { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_NOT); + } } SimplePhysicsComponent::~SimplePhysicsComponent() { } void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (bIsInitialUpdate) { - outBitStream->Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT); - outBitStream->Write(m_ClimbableType); - } + if (bIsInitialUpdate) { + outBitStream->Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT); + outBitStream->Write(m_ClimbableType); + } - outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate); - if (m_DirtyVelocity || bIsInitialUpdate) { - outBitStream->Write(m_Velocity); - outBitStream->Write(m_AngularVelocity); + outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate); + if (m_DirtyVelocity || bIsInitialUpdate) { + outBitStream->Write(m_Velocity); + outBitStream->Write(m_AngularVelocity); - m_DirtyVelocity = false; - } + m_DirtyVelocity = false; + } - // Physics motion state - if (m_PhysicsMotionState != 0) - { - outBitStream->Write1(); - outBitStream->Write(m_PhysicsMotionState); - } - else - { - outBitStream->Write0(); - } + // Physics motion state + if (m_PhysicsMotionState != 0) { + outBitStream->Write1(); + outBitStream->Write(m_PhysicsMotionState); + } else { + outBitStream->Write0(); + } - outBitStream->Write(m_IsDirty || bIsInitialUpdate); - if (m_IsDirty || bIsInitialUpdate) { - outBitStream->Write(m_Position.x); - outBitStream->Write(m_Position.y); - outBitStream->Write(m_Position.z); - outBitStream->Write(m_Rotation.x); - outBitStream->Write(m_Rotation.y); - outBitStream->Write(m_Rotation.z); - outBitStream->Write(m_Rotation.w); + outBitStream->Write(m_IsDirty || bIsInitialUpdate); + if (m_IsDirty || bIsInitialUpdate) { + outBitStream->Write(m_Position.x); + outBitStream->Write(m_Position.y); + outBitStream->Write(m_Position.z); + outBitStream->Write(m_Rotation.x); + outBitStream->Write(m_Rotation.y); + outBitStream->Write(m_Rotation.z); + outBitStream->Write(m_Rotation.w); - m_IsDirty = false; - } + m_IsDirty = false; + } } -uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const -{ - return m_PhysicsMotionState; +uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const { + return m_PhysicsMotionState; } -void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) -{ - m_PhysicsMotionState = value; +void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) { + m_PhysicsMotionState = value; } diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index 49e6be5b..51356710 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -11,6 +11,7 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -27,72 +28,72 @@ enum class eClimbableType : int32_t { */ class SimplePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS; SimplePhysicsComponent(uint32_t componentID, Entity* parent); - ~SimplePhysicsComponent() override; + ~SimplePhysicsComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the position of this entity - * @return the position of this entity - */ - NiPoint3& GetPosition() { return m_Position; } + /** + * Returns the position of this entity + * @return the position of this entity + */ + NiPoint3& GetPosition() { return m_Position; } - /** - * Sets the position of this entity - * @param pos the position to set - */ - void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; } + /** + * Sets the position of this entity + * @param pos the position to set + */ + void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; } - /** - * Returns the rotation of this entity - * @return the rotation of this entity - */ - NiQuaternion& GetRotation() { return m_Rotation; } + /** + * Returns the rotation of this entity + * @return the rotation of this entity + */ + NiQuaternion& GetRotation() { return m_Rotation; } - /** - * Sets the rotation of this entity - * @param rot - */ - void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; } + /** + * Sets the rotation of this entity + * @param rot + */ + void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; } - /** - * Returns the velocity of this entity - * @return the velocity of this entity - */ - const NiPoint3& GetVelocity() { return m_Velocity; } + /** + * Returns the velocity of this entity + * @return the velocity of this entity + */ + const NiPoint3& GetVelocity() { return m_Velocity; } - /** - * Sets the velocity of this entity - * @param value the velocity to set - */ - void SetVelocity(const NiPoint3& value) { m_Velocity = value; m_DirtyVelocity = true; } + /** + * Sets the velocity of this entity + * @param value the velocity to set + */ + void SetVelocity(const NiPoint3& value) { m_Velocity = value; m_DirtyVelocity = true; } - /** - * Returns the angular velocity of this entity - * @return the angular velocity of this entity - */ - const NiPoint3& GetAngularVelocity() { return m_AngularVelocity; } + /** + * Returns the angular velocity of this entity + * @return the angular velocity of this entity + */ + const NiPoint3& GetAngularVelocity() { return m_AngularVelocity; } - /** - * Sets the angular velocity of this entity - * @param value the angular velocity to set - */ - void SetAngularVelocity(const NiPoint3& value) { m_AngularVelocity = value; m_DirtyVelocity = true; } + /** + * Sets the angular velocity of this entity + * @param value the angular velocity to set + */ + void SetAngularVelocity(const NiPoint3& value) { m_AngularVelocity = value; m_DirtyVelocity = true; } - /** - * Returns the physics motion state - * @return the physics motion state - */ - uint32_t GetPhysicsMotionState() const; + /** + * Returns the physics motion state + * @return the physics motion state + */ + uint32_t GetPhysicsMotionState() const; - /** - * Sets the physics motion state - * @param value the motion state to set - */ - void SetPhysicsMotionState(uint32_t value); + /** + * Sets the physics motion state + * @param value the motion state to set + */ + void SetPhysicsMotionState(uint32_t value); /** * Returns the ClimbableType of this entity @@ -108,45 +109,45 @@ public: private: - /** - * The current position of the entity - */ - NiPoint3 m_Position = NiPoint3::ZERO; + /** + * The current position of the entity + */ + NiPoint3 m_Position = NiPoint3::ZERO; - /** - * The current rotation of the entity - */ - NiQuaternion m_Rotation = NiQuaternion::IDENTITY; + /** + * The current rotation of the entity + */ + NiQuaternion m_Rotation = NiQuaternion::IDENTITY; - /** - * The current velocity of the entity - */ - NiPoint3 m_Velocity = NiPoint3::ZERO; + /** + * The current velocity of the entity + */ + NiPoint3 m_Velocity = NiPoint3::ZERO; - /** - * The current angular velocity of the entity - */ - NiPoint3 m_AngularVelocity = NiPoint3::ZERO; + /** + * The current angular velocity of the entity + */ + NiPoint3 m_AngularVelocity = NiPoint3::ZERO; - /** - * Whether or not the velocity has changed - */ - bool m_DirtyVelocity = true; + /** + * Whether or not the velocity has changed + */ + bool m_DirtyVelocity = true; - /** - * Whether or not the position has changed - */ - bool m_IsDirty = true; + /** + * Whether or not the position has changed + */ + bool m_IsDirty = true; - /** - * The current physics motion state - */ - uint32_t m_PhysicsMotionState = 0; + /** + * The current physics motion state + */ + uint32_t m_PhysicsMotionState = 0; - /** - * Whether or not the entity is climbable - */ - eClimbableType m_ClimbableType = eClimbableType::CLIMBABLE_TYPE_NOT; + /** + * Whether or not the entity is climbable + */ + eClimbableType m_ClimbableType = eClimbableType::CLIMBABLE_TYPE_NOT; }; #endif // SIMPLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index 7aa29523..c2f07425 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -19,14 +19,19 @@ #include "BaseCombatAIComponent.h" #include "ScriptComponent.h" #include "BuffComponent.h" +#include "EchoStartSkill.h" +#include "DoClientProjectileImpact.h" +#include "CDClientManager.h" +#include "CDSkillBehaviorTable.h" +#include "eConnectionType.h" +#include "eClientMessageType.h" - -ProjectileSyncEntry::ProjectileSyncEntry() -{ +ProjectileSyncEntry::ProjectileSyncEntry() { } -bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID) -{ +std::unordered_map SkillComponent::m_skillBehaviorCache = {}; + +bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID) { auto* context = new BehaviorContext(this->m_Parent->GetObjectID()); context->caster = m_Parent->GetObjectID(); @@ -46,13 +51,11 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s return !context->failed; } -void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream* bitStream) -{ +void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream* bitStream) { const auto index = this->m_managedBehaviors.find(skillUid); - if (index == this->m_managedBehaviors.end()) - { - Game::logger->Log("SkillComponent", "Failed to find skill with uid (%i)!\n", skillUid, syncId); + if (index == this->m_managedBehaviors.end()) { + Game::logger->Log("SkillComponent", "Failed to find skill with uid (%i)!", skillUid, syncId); return; } @@ -63,25 +66,21 @@ void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syn } -void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::BitStream* bitStream, const LWOOBJID target) -{ +void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::BitStream* bitStream, const LWOOBJID target) { auto index = -1; - for (auto i = 0u; i < this->m_managedProjectiles.size(); ++i) - { + for (auto i = 0u; i < this->m_managedProjectiles.size(); ++i) { const auto& projectile = this->m_managedProjectiles.at(i); - if (projectile.id == projectileId) - { + if (projectile.id == projectileId) { index = i; break; } } - if (index == -1) - { - Game::logger->Log("SkillComponent", "Failed to find projectile id (%llu)!\n", projectileId); + if (index == -1) { + Game::logger->Log("SkillComponent", "Failed to find projectile id (%llu)!", projectileId); return; } @@ -90,12 +89,12 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B auto query = CDClientDatabase::CreatePreppedStmt( "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); - query.bind(1, (int) sync_entry.lot); + query.bind(1, (int)sync_entry.lot); auto result = query.execQuery(); if (result.eof()) { - Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", sync_entry.lot); + Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!", sync_entry.lot); return; } @@ -110,8 +109,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B branch.isProjectile = true; - if (target != LWOOBJID_EMPTY) - { + if (target != LWOOBJID_EMPTY) { branch.target = target; } @@ -120,8 +118,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index); } -void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot) -{ +void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot) { ProjectileSyncEntry entry; entry.context = context; @@ -132,50 +129,43 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav this->m_managedProjectiles.push_back(entry); } -void SkillComponent::Update(const float deltaTime) -{ - if (!m_Parent->HasComponent(COMPONENT_TYPE_BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) - { +void SkillComponent::Update(const float deltaTime) { + if (!m_Parent->HasComponent(eReplicaComponentType::BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) { CalculateUpdate(deltaTime); } - std::map keep {}; + if (m_Parent->IsPlayer()) { + for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime); + } - for (const auto& pair : this->m_managedBehaviors) - { + std::map keep{}; + + for (const auto& pair : this->m_managedBehaviors) { auto* context = pair.second; - if (context == nullptr) - { + if (context == nullptr) { continue; } - if (context->clientInitalized) - { + if (context->clientInitalized) { context->CalculateUpdate(deltaTime); - } - else - { + } else { context->Update(deltaTime); } // Cleanup old behaviors - if (context->syncEntries.empty() && context->timerEntries.empty()) - { + if (context->syncEntries.empty() && context->timerEntries.empty()) { auto any = false; - for (const auto& projectile : this->m_managedProjectiles) - { - if (projectile.context == context) - { + for (const auto& projectile : this->m_managedProjectiles) { + if (projectile.context == context) { any = true; break; } } - if (!any) - { + if (!any) { context->Reset(); delete context; @@ -192,10 +182,8 @@ void SkillComponent::Update(const float deltaTime) this->m_managedBehaviors = keep; } -void SkillComponent::Reset() -{ - for (const auto& behavior : this->m_managedBehaviors) - { +void SkillComponent::Reset() { + for (const auto& behavior : this->m_managedBehaviors) { delete behavior.second; } @@ -203,26 +191,24 @@ void SkillComponent::Reset() this->m_managedBehaviors.clear(); } -void SkillComponent::Interrupt() -{ - if (m_Parent->IsPlayer()) return; - +void SkillComponent::Interrupt() { + // TODO: need to check immunities on the destroyable component, but they aren't implemented auto* combat = m_Parent->GetComponent(); + if (combat != nullptr && combat->GetStunImmune()) return; - if (combat != nullptr && combat->GetStunImmune()) - { - return; - } - - for (const auto& behavior : this->m_managedBehaviors) - { + for (const auto& behavior : this->m_managedBehaviors) { + for (const auto& behaviorEndEntry : behavior.second->endEntries) { + behaviorEndEntry.behavior->End(behavior.second, behaviorEndEntry.branchContext, behaviorEndEntry.second); + } + behavior.second->endEntries.clear(); + if (m_Parent->IsPlayer()) continue; behavior.second->Interrupt(); } + } void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot, const float maxTime, - const NiPoint3& startPosition, const NiPoint3& velocity, const bool trackTarget, const float trackRadius) -{ + const NiPoint3& startPosition, const NiPoint3& velocity, const bool trackTarget, const float trackRadius) { ProjectileSyncEntry entry; entry.context = context; @@ -241,9 +227,31 @@ void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, B this->m_managedProjectiles.push_back(entry); } +bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LWOOBJID optionalOriginatorID) { + uint32_t behaviorId = -1; + // try to find it via the cache + const auto& pair = m_skillBehaviorCache.find(skillId); -SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) -{ + // if it's not in the cache look it up and cache it + if (pair == m_skillBehaviorCache.end()) { + auto skillTable = CDClientManager::Instance().GetTable(); + behaviorId = skillTable->GetSkillByID(skillId).behaviorID; + m_skillBehaviorCache.insert_or_assign(skillId, behaviorId); + } else { + behaviorId = pair->second; + } + + // check to see if we got back a valid behavior + if (behaviorId == -1) { + Game::logger->LogDebug("SkillComponent", "Tried to cast skill %i but found no behavior", skillId); + return false; + } + + return CalculateBehavior(skillId, behaviorId, target, false, false, optionalOriginatorID).success; +} + + +SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) { auto* bitStream = new RakNet::BitStream(); auto* behavior = Behavior::CreateBehavior(behaviorId); @@ -252,18 +260,19 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c context->caster = m_Parent->GetObjectID(); + context->skillID = skillId; + context->clientInitalized = clientInitalized; context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized; - behavior->Calculate(context, bitStream, { target, 0}); + behavior->Calculate(context, bitStream, { target, 0 }); for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnSkillCast(m_Parent, skillId); + script->OnSkillCast(m_Parent, skillId); } - if (!context->foundTarget) - { + if (!context->foundTarget) { delete bitStream; delete context; @@ -273,20 +282,19 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c this->m_managedBehaviors.insert_or_assign(context->skillUId, context); - if (!clientInitalized) - { + if (!clientInitalized) { // Echo start skill - GameMessages::EchoStartSkill start; + EchoStartSkill start; start.iCastType = 0; start.skillID = skillId; start.uiSkillHandle = context->skillUId; start.optionalOriginatorID = context->originator; + start.optionalTargetID = target; auto* originator = EntityManager::Instance()->GetEntity(context->originator); - if (originator != nullptr) - { + if (originator != nullptr) { start.originatorRot = originator->GetRotation(); } //start.optionalTargetID = target; @@ -296,7 +304,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c // Write message RakNet::BitStream message; - PacketUtils::WriteHeader(message, CLIENT, MSG_CLIENT_GAME_MSG); + PacketUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); start.Serialize(&message); @@ -311,23 +319,19 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c return { true, context->skillTime }; } -void SkillComponent::CalculateUpdate(const float deltaTime) -{ - if (this->m_managedBehaviors.empty()) - return; +void SkillComponent::CalculateUpdate(const float deltaTime) { + if (this->m_managedBehaviors.empty()) + return; - for (const auto& managedBehavior : this->m_managedBehaviors) - { - if (managedBehavior.second == nullptr) - { + for (const auto& managedBehavior : this->m_managedBehaviors) { + if (managedBehavior.second == nullptr) { continue; } managedBehavior.second->CalculateUpdate(deltaTime); } - for (auto& managedProjectile : this->m_managedProjectiles) - { + for (auto& managedProjectile : this->m_managedProjectiles) { auto entry = managedProjectile; if (!entry.calculation) continue; @@ -336,8 +340,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) auto* origin = EntityManager::Instance()->GetEntity(entry.context->originator); - if (origin == nullptr) - { + if (origin == nullptr) { continue; } @@ -345,8 +348,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) const auto position = entry.startPosition + (entry.velocity * entry.time); - for (const auto& targetId : targets) - { + for (const auto& targetId : targets) { auto* target = EntityManager::Instance()->GetEntity(targetId); const auto targetPosition = target->GetPosition(); @@ -355,36 +357,8 @@ void SkillComponent::CalculateUpdate(const float deltaTime) const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint); - if (distance > 3 * 3) - { - /* - if (entry.TrackTarget && distance <= entry.TrackRadius) - { - const auto rotation = NiQuaternion::LookAtUnlocked(position, targetPosition); - - const auto speed = entry.Velocity.Length(); - - const auto homingTarget = rotation.GetForwardVector() * speed; - - Vector3 homing; - - // Move towards - - const auto difference = homingTarget - entry.Velocity; - const auto mag = difference.Length(); - if (mag <= speed || mag == 0) - { - homing = homingTarget; - } - else - { - entry.Velocity + homingTarget / mag * speed; - } - - entry.Velocity = homing; - } - */ - + if (distance > 3 * 3) { + // TODO There is supposed to be an implementation for homing projectiles here continue; } @@ -404,12 +378,9 @@ void SkillComponent::CalculateUpdate(const float deltaTime) std::vector valid; - for (auto& entry : this->m_managedProjectiles) - { - if (entry.calculation) - { - if (entry.time >= entry.maxTime) - { + for (auto& entry : this->m_managedProjectiles) { + if (entry.calculation) { + if (entry.time >= entry.maxTime) { entry.branchContext.target = LWOOBJID_EMPTY; SyncProjectileCalculation(entry); @@ -425,14 +396,12 @@ void SkillComponent::CalculateUpdate(const float deltaTime) } -void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) const -{ +void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) const { auto* other = EntityManager::Instance()->GetEntity(entry.branchContext.target); if (other == nullptr) { - if (entry.branchContext.target != LWOOBJID_EMPTY) - { - Game::logger->Log("SkillComponent", "Invalid projectile target (%llu)!\n", entry.branchContext.target); + if (entry.branchContext.target != LWOOBJID_EMPTY) { + Game::logger->Log("SkillComponent", "Invalid projectile target (%llu)!", entry.branchContext.target); } return; @@ -440,11 +409,11 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) auto query = CDClientDatabase::CreatePreppedStmt( "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); - query.bind(1, (int) entry.lot); + query.bind(1, (int)entry.lot); auto result = query.execQuery(); if (result.eof()) { - Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", entry.lot); + Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!", entry.lot); return; } @@ -459,16 +428,16 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) behavior->Calculate(entry.context, bitStream, entry.branchContext); - GameMessages::DoClientProjectileImpact projectileImpact; + DoClientProjectileImpact projectileImpact; - projectileImpact.sBitStream.assign((char*) bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); + projectileImpact.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); projectileImpact.i64OwnerID = this->m_Parent->GetObjectID(); projectileImpact.i64OrgID = entry.id; projectileImpact.i64TargetID = entry.branchContext.target; RakNet::BitStream message; - PacketUtils::WriteHeader(message, CLIENT, MSG_CLIENT_GAME_MSG); + PacketUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); projectileImpact.Serialize(&message); @@ -479,8 +448,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) delete bitStream; } -void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID target, LWOOBJID source) -{ +void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID target, LWOOBJID source) { auto* context = new BehaviorContext(source); context->unmanaged = true; @@ -497,8 +465,7 @@ void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID t delete context; } -void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) -{ +void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) { auto* context = new BehaviorContext(target); context->caster = target; @@ -510,25 +477,22 @@ void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID targ delete context; } -SkillComponent::SkillComponent(Entity* parent) : Component(parent) -{ +SkillComponent::SkillComponent(Entity* parent): Component(parent) { this->m_skillUid = 0; } -SkillComponent::~SkillComponent() -{ +SkillComponent::~SkillComponent() { Reset(); } void SkillComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (bIsInitialUpdate) outBitStream->Write0(); + if (bIsInitialUpdate) outBitStream->Write0(); } /// /// Get a unique skill ID for syncing behaviors to the client /// /// Unique skill ID -uint32_t SkillComponent::GetUniqueSkillId() -{ +uint32_t SkillComponent::GetUniqueSkillId() { return ++this->m_skillUid; } diff --git a/dGame/dComponents/SkillComponent.h b/dGame/dComponents/SkillComponent.h index ad2449c3..034e65ce 100644 --- a/dGame/dComponents/SkillComponent.h +++ b/dGame/dComponents/SkillComponent.h @@ -13,188 +13,203 @@ #include "Component.h" #include "Entity.h" #include "dLogger.h" +#include "eReplicaComponentType.h" struct ProjectileSyncEntry { - LWOOBJID id = LWOOBJID_EMPTY; + LWOOBJID id = LWOOBJID_EMPTY; - bool calculation = false; + bool calculation = false; - mutable float time = 0; + mutable float time = 0; - float maxTime = 0; + float maxTime = 0; - NiPoint3 startPosition{}; + NiPoint3 startPosition{}; - NiPoint3 lastPosition{}; + NiPoint3 lastPosition{}; - NiPoint3 velocity{}; + NiPoint3 velocity{}; - bool trackTarget = false; + bool trackTarget = false; - float trackRadius = 0; + float trackRadius = 0; - BehaviorContext* context = nullptr; + BehaviorContext* context = nullptr; - LOT lot = LOT_NULL; + LOT lot = LOT_NULL; - BehaviorBranchContext branchContext{0, 0}; + BehaviorBranchContext branchContext{ 0, 0 }; - explicit ProjectileSyncEntry(); + explicit ProjectileSyncEntry(); }; struct SkillExecutionResult { - bool success; + bool success; - float skillTime; + float skillTime; }; /** * The SkillComponent of an entity. This manages both player and AI skills, such as attacks and consumables. * There are two sets of skill methods: one for player skills and one for server-side calculations. - * + * * Skills are a built up by a tree of behaviors. See dGame/dBehaviors/ for a list of behaviors. - * + * * This system is very conveluted and still has a lot of unknowns. */ class SkillComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SKILL; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SKILL; - explicit SkillComponent(Entity* parent); - ~SkillComponent() override; + explicit SkillComponent(Entity* parent); + ~SkillComponent() override; - static void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + static void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Computes skill updates. Invokes CalculateUpdate. - */ - void Update(float deltaTime) override; + /** + * Computes skill updates. Invokes CalculateUpdate. + */ + void Update(float deltaTime) override; - /** - * Computes server-side skill updates. - */ - void CalculateUpdate(float deltaTime); + /** + * Computes server-side skill updates. + */ + void CalculateUpdate(float deltaTime); - /** - * Resets all skills, projectiles, and other calculations. - */ - void Reset(); + /** + * Resets all skills, projectiles, and other calculations. + */ + void Reset(); - /** - * Interrupts active skills. - */ - void Interrupt(); + /** + * Interrupts active skills. + */ + void Interrupt(); - /** - * Starts a player skill. Should only be called when the server receives a start skill message from the client. - * @param behaviorId the root behavior ID of the skill - * @param skillUid the unique ID of the skill given by the client - * @param bitStream the bitSteam given by the client to determine the behavior path - * @param target the explicit target of the skill - */ - bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream* bitStream, LWOOBJID target, uint32_t skillID = 0); + /** + * Starts a player skill. Should only be called when the server receives a start skill message from the client. + * @param behaviorId the root behavior ID of the skill + * @param skillUid the unique ID of the skill given by the client + * @param bitStream the bitSteam given by the client to determine the behavior path + * @param target the explicit target of the skill + */ + bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream* bitStream, LWOOBJID target, uint32_t skillID = 0); - /** - * Continues a player skill. Should only be called when the server receives a sync message from the client. - * @param skillUid the unique ID of the skill given by the client - * @param syncId the unique sync ID of the skill given by the client - * @param bitStream the bitSteam given by the client to determine the behavior path - */ - void SyncPlayerSkill(uint32_t skillUid, uint32_t syncId, RakNet::BitStream* bitStream); - - /** - * Continues a player projectile calculation. Should only be called when the server receives a projectile sync message from the client. - * @param projectileId the unique ID of the projectile given by the client - * @param bitStream the bitSteam given by the client to determine the behavior path - * @param target the explicit target of the target - */ - void SyncPlayerProjectile(LWOOBJID projectileId, RakNet::BitStream* bitStream, LWOOBJID target); + /** + * Continues a player skill. Should only be called when the server receives a sync message from the client. + * @param skillUid the unique ID of the skill given by the client + * @param syncId the unique sync ID of the skill given by the client + * @param bitStream the bitSteam given by the client to determine the behavior path + */ + void SyncPlayerSkill(uint32_t skillUid, uint32_t syncId, RakNet::BitStream* bitStream); - /** - * Registers a player projectile. Should only be called when the server is computing a player projectile. - * @param projectileId the unique ID of the projectile given by the client - * @param context the current behavior context of the active skill - * @param branch the current behavior branch context of the active skill - * @param lot the LOT of the projectile - */ - void RegisterPlayerProjectile(LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, LOT lot); + /** + * Continues a player projectile calculation. Should only be called when the server receives a projectile sync message from the client. + * @param projectileId the unique ID of the projectile given by the client + * @param bitStream the bitSteam given by the client to determine the behavior path + * @param target the explicit target of the target + */ + void SyncPlayerProjectile(LWOOBJID projectileId, RakNet::BitStream* bitStream, LWOOBJID target); - /** - * Initializes a server-side skill calculation. - * @param skillId the skill ID - * @param behaviorId the root behavior ID of the skill - * @param target the explicit target of the skill - * @param ignoreTarget continue the skill calculation even if the target is invalid or no target is found - * @param clientInitalized indicates if the skill calculation was initiated by a client skill, ignores some checks - * @param originatorOverride an override for the originator of the skill calculation - * @return the result of the skill calculation - */ - SkillExecutionResult CalculateBehavior(uint32_t skillId, uint32_t behaviorId, LWOOBJID target, bool ignoreTarget = false, bool clientInitalized = false, LWOOBJID originatorOverride = LWOOBJID_EMPTY); + /** + * Registers a player projectile. Should only be called when the server is computing a player projectile. + * @param projectileId the unique ID of the projectile given by the client + * @param context the current behavior context of the active skill + * @param branch the current behavior branch context of the active skill + * @param lot the LOT of the projectile + */ + void RegisterPlayerProjectile(LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, LOT lot); - /** - * Register a server-side projectile. - * @param projectileId the unique ID of the projectile - * @param context the current behavior context of the active skill - * @param branch the current behavior branch context of the active skill - * @param lot the LOT of the projectile - * @param maxTime the maximum travel time of the projectile - * @param startPosition the start position of the projectile - * @param velocity the velocity of the projectile - * @param trackTarget whether the projectile should track the target - * @param trackRadius the radius of the tracking circle - */ - void RegisterCalculatedProjectile( - LWOOBJID projectileId, - BehaviorContext* context, - const BehaviorBranchContext& branch, - LOT lot, - const float maxTime, - const NiPoint3& startPosition, - const NiPoint3& velocity, - bool trackTarget, - float TrackRadius); + /** + * Wrapper for CalculateBehavior that mimics the call structure in scripts and helps reduce magic numbers + * @param skillId the skill to cast + * @param target the target of the skill + * @param optionalOriginatorID change the originator of the skill + * @return if the case succeeded + */ + bool CastSkill(const uint32_t skillId, LWOOBJID target = LWOOBJID_EMPTY, const LWOOBJID optionalOriginatorID = LWOOBJID_EMPTY); - /** - * Computes a server-side skill calculation without an associated entity. - * @param behaviorId the root behavior ID of the skill - * @param target the explicit target of the skill - * @param source the explicit source of the skill - */ - static void HandleUnmanaged(uint32_t behaviorId, LWOOBJID target, LWOOBJID source = LWOOBJID_EMPTY); + /** + * Initializes a server-side skill calculation. + * @param skillId the skill ID + * @param behaviorId the root behavior ID of the skill + * @param target the explicit target of the skill + * @param ignoreTarget continue the skill calculation even if the target is invalid or no target is found + * @param clientInitalized indicates if the skill calculation was initiated by a client skill, ignores some checks + * @param originatorOverride an override for the originator of the skill calculation + * @return the result of the skill calculation + */ + SkillExecutionResult CalculateBehavior(uint32_t skillId, uint32_t behaviorId, LWOOBJID target, bool ignoreTarget = false, bool clientInitalized = false, LWOOBJID originatorOverride = LWOOBJID_EMPTY); - /** - * Computes a server-side skill uncast calculation without an associated entity. - * @param behaviorId the root behavior ID of the skill - * @param target the explicit target of the skill - */ - static void HandleUnCast(uint32_t behaviorId, LWOOBJID target); + /** + * Register a server-side projectile. + * @param projectileId the unique ID of the projectile + * @param context the current behavior context of the active skill + * @param branch the current behavior branch context of the active skill + * @param lot the LOT of the projectile + * @param maxTime the maximum travel time of the projectile + * @param startPosition the start position of the projectile + * @param velocity the velocity of the projectile + * @param trackTarget whether the projectile should track the target + * @param trackRadius the radius of the tracking circle + */ + void RegisterCalculatedProjectile( + LWOOBJID projectileId, + BehaviorContext* context, + const BehaviorBranchContext& branch, + LOT lot, + const float maxTime, + const NiPoint3& startPosition, + const NiPoint3& velocity, + bool trackTarget, + float TrackRadius); - /** - * @returns a unique ID for the next skill calculation - */ - uint32_t GetUniqueSkillId(); + /** + * Computes a server-side skill calculation without an associated entity. + * @param behaviorId the root behavior ID of the skill + * @param target the explicit target of the skill + * @param source the explicit source of the skill + */ + static void HandleUnmanaged(uint32_t behaviorId, LWOOBJID target, LWOOBJID source = LWOOBJID_EMPTY); + + /** + * Computes a server-side skill uncast calculation without an associated entity. + * @param behaviorId the root behavior ID of the skill + * @param target the explicit target of the skill + */ + static void HandleUnCast(uint32_t behaviorId, LWOOBJID target); + + /** + * @returns a unique ID for the next skill calculation + */ + uint32_t GetUniqueSkillId(); private: - /** - * All of the active skills mapped by their unique ID. - */ - std::map m_managedBehaviors; + /** + * All of the active skills mapped by their unique ID. + */ + std::map m_managedBehaviors; - /** - * All active projectiles. - */ - std::vector m_managedProjectiles; + /** + * All active projectiles. + */ + std::vector m_managedProjectiles; - /** - * Unique ID counter. - */ - uint32_t m_skillUid; + /** + * Unique ID counter. + */ + uint32_t m_skillUid; - /** - * Sync a server-side projectile calculation. - * @param entry the projectile information - */ - void SyncProjectileCalculation(const ProjectileSyncEntry& entry) const; + /** + * Cache for looking up a behavior id via a skill ID + */ + static std::unordered_map m_skillBehaviorCache; + + /** + * Sync a server-side projectile calculation. + * @param entry the projectile information + */ + void SyncProjectileCalculation(const ProjectileSyncEntry& entry) const; }; #endif // SKILLCOMPONENT_H diff --git a/dGame/dComponents/SoundTriggerComponent.cpp b/dGame/dComponents/SoundTriggerComponent.cpp index 9714eca7..be62beee 100644 --- a/dGame/dComponents/SoundTriggerComponent.cpp +++ b/dGame/dComponents/SoundTriggerComponent.cpp @@ -3,91 +3,91 @@ #include "Game.h" SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) { - const auto musicCueName = parent->GetVar(u"NDAudioMusicCue_Name"); - const auto musicCueBoredomTime = parent->GetVar(u"NDAudioMusicCue_BoredomTime"); + const auto musicCueName = parent->GetVar(u"NDAudioMusicCue_Name"); + const auto musicCueBoredomTime = parent->GetVar(u"NDAudioMusicCue_BoredomTime"); - this->musicCues.push_back({ - musicCueName, - 1, - musicCueBoredomTime - }); + this->musicCues.push_back({ + musicCueName, + 1, + musicCueBoredomTime + }); - const auto mixerName = parent->GetVar(u"NDAudioMixerProgram_Name"); - this->mixerPrograms.push_back(mixerName); + const auto mixerName = parent->GetVar(u"NDAudioMixerProgram_Name"); + this->mixerPrograms.push_back(mixerName); - const auto guid2String = parent->GetVar(u"NDAudioEventGUID2"); - if (!guid2String.empty()) { - this->guids.emplace_back(guid2String); - } + const auto guid2String = parent->GetVar(u"NDAudioEventGUID2"); + if (!guid2String.empty()) { + this->guids.emplace_back(guid2String); + } } SoundTriggerComponent::~SoundTriggerComponent() = default; -void SoundTriggerComponent::Serialize(RakNet::BitStream *outBitStream, bool bIsInitialUpdate, unsigned int &flags) { - if (bIsInitialUpdate) - dirty = true; +void SoundTriggerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + if (bIsInitialUpdate) + dirty = true; - outBitStream->Write(dirty); + outBitStream->Write(dirty); - if (dirty) { - outBitStream->Write(this->musicCues.size()); - for (const auto& musicCue : this->musicCues) { - outBitStream->Write(musicCue.name.size()); - outBitStream->Write(musicCue.name.c_str(), musicCue.name.size()); - outBitStream->Write(musicCue.result); - outBitStream->Write(musicCue.boredomTime); - } + if (dirty) { + outBitStream->Write(this->musicCues.size()); + for (const auto& musicCue : this->musicCues) { + outBitStream->Write(musicCue.name.size()); + outBitStream->Write(musicCue.name.c_str(), musicCue.name.size()); + outBitStream->Write(musicCue.result); + outBitStream->Write(musicCue.boredomTime); + } - // Unknown part - outBitStream->Write(0); + // Unknown part + outBitStream->Write(0); - // GUID part - outBitStream->Write(this->guids.size()); + // GUID part + outBitStream->Write(this->guids.size()); - for (const auto guid : this->guids) { - outBitStream->Write(guid.GetData1()); - outBitStream->Write(guid.GetData2()); - outBitStream->Write(guid.GetData3()); - for (const auto& guidSubPart : guid.GetData4()) { - outBitStream->Write(guidSubPart); - } - outBitStream->Write(1); // Unknown - } + for (const auto guid : this->guids) { + outBitStream->Write(guid.GetData1()); + outBitStream->Write(guid.GetData2()); + outBitStream->Write(guid.GetData3()); + for (const auto& guidSubPart : guid.GetData4()) { + outBitStream->Write(guidSubPart); + } + outBitStream->Write(1); // Unknown + } - // Mixer program part - outBitStream->Write(this->mixerPrograms.size()); - for (const auto& mixerProgram : mixerPrograms) { - outBitStream->Write(mixerProgram.size()); - outBitStream->Write(mixerProgram.c_str(), mixerProgram.size()); - outBitStream->Write(1); // Unknown - } + // Mixer program part + outBitStream->Write(this->mixerPrograms.size()); + for (const auto& mixerProgram : mixerPrograms) { + outBitStream->Write(mixerProgram.size()); + outBitStream->Write(mixerProgram.c_str(), mixerProgram.size()); + outBitStream->Write(1); // Unknown + } - dirty = false; - } + dirty = false; + } } void SoundTriggerComponent::ActivateMusicCue(const std::string& name) { - if (std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { - return musicCue.name == name; - }) == this->musicCues.end()) { - this->musicCues.push_back({ - name, - 1, - -1.0f - }); - dirty = true; - EntityManager::Instance()->SerializeEntity(m_Parent); - } + if (std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { + return musicCue.name == name; + }) == this->musicCues.end()) { + this->musicCues.push_back({ + name, + 1, + -1.0f + }); + dirty = true; + EntityManager::Instance()->SerializeEntity(m_Parent); + } } void SoundTriggerComponent::DeactivateMusicCue(const std::string& name) { - const auto musicCue = std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { - return musicCue.name == name; - }); + const auto musicCue = std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { + return musicCue.name == name; + }); - if (musicCue != this->musicCues.end()) { - this->musicCues.erase(musicCue); - dirty = true; - EntityManager::Instance()->SerializeEntity(m_Parent); - } + if (musicCue != this->musicCues.end()) { + this->musicCues.erase(musicCue); + dirty = true; + EntityManager::Instance()->SerializeEntity(m_Parent); + } } diff --git a/dGame/dComponents/SoundTriggerComponent.h b/dGame/dComponents/SoundTriggerComponent.h index 6f16a0dd..954d8495 100644 --- a/dGame/dComponents/SoundTriggerComponent.h +++ b/dGame/dComponents/SoundTriggerComponent.h @@ -3,14 +3,15 @@ #include "Entity.h" #include "GUID.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Music that should be played by the client */ struct MusicCue { - std::string name; - uint32_t result; - float boredomTime; + std::string name; + uint32_t result; + float boredomTime; }; /** @@ -19,40 +20,40 @@ struct MusicCue { */ class SoundTriggerComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SOUND_TRIGGER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER; - explicit SoundTriggerComponent(Entity* parent); - ~SoundTriggerComponent() override; + explicit SoundTriggerComponent(Entity* parent); + ~SoundTriggerComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Activates a music cue, making it played by any client in range - * @param name the name of the music to play - */ - void ActivateMusicCue(const std::string& name); + /** + * Activates a music cue, making it played by any client in range + * @param name the name of the music to play + */ + void ActivateMusicCue(const std::string& name); - /** - * Deactivates a music cue (if active) - * @param name name of the music to deactivate - */ - void DeactivateMusicCue(const std::string& name); + /** + * Deactivates a music cue (if active) + * @param name name of the music to deactivate + */ + void DeactivateMusicCue(const std::string& name); private: - /** - * Currently active cues - */ - std::vector musicCues = {}; + /** + * Currently active cues + */ + std::vector musicCues = {}; - /** - * Currently active mixer programs - */ - std::vector mixerPrograms = {}; + /** + * Currently active mixer programs + */ + std::vector mixerPrograms = {}; - /** - * GUID found in the LDF - */ - std::vector guids = {}; - bool dirty = false; + /** + * GUID found in the LDF + */ + std::vector guids = {}; + bool dirty = false; }; diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index fb694e30..c59559c2 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -1,5 +1,6 @@ #include "SwitchComponent.h" #include "EntityManager.h" +#include "eTriggerEventType.h" std::vector SwitchComponent::petSwitches; @@ -7,15 +8,14 @@ SwitchComponent::SwitchComponent(Entity* parent) : Component(parent) { m_Active = false; m_ResetTime = m_Parent->GetVarAs(u"switch_reset_time"); - + m_Rebuild = m_Parent->GetComponent(); } SwitchComponent::~SwitchComponent() { const auto& iterator = std::find(petSwitches.begin(), petSwitches.end(), this); - if (iterator != petSwitches.end()) - { + if (iterator != petSwitches.end()) { petSwitches.erase(iterator); } } @@ -27,107 +27,91 @@ void SwitchComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitial void SwitchComponent::SetActive(bool active) { m_Active = active; - if (m_PetBouncer != nullptr) - { + if (m_PetBouncer != nullptr) { m_PetBouncer->SetPetBouncerEnabled(active); } } -bool SwitchComponent::GetActive() const -{ +bool SwitchComponent::GetActive() const { return m_Active; } void SwitchComponent::EntityEnter(Entity* entity) { if (!m_Active) { if (m_Rebuild) { - if (m_Rebuild->GetState() != eRebuildState::REBUILD_COMPLETED) return; + if (m_Rebuild->GetState() != eRebuildState::COMPLETED) return; } m_Active = true; if (!m_Parent) return; - m_Parent->TriggerEvent("OnActivated"); + m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); - if (!grpName.empty()) - { + if (!grpName.empty()) { const auto entities = EntityManager::Instance()->GetEntitiesInGroup(grpName); - for (auto* entity : entities) - { + for (auto* entity : entities) { entity->OnFireEventServerSide(entity, "OnActivated"); } } m_Timer = m_ResetTime; - if (m_PetBouncer != nullptr) - { + if (m_PetBouncer != nullptr) { GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 2602, u"pettriggeractive", "BounceEffect", LWOOBJID_EMPTY, 1, 1, true); GameMessages::SendPlayAnimation(m_Parent, u"engaged", 0, 1); m_PetBouncer->SetPetBouncerEnabled(true); - } - else - { + } else { EntityManager::Instance()->SerializeEntity(m_Parent); } - + } } void SwitchComponent::EntityLeave(Entity* entity) { - + } void SwitchComponent::Update(float deltaTime) { if (m_Active) { m_Timer -= deltaTime; - + if (m_Timer <= 0.0f) { m_Active = false; if (!m_Parent) return; - m_Parent->TriggerEvent("OnDectivated"); - + m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent); + const auto grpName = m_Parent->GetVarAsString(u"grp_name"); - if (!grpName.empty()) - { + if (!grpName.empty()) { const auto entities = EntityManager::Instance()->GetEntitiesInGroup(grpName); - for (auto* entity : entities) - { + for (auto* entity : entities) { entity->OnFireEventServerSide(entity, "OnDectivated"); } } - if (m_PetBouncer != nullptr) - { + if (m_PetBouncer != nullptr) { m_PetBouncer->SetPetBouncerEnabled(false); - } - else - { + } else { EntityManager::Instance()->SerializeEntity(m_Parent); } } } } -Entity* SwitchComponent::GetParentEntity() const -{ +Entity* SwitchComponent::GetParentEntity() const { return m_Parent; } -SwitchComponent* SwitchComponent::GetClosestSwitch(NiPoint3 position) -{ +SwitchComponent* SwitchComponent::GetClosestSwitch(NiPoint3 position) { float closestDistance = 0; SwitchComponent* closest = nullptr; - for (SwitchComponent* petSwitch : petSwitches) - { + for (SwitchComponent* petSwitch : petSwitches) { float distance = Vector3::DistanceSquared(petSwitch->m_Parent->GetPosition(), position); - - if (closest == nullptr || distance < closestDistance) - { + + if (closest == nullptr || distance < closestDistance) { closestDistance = distance; closest = petSwitch; } @@ -137,18 +121,15 @@ SwitchComponent* SwitchComponent::GetClosestSwitch(NiPoint3 position) } -void SwitchComponent::SetPetBouncer(BouncerComponent* value) -{ +void SwitchComponent::SetPetBouncer(BouncerComponent* value) { m_PetBouncer = value; - - if (value != nullptr) - { + + if (value != nullptr) { m_PetBouncer->SetPetEnabled(true); petSwitches.push_back(this); } } -BouncerComponent* SwitchComponent::GetPetBouncer() const -{ +BouncerComponent* SwitchComponent::GetPetBouncer() const { return m_PetBouncer; } diff --git a/dGame/dComponents/SwitchComponent.h b/dGame/dComponents/SwitchComponent.h index c7ff04c2..fde3cfc0 100644 --- a/dGame/dComponents/SwitchComponent.h +++ b/dGame/dComponents/SwitchComponent.h @@ -9,19 +9,20 @@ #include "BouncerComponent.h" #include #include "Component.h" +#include "eReplicaComponentType.h" /** * A component for switches in game, including pet triggered switches. */ class SwitchComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SWITCH; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::SWITCH; + SwitchComponent(Entity* parent); ~SwitchComponent() override; void Update(float deltaTime) override; - + Entity* GetParentEntity() const; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp new file mode 100644 index 00000000..7adf47a8 --- /dev/null +++ b/dGame/dComponents/TriggerComponent.cpp @@ -0,0 +1,443 @@ +#include "TriggerComponent.h" +#include "dZoneManager.h" +#include "TeamManager.h" +#include "eTriggerCommandType.h" +#include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" + +#include "CharacterComponent.h" +#include "ControllablePhysicsComponent.h" +#include "MissionComponent.h" +#include "PhantomPhysicsComponent.h" +#include "Player.h" +#include "RebuildComponent.h" +#include "SkillComponent.h" +#include "eEndBehavior.h" + + +TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) { + m_Parent = parent; + m_Trigger = nullptr; + + std::vector tokens = GeneralUtils::SplitString(triggerInfo, ':'); + + uint32_t sceneID; + GeneralUtils::TryParse(tokens.at(0), sceneID); + uint32_t triggerID; + GeneralUtils::TryParse(tokens.at(1), triggerID); + + m_Trigger = dZoneManager::Instance()->GetZone()->GetTrigger(sceneID, triggerID); + + if (!m_Trigger) m_Trigger = new LUTriggers::Trigger(); +} + +void TriggerComponent::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) { + if (m_Trigger && m_Trigger->enabled) { + for (LUTriggers::Event* triggerEvent : m_Trigger->events) { + if (triggerEvent->id == event) { + for (LUTriggers::Command* command : triggerEvent->commands) { + HandleTriggerCommand(command, optionalTarget); + } + } + } + } +} + +void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget) { + auto argArray = GeneralUtils::SplitString(command->args, ','); + + // determine targets + std::vector targetEntities = GatherTargets(command, optionalTarget); + + // if we have no targets, then we are done + if (targetEntities.empty()) return; + + for (Entity* targetEntity : targetEntities) { + if (!targetEntity) continue; + + switch (command->id) { + case eTriggerCommandType::ZONE_PLAYER: break; + case eTriggerCommandType::FIRE_EVENT: + HandleFireEvent(targetEntity, command->args); + break; + case eTriggerCommandType::DESTROY_OBJ: + HandleDestroyObject(targetEntity, command->args); + break; + case eTriggerCommandType::TOGGLE_TRIGGER: + HandleToggleTrigger(targetEntity, command->args); + break; + case eTriggerCommandType::RESET_REBUILD: + HandleResetRebuild(targetEntity, command->args); + break; + case eTriggerCommandType::SET_PATH: break; + case eTriggerCommandType::SET_PICK_TYPE: break; + case eTriggerCommandType::MOVE_OBJECT: + HandleMoveObject(targetEntity, argArray); + break; + case eTriggerCommandType::ROTATE_OBJECT: + HandleRotateObject(targetEntity, argArray); + break; + case eTriggerCommandType::PUSH_OBJECT: + HandlePushObject(targetEntity, argArray); + break; + case eTriggerCommandType::REPEL_OBJECT: + HandleRepelObject(targetEntity, command->args); + break; + case eTriggerCommandType::SET_TIMER: + HandleSetTimer(targetEntity, argArray); + break; + case eTriggerCommandType::CANCEL_TIMER: + HandleCancelTimer(targetEntity, command->args); + break; + case eTriggerCommandType::PLAY_CINEMATIC: + HandlePlayCinematic(targetEntity, argArray); + break; + case eTriggerCommandType::TOGGLE_BBB: + HandleToggleBBB(targetEntity, command->args); + break; + case eTriggerCommandType::UPDATE_MISSION: + HandleUpdateMission(targetEntity, argArray); + break; + case eTriggerCommandType::SET_BOUNCER_STATE: break; + case eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER: break; + case eTriggerCommandType::TURN_AROUND_ON_PATH: break; + case eTriggerCommandType::GO_FORWARD_ON_PATH: break; + case eTriggerCommandType::GO_BACKWARD_ON_PATH: break; + case eTriggerCommandType::STOP_PATHING: break; + case eTriggerCommandType::START_PATHING: break; + case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break; + case eTriggerCommandType::PLAY_EFFECT: + HandlePlayEffect(targetEntity, argArray); + break; + case eTriggerCommandType::STOP_EFFECT: + GameMessages::SendStopFXEffect(targetEntity, true, command->args); + break; + case eTriggerCommandType::CAST_SKILL: + HandleCastSkill(targetEntity, command->args); + break; + case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: + GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: + HandleSetPhysicsVolumeEffect(targetEntity, argArray); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: + HandleSetPhysicsVolumeStatus(targetEntity, command->args); + break; + case eTriggerCommandType::SET_MODEL_TO_BUILD: break; + case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; + case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: + HandleActivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: + HandleDeactivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::RESET_SPAWNER_NETWORK: + HandleResetSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: + HandleDestroySpawnerNetworkObjects(command->args); + break; + case eTriggerCommandType::GO_TO_WAYPOINT: break; + case eTriggerCommandType::ACTIVATE_PHYSICS: + HandleActivatePhysics(targetEntity, command->args); + break; + // DEPRECATED BLOCK START + case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::FLASH_MUSIC_CUE: break; + case eTriggerCommandType::SET_MUSIC_PARAMETER: break; + case eTriggerCommandType::PLAY_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::PLAY_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break; + case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break; + // DEPRECATED BLOCK END + default: + Game::logger->LogDebug("TriggerComponent", "Event %i was not handled!", command->id); + break; + } + } +} + +std::vector TriggerComponent::GatherTargets(LUTriggers::Command* command, Entity* optionalTarget) { + std::vector entities = {}; + + if (command->target == "self") entities.push_back(m_Parent); + else if (command->target == "zone") { /*TODO*/ } + else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget); + else if (command->target == "targetTeam" && optionalTarget) { + auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID()); + for (const auto memberId : team->members) { + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) entities.push_back(member); + } + } else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName); + else if (command->target == "allPlayers") { + for (auto* player : Player::GetAllPlayers()) { + entities.push_back(player); + } + } else if (command->target == "allNPCs") { /*UNUSED*/ } + + return entities; +} + +void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { + script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0); + } +} + +void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){ + uint32_t killType; + GeneralUtils::TryParse(args, killType); + targetEntity->Smash(m_Parent->GetObjectID(), static_cast(killType)); +} + +void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){ + auto* triggerComponent = targetEntity->GetComponent(); + if (!triggerComponent) { + Game::logger->LogDebug("TriggerComponent::HandleToggleTrigger", "Trigger component not found!"); + return; + } + triggerComponent->SetTriggerEnabled(args == "1"); +} + +void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){ + auto* rebuildComponent = targetEntity->GetComponent(); + if (!rebuildComponent) { + Game::logger->LogDebug("TriggerComponent::HandleResetRebuild", "Rebuild component not found!"); + return; + } + rebuildComponent->ResetRebuild(args == "1"); +} + +void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector argArray){ + if (argArray.size() <= 2) return; + + auto position = targetEntity->GetPosition(); + NiPoint3 offset = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), offset); + + position += offset; + targetEntity->SetPosition(position); +} + +void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector argArray){ + if (argArray.size() <= 2) return; + + NiPoint3 vector = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), vector); + + NiQuaternion rotation = NiQuaternion::FromEulerAngles(vector); + targetEntity->SetRotation(rotation); +} + +void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector argArray){ + if (argArray.size() < 3) return; + + auto* phantomPhysicsComponent = m_Parent->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->LogDebug("TriggerComponent::HandlePushObject", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); + phantomPhysicsComponent->SetDirectionalMultiplier(1); + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), direction); + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + + +void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args){ + auto* phantomPhysicsComponent = m_Parent->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->LogDebug("TriggerComponent::HandleRepelObject", "Phantom Physics component not found!"); + return; + } + float forceMultiplier; + GeneralUtils::TryParse(args, forceMultiplier); + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::REPULSE); + phantomPhysicsComponent->SetDirectionalMultiplier(forceMultiplier); + + auto triggerPos = m_Parent->GetPosition(); + auto targetPos = targetEntity->GetPosition(); + + // normalize the vectors to get the direction + auto delta = targetPos - triggerPos; + auto length = delta.Length(); + NiPoint3 direction = delta / length; + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void TriggerComponent::HandleSetTimer(Entity* targetEntity, std::vector argArray){ + if (argArray.size() != 2) { + Game::logger->LogDebug("TriggerComponent::HandleSetTimer", "Not ehought variables!"); + return; + } + float time = 0.0; + GeneralUtils::TryParse(argArray.at(1), time); + m_Parent->AddTimer(argArray.at(0), time); +} + +void TriggerComponent::HandleCancelTimer(Entity* targetEntity, std::string args){ + m_Parent->CancelTimer(args); +} + +void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vector argArray) { + float leadIn = -1.0; + auto wait = eEndBehavior::RETURN; + bool unlock = true; + bool leaveLocked = false; + bool hidePlayer = false; + + if (argArray.size() >= 2) { + GeneralUtils::TryParse(argArray.at(1), leadIn); + if (argArray.size() >= 3 && argArray.at(2) == "wait") { + wait = eEndBehavior::WAIT; + if (argArray.size() >= 4 && argArray.at(3) == "unlock") { + unlock = false; + if (argArray.size() >= 5 && argArray.at(4) == "leavelocked") { + leaveLocked = true; + if (argArray.size() >= 6 && argArray.at(5) == "hideplayer") { + hidePlayer = true; + } + } + } + } + } + + GameMessages::SendPlayCinematic(targetEntity->GetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock); +} + +void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) { + auto* character = targetEntity->GetCharacter(); + if (!character) { + Game::logger->LogDebug("TriggerComponent::HandleToggleBBB", "Character was not found!"); + return; + } + bool buildMode = !(character->GetBuildMode()); + if (args == "enter") buildMode = true; + else if (args == "exit") buildMode = false; + character->SetBuildMode(buildMode); +} + +void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector argArray) { + // there are only explore tasks used + // If others need to be implemented for modding + // then we need a good way to convert this from a string to that enum + if (argArray.at(0) != "exploretask") return; + MissionComponent* missionComponent = targetEntity->GetComponent(); + if (!missionComponent){ + Game::logger->LogDebug("TriggerComponent::HandleUpdateMission", "Mission component not found!"); + return; + } + missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, argArray.at(4)); +} + +void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector argArray) { + if (argArray.size() < 3) return; + int32_t effectID = 0; + if (!GeneralUtils::TryParse(argArray.at(1), effectID)) return; + std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2)); + float priority = 1; + if (argArray.size() == 4) GeneralUtils::TryParse(argArray.at(3), priority); + GameMessages::SendPlayFXEffect(targetEntity, effectID, effectType, argArray.at(0), LWOOBJID_EMPTY, priority); +} + +void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args){ + auto* skillComponent = targetEntity->GetComponent(); + if (!skillComponent) { + Game::logger->LogDebug("TriggerComponent::HandleCastSkill", "Skill component not found!"); + return; + } + uint32_t skillId; + GeneralUtils::TryParse(args, skillId); + skillComponent->CastSkill(skillId, targetEntity->GetObjectID()); +} + +void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector argArray) { + auto* phantomPhysicsComponent = targetEntity->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->LogDebug("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + ePhysicsEffectType effectType = ePhysicsEffectType::PUSH; + std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase + if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH; + else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT; + else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE; + else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE; + else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION; + + phantomPhysicsComponent->SetEffectType(effectType); + phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1))); + if (argArray.size() > 4) { + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), direction); + phantomPhysicsComponent->SetDirection(direction); + } + if (argArray.size() > 5) { + uint32_t min; + GeneralUtils::TryParse(argArray.at(6), min); + phantomPhysicsComponent->SetMin(min); + + uint32_t max; + GeneralUtils::TryParse(argArray.at(7), max); + phantomPhysicsComponent->SetMax(max); + } + + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args) { + auto* phantomPhysicsComponent = targetEntity->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->LogDebug("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(args == "On"); + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Activate(); + } +} + +void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Deactivate(); + } +} + +void TriggerComponent::HandleResetSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Reset(); + } +} + +void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->DestroyAllEntities(); + } +} + +void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) { + if (args == "true") { + // TODO add physics entity if there isn't one + } else if (args == "false"){ + // TODO remove Phsyics entity if there is one + } else { + Game::logger->LogDebug("TriggerComponent", "Invalid argument for ActivatePhysics Trigger: %s", args.c_str()); + } +} diff --git a/dGame/dComponents/TriggerComponent.h b/dGame/dComponents/TriggerComponent.h new file mode 100644 index 00000000..df65707f --- /dev/null +++ b/dGame/dComponents/TriggerComponent.h @@ -0,0 +1,50 @@ +#ifndef __TRIGGERCOMPONENT__H__ +#define __TRIGGERCOMPONENT__H__ + +#include "Component.h" +#include "LUTriggers.h" +#include "eReplicaComponentType.h" + +class TriggerComponent : public Component { +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::TRIGGER; + + explicit TriggerComponent(Entity* parent, const std::string triggerInfo); + + void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr); + LUTriggers::Trigger* GetTrigger() const { return m_Trigger; } + void SetTriggerEnabled(bool enabled){ m_Trigger->enabled = enabled; }; + + +private: + + void HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget); + std::vector GatherTargets(LUTriggers::Command* command, Entity* optionalTarget); + + // Trigger Event Handlers + void HandleFireEvent(Entity* targetEntity, std::string args); + void HandleDestroyObject(Entity* targetEntity, std::string args); + void HandleToggleTrigger(Entity* targetEntity, std::string args); + void HandleResetRebuild(Entity* targetEntity, std::string args); + void HandleMoveObject(Entity* targetEntity, std::vector argArray); + void HandleRotateObject(Entity* targetEntity, std::vector argArray); + void HandlePushObject(Entity* targetEntity, std::vector argArray); + void HandleRepelObject(Entity* targetEntity, std::string args); + void HandleSetTimer(Entity* targetEntity, std::vector argArray); + void HandleCancelTimer(Entity* targetEntity, std::string args); + void HandlePlayCinematic(Entity* targetEntity, std::vector argArray); + void HandleToggleBBB(Entity* targetEntity, std::string args); + void HandleUpdateMission(Entity* targetEntity, std::vector argArray); + void HandlePlayEffect(Entity* targetEntity, std::vector argArray); + void HandleCastSkill(Entity* targetEntity, std::string args); + void HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector argArray); + void HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args); + void HandleActivateSpawnerNetwork(std::string args); + void HandleDeactivateSpawnerNetwork(std::string args); + void HandleResetSpawnerNetwork(std::string args); + void HandleDestroySpawnerNetworkObjects(std::string args); + void HandleActivatePhysics(Entity* targetEntity, std::string args); + + LUTriggers::Trigger* m_Trigger; +}; +#endif //!__TRIGGERCOMPONENT__H__ diff --git a/dGame/dComponents/VehiclePhysicsComponent.cpp b/dGame/dComponents/VehiclePhysicsComponent.cpp index dc6dcf1a..d981acf7 100644 --- a/dGame/dComponents/VehiclePhysicsComponent.cpp +++ b/dGame/dComponents/VehiclePhysicsComponent.cpp @@ -1,8 +1,7 @@ #include "VehiclePhysicsComponent.h" #include "EntityManager.h" -VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : Component(parent) -{ +VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : Component(parent) { m_Position = NiPoint3::ZERO; m_Rotation = NiQuaternion::IDENTITY; m_Velocity = NiPoint3::ZERO; @@ -12,121 +11,102 @@ VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : Component(par m_DirtyPosition = true; m_DirtyVelocity = true; m_DirtyAngularVelocity = true; + m_EndBehavior = GeneralUtils::GenerateRandomNumber(0, 7); } -VehiclePhysicsComponent::~VehiclePhysicsComponent() -{ - +VehiclePhysicsComponent::~VehiclePhysicsComponent() { + } -void VehiclePhysicsComponent::SetPosition(const NiPoint3& pos) -{ - m_Position = pos; +void VehiclePhysicsComponent::SetPosition(const NiPoint3& pos) { + m_Position = pos; } -void VehiclePhysicsComponent::SetRotation(const NiQuaternion& rot) -{ +void VehiclePhysicsComponent::SetRotation(const NiQuaternion& rot) { m_DirtyPosition = true; - m_Rotation = rot; + m_Rotation = rot; } -void VehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) -{ +void VehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) { m_DirtyPosition = true; - m_Velocity = vel; + m_Velocity = vel; } -void VehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) -{ +void VehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) { m_DirtyPosition = true; - m_AngularVelocity = vel; + m_AngularVelocity = vel; } -void VehiclePhysicsComponent::SetIsOnGround(bool val) -{ +void VehiclePhysicsComponent::SetIsOnGround(bool val) { m_DirtyPosition = true; - m_IsOnGround = val; + m_IsOnGround = val; } -void VehiclePhysicsComponent::SetIsOnRail(bool val) -{ +void VehiclePhysicsComponent::SetIsOnRail(bool val) { m_DirtyPosition = true; - m_IsOnRail = val; + m_IsOnRail = val; } -void VehiclePhysicsComponent::SetDirtyPosition(bool val) -{ - m_DirtyPosition = val; +void VehiclePhysicsComponent::SetDirtyPosition(bool val) { + m_DirtyPosition = val; } -void VehiclePhysicsComponent::SetDirtyVelocity(bool val) -{ - m_DirtyVelocity = val; +void VehiclePhysicsComponent::SetDirtyVelocity(bool val) { + m_DirtyVelocity = val; } -void VehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) -{ - m_DirtyAngularVelocity = val; +void VehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) { + m_DirtyAngularVelocity = val; } -void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - outBitStream->Write(bIsInitialUpdate || m_DirtyPosition); +void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(bIsInitialUpdate || m_DirtyPosition); - if (bIsInitialUpdate || m_DirtyPosition) - { - outBitStream->Write(m_Position); - - outBitStream->Write(m_Rotation); + if (bIsInitialUpdate || m_DirtyPosition) { + outBitStream->Write(m_Position); - outBitStream->Write(m_IsOnGround); - outBitStream->Write(m_IsOnRail); + outBitStream->Write(m_Rotation); - outBitStream->Write(bIsInitialUpdate || m_DirtyVelocity); + outBitStream->Write(m_IsOnGround); + outBitStream->Write(m_IsOnRail); - if (bIsInitialUpdate || m_DirtyVelocity) - { - outBitStream->Write(m_Velocity); - } + outBitStream->Write(bIsInitialUpdate || m_DirtyVelocity); - outBitStream->Write(bIsInitialUpdate || m_DirtyAngularVelocity); + if (bIsInitialUpdate || m_DirtyVelocity) { + outBitStream->Write(m_Velocity); + } - if (bIsInitialUpdate || m_DirtyAngularVelocity) - { - outBitStream->Write(m_AngularVelocity); - } + outBitStream->Write(bIsInitialUpdate || m_DirtyAngularVelocity); - outBitStream->Write0(); + if (bIsInitialUpdate || m_DirtyAngularVelocity) { + outBitStream->Write(m_AngularVelocity); + } + + outBitStream->Write0(); outBitStream->Write0(); outBitStream->Write(0.0f); - if (!bIsInitialUpdate) - { - outBitStream->Write0(); - } - } + if (!bIsInitialUpdate) { + outBitStream->Write0(); + } + } - if (bIsInitialUpdate) - { - outBitStream->Write(5); - outBitStream->Write1(); - } + if (bIsInitialUpdate) { + outBitStream->Write(m_EndBehavior); + outBitStream->Write1(); + } - outBitStream->Write0(); + outBitStream->Write0(); } -void VehiclePhysicsComponent::Update(float deltaTime) -{ - if (m_SoftUpdate > 5) - { - EntityManager::Instance()->SerializeEntity(m_Parent); +void VehiclePhysicsComponent::Update(float deltaTime) { + if (m_SoftUpdate > 5) { + EntityManager::Instance()->SerializeEntity(m_Parent); - m_SoftUpdate = 0; - } - else - { - m_SoftUpdate += deltaTime; - } + m_SoftUpdate = 0; + } else { + m_SoftUpdate += deltaTime; + } } diff --git a/dGame/dComponents/VehiclePhysicsComponent.h b/dGame/dComponents/VehiclePhysicsComponent.h index de2e6b82..64609edf 100644 --- a/dGame/dComponents/VehiclePhysicsComponent.h +++ b/dGame/dComponents/VehiclePhysicsComponent.h @@ -3,109 +3,111 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Physics component for vehicles. */ class VehiclePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_VEHICLE_PHYSICS; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS; + VehiclePhysicsComponent(Entity* parentEntity); ~VehiclePhysicsComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; - - /** - * Sets the position - * @param pos the new position - */ - void SetPosition(const NiPoint3& pos); - - /** - * Gets the position - * @return the position - */ - const NiPoint3& GetPosition() const { return m_Position; } - - /** - * Sets the rotation - * @param rot the new rotation - */ - void SetRotation(const NiQuaternion& rot); + void Update(float deltaTime) override; - /** - * Gets the rotation - * @return the rotation - */ - const NiQuaternion& GetRotation() const { return m_Rotation; } + /** + * Sets the position + * @param pos the new position + */ + void SetPosition(const NiPoint3& pos); - /** - * Sets the velocity - * @param vel the new velocity - */ - void SetVelocity(const NiPoint3& vel); + /** + * Gets the position + * @return the position + */ + const NiPoint3& GetPosition() const { return m_Position; } - /** - * Gets the velocity - * @return the velocity - */ - const NiPoint3& GetVelocity() const { return m_Velocity; } + /** + * Sets the rotation + * @param rot the new rotation + */ + void SetRotation(const NiQuaternion& rot); - /** - * Sets the angular velocity - * @param vel the new angular velocity - */ - void SetAngularVelocity(const NiPoint3& vel); + /** + * Gets the rotation + * @return the rotation + */ + const NiQuaternion& GetRotation() const { return m_Rotation; } - /** - * Gets the angular velocity - * @return the angular velocity - */ - const NiPoint3& GetAngularVelocity() const { return m_AngularVelocity; } + /** + * Sets the velocity + * @param vel the new velocity + */ + void SetVelocity(const NiPoint3& vel); - /** - * Sets whether the vehicle is on the ground - * @param val whether the vehicle is on the ground - */ - void SetIsOnGround(bool val); + /** + * Gets the velocity + * @return the velocity + */ + const NiPoint3& GetVelocity() const { return m_Velocity; } - /** - * Gets whether the vehicle is on the ground - * @return whether the vehicle is on the ground - */ - const bool GetIsOnGround() const { return m_IsOnGround; } + /** + * Sets the angular velocity + * @param vel the new angular velocity + */ + void SetAngularVelocity(const NiPoint3& vel); - /** - * Gets whether the vehicle is on rail - * @return whether the vehicle is on rail - */ - void SetIsOnRail(bool val); + /** + * Gets the angular velocity + * @return the angular velocity + */ + const NiPoint3& GetAngularVelocity() const { return m_AngularVelocity; } - /** - * Gets whether the vehicle is on rail - * @return whether the vehicle is on rail - */ - const bool GetIsOnRail() const { return m_IsOnRail; } + /** + * Sets whether the vehicle is on the ground + * @param val whether the vehicle is on the ground + */ + void SetIsOnGround(bool val); - void SetDirtyPosition(bool val); - void SetDirtyVelocity(bool val); - void SetDirtyAngularVelocity(bool val); + /** + * Gets whether the vehicle is on the ground + * @return whether the vehicle is on the ground + */ + const bool GetIsOnGround() const { return m_IsOnGround; } + + /** + * Gets whether the vehicle is on rail + * @return whether the vehicle is on rail + */ + void SetIsOnRail(bool val); + + /** + * Gets whether the vehicle is on rail + * @return whether the vehicle is on rail + */ + const bool GetIsOnRail() const { return m_IsOnRail; } + + void SetDirtyPosition(bool val); + void SetDirtyVelocity(bool val); + void SetDirtyAngularVelocity(bool val); private: - bool m_DirtyPosition; - NiPoint3 m_Position; - NiQuaternion m_Rotation; - - bool m_DirtyVelocity; - NiPoint3 m_Velocity; - - bool m_DirtyAngularVelocity; - NiPoint3 m_AngularVelocity; - bool m_IsOnGround; - bool m_IsOnRail; + bool m_DirtyPosition; + NiPoint3 m_Position; + NiQuaternion m_Rotation; - float m_SoftUpdate = 0; + bool m_DirtyVelocity; + NiPoint3 m_Velocity; + + bool m_DirtyAngularVelocity; + NiPoint3 m_AngularVelocity; + bool m_IsOnGround; + bool m_IsOnRail; + + float m_SoftUpdate = 0; + uint32_t m_EndBehavior; }; diff --git a/dGame/dComponents/VendorComponent.cpp b/dGame/dComponents/VendorComponent.cpp index 6a8e7356..c9178785 100644 --- a/dGame/dComponents/VendorComponent.cpp +++ b/dGame/dComponents/VendorComponent.cpp @@ -5,6 +5,11 @@ #include "Game.h" #include "dServer.h" +#include "CDComponentsRegistryTable.h" +#include "CDVendorComponentTable.h" +#include "CDLootMatrixTable.h" +#include "CDLootTableTable.h" + VendorComponent::VendorComponent(Entity* parent) : Component(parent) { SetupConstants(); RefreshInventory(true); @@ -13,9 +18,9 @@ VendorComponent::VendorComponent(Entity* parent) : Component(parent) { VendorComponent::~VendorComponent() = default; void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write1(); + outBitStream->Write1(); outBitStream->Write1(); // Has standard items (Required for vendors with missions.) - outBitStream->Write(HasCraftingStation()); // Has multi use items + outBitStream->Write(HasCraftingStation()); // Has multi use items } void VendorComponent::OnUse(Entity* originator) { @@ -52,27 +57,27 @@ void VendorComponent::RefreshInventory(bool isCreation) { //Custom code for Max vanity NPC if (m_Parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) { if (!isCreation) return; - m_Inventory.insert({11909, 0}); //Top hat w frog - m_Inventory.insert({7785, 0}); //Flash bulb - m_Inventory.insert({12764, 0}); //Big fountain soda - m_Inventory.insert({12241, 0}); //Hot cocoa (from fb) + m_Inventory.insert({ 11909, 0 }); //Top hat w frog + m_Inventory.insert({ 7785, 0 }); //Flash bulb + m_Inventory.insert({ 12764, 0 }); //Big fountain soda + m_Inventory.insert({ 12241, 0 }); //Hot cocoa (from fb) return; } m_Inventory.clear(); - auto* lootMatrixTable = CDClientManager::Instance()->GetTable("LootMatrix"); + auto* lootMatrixTable = CDClientManager::Instance().GetTable(); std::vector lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == m_LootMatrixID); }); if (lootMatrices.empty()) return; // Done with lootMatrix table - auto* lootTableTable = CDClientManager::Instance()->GetTable("LootTable"); + auto* lootTableTable = CDClientManager::Instance().GetTable(); for (const auto& lootMatrix : lootMatrices) { int lootTableID = lootMatrix.LootTableIndex; std::vector vendorItems = lootTableTable->Query([=](CDLootTable entry) { return (entry.LootTableIndex == lootTableID); }); if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) { for (CDLootTable item : vendorItems) { - m_Inventory.insert({item.itemid, item.sortPriority}); + m_Inventory.insert({ item.itemid, item.sortPriority }); } } else { auto randomCount = GeneralUtils::GenerateRandomNumber(lootMatrix.minToDrop, lootMatrix.maxToDrop); @@ -86,7 +91,7 @@ void VendorComponent::RefreshInventory(bool isCreation) { vendorItems.erase(vendorItems.begin() + randomItemIndex); - m_Inventory.insert({randomItem.itemid, randomItem.sortPriority}); + m_Inventory.insert({ randomItem.itemid, randomItem.sortPriority }); } } } @@ -96,36 +101,36 @@ void VendorComponent::RefreshInventory(bool isCreation) { auto randomCamera = GeneralUtils::GenerateRandomNumber(0, 2); switch (randomCamera) { - case 0: - m_Inventory.insert({16253, 0}); //Grungagroid - break; - case 1: - m_Inventory.insert({16254, 0}); //Hipstabrick - break; - case 2: - m_Inventory.insert({16204, 0}); //Megabrixel snapshot - break; - default: - break; + case 0: + m_Inventory.insert({ 16253, 0 }); //Grungagroid + break; + case 1: + m_Inventory.insert({ 16254, 0 }); //Hipstabrick + break; + case 2: + m_Inventory.insert({ 16204, 0 }); //Megabrixel snapshot + break; + default: + break; } } // Callback timer to refresh this inventory. m_Parent->AddCallbackTimer(m_RefreshTimeSeconds, [this]() { RefreshInventory(); - }); + }); GameMessages::SendVendorStatusUpdate(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); } void VendorComponent::SetupConstants() { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::VENDOR); - auto* vendorComponentTable = CDClientManager::Instance()->GetTable("VendorComponent"); + auto* vendorComponentTable = CDClientManager::Instance().GetTable(); std::vector vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); }); if (vendorComps.empty()) return; m_BuyScalar = vendorComps[0].buyScalar; m_SellScalar = vendorComps[0].sellScalar; m_RefreshTimeSeconds = vendorComps[0].refreshTimeSeconds; m_LootMatrixID = vendorComps[0].LootMatrixIndex; -} \ No newline at end of file +} diff --git a/dGame/dComponents/VendorComponent.h b/dGame/dComponents/VendorComponent.h index c037d875..bf372bf2 100644 --- a/dGame/dComponents/VendorComponent.h +++ b/dGame/dComponents/VendorComponent.h @@ -7,50 +7,51 @@ #include "Entity.h" #include "GameMessages.h" #include "RakNetTypes.h" +#include "eReplicaComponentType.h" /** * A component for vendor NPCs. A vendor sells items to the player. */ class VendorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_VENDOR; - + static const eReplicaComponentType ComponentType = eReplicaComponentType::VENDOR; + VendorComponent(Entity* parent); ~VendorComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - + void OnUse(Entity* originator) override; - + /** * Gets the buy scaler * @return the buy scaler */ float GetBuyScalar() const; - /** - * Sets the buy scalar. - * @param value the new value. - */ + /** + * Sets the buy scalar. + * @param value the new value. + */ void SetBuyScalar(float value); - + /** * Gets the buy scaler * @return the buy scaler */ float GetSellScalar() const; - /** - * Sets the sell scalar. - * @param value the new value. - */ + /** + * Sets the sell scalar. + * @param value the new value. + */ void SetSellScalar(float value); /** * True if the NPC LOT is 13800, the only NPC with a crafting station. */ bool HasCraftingStation(); - + /** * Gets the list if items the vendor sells. * @return the list of items. @@ -61,7 +62,7 @@ public: * Refresh the inventory of this vendor. */ void RefreshInventory(bool isCreation = false); - + /** * Called on startup of vendor to setup the variables for the component. */ diff --git a/dGame/dEntity/CMakeLists.txt b/dGame/dEntity/CMakeLists.txt new file mode 100644 index 00000000..4bb49799 --- /dev/null +++ b/dGame/dEntity/CMakeLists.txt @@ -0,0 +1,2 @@ +set(DGAME_DENTITY_SOURCES "EntityCallbackTimer.cpp" + "EntityTimer.cpp" PARENT_SCOPE) diff --git a/dGame/dEntity/EntityCallbackTimer.cpp b/dGame/dEntity/EntityCallbackTimer.cpp index 48a0ab06..e07c1189 100644 --- a/dGame/dEntity/EntityCallbackTimer.cpp +++ b/dGame/dEntity/EntityCallbackTimer.cpp @@ -6,7 +6,7 @@ EntityCallbackTimer::EntityCallbackTimer(float time, std::function callb } EntityCallbackTimer::~EntityCallbackTimer() { - + } std::function EntityCallbackTimer::GetCallback() { diff --git a/dGame/dEntity/EntityCallbackTimer.h b/dGame/dEntity/EntityCallbackTimer.h index 63613dda..2a7e58f0 100644 --- a/dGame/dEntity/EntityCallbackTimer.h +++ b/dGame/dEntity/EntityCallbackTimer.h @@ -10,7 +10,7 @@ public: std::function GetCallback(); float GetTime(); - + void Update(float deltaTime); private: diff --git a/dGame/dEntity/EntityInfo.h b/dGame/dEntity/EntityInfo.h index 7e5fa5b5..049c5ce3 100644 --- a/dGame/dEntity/EntityInfo.h +++ b/dGame/dEntity/EntityInfo.h @@ -17,24 +17,24 @@ struct EntityInfo { spawnerNodeID = 0; id = 0; lot = LOT_NULL; - pos = {0,0,0}; - rot = {0,0,0,0}; + pos = { 0,0,0 }; + rot = { 0,0,0,0 }; settings = {}; networkSettings = {}; scale = 1.0f; } Spawner* spawner; - LWOOBJID spawnerID; - - bool hasSpawnerNodeID; - uint32_t spawnerNodeID; - - LWOOBJID id; - LOT lot; - NiPoint3 pos; - NiQuaternion rot; - std::vector settings; - std::vector networkSettings; + LWOOBJID spawnerID; + + bool hasSpawnerNodeID; + uint32_t spawnerNodeID; + + LWOOBJID id; + LOT lot; + NiPoint3 pos; + NiQuaternion rot; + std::vector settings; + std::vector networkSettings; float scale; }; diff --git a/dGame/dEntity/EntityTimer.cpp b/dGame/dEntity/EntityTimer.cpp index deff2d31..0363fc5b 100644 --- a/dGame/dEntity/EntityTimer.cpp +++ b/dGame/dEntity/EntityTimer.cpp @@ -6,7 +6,7 @@ EntityTimer::EntityTimer(std::string name, float time) { } EntityTimer::~EntityTimer() { - + } std::string EntityTimer::GetName() { @@ -19,4 +19,4 @@ float EntityTimer::GetTime() { void EntityTimer::Update(float deltaTime) { m_Time -= deltaTime; -} \ No newline at end of file +} diff --git a/dGame/dGameMessages/CMakeLists.txt b/dGame/dGameMessages/CMakeLists.txt new file mode 100644 index 00000000..3c3cb53f --- /dev/null +++ b/dGame/dGameMessages/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp" + "GameMessages.cpp" + "PropertyDataMessage.cpp" + "PropertySelectQueryProperty.cpp" PARENT_SCOPE) diff --git a/dGame/dGameMessages/DoClientProjectileImpact.h b/dGame/dGameMessages/DoClientProjectileImpact.h new file mode 100644 index 00000000..6b381aa5 --- /dev/null +++ b/dGame/dGameMessages/DoClientProjectileImpact.h @@ -0,0 +1,80 @@ +#ifndef __DOCLIENTPROJECTILEIMPACT__H__ +#define __DOCLIENTPROJECTILEIMPACT__H__ + +#include "dCommonVars.h" + +/* Tell a client local projectile to impact */ +class DoClientProjectileImpact { +public: + DoClientProjectileImpact() { + i64OrgID = LWOOBJID_EMPTY; + i64OwnerID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64OrgID = _i64OrgID; + i64OwnerID = _i64OwnerID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + DoClientProjectileImpact(RakNet::BitStream* stream) : DoClientProjectileImpact() { + Deserialize(stream); + } + + ~DoClientProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT); + + stream->Write(i64OrgID != LWOOBJID_EMPTY); + if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); + + stream->Write(i64OwnerID != LWOOBJID_EMPTY); + if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64OrgIDIsDefault{}; + stream->Read(i64OrgIDIsDefault); + if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); + + bool i64OwnerIDIsDefault{}; + stream->Read(i64OwnerIDIsDefault); + if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64OrgID; + LWOOBJID i64OwnerID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__DOCLIENTPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/EchoStartSkill.h b/dGame/dGameMessages/EchoStartSkill.h new file mode 100644 index 00000000..f5dee816 --- /dev/null +++ b/dGame/dGameMessages/EchoStartSkill.h @@ -0,0 +1,130 @@ +#ifndef __ECHOSTARTSKILL__H__ +#define __ECHOSTARTSKILL__H__ + +#include "dCommonVars.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" +#include "eGameMessageType.h" + +/* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ +class EchoStartSkill { +public: + EchoStartSkill() { + bUsedMouse = false; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + EchoStartSkill(RakNet::BitStream* stream) : EchoStartSkill() { + Deserialize(stream); + } + + ~EchoStartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::ECHO_START_SKILL); + + stream->Write(bUsedMouse); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse; + float fCasterLatency; + int32_t iCastType; + NiPoint3 lastClickedPosit; + LWOOBJID optionalOriginatorID; + LWOOBJID optionalTargetID; + NiQuaternion originatorRot; + std::string sBitStream; + TSkillID skillID; + uint32_t uiSkillHandle; +}; + +#endif //!__ECHOSTARTSKILL__H__ diff --git a/dGame/dGameMessages/EchoSyncSkill.h b/dGame/dGameMessages/EchoSyncSkill.h new file mode 100644 index 00000000..ab5a3f2b --- /dev/null +++ b/dGame/dGameMessages/EchoSyncSkill.h @@ -0,0 +1,68 @@ +#ifndef __ECHOSYNCSKILL__H__ +#define __ECHOSYNCSKILL__H__ + +#include + +#include "BitStream.h" +#include "eGameMessageType.h" + + +/* Message to synchronize a skill cast */ +class EchoSyncSkill { +public: + EchoSyncSkill() { + bDone = false; + } + + EchoSyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + EchoSyncSkill(RakNet::BitStream* stream) : EchoSyncSkill() { + Deserialize(stream); + } + + ~EchoSyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::ECHO_SYNC_SKILL); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__ECHOSYNCSKILL__H__ diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index cdaae38c..50c7876b 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -26,631 +26,659 @@ #include "CDSkillBehaviorTable.h" #include "SkillComponent.h" #include "RacingControlComponent.h" +#include "RequestServerProjectileImpact.h" +#include "SyncSkill.h" +#include "StartSkill.h" +#include "EchoStartSkill.h" +#include "EchoSyncSkill.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" +#include "eConnectionType.h" using namespace std; -void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, GAME_MSG messageID) { - - CBITSTREAM +void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID) { + + CBITSTREAM; // Get the entity Entity* entity = EntityManager::Instance()->GetEntity(objectID); - User * usr = UserManager::Instance()->GetUser(sysAddr); + User* usr = UserManager::Instance()->GetUser(sysAddr); - if (!entity) - { - Game::logger->Log("GameMessageHandler", "Failed to find associated entity (%llu), aborting GM (%X)!\n", objectID, messageID); + if (!entity) { + Game::logger->Log("GameMessageHandler", "Failed to find associated entity (%llu), aborting GM (%X)!", objectID, messageID); - return; - } + return; + } - switch (messageID) { + switch (messageID) { - case GAME_MSG_PLAY_EMOTE: { - GameMessages::HandlePlayEmote(inStream, entity); - break; - } + case eGameMessageType::UN_USE_BBB_MODEL: { + GameMessages::HandleUnUseModel(inStream, entity, sysAddr); + break; + } + case eGameMessageType::PLAY_EMOTE: { + GameMessages::HandlePlayEmote(inStream, entity); + break; + } - case GAME_MSG_MOVE_ITEM_IN_INVENTORY: { - GameMessages::HandleMoveItemInInventory(inStream, entity); - break; + case eGameMessageType::MOVE_ITEM_IN_INVENTORY: { + GameMessages::HandleMoveItemInInventory(inStream, entity); + break; + } + + case eGameMessageType::REMOVE_ITEM_FROM_INVENTORY: { + GameMessages::HandleRemoveItemFromInventory(inStream, entity, sysAddr); + break; + } + + case eGameMessageType::EQUIP_ITEM: + GameMessages::HandleEquipItem(inStream, entity); + break; + + case eGameMessageType::UN_EQUIP_ITEM: + GameMessages::HandleUnequipItem(inStream, entity); + break; + + case eGameMessageType::RESPOND_TO_MISSION: { + GameMessages::HandleRespondToMission(inStream, entity); + break; + } + + case eGameMessageType::REQUEST_USE: { + GameMessages::HandleRequestUse(inStream, entity, sysAddr); + break; + } + + case eGameMessageType::SET_FLAG: { + GameMessages::HandleSetFlag(inStream, entity); + break; + } + + case eGameMessageType::HAS_BEEN_COLLECTED: { + GameMessages::HandleHasBeenCollected(inStream, entity); + break; + } + + case eGameMessageType::PLAYER_LOADED: { + GameMessages::SendRestoreToPostLoadStats(entity, sysAddr); + entity->SetPlayerReadyForUpdates(); + + auto* player = dynamic_cast(entity); + if (player != nullptr) { + player->ConstructLimboEntities(); } - case GAME_MSG_REMOVE_ITEM_FROM_INVENTORY: { - GameMessages::HandleRemoveItemFromInventory(inStream, entity, sysAddr); - break; - } + InventoryComponent* inv = entity->GetComponent(); + if (inv) { + auto items = inv->GetEquippedItems(); + for (auto pair : items) { + const auto item = pair.second; - case GAME_MSG_EQUIP_ITEM: - GameMessages::HandleEquipItem(inStream, entity); - break; - - case GAME_MSG_UN_EQUIP_ITEM: - GameMessages::HandleUnequipItem(inStream, entity); - break; - - case GAME_MSG_RESPOND_TO_MISSION: { - GameMessages::HandleRespondToMission(inStream, entity); - break; - } - - case GAME_MSG_REQUEST_USE: { - GameMessages::HandleRequestUse(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_SET_FLAG: { - GameMessages::HandleSetFlag(inStream, entity); - break; - } - - case GAME_MSG_HAS_BEEN_COLLECTED: { - GameMessages::HandleHasBeenCollected(inStream, entity); - break; - } - - case GAME_MSG_PLAYER_LOADED: { - GameMessages::SendRestoreToPostLoadStats(entity, sysAddr); - entity->SetPlayerReadyForUpdates(); - - auto* player = dynamic_cast(entity); - if (player != nullptr) - { - player->ConstructLimboEntities(); + inv->AddItemSkills(item.lot); } + } - InventoryComponent* inv = entity->GetComponent(); - if (inv) { - auto items = inv->GetEquippedItems(); - for (auto pair : items) { - const auto item = pair.second; + auto* destroyable = entity->GetComponent(); + destroyable->SetImagination(destroyable->GetImagination()); + EntityManager::Instance()->SerializeEntity(entity); - inv->AddItemSkills(item.lot); + std::vector racingControllers = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + for (Entity* racingController : racingControllers) { + auto* racingComponent = racingController->GetComponent(); + if (racingComponent != nullptr) { + racingComponent->OnPlayerLoaded(entity); + } + } + + Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { + script->OnPlayerLoaded(zoneControl, player); + } + + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); + for (Entity* scriptEntity : scriptedActs) { + if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds + for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { + script->OnPlayerLoaded(scriptEntity, player); } } - - auto* destroyable = entity->GetComponent(); - destroyable->SetImagination(destroyable->GetImagination()); - EntityManager::Instance()->SerializeEntity(entity); - - std::vector racingControllers = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RACING_CONTROL); - for (Entity* racingController : racingControllers) { - auto* racingComponent = racingController->GetComponent(); - if (racingComponent != nullptr) - { - racingComponent->OnPlayerLoaded(entity); - } - } - - Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerLoaded(zoneControl, player); - } - - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); - for (Entity* scriptEntity : scriptedActs) { - if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerLoaded(scriptEntity, player); - } - } - } - - //Kill player if health == 0 - if (entity->GetIsDead()) { - entity->Smash(entity->GetObjectID()); - } - - //if the player has moved significantly, move them back: - if ((entity->GetPosition().y - entity->GetCharacter()->GetOriginalPos().y) > 2.0f) { - // Disabled until fixed - //GameMessages::SendTeleport(entity->GetObjectID(), entity->GetCharacter()->GetOriginalPos(), entity->GetCharacter()->GetOriginalRot(), entity->GetSystemAddress(), true, true); - } - - /** - * Invoke the OnZoneLoad event on the player character - */ - auto* character = entity->GetCharacter(); - - if (character != nullptr) { - character->OnZoneLoad(); - } - - Game::logger->Log("GameMessageHandler", "Player %s (%llu) loaded.\n", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID()); - - // After we've done our thing, tell the client they're ready - GameMessages::SendPlayerReady(dZoneManager::Instance()->GetZoneControlObject(), sysAddr); - GameMessages::SendPlayerReady(entity, sysAddr); - - break; - } - - case GAME_MSG_REQUEST_LINKED_MISSION: { - GameMessages::HandleRequestLinkedMission(inStream, entity); - break; - } - - case GAME_MSG_MISSION_DIALOGUE_OK: { - GameMessages::HandleMissionDialogOK(inStream, entity); - break; - } - - case GAME_MSG_MISSION_DIALOGUE_CANCELLED: { - //This message is pointless for our implementation, as the client just carries on after - //rejecting a mission offer. We dont need to do anything. This is just here to remove a warning in our logs :) - break; - } - - case GAME_MSG_REQUEST_PLATFORM_RESYNC: { - GameMessages::HandleRequestPlatformResync(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_FIRE_EVENT_SERVER_SIDE: { - GameMessages::HandleFireEventServerSide(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { - GameMessages::HandleActivitySummaryLeaderboardData(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { - GameMessages::HandleRequestActivitySummaryLeaderboardData(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST: { - GameMessages::HandleActivityStateChangeRequest(inStream, entity); - break; - } - - case GAME_MSG_PARSE_CHAT_MESSAGE: { - GameMessages::HandleParseChatMessage(inStream, entity, sysAddr); - break; - } - - case GAME_MSG_NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE: { - GameMessages::HandleNotifyServerLevelProcessingComplete(inStream, entity); - break; } - case GAME_MSG_PICKUP_CURRENCY: { - GameMessages::HandlePickupCurrency(inStream, entity); - break; - } - - case GAME_MSG_PICKUP_ITEM: { - GameMessages::HandlePickupItem(inStream, entity); - break; - } - - case GAME_MSG_RESURRECT: { - GameMessages::HandleResurrect(inStream, entity); - break; - } - - case GAME_MSG_REQUEST_RESURRECT: { - GameMessages::SendResurrect(entity); - /*auto* dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - if (dest) { - dest->SetHealth(4); - dest->SetArmor(0); - dest->SetImagination(6); - EntityManager::Instance()->SerializeEntity(entity); - }*/ - break; - } - - case GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT: - { - auto message = GameMessages::RequestServerProjectileImpact(); - - message.Deserialize(inStream); - - auto* skill_component = entity->GetComponent(); - - if (skill_component != nullptr) - { - auto* bs = new RakNet::BitStream((unsigned char*) message.sBitStream.c_str(), message.sBitStream.size(), false); - - skill_component->SyncPlayerProjectile(message.i64LocalID, bs, message.i64TargetID); - - delete bs; - } - - break; - } - - case GAME_MSG_START_SKILL: { - GameMessages::StartSkill startSkill = GameMessages::StartSkill(); - startSkill.Deserialize(inStream); // inStream replaces &bitStream - - if (startSkill.skillID == 1561 || startSkill.skillID == 1562 || startSkill.skillID == 1541) return; - - MissionComponent* comp = entity->GetComponent(); - if (comp) { - comp->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, startSkill.skillID); - } - - CDSkillBehaviorTable* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); - unsigned int behaviorId = skillTable->GetSkillByID(startSkill.skillID).behaviorID; - - bool success = false; - - if (behaviorId > 0) { - RakNet::BitStream * bs = new RakNet::BitStream((unsigned char *)startSkill.sBitStream.c_str(), startSkill.sBitStream.size(), false); - - auto* skillComponent = entity->GetComponent(); - - success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, bs, startSkill.optionalTargetID, startSkill.skillID); - - if (success && entity->GetCharacter()) { - DestroyableComponent* destComp = entity->GetComponent(); - destComp->SetImagination(destComp->GetImagination() - skillTable->GetSkillByID(startSkill.skillID).imaginationcost); - } - - delete bs; - } - - if (Game::server->GetZoneID() == 1302) { - break; - } - - if (success) { - //Broadcast our startSkill: - RakNet::BitStream bitStreamLocal; - PacketUtils::WriteHeader(bitStreamLocal, CLIENT, MSG_CLIENT_GAME_MSG); - bitStreamLocal.Write(entity->GetObjectID()); - - GameMessages::EchoStartSkill echoStartSkill; - echoStartSkill.bUsedMouse = startSkill.bUsedMouse; - echoStartSkill.fCasterLatency = startSkill.fCasterLatency; - echoStartSkill.iCastType = startSkill.iCastType; - echoStartSkill.lastClickedPosit = startSkill.lastClickedPosit; - echoStartSkill.optionalOriginatorID = startSkill.optionalOriginatorID; - echoStartSkill.optionalTargetID = startSkill.optionalTargetID; - echoStartSkill.originatorRot = startSkill.originatorRot; - echoStartSkill.sBitStream = startSkill.sBitStream; - echoStartSkill.skillID = startSkill.skillID; - echoStartSkill.uiSkillHandle = startSkill.uiSkillHandle; - echoStartSkill.Serialize(&bitStreamLocal); - - Game::server->Send(&bitStreamLocal, entity->GetSystemAddress(), true); - } - } break; - - case GAME_MSG_SYNC_SKILL: { - RakNet::BitStream bitStreamLocal; - PacketUtils::WriteHeader(bitStreamLocal, CLIENT, MSG_CLIENT_GAME_MSG); - bitStreamLocal.Write(entity->GetObjectID()); - //bitStreamLocal.Write((unsigned short)GAME_MSG_ECHO_SYNC_SKILL); - //bitStreamLocal.Write(inStream); - - GameMessages::SyncSkill sync = GameMessages::SyncSkill(inStream); // inStream replaced &bitStream - //sync.Serialize(&bitStreamLocal); - - ostringstream buffer; - - for (unsigned int k = 0; k < sync.sBitStream.size(); k++){ - char s; - s = sync.sBitStream.at(k); - buffer << setw(2) << hex << setfill('0') << (int) s << " "; - } - - //cout << buffer.str() << endl; - - if(usr != nullptr) { - RakNet::BitStream * bs = new RakNet::BitStream((unsigned char *)sync.sBitStream.c_str(), sync.sBitStream.size(), false); - - auto* skillComponent = entity->GetComponent(); - - skillComponent->SyncPlayerSkill(sync.uiSkillHandle, sync.uiBehaviorHandle, bs); - - delete bs; - } - - GameMessages::EchoSyncSkill echo = GameMessages::EchoSyncSkill(); - echo.bDone = sync.bDone; - echo.sBitStream = sync.sBitStream; - echo.uiBehaviorHandle = sync.uiBehaviorHandle; - echo.uiSkillHandle = sync.uiSkillHandle; - - echo.Serialize(&bitStreamLocal); - - Game::server->Send(&bitStreamLocal, sysAddr, true); - } break; - - case GAME_MSG_REQUEST_SMASH_PLAYER: + //Kill player if health == 0 + if (entity->GetIsDead()) { entity->Smash(entity->GetObjectID()); - break; + } - case GAME_MSG_MOVE_ITEM_BETWEEN_INVENTORY_TYPES: - GameMessages::HandleMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); - break; + //if the player has moved significantly, move them back: + if ((entity->GetPosition().y - entity->GetCharacter()->GetOriginalPos().y) > 2.0f) { + // Disabled until fixed + //GameMessages::SendTeleport(entity->GetObjectID(), entity->GetCharacter()->GetOriginalPos(), entity->GetCharacter()->GetOriginalRot(), entity->GetSystemAddress(), true, true); + } - case GAME_MSG_MODULAR_BUILD_FINISH: - GameMessages::HandleModularBuildFinish(inStream, entity, sysAddr); - break; - - case GAME_MSG_PUSH_EQUIPPED_ITEMS_STATE: - GameMessages::HandlePushEquippedItemsState(inStream, entity); - break; + /** + * Invoke the OnZoneLoad event on the player character + */ + auto* character = entity->GetCharacter(); - case GAME_MSG_POP_EQUIPPED_ITEMS_STATE: - GameMessages::HandlePopEquippedItemsState(inStream, entity); - break; - - case GAME_MSG_BUY_FROM_VENDOR: - GameMessages::HandleBuyFromVendor(inStream, entity, sysAddr); - break; + if (character != nullptr) { + character->OnZoneLoad(); + } - case GAME_MSG_SELL_TO_VENDOR: - GameMessages::HandleSellToVendor(inStream, entity, sysAddr); - break; + Game::logger->Log("GameMessageHandler", "Player %s (%llu) loaded.", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID()); - case GAME_MSG_BUYBACK_FROM_VENDOR: - GameMessages::HandleBuybackFromVendor(inStream, entity, sysAddr); - break; + // After we've done our thing, tell the client they're ready + GameMessages::SendPlayerReady(entity, sysAddr); + GameMessages::SendPlayerReady(dZoneManager::Instance()->GetZoneControlObject(), sysAddr); - case GAME_MSG_MODULAR_BUILD_MOVE_AND_EQUIP: - GameMessages::HandleModularBuildMoveAndEquip(inStream, entity, sysAddr); - break; + break; + } - case GAME_MSG_DONE_ARRANGING_WITH_ITEM: - GameMessages::HandleDoneArrangingWithItem(inStream, entity, sysAddr); - break; + case eGameMessageType::REQUEST_LINKED_MISSION: { + GameMessages::HandleRequestLinkedMission(inStream, entity); + break; + } - case GAME_MSG_MODULAR_BUILD_CONVERT_MODEL: - GameMessages::HandleModularBuildConvertModel(inStream, entity, sysAddr); - break; + case eGameMessageType::MISSION_DIALOGUE_OK: { + GameMessages::HandleMissionDialogOK(inStream, entity); + break; + } - case GAME_MSG_BUILD_MODE_SET: - GameMessages::HandleBuildModeSet(inStream, entity); - break; + case eGameMessageType::MISSION_DIALOGUE_CANCELLED: { + //This message is pointless for our implementation, as the client just carries on after + //rejecting a mission offer. We dont need to do anything. This is just here to remove a warning in our logs :) + break; + } - case GAME_MSG_REBUILD_CANCEL: - GameMessages::HandleRebuildCancel(inStream, entity); - break; + case eGameMessageType::REQUEST_PLATFORM_RESYNC: { + GameMessages::HandleRequestPlatformResync(inStream, entity, sysAddr); + break; + } - case GAME_MSG_MATCH_REQUEST: - GameMessages::HandleMatchRequest(inStream, entity); - break; + case eGameMessageType::FIRE_EVENT_SERVER_SIDE: { + GameMessages::HandleFireEventServerSide(inStream, entity, sysAddr); + break; + } - case GAME_MSG_USE_NON_EQUIPMENT_ITEM: - GameMessages::HandleUseNonEquipmentItem(inStream, entity); - break; + case eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { + GameMessages::HandleActivitySummaryLeaderboardData(inStream, entity, sysAddr); + break; + } - case GAME_MSG_CLIENT_ITEM_CONSUMED: - GameMessages::HandleClientItemConsumed(inStream, entity); - break; + case eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { + GameMessages::HandleRequestActivitySummaryLeaderboardData(inStream, entity, sysAddr); + break; + } - case GAME_MSG_SET_CONSUMABLE_ITEM: - GameMessages::HandleSetConsumableItem(inStream, entity, sysAddr); - break; + case eGameMessageType::ACTIVITY_STATE_CHANGE_REQUEST: { + GameMessages::HandleActivityStateChangeRequest(inStream, entity); + break; + } - case GAME_MSG_VERIFY_ACK: - GameMessages::HandleVerifyAck(inStream, entity, sysAddr); + case eGameMessageType::PARSE_CHAT_MESSAGE: { + GameMessages::HandleParseChatMessage(inStream, entity, sysAddr); + break; + } + + case eGameMessageType::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE: { + GameMessages::HandleNotifyServerLevelProcessingComplete(inStream, entity); + break; + } + + case eGameMessageType::PICKUP_CURRENCY: { + GameMessages::HandlePickupCurrency(inStream, entity); + break; + } + + case eGameMessageType::PICKUP_ITEM: { + GameMessages::HandlePickupItem(inStream, entity); + break; + } + + case eGameMessageType::RESURRECT: { + GameMessages::HandleResurrect(inStream, entity); + break; + } + + case eGameMessageType::REQUEST_RESURRECT: { + GameMessages::SendResurrect(entity); + /*auto* dest = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(4); + dest->SetArmor(0); + dest->SetImagination(6); + EntityManager::Instance()->SerializeEntity(entity); + }*/ + break; + } + case eGameMessageType::HANDLE_HOT_PROPERTY_DATA: { + GameMessages::HandleGetHotPropertyData(inStream, entity, sysAddr); + break; + } + + case eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT: + { + auto message = RequestServerProjectileImpact(); + + message.Deserialize(inStream); + + auto* skill_component = entity->GetComponent(); + + if (skill_component != nullptr) { + auto* bs = new RakNet::BitStream((unsigned char*)message.sBitStream.c_str(), message.sBitStream.size(), false); + + skill_component->SyncPlayerProjectile(message.i64LocalID, bs, message.i64TargetID); + + delete bs; + } + + break; + } + + case eGameMessageType::START_SKILL: { + StartSkill startSkill = StartSkill(); + startSkill.Deserialize(inStream); // inStream replaces &bitStream + + if (startSkill.skillID == 1561 || startSkill.skillID == 1562 || startSkill.skillID == 1541) return; + + MissionComponent* comp = entity->GetComponent(); + if (comp) { + comp->Progress(eMissionTaskType::USE_SKILL, startSkill.skillID); + } + + CDSkillBehaviorTable* skillTable = CDClientManager::Instance().GetTable(); + unsigned int behaviorId = skillTable->GetSkillByID(startSkill.skillID).behaviorID; + + bool success = false; + + if (behaviorId > 0) { + RakNet::BitStream* bs = new RakNet::BitStream((unsigned char*)startSkill.sBitStream.c_str(), startSkill.sBitStream.size(), false); + + auto* skillComponent = entity->GetComponent(); + + success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, bs, startSkill.optionalTargetID, startSkill.skillID); + + if (success && entity->GetCharacter()) { + DestroyableComponent* destComp = entity->GetComponent(); + destComp->SetImagination(destComp->GetImagination() - skillTable->GetSkillByID(startSkill.skillID).imaginationcost); + } + + delete bs; + } + + if (Game::server->GetZoneID() == 1302) { break; + } + + if (success) { + //Broadcast our startSkill: + RakNet::BitStream bitStreamLocal; + PacketUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + bitStreamLocal.Write(entity->GetObjectID()); + + EchoStartSkill echoStartSkill; + echoStartSkill.bUsedMouse = startSkill.bUsedMouse; + echoStartSkill.fCasterLatency = startSkill.fCasterLatency; + echoStartSkill.iCastType = startSkill.iCastType; + echoStartSkill.lastClickedPosit = startSkill.lastClickedPosit; + echoStartSkill.optionalOriginatorID = startSkill.optionalOriginatorID; + echoStartSkill.optionalTargetID = startSkill.optionalTargetID; + echoStartSkill.originatorRot = startSkill.originatorRot; + echoStartSkill.sBitStream = startSkill.sBitStream; + echoStartSkill.skillID = startSkill.skillID; + echoStartSkill.uiSkillHandle = startSkill.uiSkillHandle; + echoStartSkill.Serialize(&bitStreamLocal); + + Game::server->Send(&bitStreamLocal, entity->GetSystemAddress(), true); + } + } break; + + case eGameMessageType::SYNC_SKILL: { + RakNet::BitStream bitStreamLocal; + PacketUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + bitStreamLocal.Write(entity->GetObjectID()); + //bitStreamLocal.Write((unsigned short)eGameMessageType::ECHO_SYNC_SKILL); + //bitStreamLocal.Write(inStream); + + SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream + //sync.Serialize(&bitStreamLocal); + + ostringstream buffer; + + for (unsigned int k = 0; k < sync.sBitStream.size(); k++) { + char s; + s = sync.sBitStream.at(k); + buffer << setw(2) << hex << setfill('0') << (int)s << " "; + } + + //cout << buffer.str() << endl; + + if (usr != nullptr) { + RakNet::BitStream* bs = new RakNet::BitStream((unsigned char*)sync.sBitStream.c_str(), sync.sBitStream.size(), false); + + auto* skillComponent = entity->GetComponent(); + + skillComponent->SyncPlayerSkill(sync.uiSkillHandle, sync.uiBehaviorHandle, bs); + + delete bs; + } + + EchoSyncSkill echo = EchoSyncSkill(); + echo.bDone = sync.bDone; + echo.sBitStream = sync.sBitStream; + echo.uiBehaviorHandle = sync.uiBehaviorHandle; + echo.uiSkillHandle = sync.uiSkillHandle; + + echo.Serialize(&bitStreamLocal); + + Game::server->Send(&bitStreamLocal, sysAddr, true); + } break; + + case eGameMessageType::REQUEST_SMASH_PLAYER: + entity->Smash(entity->GetObjectID()); + break; + + case eGameMessageType::MOVE_ITEM_BETWEEN_INVENTORY_TYPES: + GameMessages::HandleMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); + break; + + case eGameMessageType::MODULAR_BUILD_FINISH: + GameMessages::HandleModularBuildFinish(inStream, entity, sysAddr); + break; + + case eGameMessageType::PUSH_EQUIPPED_ITEMS_STATE: + GameMessages::HandlePushEquippedItemsState(inStream, entity); + break; + + case eGameMessageType::POP_EQUIPPED_ITEMS_STATE: + GameMessages::HandlePopEquippedItemsState(inStream, entity); + break; + + case eGameMessageType::BUY_FROM_VENDOR: + GameMessages::HandleBuyFromVendor(inStream, entity, sysAddr); + break; + + case eGameMessageType::SELL_TO_VENDOR: + GameMessages::HandleSellToVendor(inStream, entity, sysAddr); + break; + + case eGameMessageType::BUYBACK_FROM_VENDOR: + GameMessages::HandleBuybackFromVendor(inStream, entity, sysAddr); + break; + + case eGameMessageType::MODULAR_BUILD_MOVE_AND_EQUIP: + GameMessages::HandleModularBuildMoveAndEquip(inStream, entity, sysAddr); + break; + + case eGameMessageType::DONE_ARRANGING_WITH_ITEM: + GameMessages::HandleDoneArrangingWithItem(inStream, entity, sysAddr); + break; + + case eGameMessageType::MODULAR_BUILD_CONVERT_MODEL: + GameMessages::HandleModularBuildConvertModel(inStream, entity, sysAddr); + break; + + case eGameMessageType::BUILD_MODE_SET: + GameMessages::HandleBuildModeSet(inStream, entity); + break; + + case eGameMessageType::REBUILD_CANCEL: + GameMessages::HandleRebuildCancel(inStream, entity); + break; + + case eGameMessageType::MATCH_REQUEST: + GameMessages::HandleMatchRequest(inStream, entity); + break; + + case eGameMessageType::USE_NON_EQUIPMENT_ITEM: + GameMessages::HandleUseNonEquipmentItem(inStream, entity); + break; + + case eGameMessageType::CLIENT_ITEM_CONSUMED: + GameMessages::HandleClientItemConsumed(inStream, entity); + break; + + case eGameMessageType::SET_CONSUMABLE_ITEM: + GameMessages::HandleSetConsumableItem(inStream, entity, sysAddr); + break; + + case eGameMessageType::VERIFY_ACK: + GameMessages::HandleVerifyAck(inStream, entity, sysAddr); + break; // Trading - case GAME_MSG_CLIENT_TRADE_REQUEST: - GameMessages::HandleClientTradeRequest(inStream, entity, sysAddr); - break; - case GAME_MSG_CLIENT_TRADE_CANCEL: - GameMessages::HandleClientTradeCancel(inStream, entity, sysAddr); - break; - case GAME_MSG_CLIENT_TRADE_ACCEPT: - GameMessages::HandleClientTradeAccept(inStream, entity, sysAddr); - break; - case GAME_MSG_CLIENT_TRADE_UPDATE: - GameMessages::HandleClientTradeUpdate(inStream, entity, sysAddr); - break; + case eGameMessageType::CLIENT_TRADE_REQUEST: + GameMessages::HandleClientTradeRequest(inStream, entity, sysAddr); + break; + case eGameMessageType::CLIENT_TRADE_CANCEL: + GameMessages::HandleClientTradeCancel(inStream, entity, sysAddr); + break; + case eGameMessageType::CLIENT_TRADE_ACCEPT: + GameMessages::HandleClientTradeAccept(inStream, entity, sysAddr); + break; + case eGameMessageType::CLIENT_TRADE_UPDATE: + GameMessages::HandleClientTradeUpdate(inStream, entity, sysAddr); + break; // Pets - case GAME_MSG_PET_TAMING_TRY_BUILD: - GameMessages::HandlePetTamingTryBuild(inStream, entity, sysAddr); - break; + case eGameMessageType::PET_TAMING_TRY_BUILD: + GameMessages::HandlePetTamingTryBuild(inStream, entity, sysAddr); + break; - case GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS: - GameMessages::HandleNotifyTamingBuildSuccess(inStream, entity, sysAddr); - break; + case eGameMessageType::NOTIFY_TAMING_BUILD_SUCCESS: + GameMessages::HandleNotifyTamingBuildSuccess(inStream, entity, sysAddr); + break; - case GAME_MSG_REQUEST_SET_PET_NAME: - GameMessages::HandleRequestSetPetName(inStream, entity, sysAddr); - break; + case eGameMessageType::REQUEST_SET_PET_NAME: + GameMessages::HandleRequestSetPetName(inStream, entity, sysAddr); + break; - case GAME_MSG_START_SERVER_PET_MINIGAME_TIMER: - GameMessages::HandleStartServerPetMinigameTimer(inStream, entity, sysAddr); - break; + case eGameMessageType::START_SERVER_PET_MINIGAME_TIMER: + GameMessages::HandleStartServerPetMinigameTimer(inStream, entity, sysAddr); + break; - case GAME_MSG_CLIENT_EXIT_TAMING_MINIGAME: - GameMessages::HandleClientExitTamingMinigame(inStream, entity, sysAddr); - break; + case eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME: + GameMessages::HandleClientExitTamingMinigame(inStream, entity, sysAddr); + break; - case GAME_MSG_COMMAND_PET: - GameMessages::HandleCommandPet(inStream, entity, sysAddr); - break; - - case GAME_MSG_DESPAWN_PET: - GameMessages::HandleDespawnPet(inStream, entity, sysAddr); - break; + case eGameMessageType::COMMAND_PET: + GameMessages::HandleCommandPet(inStream, entity, sysAddr); + break; - case GAME_MSG_MESSAGE_BOX_RESPOND: - GameMessages::HandleMessageBoxResponse(inStream, entity, sysAddr); - break; + case eGameMessageType::DESPAWN_PET: + GameMessages::HandleDespawnPet(inStream, entity, sysAddr); + break; - case GAME_MSG_CHOICE_BOX_RESPOND: - GameMessages::HandleChoiceBoxRespond(inStream, entity, sysAddr); - break; + case eGameMessageType::MESSAGE_BOX_RESPOND: + GameMessages::HandleMessageBoxResponse(inStream, entity, sysAddr); + break; - // Property - case GAME_MSG_QUERY_PROPERTY_DATA: - GameMessages::HandleQueryPropertyData(inStream, entity, sysAddr); - break; + case eGameMessageType::CHOICE_BOX_RESPOND: + GameMessages::HandleChoiceBoxRespond(inStream, entity, sysAddr); + break; - case GAME_MSG_START_BUILDING_WITH_ITEM: - GameMessages::HandleStartBuildingWithItem(inStream, entity, sysAddr); - break; + // Property + case eGameMessageType::QUERY_PROPERTY_DATA: + GameMessages::HandleQueryPropertyData(inStream, entity, sysAddr); + break; - case GAME_MSG_SET_BUILD_MODE: - GameMessages::HandleSetBuildMode(inStream, entity, sysAddr); - break; + case eGameMessageType::START_BUILDING_WITH_ITEM: + GameMessages::HandleStartBuildingWithItem(inStream, entity, sysAddr); + break; - case GAME_MSG_PROPERTY_EDITOR_BEGIN: - GameMessages::HandlePropertyEditorBegin(inStream, entity, sysAddr); - break; + case eGameMessageType::SET_BUILD_MODE: + GameMessages::HandleSetBuildMode(inStream, entity, sysAddr); + break; - case GAME_MSG_PROPERTY_EDITOR_END: - GameMessages::HandlePropertyEditorEnd(inStream, entity, sysAddr); - break; + case eGameMessageType::PROPERTY_EDITOR_BEGIN: + GameMessages::HandlePropertyEditorBegin(inStream, entity, sysAddr); + break; - case GAME_MSG_PROPERTY_CONTENTS_FROM_CLIENT: - GameMessages::HandlePropertyContentsFromClient(inStream, entity, sysAddr); - break; + case eGameMessageType::PROPERTY_EDITOR_END: + GameMessages::HandlePropertyEditorEnd(inStream, entity, sysAddr); + break; - case GAME_MSG_ZONE_PROPERTY_MODEL_EQUIPPED: - GameMessages::HandlePropertyModelEquipped(inStream, entity, sysAddr); - break; + case eGameMessageType::PROPERTY_CONTENTS_FROM_CLIENT: + GameMessages::HandlePropertyContentsFromClient(inStream, entity, sysAddr); + break; - case GAME_MSG_PLACE_PROPERTY_MODEL: - GameMessages::HandlePlacePropertyModel(inStream, entity, sysAddr); - break; + case eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED: + GameMessages::HandlePropertyModelEquipped(inStream, entity, sysAddr); + break; - case GAME_MSG_UPDATE_MODEL_FROM_CLIENT: - GameMessages::HandleUpdatePropertyModel(inStream, entity, sysAddr); - break; + case eGameMessageType::PLACE_PROPERTY_MODEL: + GameMessages::HandlePlacePropertyModel(inStream, entity, sysAddr); + break; - case GAME_MSG_DELETE_MODEL_FROM_CLIENT: - GameMessages::HandleDeletePropertyModel(inStream, entity, sysAddr); - break; + case eGameMessageType::UPDATE_MODEL_FROM_CLIENT: + GameMessages::HandleUpdatePropertyModel(inStream, entity, sysAddr); + break; - case GAME_MSG_BBB_LOAD_ITEM_REQUEST: - GameMessages::HandleBBBLoadItemRequest(inStream, entity, sysAddr); - break; + case eGameMessageType::DELETE_MODEL_FROM_CLIENT: + GameMessages::HandleDeletePropertyModel(inStream, entity, sysAddr); + break; - case GAME_MSG_BBB_SAVE_REQUEST: - GameMessages::HandleBBBSaveRequest(inStream, entity, sysAddr); - break; + case eGameMessageType::BBB_LOAD_ITEM_REQUEST: + GameMessages::HandleBBBLoadItemRequest(inStream, entity, sysAddr); + break; - case GAME_MSG_PROPERTY_ENTRANCE_SYNC: - GameMessages::HandlePropertyEntranceSync(inStream, entity, sysAddr); - break; + case eGameMessageType::BBB_SAVE_REQUEST: + GameMessages::HandleBBBSaveRequest(inStream, entity, sysAddr); + break; - case GAME_MSG_ENTER_PROPERTY1: - GameMessages::HandleEnterProperty(inStream, entity, sysAddr); - break; + case eGameMessageType::CONTROL_BEHAVIOR: + GameMessages::HandleControlBehaviors(inStream, entity, sysAddr); + break; - case GAME_MSG_ZONE_PROPERTY_MODEL_ROTATED: - EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelRotated(usr->GetLastUsedChar()->GetEntity()); - break; + case eGameMessageType::PROPERTY_ENTRANCE_SYNC: + GameMessages::HandlePropertyEntranceSync(inStream, entity, sysAddr); + break; - case GAME_MSG_UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK: - GameMessages::HandleUpdatePropertyOrModelForFilterCheck(inStream, entity, sysAddr); - break; - - case GAME_MSG_SET_PROPERTY_ACCESS: - GameMessages::HandleSetPropertyAccess(inStream, entity, sysAddr); - break; + case eGameMessageType::ENTER_PROPERTY1: + GameMessages::HandleEnterProperty(inStream, entity, sysAddr); + break; + + case eGameMessageType::ZONE_PROPERTY_MODEL_ROTATED: + EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelRotated(usr->GetLastUsedChar()->GetEntity()); + break; + + case eGameMessageType::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK: + GameMessages::HandleUpdatePropertyOrModelForFilterCheck(inStream, entity, sysAddr); + break; + + case eGameMessageType::SET_PROPERTY_ACCESS: + GameMessages::HandleSetPropertyAccess(inStream, entity, sysAddr); + break; // Racing - case GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA: - GameMessages::HandleModuleAssemblyQueryData(inStream, entity, sysAddr); - break; + case eGameMessageType::MODULE_ASSEMBLY_QUERY_DATA: + GameMessages::HandleModuleAssemblyQueryData(inStream, entity, sysAddr); + break; - case GAME_MSG_ACKNOWLEDGE_POSSESSION: - GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr); - break; + case eGameMessageType::ACKNOWLEDGE_POSSESSION: + GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr); + break; - case GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE: - GameMessages::HandleVehicleSetWheelLockState(inStream, entity, sysAddr); - break; + case eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE: + GameMessages::HandleVehicleSetWheelLockState(inStream, entity, sysAddr); + break; - case GAME_MSG_MODULAR_ASSEMBLY_NIF_COMPLETED: - GameMessages::HandleModularAssemblyNIFCompleted(inStream, entity, sysAddr); - break; + case eGameMessageType::MODULAR_ASSEMBLY_NIF_COMPLETED: + GameMessages::HandleModularAssemblyNIFCompleted(inStream, entity, sysAddr); + break; - case GAME_MSG_RACING_CLIENT_READY: - GameMessages::HandleRacingClientReady(inStream, entity, sysAddr); - break; + case eGameMessageType::RACING_CLIENT_READY: + GameMessages::HandleRacingClientReady(inStream, entity, sysAddr); + break; - case GAME_MSG_REQUEST_DIE: - GameMessages::HandleRequestDie(inStream, entity, sysAddr); - break; + case eGameMessageType::REQUEST_DIE: + GameMessages::HandleRequestDie(inStream, entity, sysAddr); + break; - case GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION: - GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(inStream, entity, sysAddr); - break; + case eGameMessageType::VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION: + GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(inStream, entity, sysAddr); + break; - case GAME_MSG_VEHICLE_NOTIFY_SERVER_REMOVE_PASSIVE_BOOST_ACTION: - GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(inStream, entity, sysAddr); - break; + case eGameMessageType::VEHICLE_NOTIFY_SERVER_REMOVE_PASSIVE_BOOST_ACTION: + GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(inStream, entity, sysAddr); + break; - case GAME_MSG_RACING_PLAYER_INFO_RESET_FINISHED: - GameMessages::HandleRacingPlayerInfoResetFinished(inStream, entity, sysAddr); - break; + case eGameMessageType::RACING_PLAYER_INFO_RESET_FINISHED: + GameMessages::HandleRacingPlayerInfoResetFinished(inStream, entity, sysAddr); + break; - case GAME_MSG_VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER: - GameMessages::HandleVehicleNotifyHitImaginationServer(inStream, entity, sysAddr); - break; - case GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST: - GameMessages::HandleUpdatePropertyPerformanceCost(inStream, entity, sysAddr); - break; + case eGameMessageType::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER: + GameMessages::HandleVehicleNotifyHitImaginationServer(inStream, entity, sysAddr); + break; + case eGameMessageType::UPDATE_PROPERTY_PERFORMANCE_COST: + GameMessages::HandleUpdatePropertyPerformanceCost(inStream, entity, sysAddr); + break; // SG - case GAME_MSG_UPDATE_SHOOTING_GALLERY_ROTATION: - GameMessages::HandleUpdateShootingGalleryRotation(inStream, entity, sysAddr); - break; + case eGameMessageType::UPDATE_SHOOTING_GALLERY_ROTATION: + GameMessages::HandleUpdateShootingGalleryRotation(inStream, entity, sysAddr); + break; // NT - case GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES: - GameMessages::HandleRequestMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); - break; + case eGameMessageType::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES: + GameMessages::HandleRequestMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); + break; - case GAME_MSG_TOGGLE_GHOST_REFERENCE_OVERRIDE: - GameMessages::HandleToggleGhostReferenceOverride(inStream, entity, sysAddr); - break; + case eGameMessageType::TOGGLE_GHOST_REFERENCE_OVERRIDE: + GameMessages::HandleToggleGhostReferenceOverride(inStream, entity, sysAddr); + break; - case GAME_MSG_SET_GHOST_REFERENCE_POSITION: - GameMessages::HandleSetGhostReferencePosition(inStream, entity, sysAddr); - break; + case eGameMessageType::SET_GHOST_REFERENCE_POSITION: + GameMessages::HandleSetGhostReferencePosition(inStream, entity, sysAddr); + break; - case GAME_MSG_READY_FOR_UPDATES: - //We don't really care about this message, as it's simply here to inform us that the client is done loading an object. - //In the event we _do_ send an update to an object that hasn't finished loading, the client will handle it anyway. - break; + case eGameMessageType::READY_FOR_UPDATES: + //We don't really care about this message, as it's simply here to inform us that the client is done loading an object. + //In the event we _do_ send an update to an object that hasn't finished loading, the client will handle it anyway. + break; - case GAME_MSG_REPORT_BUG: - GameMessages::HandleReportBug(inStream, entity); - break; + case eGameMessageType::REPORT_BUG: + GameMessages::HandleReportBug(inStream, entity); + break; - case GAME_MSG_CLIENT_RAIL_MOVEMENT_READY: - GameMessages::HandleClientRailMovementReady(inStream, entity, sysAddr); - break; + case eGameMessageType::CLIENT_RAIL_MOVEMENT_READY: + GameMessages::HandleClientRailMovementReady(inStream, entity, sysAddr); + break; - case GAME_MSG_CANCEL_RAIL_MOVEMENT: - GameMessages::HandleCancelRailMovement(inStream, entity, sysAddr); - break; + case eGameMessageType::CANCEL_RAIL_MOVEMENT: + GameMessages::HandleCancelRailMovement(inStream, entity, sysAddr); + break; - case GAME_MSG_PLAYER_RAIL_ARRIVED_NOTIFICATION: - GameMessages::HandlePlayerRailArrivedNotification(inStream, entity, sysAddr); - break; + case eGameMessageType::PLAYER_RAIL_ARRIVED_NOTIFICATION: + GameMessages::HandlePlayerRailArrivedNotification(inStream, entity, sysAddr); + break; - case GAME_MSG_CINEMATIC_UPDATE: - GameMessages::HandleCinematicUpdate(inStream, entity, sysAddr); - break; + case eGameMessageType::CINEMATIC_UPDATE: + GameMessages::HandleCinematicUpdate(inStream, entity, sysAddr); + break; - case GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC: - GameMessages::HandleModifyPlayerZoneStatistic(inStream, entity); - break; + case eGameMessageType::MODIFY_PLAYER_ZONE_STATISTIC: + GameMessages::HandleModifyPlayerZoneStatistic(inStream, entity); + break; - case GAME_MSG_UPDATE_PLAYER_STATISTIC: - GameMessages::HandleUpdatePlayerStatistic(inStream, entity); - break; + case eGameMessageType::UPDATE_PLAYER_STATISTIC: + GameMessages::HandleUpdatePlayerStatistic(inStream, entity); + break; - default: - //Game::logger->Log("GameMessageHandler", "Unknown game message ID: %X\n", messageID); - break; - } + case eGameMessageType::DISMOUNT_COMPLETE: + GameMessages::HandleDismountComplete(inStream, entity, sysAddr); + break; + case eGameMessageType::DEACTIVATE_BUBBLE_BUFF: + GameMessages::HandleDeactivateBubbleBuff(inStream, entity); + break; + case eGameMessageType::ACTIVATE_BUBBLE_BUFF: + GameMessages::HandleActivateBubbleBuff(inStream, entity); + break; + case eGameMessageType::ZONE_SUMMARY_DISMISSED: + GameMessages::HandleZoneSummaryDismissed(inStream, entity); + break; + default: + // Game::logger->Log("GameMessageHandler", "Unknown game message ID: %i", messageID); + break; + } } diff --git a/dGame/dGameMessages/GameMessageHandler.h b/dGame/dGameMessages/GameMessageHandler.h index 0d14dc5b..8b6685cb 100644 --- a/dGame/dGameMessages/GameMessageHandler.h +++ b/dGame/dGameMessages/GameMessageHandler.h @@ -7,7 +7,6 @@ #define GAMEMESSAGEHANDLER_H #include "RakNetTypes.h" -#include "dMessageIdentifiers.h" #include "dCommonVars.h" #include #include @@ -21,8 +20,10 @@ #include "GameMessages.h" #include "../dDatabase/CDClientDatabase.h" +enum class eGameMessageType : uint16_t; + namespace GameMessageHandler { - void HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, GAME_MSG messageID); + void HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID); }; #endif // GAMEMESSAGEHANDLER_H diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 4f5cb1f4..99b1c67f 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -4,7 +4,6 @@ #include "PacketUtils.h" #include "BitStream.h" #include "Game.h" -#include "dMessageIdentifiers.h" #include "SlashCommandHandler.h" #include "NiPoint3.h" #include "NiQuaternion.h" @@ -25,8 +24,24 @@ #include "dConfig.h" #include "TeamManager.h" #include "ChatPackets.h" -#include "GameConfig.h" #include "RocketLaunchLupComponent.h" +#include "eUnequippableActiveType.h" +#include "eMovementPlatformState.h" +#include "LeaderboardManager.h" +#include "AMFFormat.h" +#include "Loot.h" +#include "eRacingTaskParam.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eObjectBits.h" +#include "eTriggerEventType.h" +#include "eMatchUpdate.h" +#include "eCyclingMode.h" +#include "eCinematicEvent.h" +#include "eQuickBuildFailReason.h" +#include "eControlScheme.h" +#include "eStateChangeType.h" +#include "eConnectionType.h" #include #include @@ -48,6 +63,7 @@ #include "ScriptComponent.h" #include "RebuildComponent.h" #include "VendorComponent.h" +#include "InventoryComponent.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" #include "MovingPlatformComponent.h" @@ -58,6 +74,7 @@ #include "PossessorComponent.h" #include "RacingControlComponent.h" #include "RailActivatorComponent.h" +#include "LevelProgressionComponent.h" // Message includes: #include "dZoneManager.h" @@ -66,13 +83,24 @@ #include "PropertyVendorComponent.h" #include "PropertySelectQueryProperty.h" #include "TradingManager.h" +#include "ControlBehaviors.h" +#include "AMFDeserialize.h" +#include "eBlueprintSaveResponseType.h" +#include "eAninmationFlags.h" +#include "AMFFormat_BitStream.h" +#include "eReplicaComponentType.h" +#include "eClientMessageType.h" +#include "eGameMessageType.h" + +#include "CDComponentsRegistryTable.h" +#include "CDObjectsTable.h" void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_FIRE_EVENT_CLIENT_SIDE); + bitStream.Write(eGameMessageType::FIRE_EVENT_CLIENT_SIDE); //bitStream.Write(args); uint32_t argSize = args.size(); @@ -87,14 +115,14 @@ void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const Syste //bitStream.Write(param2); bitStream.Write(sender); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation, bool noGravTeleport) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_TELEPORT); + bitStream.Write(eGameMessageType::TELEPORT); bool bIgnoreY = (pos.y == 0.0f); bool bUseNavmesh = false; @@ -120,19 +148,18 @@ void GameMessages::SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, c bitStream.Write(rot.y); bitStream.Write(rot.z); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority, float fScale) { if (!entity) { - Game::logger->Log("SendPlayAnimation", "Trying to play animation, but entity var is nullptr!\n"); + Game::logger->Log("SendPlayAnimation", "Trying to play animation, but entity var is nullptr!"); return; } //Stolen from the old DLU codebase as the new one's autogenerated code doesn't work properly for animationIDs longer than 6 characters. CBITSTREAM; CMSGHEADER; - uint16_t gameMsgID = GAME_MSG_PLAY_ANIMATION; std::string sAnimationID = GeneralUtils::UTF16ToWTF8(animationName); uint32_t animationIDLength = sAnimationID.size(); @@ -141,13 +168,13 @@ void GameMessages::SendPlayAnimation(Entity* entity, const std::u16string& anima bool bTriggerOnCompleteMsg = false; bitStream.Write(entity->GetObjectID()); - bitStream.Write(gameMsgID); + bitStream.Write(eGameMessageType::PLAY_ANIMATION); bitStream.Write(animationIDLength); PacketUtils::WriteWString(bitStream, animationName, animationIDLength); bitStream.Write(bExpectAnimToExist); - + bitStream.Write(bPlayImmediate); bitStream.Write(bTriggerOnCompleteMsg); @@ -165,27 +192,27 @@ void GameMessages::SendPlayerReady(Entity* entity, const SystemAddress& sysAddr) CBITSTREAM; CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_PLAYER_READY); + bitStream.Write(eGameMessageType::PLAYER_READY); SEND_PACKET; } -void GameMessages::SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress &sysAddr) { - CBITSTREAM - CMSGHEADER; +void GameMessages::SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; - bitStream.Write(entityID); - bitStream.Write(GAME_MSG::GAME_MSG_SET_PLAYER_ALLOWED_RESPAWN); - bitStream.Write(doNotPromptRespawn); + bitStream.Write(entityID); + bitStream.Write(eGameMessageType::SET_PLAYER_ALLOWED_RESPAWN); + bitStream.Write(doNotPromptRespawn); - SEND_PACKET; + SEND_PACKET; } void GameMessages::SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_INVALID_ZONE_TRANSFER_LIST); + bitStream.Write(eGameMessageType::INVALID_ZONE_TRANSFER_LIST); uint32_t CustomerFeedbackURLLength = feedbackURL.size(); bitStream.Write(CustomerFeedbackURLLength); @@ -202,16 +229,15 @@ void GameMessages::SendInvalidZoneTransferList(Entity* entity, const SystemAddre bitStream.Write(feedbackOnExit); bitStream.Write(feedbackOnInvalidTransfer); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caster, const LWOOBJID& originator, int knockBackTimeMS, const NiPoint3& vector) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caster, const LWOOBJID& originator, int knockBackTimeMS, const NiPoint3& vector) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG_KNOCKBACK); + bitStream.Write(eGameMessageType::KNOCKBACK); bool casterFlag = caster != LWOOBJID_EMPTY; bool originatorFlag = originator != LWOOBJID_EMPTY; @@ -225,7 +251,7 @@ void GameMessages::SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caste if (knockBackTimeMSFlag) bitStream.Write(knockBackTimeMS); bitStream.Write(vector); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendStartArrangingWithItem( @@ -243,11 +269,11 @@ void GameMessages::SendStartArrangingWithItem( NiPoint3 targetPOS, int targetTYPE ) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_START_ARRANGING_WITH_ITEM); + bitStream.Write(eGameMessageType::START_ARRANGING_WITH_ITEM); bitStream.Write(bFirstTime); bitStream.Write(buildAreaID != LWOOBJID_EMPTY); @@ -262,33 +288,33 @@ void GameMessages::SendStartArrangingWithItem( bitStream.Write(targetPOS); bitStream.Write(targetTYPE); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, - bool bAllowCyclingWhileDeadOnly, eCyclingMode cyclingMode) { - CBITSTREAM - CMSGHEADER + bool bAllowCyclingWhileDeadOnly, eCyclingMode cyclingMode) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE); + bitStream.Write(eGameMessageType::PLAYER_SET_CAMERA_CYCLING_MODE); bitStream.Write(bAllowCyclingWhileDeadOnly); - bitStream.Write(cyclingMode != ALLOW_CYCLE_TEAMMATES); - if (cyclingMode != ALLOW_CYCLE_TEAMMATES) { - bitStream.Write(cyclingMode); + bitStream.Write(cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES); + if (cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES) { + bitStream.Write(cyclingMode); } - SEND_PACKET + SEND_PACKET; } void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLAY_ND_AUDIO_EMITTER); + bitStream.Write((uint16_t)eGameMessageType::PLAY_ND_AUDIO_EMITTER); bitStream.Write0(); bitStream.Write0(); @@ -309,7 +335,7 @@ void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& s bitStream.Write0(); bitStream.Write0(); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendStartPathing(Entity* entity) { @@ -317,30 +343,29 @@ void GameMessages::SendStartPathing(Entity* entity) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG_START_PATHING); + bitStream.Write(eGameMessageType::START_PATHING); SEND_PACKET_BROADCAST; } void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint, - int iIndex, int iDesiredWaypointIndex, int nextIndex, - MovementPlatformState movementState) { - CBITSTREAM - CMSGHEADER + int iIndex, int iDesiredWaypointIndex, int nextIndex, + eMovementPlatformState movementState) { + CBITSTREAM; + CMSGHEADER; const auto lot = entity->GetLOT(); - if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449) - { + if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449) { iDesiredWaypointIndex = 0; iIndex = 0; nextIndex = 0; bStopAtDesiredWaypoint = true; - movementState = MovementPlatformState::Stationary; + movementState = eMovementPlatformState::Stationary; } bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLATFORM_RESYNC); + bitStream.Write((uint16_t)eGameMessageType::PLATFORM_RESYNC); bool bReverse = false; int eCommand = 0; @@ -374,68 +399,67 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd bitStream.Write(qUnexpectedRotation.w); } - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_RESTORE_TO_POST_LOAD_STATS); - SEND_PACKET + bitStream.Write(eGameMessageType::RESTORE_TO_POST_LOAD_STATS); + SEND_PACKET; } void GameMessages::SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_DONE_LOADING_ALL_OBJECTS); - SEND_PACKET + bitStream.Write(eGameMessageType::SERVER_DONE_LOADING_ALL_OBJECTS); + SEND_PACKET; } -void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG_UPDATE_CHAT_MODE); + bitStream.Write((uint16_t)eGameMessageType::UPDATE_CHAT_MODE); bitStream.Write(level); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } -void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG_SET_GM_LEVEL); + bitStream.Write((uint16_t)eGameMessageType::SET_GM_LEVEL); bitStream.Write1(); bitStream.Write(level); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const SystemAddress& sysAddr, Item* item, const LWOOBJID& objectID, bool showFlyingLoot, int itemCount, LWOOBJID subKey, eLootSourceType lootSourceType) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(static_cast(GAME_MSG_ADD_ITEM_TO_INVENTORY_CLIENT_SYNC)); + bitStream.Write(eGameMessageType::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC); bitStream.Write(item->GetBound()); bitStream.Write(item->GetInfo().isBOE); bitStream.Write(item->GetInfo().isBOP); - bitStream.Write(lootSourceType != eLootSourceType::LOOT_SOURCE_NONE); // Loot source - if (lootSourceType != eLootSourceType::LOOT_SOURCE_NONE) bitStream.Write(lootSourceType); + bitStream.Write(lootSourceType != eLootSourceType::NONE); // Loot source + if (lootSourceType != eLootSourceType::NONE) bitStream.Write(lootSourceType); LWONameValue extraInfo; auto config = item->GetConfig(); - - for (auto* data : config) - { + + for (auto* data : config) { extraInfo.name += GeneralUtils::ASCIIToUTF16(data->GetString()) + u","; } if (extraInfo.name.length() > 0) extraInfo.name.pop_back(); // remove the last comma - bitStream.Write(extraInfo.name.size()); + bitStream.Write(extraInfo.name.size()); if (extraInfo.name.size() > 0) { for (uint32_t i = 0; i < extraInfo.name.size(); ++i) { bitStream.Write(static_cast(extraInfo.name[i])); @@ -447,10 +471,10 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System bitStream.Write(subKey != LWOOBJID_EMPTY); if (subKey != LWOOBJID_EMPTY) bitStream.Write(subKey); - + auto* inventory = item->GetInventory(); const auto inventoryType = inventory->GetType(); - + bitStream.Write(inventoryType != eInventoryType::ITEMS); if (inventoryType != eInventoryType::ITEMS) bitStream.Write(inventoryType); @@ -458,7 +482,7 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System if (itemCount != 1) bitStream.Write(itemCount); const auto count = item->GetCount(); - + bitStream.Write(count != 0); //items total if (count != 0) bitStream.Write(count); @@ -469,32 +493,31 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System bitStream.Write(showFlyingLoot); bitStream.Write(item->GetSlot()); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendNotifyClientFlagChange(const LWOOBJID& objectID, int iFlagID, bool bFlag, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendNotifyClientFlagChange(const LWOOBJID& objectID, uint32_t iFlagID, bool bFlag, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG_NOTIFY_CLIENT_FLAG_CHANGE); + bitStream.Write((uint16_t)eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE); bitStream.Write(bFlag); bitStream.Write(iFlagID); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendChangeObjectWorldState(const LWOOBJID& objectID, int state, const SystemAddress& sysAddr) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG_CHANGE_OBJECT_WORLD_STATE); + bitStream.Write((uint16_t)eGameMessageType::CHANGE_OBJECT_WORLD_STATE); bitStream.Write(state); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST - SEND_PACKET + SEND_PACKET; } void GameMessages::SendOfferMission(const LWOOBJID& entity, const SystemAddress& sysAddr, int32_t missionID, const LWOOBJID& offererID) { @@ -504,48 +527,48 @@ void GameMessages::SendOfferMission(const LWOOBJID& entity, const SystemAddress& //The second, actually makes the UI pop up so you can be offered the mission. //Why is it like this? Because LU isn't just a clown, it's the entire circus. - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(offererID); - bitStream.Write(uint16_t(GAME_MSG_OFFER_MISSION)); + bitStream.Write(eGameMessageType::OFFER_MISSION); bitStream.Write(missionID); bitStream.Write(offererID); - SEND_PACKET + SEND_PACKET; { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity); - bitStream.Write(uint16_t(GAME_MSG_OFFER_MISSION)); + bitStream.Write(eGameMessageType::OFFER_MISSION); bitStream.Write(missionID); bitStream.Write(offererID); - SEND_PACKET + SEND_PACKET; } } void GameMessages::SendNotifyMission(Entity* entity, const SystemAddress& sysAddr, int missionID, int missionState, bool sendingRewards) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_NOTIFY_MISSION)); + bitStream.Write(eGameMessageType::NOTIFY_MISSION); bitStream.Write(missionID); bitStream.Write(missionState); bitStream.Write(sendingRewards); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendNotifyMissionTask(Entity* entity, const SystemAddress& sysAddr, int missionID, int taskMask, std::vector updates) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_NOTIFY_MISSION_TASK); + bitStream.Write((uint16_t)eGameMessageType::NOTIFY_MISSION_TASK); bitStream.Write(missionID); bitStream.Write(taskMask); @@ -555,29 +578,29 @@ void GameMessages::SendNotifyMissionTask(Entity* entity, const SystemAddress& sy bitStream.Write(updates[i]); } - SEND_PACKET + SEND_PACKET; } void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_MODIFY_LEGO_SCORE); + bitStream.Write((uint16_t)eGameMessageType::MODIFY_LEGO_SCORE); bitStream.Write(score); - bitStream.Write(sourceType != eLootSourceType::LOOT_SOURCE_NONE); - if (sourceType != eLootSourceType::LOOT_SOURCE_NONE) bitStream.Write(sourceType); + bitStream.Write(sourceType != eLootSourceType::NONE); + if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); + bitStream.Write((uint16_t)eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); bitStream.Write(args); uint32_t strMessageNameLength = message.size(); @@ -587,16 +610,16 @@ void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const Syste bitStream.Write(static_cast(message[k])); } - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args) { +void GameMessages::SendUIMessageServerToAllClients(const std::string& message, AMFValue* args) { CBITSTREAM; CMSGHEADER; LWOOBJID empty = 0; bitStream.Write(empty); - bitStream.Write((uint16_t)GAME_MSG_UI_MESSAGE_SERVER_TO_ALL_CLIENTS); + bitStream.Write((uint16_t)eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); bitStream.Write(args); uint32_t strMessageNameLength = message.size(); @@ -609,13 +632,12 @@ void GameMessages::SendUIMessageServerToAllClients(const std::string& message, N SEND_PACKET_BROADCAST; } -void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); + bitStream.Write((uint16_t)eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); bitStream.Write(static_cast(effectName.length())); for (uint32_t k = 0; k < effectName.length(); k++) { @@ -624,7 +646,7 @@ void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, bitStream.Write(fromObjectID); bitStream.Write(radius); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) { @@ -636,7 +658,7 @@ void GameMessages::SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, co CMSGHEADER; bitStream.Write(entity); - bitStream.Write((uint16_t)GAME_MSG::GAME_MSG_PLAY_FX_EFFECT); + bitStream.Write((uint16_t)eGameMessageType::PLAY_FX_EFFECT); bitStream.Write(effectID != -1); if (effectID != -1) bitStream.Write(effectID); @@ -662,29 +684,29 @@ void GameMessages::SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, co bitStream.Write(serialize); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendStopFXEffect(Entity* entity, bool killImmediate, std::string name) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_STOP_FX_EFFECT); + bitStream.Write(eGameMessageType::STOP_FX_EFFECT); - bitStream.Write(killImmediate); + bitStream.Write(killImmediate); bitStream.Write(name.size()); bitStream.Write(name.c_str(), name.size()); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG::GAME_MSG_BROADCAST_TEXT_TO_CHATBOX); + bitStream.Write((uint16_t)eGameMessageType::BROADCAST_TEXT_TO_CHATBOX); LWONameValue attribs; attribs.name = attrs; @@ -702,15 +724,15 @@ void GameMessages::SendBroadcastTextToChatbox(Entity* entity, const SystemAddres bitStream.Write(static_cast(wsText[k])); } - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_SET_CURRENCY)); + bitStream.Write(eGameMessageType::SET_CURRENCY); bitStream.Write(currency); @@ -728,69 +750,66 @@ void GameMessages::SendSetCurrency(Entity* entity, int64_t currency, int lootTyp bitStream.Write(sourceTradeID != LWOOBJID_EMPTY); if (sourceTradeID != LWOOBJID_EMPTY) bitStream.Write(sourceTradeID); - bitStream.Write(sourceType != LOOTTYPE_NONE); - if (sourceType != LOOTTYPE_NONE) bitStream.Write(sourceType); + bitStream.Write(sourceType != eLootSourceType::NONE); + if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendRebuildNotifyState(Entity* entity, int prevState, int state, const LWOOBJID& playerID) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendRebuildNotifyState(Entity* entity, eRebuildState prevState, eRebuildState state, const LWOOBJID& playerID) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_REBUILD_NOTIFY_STATE); + bitStream.Write((uint16_t)eGameMessageType::REBUILD_NOTIFY_STATE); bitStream.Write(prevState); bitStream.Write(state); bitStream.Write(playerID); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } -void GameMessages::SendEnableRebuild(Entity* entity, bool enable, bool fail, bool success, int failReason, float duration, const LWOOBJID& playerID) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendEnableRebuild(Entity* entity, bool enable, bool fail, bool success, eQuickBuildFailReason failReason, float duration, const LWOOBJID& playerID) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_ENABLE_REBUILD); + bitStream.Write((uint16_t)eGameMessageType::ENABLE_REBUILD); bitStream.Write(enable); bitStream.Write(fail); bitStream.Write(success); - bitStream.Write(failReason != eFailReason::REASON_NOT_GIVEN); - if (failReason != eFailReason::REASON_NOT_GIVEN) bitStream.Write(failReason); + bitStream.Write(failReason != eQuickBuildFailReason::NOT_GIVEN); + if (failReason != eQuickBuildFailReason::NOT_GIVEN) bitStream.Write(failReason); bitStream.Write(duration); bitStream.Write(playerID); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendTerminateInteraction(const LWOOBJID& objectID, eTerminateType type, const LWOOBJID& terminator) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG_TERMINATE_INTERACTION); + bitStream.Write((uint16_t)eGameMessageType::TERMINATE_INTERACTION); bitStream.Write(terminator); bitStream.Write(type); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } -void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, const LWOOBJID& lootOwnerID, eKillType killType, std::u16string deathType, float directionRelative_AngleY, float directionRelative_AngleXZ, float directionRelative_Force, bool bClientDeath, bool bSpawnLoot) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, const LWOOBJID& lootOwnerID, eKillType killType, std::u16string deathType, float directionRelative_AngleY, float directionRelative_AngleXZ, float directionRelative_Force, bool bClientDeath, bool bSpawnLoot) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_DIE)); + bitStream.Write(eGameMessageType::DIE); bitStream.Write(bClientDeath); bitStream.Write(bSpawnLoot); bitStream.Write(deathType); @@ -804,7 +823,7 @@ void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, c bitStream.Write(killerID); bitStream.Write(lootOwnerID); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOBJID& lootOwnerID, bool bDieAccepted, eKillType killType, std::u16string deathType, float directionRelative_AngleY, float directionRelative_AngleXZ, float directionRelative_Force, bool bClientDeath, bool bSpawnLoot, float coinSpawnTime) { @@ -813,7 +832,7 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_DIE); + bitStream.Write((uint16_t)eGameMessageType::DIE); bitStream.Write(bClientDeath); bitStream.Write(bSpawnLoot); @@ -831,8 +850,8 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB bitStream.Write(directionRelative_AngleY); bitStream.Write(directionRelative_Force); - bitStream.Write(killType != VIOLENT); - if (killType != VIOLENT) bitStream.Write(killType); + bitStream.Write(killType != eKillType::VIOLENT); + if (killType != eKillType::VIOLENT) bitStream.Write(killType); bitStream.Write(killerID); @@ -845,30 +864,29 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB } void GameMessages::SendSetInventorySize(Entity* entity, int invType, int size) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_SET_INVENTORY_SIZE)); + bitStream.Write(eGameMessageType::SET_INVENTORY_SIZE); bitStream.Write(invType); bitStream.Write(size); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_SET_EMOTE_LOCK_STATE)); + bitStream.Write(eGameMessageType::SET_EMOTE_LOCK_STATE); bitStream.Write(bLock); bitStream.Write(emoteID); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassChecks, bool doHover, int effectID, float airspeed, float maxAirspeed, float verticalVelocity, int warningEffectID) { @@ -880,11 +898,11 @@ void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassCheck } */ - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_SET_JET_PACK_MODE)); + bitStream.Write(eGameMessageType::SET_JET_PACK_MODE); bitStream.Write(bypassChecks); bitStream.Write(doHover); @@ -905,24 +923,34 @@ void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassCheck bitStream.Write(warningEffectID != -1); if (warningEffectID != -1) bitStream.Write(warningEffectID); - SEND_PACKET_BROADCAST + SEND_PACKET_BROADCAST; } void GameMessages::SendResurrect(Entity* entity) { - DestroyableComponent* dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + // Restore the players health after the animation for respawning has finished. + // This is when the health appered back in live, not immediately upon requesting respawn + // Add a half second in case someone decides to cheat and move during the death animation + // and just make sure the client has time to be ready. + constexpr float respawnTime = 3.66700005531311f + 0.5f; + entity->AddCallbackTimer(respawnTime, [=]() { + auto* destroyableComponent = entity->GetComponent(); - if (dest != nullptr && entity->GetLOT() == 1) { - auto* characterComponent = entity->GetComponent(); + if (destroyableComponent != nullptr && entity->GetLOT() == 1) { + auto* levelComponent = entity->GetComponent(); + if (levelComponent) { + int32_t healthToRestore = levelComponent->GetLevel() >= 45 ? 8 : 4; + if (healthToRestore > destroyableComponent->GetMaxHealth()) healthToRestore = destroyableComponent->GetMaxHealth(); + destroyableComponent->SetHealth(healthToRestore); - if (characterComponent == nullptr) { - return; + int32_t imaginationToRestore = levelComponent->GetLevel() >= 45 ? 20 : 6; + if (imaginationToRestore > destroyableComponent->GetMaxImagination()) imaginationToRestore = destroyableComponent->GetMaxImagination(); + destroyableComponent->SetImagination(imaginationToRestore); + } } + }); - dest->SetHealth(characterComponent->GetLevel() >= 45 ? 8 : 4); - dest->SetImagination(characterComponent->GetLevel() >= 45 ? 20 : 6); - } - auto cont = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + auto cont = static_cast(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (cont && entity->GetLOT() == 1) { cont->SetPosition(entity->GetRespawnPosition()); cont->SetRotation(entity->GetRespawnRotation()); @@ -934,27 +962,25 @@ void GameMessages::SendResurrect(Entity* entity) { bool bRezImmediately = false; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_RESURRECT)); + bitStream.Write(eGameMessageType::RESURRECT); bitStream.Write(bRezImmediately); SEND_PACKET_BROADCAST; } -void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLAY2_DAMBIENT_SOUND); + bitStream.Write((uint16_t)eGameMessageType::PLAY2_DAMBIENT_SOUND); uint32_t audioGUIDSize = audioGUID.size(); bitStream.Write(force); bitStream.Write(audioGUIDSize); - for (uint32_t k = 0; k < audioGUIDSize; k++) - { + for (uint32_t k = 0; k < audioGUIDSize; k++) { bitStream.Write(static_cast(audioGUID[k])); } @@ -962,15 +988,15 @@ void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::strin SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLAY2_DAMBIENT_SOUND); + bitStream.Write((uint16_t)eGameMessageType::PLAY2_DAMBIENT_SOUND); uint32_t audioGUIDSize = audioGUID.size(); @@ -981,16 +1007,18 @@ void GameMessages::SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bitStream.Write(result); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_SET_NETWORK_SCRIPT_VAR); + bitStream.Write((uint16_t)eGameMessageType::SET_NETWORK_SCRIPT_VAR); + // FIXME: this is a bad place to need to do a conversion because we have no clue whether data is utf8 or plain ascii + // an this has performance implications const auto u16Data = GeneralUtils::ASCIIToUTF16(data); uint32_t dataSize = static_cast(u16Data.size()); @@ -1005,10 +1033,10 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& } void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) { - if (GameConfig::GetValue("no_drops") == 1) { + if (Game::config->GetValue("disable_drops") == "1") { return; } - + bool bUsePosition = false; NiPoint3 finalPosition; LWOOBJID lootID = LWOOBJID_EMPTY; @@ -1046,7 +1074,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_DROP_CLIENT_LOOT)); + bitStream.Write(eGameMessageType::DROP_CLIENT_LOOT); bitStream.Write(bUsePosition); @@ -1063,18 +1091,15 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, if (spawnPos != NiPoint3::ZERO) bitStream.Write(spawnPos); auto* team = TeamManager::Instance()->GetTeam(owner); - + // Currency and powerups should not sync - if (team != nullptr && currency == 0) - { - CDObjectsTable* objectsTable = CDClientManager::Instance()->GetTable("Objects"); + if (team != nullptr && currency == 0) { + CDObjectsTable* objectsTable = CDClientManager::Instance().GetTable(); const CDObjects& object = objectsTable->GetByID(item); - if (object.type != "Powerup") - { - for (const auto memberId : team->members) - { + if (object.type != "Powerup") { + for (const auto memberId : team->members) { auto* member = EntityManager::Instance()->GetEntity(memberId); if (member == nullptr) continue; @@ -1086,26 +1111,26 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, return; } } - + SystemAddress sysAddr = entity->GetSystemAddress(); SEND_PACKET; } -void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlSceme controlScheme) { +void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme) { CBITSTREAM; CMSGHEADER; bool bDelayCamSwitchIfInCinematic = true; bool bSwitchCam = true; - + bitStream.Write(entity->GetObjectID()); - bitStream.Write(uint16_t(GAME_MSG_SET_PLAYER_CONTROL_SCHEME)); + bitStream.Write(eGameMessageType::SET_PLAYER_CONTROL_SCHEME); bitStream.Write(bDelayCamSwitchIfInCinematic); bitStream.Write(bSwitchCam); - bitStream.Write(controlScheme != SCHEME_A); - if (controlScheme != SCHEME_A) bitStream.Write(controlScheme); + bitStream.Write(controlScheme != eControlScheme::SCHEME_A); + if (controlScheme != eControlScheme::SCHEME_A) bitStream.Write(controlScheme); SystemAddress sysAddr = entity->GetSystemAddress(); SEND_PACKET; @@ -1116,13 +1141,13 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_PLAYER_REACHED_RESPAWN_CHECKPOINT); + bitStream.Write((uint16_t)eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT); bitStream.Write(position.x); bitStream.Write(position.y); bitStream.Write(position.z); - auto con = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + auto con = static_cast(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (con) { auto rot = con->GetRotation(); bitStream.Write(rot.x); @@ -1150,7 +1175,7 @@ void GameMessages::SendAddSkill(Entity* entity, TSkillID skillID, int slotID) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write((uint16_t)GAME_MSG_ADD_SKILL); + bitStream.Write((uint16_t)eGameMessageType::ADD_SKILL); bitStream.Write(AICombatWeight != 0); if (AICombatWeight != 0) bitStream.Write(AICombatWeight); @@ -1182,7 +1207,7 @@ void GameMessages::SendRemoveSkill(Entity* entity, TSkillID skillID) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG_REMOVE_SKILL); + bitStream.Write(eGameMessageType::REMOVE_SKILL); bitStream.Write(false); bitStream.Write(skillID); @@ -1191,8 +1216,8 @@ void GameMessages::SendRemoveSkill(Entity* entity, TSkillID skillID) { } void GameMessages::SendFinishArrangingWithItem(Entity* entity, const LWOOBJID& buildArea) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bool bFirstTime = true; const LWOOBJID& buildAreaID = buildArea; @@ -1211,7 +1236,7 @@ void GameMessages::SendFinishArrangingWithItem(Entity* entity, const LWOOBJID& b bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_FINISH_ARRANGING_WITH_ITEM); + bitStream.Write(eGameMessageType::FINISH_ARRANGING_WITH_ITEM); bitStream.Write(buildAreaID != LWOOBJID_EMPTY); if (buildAreaID != LWOOBJID_EMPTY) bitStream.Write(buildAreaID); @@ -1229,43 +1254,43 @@ void GameMessages::SendFinishArrangingWithItem(Entity* entity, const LWOOBJID& b bitStream.Write(oldItemTYPE); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendModularBuildEnd(Entity* entity) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_MODULAR_BUILD_END); + bitStream.Write(eGameMessageType::MODULAR_BUILD_END); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_OPEN_WINDOW); + bitStream.Write(eGameMessageType::VENDOR_OPEN_WINDOW); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - VendorComponent* vendor = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vendor = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vendor) return; std::map vendorItems = vendor->GetInventory(); bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE); + bitStream.Write(eGameMessageType::VENDOR_STATUS_UPDATE); - bitStream.Write(bUpdateOnly); + bitStream.Write(bUpdateOnly); bitStream.Write(static_cast(vendorItems.size())); for (std::pair item : vendorItems) { @@ -1274,25 +1299,25 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s } if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST - SEND_PACKET + SEND_PACKET; } void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; int iResult = 0x02; // success, seems to be the only relevant one - + bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_TRANSACTION_RESULT); + bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT); bitStream.Write(iResult); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID objectID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; // this is used for a lot more than just inventory trashing (trades, vendors, etc.) but for now since it's just used for that, that's all im going to implement bool bConfirmed = true; bool bDeleteItem = true; @@ -1310,7 +1335,7 @@ void GameMessages::SendRemoveItemFromInventory(Entity* entity, const SystemAddre LWOOBJID iTradeID = LWOOBJID_EMPTY; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_REMOVE_ITEM_FROM_INVENTORY); + bitStream.Write(eGameMessageType::REMOVE_ITEM_FROM_INVENTORY); bitStream.Write(bConfirmed); bitStream.Write(bDeleteItem); bitStream.Write(bOutSuccess); @@ -1334,52 +1359,52 @@ void GameMessages::SendRemoveItemFromInventory(Entity* entity, const SystemAddre bitStream.Write0(); bitStream.Write0(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID item) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG_CONSUME_CLIENT_ITEM); + bitStream.Write(eGameMessageType::CONSUME_CLIENT_ITEM); bitStream.Write(bSuccess); bitStream.Write(item); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendUseItemResult(Entity* entity, LOT templateID, bool useItemResult) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG_USE_ITEM_RESULT); + bitStream.Write(eGameMessageType::USE_ITEM_RESULT); bitStream.Write(templateID); bitStream.Write(useItemResult); SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, eUseItemResponse itemResponse) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE); + bitStream.Write(eGameMessageType::USE_ITEM_REQUIREMENTS_RESPONSE); bitStream.Write(itemResponse); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, int srcInv, int dstInv, const LWOOBJID& iObjID) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; Item* itemStack = inv->FindItemById(iObjID); @@ -1399,15 +1424,13 @@ void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, i bitStream.Write(bOutSuccess); if (count == 1) { bitStream.Write0(); - } - else { + } else { bitStream.Write1(); bitStream.Write(count); } if (dstBag == 0) { bitStream.Write0(); - } - else { + } else { bitStream.Write1(); bitStream.Write(dstBag); } @@ -1415,8 +1438,7 @@ void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, i bitStream.Write(showFlyingLoot); if (srcBag == 0) { bitStream.Write0(); - } - else { + } else { bitStream.Write1(); bitStream.Write(srcBag); } @@ -1425,26 +1447,26 @@ void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, i auto sysAddr = entity->GetSystemAddress(); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_MATCH_RESPONSE); + bitStream.Write(eGameMessageType::MATCH_RESPONSE); bitStream.Write(response); - SEND_PACKET + SEND_PACKET; } -void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, int type) { - CBITSTREAM - CMSGHEADER +void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_MATCH_UPDATE); + bitStream.Write(eGameMessageType::MATCH_UPDATE); bitStream.Write(uint32_t(data.size())); for (char character : data) { bitStream.Write(uint16_t(character)); @@ -1452,110 +1474,109 @@ void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, if (data.size() > 0) bitStream.Write(uint16_t(0)); bitStream.Write(type); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, - const SystemAddress& sysAddr, const int32_t& gameID, - const int32_t& queryType, const int32_t& resultsEnd, - const int32_t& resultsStart, bool weekly) { - CBITSTREAM - CMSGHEADER + const SystemAddress& sysAddr, const int32_t& gameID, + const int32_t& queryType, const int32_t& resultsEnd, + const int32_t& resultsStart, bool weekly) { + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + bitStream.Write(objectID); + bitStream.Write(eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); - bitStream.Write(gameID != 0); - if (gameID != 0) { - bitStream.Write(gameID); - } + bitStream.Write(gameID != 0); + if (gameID != 0) { + bitStream.Write(gameID); + } - bitStream.Write(queryType != 1); - if (queryType != 1) { - bitStream.Write(queryType); - } + bitStream.Write(queryType != 1); + if (queryType != 1) { + bitStream.Write(queryType); + } - bitStream.Write(resultsEnd != 10); - if (resultsEnd != 10) { - bitStream.Write(resultsEnd); - } + bitStream.Write(resultsEnd != 10); + if (resultsEnd != 10) { + bitStream.Write(resultsEnd); + } - bitStream.Write(resultsStart != 0); - if (resultsStart != 0) { - bitStream.Write(resultsStart); - } + bitStream.Write(resultsStart != 0); + if (resultsStart != 0) { + bitStream.Write(resultsStart); + } - bitStream.Write(targetID); - bitStream.Write(weekly); + bitStream.Write(targetID); + bitStream.Write(weekly); - SEND_PACKET + SEND_PACKET; } void GameMessages::SendActivityPause(LWOOBJID objectId, bool pause, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ACTIVITY_PAUSE); - bitStream.Write(pause); + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::ACTIVITY_PAUSE); + bitStream.Write(pause); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } void GameMessages::SendStartActivityTime(LWOOBJID objectId, float_t startTime, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_START_ACTIVITY_TIME); - bitStream.Write(startTime); + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::START_ACTIVITY_TIME); + bitStream.Write(startTime); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } void GameMessages::SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_REQUEST_ACTIVITY_ENTER); - bitStream.Write(bStart); + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::REQUEST_ACTIVITY_ENTER); + bitStream.Write(bStart); bitStream.Write(userID); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } void GameMessages::NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sysAddr, int level, bool sending_rewards) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectID); - bitStream.Write((uint16_t)GAME_MSG::GAME_MSG_NOTIFY_LEVEL_REWARDS); + bitStream.Write((uint16_t)eGameMessageType::NOTIFY_LEVEL_REWARDS); bitStream.Write(level); bitStream.Write(sending_rewards); - - SEND_PACKET + + SEND_PACKET; } void GameMessages::SendSetShootingGalleryParams(LWOOBJID objectId, const SystemAddress& sysAddr, - float cameraFOV, - float cooldown, - float minDistance, - NiPoint3 muzzlePosOffset, - NiPoint3 playerPosOffset, - float projectileVelocity, - float timeLimit, - bool bUseLeaderboards) -{ - CBITSTREAM - CMSGHEADER + float cameraFOV, + float cooldown, + float minDistance, + NiPoint3 muzzlePosOffset, + NiPoint3 playerPosOffset, + float projectileVelocity, + float timeLimit, + bool bUseLeaderboards) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SET_SHOOTING_GALLERY_PARAMS); + bitStream.Write(eGameMessageType::SET_SHOOTING_GALLERY_PARAMS); /* bitStream.Write(cameraFOV); bitStream.Write(cooldown); @@ -1577,33 +1598,31 @@ void GameMessages::SendSetShootingGalleryParams(LWOOBJID objectId, const SystemA bitStream.Write(timeLimit); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET + SEND_PACKET; } void GameMessages::SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const SystemAddress& sysAddr, - float addTime, - int32_t score, - LWOOBJID target, - NiPoint3 targetPos) -{ - CBITSTREAM - CMSGHEADER + float addTime, + int32_t score, + LWOOBJID target, + NiPoint3 targetPos) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); + bitStream.Write(eGameMessageType::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); bitStream.Write(addTime); bitStream.Write(score); bitStream.Write(target); bitStream.Write(targetPos); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET + SEND_PACKET; } -void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { float angle = 0.0f; NiPoint3 facing = NiPoint3::ZERO; NiPoint3 muzzlePos = NiPoint3::ZERO; @@ -1614,87 +1633,87 @@ void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream* inStre void GameMessages::HandleActivitySummaryLeaderboardData(RakNet::BitStream* instream, Entity* entity, - const SystemAddress& sysAddr) { - Game::logger->Log("AGS", "We got mail!\n"); + const SystemAddress& sysAddr) { + Game::logger->Log("AGS", "We got mail!"); } void GameMessages::SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, const SystemAddress& sysAddr) { - CBITSTREAM - CMSGHEADER + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + bitStream.Write(objectID); + bitStream.Write(eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); - bitStream.Write(leaderboard->GetGameID()); - bitStream.Write(leaderboard->GetInfoType()); + bitStream.Write(leaderboard->GetGameID()); + bitStream.Write(leaderboard->GetInfoType()); - // Leaderboard is written back as LDF string - const auto leaderboardString = leaderboard->ToString(); - bitStream.Write(leaderboardString.size()); - for (const auto c : leaderboardString) { - bitStream.Write(c); - } - if (!leaderboardString.empty()) bitStream.Write(uint16_t(0)); + // Leaderboard is written back as LDF string + const auto leaderboardString = leaderboard->ToString(); + bitStream.Write(leaderboardString.size()); + for (const auto c : leaderboardString) { + bitStream.Write(c); + } + if (!leaderboardString.empty()) bitStream.Write(uint16_t(0)); - bitStream.Write0(); - bitStream.Write0(); + bitStream.Write0(); + bitStream.Write0(); - SEND_PACKET + SEND_PACKET; } void GameMessages::HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - int32_t gameID = 0; - if (inStream->ReadBit()) inStream->Read(gameID); + int32_t gameID = 0; + if (inStream->ReadBit()) inStream->Read(gameID); - int32_t queryType = 1; - if (inStream->ReadBit()) inStream->Read(queryType); + int32_t queryType = 1; + if (inStream->ReadBit()) inStream->Read(queryType); - int32_t resultsEnd = 10; - if (inStream->ReadBit()) inStream->Read(resultsEnd); + int32_t resultsEnd = 10; + if (inStream->ReadBit()) inStream->Read(resultsEnd); - int32_t resultsStart = 0; - if (inStream->ReadBit()) inStream->Read(resultsStart); + int32_t resultsStart = 0; + if (inStream->ReadBit()) inStream->Read(resultsStart); - LWOOBJID target {}; - inStream->Read(target); + LWOOBJID target{}; + inStream->Read(target); - bool weekly = inStream->ReadBit(); + bool weekly = inStream->ReadBit(); - const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, (InfoType)queryType, weekly, entity->GetObjectID()); - SendActivitySummaryLeaderboardData(entity->GetObjectID(), leaderboard, sysAddr); - delete leaderboard; + const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, (InfoType)queryType, weekly, entity->GetObjectID()); + SendActivitySummaryLeaderboardData(entity->GetObjectID(), leaderboard, sysAddr); + delete leaderboard; } -void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream *inStream, Entity *entity) { - LWOOBJID objectID; - inStream->Read(objectID); +void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity) { + LWOOBJID objectID; + inStream->Read(objectID); - int32_t value1; - inStream->Read(value1); + int32_t value1; + inStream->Read(value1); - int32_t value2; - inStream->Read(value2); + int32_t value2; + inStream->Read(value2); - uint32_t stringValueLength; - inStream->Read(stringValueLength); + uint32_t stringValueLength; + inStream->Read(stringValueLength); - std::u16string stringValue; - for (uint32_t i = 0; i < stringValueLength; ++i) { - uint16_t character; - inStream->Read(character); - stringValue.push_back(character); - } + std::u16string stringValue; + for (uint32_t i = 0; i < stringValueLength; ++i) { + uint16_t character; + inStream->Read(character); + stringValue.push_back(character); + } auto* assosiate = EntityManager::Instance()->GetEntity(objectID); - Game::logger->Log("Activity State Change", "%s [%i, %i] from %i to %i\n", GeneralUtils::UTF16ToWTF8(stringValue).c_str(), value1, value2, entity->GetLOT(), assosiate != nullptr ? assosiate->GetLOT() : 0); + Game::logger->Log("Activity State Change", "%s [%i, %i] from %i to %i", GeneralUtils::UTF16ToWTF8(stringValue).c_str(), value1, value2, entity->GetLOT(), assosiate != nullptr ? assosiate->GetLOT() : 0); - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SHOOTING_GALLERY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY); for (Entity* scriptEntity : scriptedActs) { scriptEntity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); } - entity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); + entity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); } void GameMessages::SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID) { @@ -1702,7 +1721,7 @@ void GameMessages::SendStartCelebrationEffect(Entity* entity, const SystemAddres CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_START_CELEBRATION_EFFECT); + bitStream.Write(eGameMessageType::START_CELEBRATION_EFFECT); bitStream.Write(0); //animation bitStream.Write0(); //No custom bg obj @@ -1727,99 +1746,99 @@ void GameMessages::SendStartCelebrationEffect(Entity* entity, const SystemAddres void GameMessages::SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, - uint32_t pathStart, const SystemAddress& sysAddr, int32_t railActivatorComponentID, - LWOOBJID railActivatorObjectID) { - CBITSTREAM; - CMSGHEADER; + uint32_t pathStart, const SystemAddress& sysAddr, int32_t railActivatorComponentID, + LWOOBJID railActivatorObjectID) { + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_SET_RAIL_MOVEMENT); + bitStream.Write(objectID); + bitStream.Write(eGameMessageType::SET_RAIL_MOVEMENT); - bitStream.Write(pathGoForward); + bitStream.Write(pathGoForward); - bitStream.Write(uint32_t(pathName.size())); - for (auto character : pathName) { - bitStream.Write(character); - } + bitStream.Write(uint32_t(pathName.size())); + for (auto character : pathName) { + bitStream.Write(character); + } - bitStream.Write(pathStart); + bitStream.Write(pathStart); - const auto componentIDIsDefault = railActivatorComponentID == -1; - bitStream.Write(!componentIDIsDefault); - if (!componentIDIsDefault) - bitStream.Write(railActivatorComponentID); + const auto componentIDIsDefault = railActivatorComponentID == -1; + bitStream.Write(!componentIDIsDefault); + if (!componentIDIsDefault) + bitStream.Write(railActivatorComponentID); - const auto activatorObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; - bitStream.Write(!activatorObjectIDIsDefault); - if (!activatorObjectIDIsDefault) - bitStream.Write(railActivatorObjectID); + const auto activatorObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; + bitStream.Write(!activatorObjectIDIsDefault); + if (!activatorObjectIDIsDefault) + bitStream.Write(railActivatorObjectID); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } -void GameMessages::SendStartRailMovement(const LWOOBJID &objectID, std::u16string pathName, std::u16string startSound, - std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr, - uint32_t pathStart, bool goForward, bool damageImmune, bool noAggro, bool notifyActor, - bool showNameBillboard, bool cameraLocked, bool collisionEnabled, bool useDB, - int32_t railComponentID, LWOOBJID railActivatorObjectID) { - CBITSTREAM; - CMSGHEADER; +void GameMessages::SendStartRailMovement(const LWOOBJID& objectID, std::u16string pathName, std::u16string startSound, + std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr, + uint32_t pathStart, bool goForward, bool damageImmune, bool noAggro, bool notifyActor, + bool showNameBillboard, bool cameraLocked, bool collisionEnabled, bool useDB, + int32_t railComponentID, LWOOBJID railActivatorObjectID) { + CBITSTREAM; + CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_START_RAIL_MOVEMENT); + bitStream.Write(objectID); + bitStream.Write(eGameMessageType::START_RAIL_MOVEMENT); - bitStream.Write(damageImmune); - bitStream.Write(noAggro); - bitStream.Write(notifyActor); - bitStream.Write(showNameBillboard); - bitStream.Write(cameraLocked); - bitStream.Write(collisionEnabled); + bitStream.Write(damageImmune); + bitStream.Write(noAggro); + bitStream.Write(notifyActor); + bitStream.Write(showNameBillboard); + bitStream.Write(cameraLocked); + bitStream.Write(collisionEnabled); - bitStream.Write(uint32_t(loopSound.size())); - for (auto character : loopSound) { - bitStream.Write(character); - } + bitStream.Write(uint32_t(loopSound.size())); + for (auto character : loopSound) { + bitStream.Write(character); + } - bitStream.Write(goForward); + bitStream.Write(goForward); - bitStream.Write(uint32_t(pathName.size())); - for (auto character : pathName) { - bitStream.Write(character); - } + bitStream.Write(uint32_t(pathName.size())); + for (auto character : pathName) { + bitStream.Write(character); + } - const auto pathStartIsDefault = pathStart == 0; - bitStream.Write(!pathStartIsDefault); - if (!pathStartIsDefault) { - bitStream.Write(pathStart); - } + const auto pathStartIsDefault = pathStart == 0; + bitStream.Write(!pathStartIsDefault); + if (!pathStartIsDefault) { + bitStream.Write(pathStart); + } - const auto railComponentIDIsDefault = railComponentID == -1; - bitStream.Write(!railComponentIDIsDefault); - if (!railComponentIDIsDefault) { - bitStream.Write(railComponentID); - } + const auto railComponentIDIsDefault = railComponentID == -1; + bitStream.Write(!railComponentIDIsDefault); + if (!railComponentIDIsDefault) { + bitStream.Write(railComponentID); + } - const auto railObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; - bitStream.Write(!railObjectIDIsDefault); - if (!railObjectIDIsDefault) { - bitStream.Write(railActivatorObjectID); - } + const auto railObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; + bitStream.Write(!railObjectIDIsDefault); + if (!railObjectIDIsDefault) { + bitStream.Write(railActivatorObjectID); + } - bitStream.Write(uint32_t(startSound.size())); - for (auto character : startSound) { - bitStream.Write(character); - } + bitStream.Write(uint32_t(startSound.size())); + for (auto character : startSound) { + bitStream.Write(character); + } - bitStream.Write(uint32_t(stopSound.size())); - for (auto character : stopSound) { - bitStream.Write(character); - } + bitStream.Write(uint32_t(stopSound.size())); + for (auto character : stopSound) { + bitStream.Write(character); + } - bitStream.Write(useDB); + bitStream.Write(useDB); - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16string name, int param1, int param2, const LWOOBJID& paramObj, std::string paramStr, const SystemAddress& sysAddr) { @@ -1827,19 +1846,19 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_CLIENT_OBJECT); + bitStream.Write(eGameMessageType::NOTIFY_CLIENT_OBJECT); bitStream.Write(uint32_t(name.size())); for (auto character : name) { bitStream.Write(character); } - + bitStream.Write(param1); - + bitStream.Write(param2); bitStream.Write(paramObj); - + bitStream.Write(uint32_t(paramStr.size())); for (auto character : paramStr) { bitStream.Write(character); @@ -1850,13 +1869,13 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri } void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, - int param2, const LWOOBJID& paramObj, const std::string& paramStr, - const SystemAddress& sysAddr) { + int param2, const LWOOBJID& paramObj, const std::string& paramStr, + const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT); + bitStream.Write(eGameMessageType::NOTIFY_CLIENT_ZONE_OBJECT); bitStream.Write(uint32_t(name.size())); for (const auto& character : name) { @@ -1877,13 +1896,12 @@ void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const st } void GameMessages::SendNotifyClientFailedPrecondition(LWOOBJID objectId, const SystemAddress& sysAddr, - const std::u16string& failedReason, int preconditionID) -{ + const std::u16string& failedReason, int preconditionID) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_CLIENT_FAILED_PRECONDITION); + bitStream.Write(eGameMessageType::NOTIFY_CLIENT_FAILED_PRECONDITION); bitStream.Write(uint32_t(failedReason.size())); for (uint16_t character : failedReason) { @@ -1896,26 +1914,24 @@ void GameMessages::SendNotifyClientFailedPrecondition(LWOOBJID objectId, const S SEND_PACKET; } -void GameMessages::SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr) -{ +void GameMessages::SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_TOGGLE_GM_INVIS); + bitStream.Write(eGameMessageType::TOGGLE_GM_INVIS); bitStream.Write(enabled); // does not matter? if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendSetName(LWOOBJID objectID, std::u16string name, const SystemAddress& sysAddr) -{ +void GameMessages::SendSetName(LWOOBJID objectID, std::u16string name, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_SET_NAME); + bitStream.Write(eGameMessageType::SET_NAME); bitStream.Write(name.size()); @@ -1931,7 +1947,7 @@ void GameMessages::SendBBBSaveResponse(const LWOOBJID& objectId, const LWOOBJID& CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_BBB_SAVE_RESPONSE); + bitStream.Write(eGameMessageType::BBB_SAVE_RESPONSE); bitStream.Write(localID); @@ -1948,64 +1964,60 @@ void GameMessages::SendBBBSaveResponse(const LWOOBJID& objectId, const LWOOBJID& bitStream.Write(buffer[i]); SEND_PACKET; - PacketUtils::SavePacket("GAME_MSG_BBB_SAVE_RESPONSE.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); + PacketUtils::SavePacket("eGameMessageType::BBB_SAVE_RESPONSE.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); } // Property -void GameMessages::SendOpenPropertyVendor(const LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendOpenPropertyVendor(const LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_OPEN_PROPERTY_VENDOR); + bitStream.Write(eGameMessageType::OPEN_PROPERTY_VENDOR); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendOpenPropertyManagment(const LWOOBJID objectId, const SystemAddress& sysAddr) -{ - CBITSTREAM - CMSGHEADER +void GameMessages::SendOpenPropertyManagment(const LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; bitStream.Write(PropertyManagementComponent::Instance()->GetParent()->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_OPEN_PROPERTY_MANAGEMENT); + bitStream.Write(eGameMessageType::OPEN_PROPERTY_MANAGEMENT); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendDownloadPropertyData(const LWOOBJID objectId, const PropertyDataMessage& data, const SystemAddress& sysAddr) -{ +void GameMessages::SendDownloadPropertyData(const LWOOBJID objectId, const PropertyDataMessage& data, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_DOWNLOAD_PROPERTY_DATA); + bitStream.Write(eGameMessageType::DOWNLOAD_PROPERTY_DATA); data.Serialize(bitStream); - Game::logger->Log("SendDownloadPropertyData", "(%llu) sending property data (%d)\n", objectId, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); - + Game::logger->Log("SendDownloadPropertyData", "(%llu) sending property data (%d)", objectId, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendPropertyRentalResponse(const LWOOBJID objectId, const LWOCLONEID cloneId, const uint32_t code, const LWOOBJID propertyId, const int64_t rentDue, const SystemAddress& sysAddr) -{ +void GameMessages::SendPropertyRentalResponse(const LWOOBJID objectId, const LWOCLONEID cloneId, const uint32_t code, const LWOOBJID propertyId, const int64_t rentDue, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PROPERTY_RENTAL_RESPONSE); - + bitStream.Write(eGameMessageType::PROPERTY_RENTAL_RESPONSE); + bitStream.Write(cloneId); bitStream.Write(code); bitStream.Write(propertyId); bitStream.Write(rentDue); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -2015,7 +2027,7 @@ void GameMessages::SendLockNodeRotation(Entity* entity, std::string nodeName) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(GAME_MSG::GAME_MSG_LOCK_NODE_ROTATION); + bitStream.Write(eGameMessageType::LOCK_NODE_ROTATION); bitStream.Write(uint32_t(nodeName.size())); for (char character : nodeName) { @@ -2025,13 +2037,12 @@ void GameMessages::SendLockNodeRotation(Entity* entity, std::string nodeName) { SEND_PACKET_BROADCAST; } -void GameMessages::SendSetBuildModeConfirmed(LWOOBJID objectId, const SystemAddress& sysAddr, bool start, bool warnVisitors, bool modePaused, int32_t modeValue, LWOOBJID playerId, NiPoint3 startPos) -{ +void GameMessages::SendSetBuildModeConfirmed(LWOOBJID objectId, const SystemAddress& sysAddr, bool start, bool warnVisitors, bool modePaused, int32_t modeValue, LWOOBJID playerId, NiPoint3 startPos) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SET_BUILD_MODE_CONFIRMED); + bitStream.Write(eGameMessageType::SET_BUILD_MODE_CONFIRMED); bitStream.Write(start); bitStream.Write(warnVisitors); @@ -2046,109 +2057,98 @@ void GameMessages::SendSetBuildModeConfirmed(LWOOBJID objectId, const SystemAddr SEND_PACKET; } -void GameMessages::SendGetModelsOnProperty(LWOOBJID objectId, std::map models, const SystemAddress& sysAddr) -{ +void GameMessages::SendGetModelsOnProperty(LWOOBJID objectId, std::map models, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_GET_MODELS_ON_PROPERTY); + bitStream.Write(eGameMessageType::GET_MODELS_ON_PROPERTY); bitStream.Write(static_cast(models.size())); - for (const auto& pair : models) - { + for (const auto& pair : models) { bitStream.Write(pair.first); bitStream.Write(pair.second); } - Game::logger->Log("SendGetModelsOnProperty", "Sending property models to (%llu) (%d)\n", objectId, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); + Game::logger->Log("SendGetModelsOnProperty", "Sending property models to (%llu) (%d)", objectId, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendZonePropertyModelEquipped(LWOOBJID objectId, LWOOBJID playerId, LWOOBJID propertyId, const SystemAddress& sysAddr) -{ +void GameMessages::SendZonePropertyModelEquipped(LWOOBJID objectId, LWOOBJID playerId, LWOOBJID propertyId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ZONE_PROPERTY_MODEL_EQUIPPED); + bitStream.Write(eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED); bitStream.Write(playerId); bitStream.Write(propertyId); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } void GameMessages::SendPlaceModelResponse(LWOOBJID objectId, const SystemAddress& sysAddr, NiPoint3 position, - LWOOBJID plaque, int32_t response, NiQuaternion rotation) -{ + LWOOBJID plaque, int32_t response, NiQuaternion rotation) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PLACE_MODEL_RESPONSE); + bitStream.Write(eGameMessageType::PLACE_MODEL_RESPONSE); bitStream.Write(position != NiPoint3::ZERO); - if (position != NiPoint3::ZERO) - { + if (position != NiPoint3::ZERO) { bitStream.Write(position); } bitStream.Write(plaque != LWOOBJID_EMPTY); - if (plaque != LWOOBJID_EMPTY) - { + if (plaque != LWOOBJID_EMPTY) { bitStream.Write(plaque); } bitStream.Write(response != 0); - if (response != 0) - { + if (response != 0) { bitStream.Write(response); } bitStream.Write(rotation != NiQuaternion::IDENTITY); - if (rotation != NiQuaternion::IDENTITY) - { + if (rotation != NiQuaternion::IDENTITY) { bitStream.Write(response); } - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendUGCEquipPreCreateBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, int modelCount, LWOOBJID model) -{ +void GameMessages::SendUGCEquipPreCreateBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, int modelCount, LWOOBJID model) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE); + bitStream.Write(eGameMessageType::HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE); bitStream.Write(modelCount); bitStream.Write(model); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, LWOOBJID inventoryItem, int itemTotal) -{ +void GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, LWOOBJID inventoryItem, int itemTotal) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE); + bitStream.Write(eGameMessageType::HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE); bitStream.Write(inventoryItem); bitStream.Write(itemTotal != 0); - if (itemTotal != 0) - { + if (itemTotal != 0) { bitStream.Write(itemTotal); } @@ -2156,8 +2156,7 @@ void GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, cons SEND_PACKET; } -void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { uint8_t accessType{}; int32_t renew{}; @@ -2169,15 +2168,40 @@ void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* inStream->Read(renewIsDefault); if (renewIsDefault != 0) inStream->Read(renew); - Game::logger->Log("GameMessages", "Set privacy option to: %i\n", accessType); + Game::logger->Log("GameMessages", "Set privacy option to: %i", accessType); if (PropertyManagementComponent::Instance() == nullptr) return; PropertyManagementComponent::Instance()->SetPrivacyOption(static_cast(accessType)); } -void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + bool unknown{}; + LWOOBJID objIdToAddToInventory{}; + inStream->Read(unknown); + inStream->Read(objIdToAddToInventory); + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(eInventoryType::MODELS_IN_BBB); + auto* item = inventory->FindItemById(objIdToAddToInventory); + if (item) { + inventoryComponent->MoveItemToInventory(item, eInventoryType::MODELS, 1); + } else { + Game::logger->Log("GameMessages", "item id %llu not found in MODELS_IN_BBB inventory, likely because it does not exist", objIdToAddToInventory); + } + } + + if (unknown) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + bitStream.Write(LWOOBJID_EMPTY); //always zero so that a check on the client passes + bitStream.Write(eBlueprintSaveResponseType::PlacementFailed); // Sending a non-zero error code here prevents the client from deleting its in progress build for some reason? + bitStream.Write(0); + SEND_PACKET; + } +} + +void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool isProperty{}; LWOOBJID objectId{}; LWOOBJID playerId{}; @@ -2193,16 +2217,14 @@ void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream->Read(worldId); inStream->Read(descriptionLength); - for (uint32_t i = 0; i < descriptionLength; ++i) - { + for (uint32_t i = 0; i < descriptionLength; ++i) { uint16_t character; inStream->Read(character); description.push_back(character); } inStream->Read(nameLength); - for (uint32_t i = 0; i < nameLength; ++i) - { + for (uint32_t i = 0; i < nameLength; ++i) { uint16_t character; inStream->Read(character); name.push_back(character); @@ -2211,37 +2233,35 @@ void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* PropertyManagementComponent::Instance()->UpdatePropertyDetails(GeneralUtils::UTF16ToWTF8(name), GeneralUtils::UTF16ToWTF8(description)); } -void GameMessages::HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - Game::logger->Log("HandleQueryPropertyData", "Entity (%i) requesting data\n", entity->GetLOT()); +void GameMessages::HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + Game::logger->Log("HandleQueryPropertyData", "Entity (%i) requesting data", entity->GetLOT()); /* - auto entites = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_VENDOR); + auto entites = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_VENDOR); entity = entites[0]; */ - auto* propertyVendorComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_VENDOR)); + auto* propertyVendorComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); if (propertyVendorComponent != nullptr) { propertyVendorComponent->OnQueryPropertyData(entity, sysAddr); } /* - entites = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT); + entites = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_MANAGEMENT); entity = entites[0]; */ - auto* propertyManagerComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT)); + auto* propertyManagerComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_MANAGEMENT)); if (propertyManagerComponent != nullptr) { propertyManagerComponent->OnQueryPropertyData(entity, sysAddr); } } -void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool start{}; int32_t distanceType = -1; bool modePaused{}; @@ -2250,7 +2270,7 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit NiPoint3 startPosition = NiPoint3::ZERO; inStream->Read(start); - + if (inStream->ReadBit()) inStream->Read(distanceType); @@ -2272,18 +2292,16 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit player->GetCharacter()->SetBuildMode(start); - Game::logger->Log("GameMessages", "Sending build mode confirm (%i): (%d) (%i) (%d) (%i) (%llu)\n", entity->GetLOT(), start, distanceType, modePaused, modeValue, playerId); - + Game::logger->Log("GameMessages", "Sending build mode confirm (%i): (%d) (%i) (%d) (%i) (%llu)", entity->GetLOT(), start, distanceType, modePaused, modeValue, playerId); + SendSetBuildModeConfirmed(entity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, start, false, modePaused, modeValue, playerId, startPosition); } -void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - if (!entity->HasComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT)) - { +void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + if (!entity->HasComponent(eReplicaComponentType::PROPERTY_MANAGEMENT)) { return; } - + bool firstTime{}; bool success{}; int32_t sourceBag{}; @@ -2310,12 +2328,12 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti sourceType = 4; } - Game::logger->Log("GameMessages", "Handling start building with item (%i): (%d) (%d) (%i) (%llu) (%i) (%i) (%llu) (%i) (%i)\n", entity->GetLOT(), firstTime, success, sourceBag, sourceId, sourceLot, sourceType, targetId, targetLot, targetType); - + Game::logger->Log("GameMessages", "Handling start building with item (%i): (%d) (%d) (%i) (%llu) (%i) (%i) (%llu) (%i) (%i)", entity->GetLOT(), firstTime, success, sourceBag, sourceId, sourceLot, sourceType, targetId, targetLot, targetType); + auto* user = UserManager::Instance()->GetUser(sysAddr); auto* player = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); - + SendStartArrangingWithItem( player, sysAddr, @@ -2333,22 +2351,19 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti ); } -void GameMessages::HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { PropertyManagementComponent::Instance()->OnStartBuilding(); - + dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyEditBegin(); } -void GameMessages::HandlePropertyEditorEnd(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePropertyEditorEnd(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { PropertyManagementComponent::Instance()->OnFinishBuilding(); dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyEditEnd(); } -void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { User* user = UserManager::Instance()->GetUser(sysAddr); Entity* player = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); @@ -2356,22 +2371,19 @@ void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream* inStream, SendGetModelsOnProperty(player->GetObjectID(), PropertyManagementComponent::Instance()->GetModels(), UNASSIGNED_SYSTEM_ADDRESS); } -void GameMessages::HandlePropertyModelEquipped(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePropertyModelEquipped(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyModelEquipped(); } -void GameMessages::HandlePlacePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePlacePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model; inStream->Read(model); - + PropertyManagementComponent::Instance()->UpdateModelPosition(model, NiPoint3::ZERO, NiQuaternion::IDENTITY); } -void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model; NiPoint3 position; NiQuaternion rotation = NiQuaternion::IDENTITY; @@ -2379,26 +2391,22 @@ void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity inStream->Read(model); inStream->Read(position); - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(rotation); } - + PropertyManagementComponent::Instance()->UpdateModelPosition(model, position, rotation); } -void GameMessages::HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model = LWOOBJID_EMPTY; int deleteReason = 0; - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(model); } - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(deleteReason); } @@ -2407,33 +2415,108 @@ void GameMessages::HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity } void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - LWOOBJID itemID = LWOOBJID_EMPTY; - inStream->Read(itemID); + LWOOBJID previousItemID = LWOOBJID_EMPTY; + inStream->Read(previousItemID); - Game::logger->Log("BBB", "Load item request for: " + std::to_string(itemID) + "\n"); + Game::logger->Log("BBB", "Load item request for: %lld", previousItemID); + LWOOBJID newId = previousItemID; + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(eInventoryType::MODELS); + auto* itemToMove = inventory->FindItemById(previousItemID); + if (itemToMove) { + LOT previousLot = itemToMove->GetLot(); + inventoryComponent->MoveItemToInventory(itemToMove, eInventoryType::MODELS_IN_BBB, 1, false); + + auto* destinationInventory = inventoryComponent->GetInventory(eInventoryType::MODELS_IN_BBB); + if (destinationInventory) { + auto* movedItem = destinationInventory->FindItemByLot(previousLot); + if (movedItem) newId = movedItem->GetId(); + } + } else { + Game::logger->Log("GameMessages", "item id %llu not found in MODELS inventory, likely because it does not exist", previousItemID); + } + } + + // Second argument always true (successful) for now + SendBlueprintLoadItemResponse(sysAddr, true, previousItemID, newId); +} + +void GameMessages::SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_LOAD_RESPONSE_ITEMID); - bitStream.Write(static_cast(1)); - bitStream.Write(itemID); - bitStream.Write(itemID); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_LOAD_RESPONSE_ITEMID); + bitStream.Write(static_cast(success)); + bitStream.Write(oldItemId); + bitStream.Write(newItemId); SEND_PACKET; } +void GameMessages::SendSmash(Entity* entity, float force, float ghostOpacity, LWOOBJID killerID, bool ignoreObjectVisibility) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::SMASH); + + bitStream.Write(ignoreObjectVisibility); + bitStream.Write(force); + bitStream.Write(ghostOpacity); + bitStream.Write(killerID); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendUnSmash(Entity* entity, LWOOBJID builderID, float duration) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::UNSMASH); + + bitStream.Write(builderID != LWOOBJID_EMPTY); + if (builderID != LWOOBJID_EMPTY) bitStream.Write(builderID); + + bitStream.Write(duration != 3.0f); + if (duration != 3.0f) bitStream.Write(duration); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + AMFDeserialize reader; + std::unique_ptr amfArguments(reader.Read(inStream)); + if (amfArguments->GetValueType() != AMFValueType::AMFArray) return; + + uint32_t commandLength{}; + inStream->Read(commandLength); + + std::string command; + for (uint32_t i = 0; i < commandLength; i++) { + unsigned char character; + inStream->Read(character); + command.push_back(character); + } + + auto owner = PropertyManagementComponent::Instance()->GetOwner(); + if (!owner) return; + + ControlBehaviors::Instance().ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); +} + void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { /* - ___ ___ - /\ /\___ _ __ ___ / __\ ___ / \_ __ __ _ __ _ ___ _ __ ___ + ___ ___ + /\ /\___ _ __ ___ / __\ ___ / \_ __ __ _ __ _ ___ _ __ ___ / /_/ / _ \ '__/ _ \ /__\/// _ \ / /\ / '__/ _` |/ _` |/ _ \| '_ \/ __| / __ / __/ | | __/ / \/ \ __/ / /_//| | | (_| | (_| | (_) | | | \__ \ \/ /_/ \___|_| \___| \_____/\___| /___,' |_| \__,_|\__, |\___/|_| |_|___/ - |___/ - ___ _ - / __\ _____ ____ _ _ __ ___ / \ - /__\/// _ \ \ /\ / / _` | '__/ _ \/ / - / \/ \ __/\ V V / (_| | | | __/\_/ - \_____/\___| \_/\_/ \__,_|_| \___\/ - + |___/ + ___ _ + / __\ _____ ____ _ _ __ ___ / \ + /__\/// _ \ \ /\ / / _` | '__/ _ \/ / + / \/ \ __/\ V V / (_| | | | __/\_/ + \_____/\___| \_/\_/ \__,_|_| \___\/ <>=======() (/\___ /|\\ ()==========<>_ \_/ | \\ //|\ ______/ \) @@ -2450,34 +2533,25 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent ______/ / '------' */ - - //First, we have Wincent's clean methods of reading in the data received from the client. LWOOBJID localId; - uint32_t timeTaken; inStream->Read(localId); - uint32_t ld0Size; - inStream->Read(ld0Size); - for (auto i = 0; i < 5; ++i) { - uint8_t c; - inStream->Read(c); - } - - uint32_t lxfmlSize; - inStream->Read(lxfmlSize); - uint8_t* inData = static_cast(std::malloc(lxfmlSize)); + uint32_t sd0Size; + inStream->Read(sd0Size); + std::shared_ptr sd0Data(new char[sd0Size]); - if (inData == nullptr) { + if (sd0Data == nullptr) { return; } - - for (uint32_t i = 0; i < lxfmlSize; ++i) { + + for (uint32_t i = 0; i < sd0Size; ++i) { uint8_t c; inStream->Read(c); - inData[i] = c; + sd0Data[i] = c; } - + + uint32_t timeTaken; inStream->Read(timeTaken); /* @@ -2489,6 +2563,8 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent Note, in the live client it'll still display the bricks going out as they're being used, but on relog/world change, they reappear as we didn't take them. + + TODO Apparently the bricks are supposed to be taken via MoveInventoryBatch? */ ////Decompress the SD0 from the client so we can process the lxfml properly @@ -2497,7 +2573,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent //int32_t size = ZCompression::Decompress(inData, lxfmlSize, outData, 327680, error); //if (size == -1) { - // Game::logger->Log("GameMessages", "Failed to decompress LXFML: (%i)\n", error); + // Game::logger->Log("GameMessages", "Failed to decompress LXFML: (%i)", error); // return; //} // @@ -2505,21 +2581,21 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent //Now, the cave of dragons: - //We runs this in async because the http library here is blocking, meaning it'll halt the thread. + //We runs this in async because the http library here is blocking, meaning it'll halt the thread. //But we don't want the server to go unresponsive, because then the client would disconnect. - std::async(std::launch::async, [&]() { + auto returnVal = std::async(std::launch::async, [&]() { //We need to get a new ID for our model first: ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t newID) { LWOOBJID newIDL = newID; - newIDL = GeneralUtils::SetBit(newIDL, OBJECT_BIT_CHARACTER); - newIDL = GeneralUtils::SetBit(newIDL, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(newIDL, eObjectBits::CHARACTER); + GeneralUtils::SetBit(newIDL, eObjectBits::PERSISTENT); ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t blueprintIDSmall) { blueprintIDSmall = ObjectIDManager::Instance()->GenerateRandomObjectID(); LWOOBJID blueprintID = blueprintIDSmall; - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_CHARACTER); - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); //We need to get the propertyID: (stolen from Wincent's propertyManagementComp) const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); @@ -2529,13 +2605,11 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent auto query = CDClientDatabase::CreatePreppedStmt( "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int) zoneId); + query.bind(1, (int)zoneId); auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) { - return; - } + if (result.eof() || result.fieldIsNull(0)) return; int templateId = result.getIntField(0); @@ -2553,6 +2627,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent propertyId = propertyEntry->getUInt64(1); } + delete propertyEntry; delete propertyLookup; //Insert into ugc: @@ -2563,7 +2638,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent ugcs->setInt(4, 0); //whacky stream biz - std::string s((char*)inData, lxfmlSize); + std::string s(sd0Data.get(), sd0Size); std::istringstream iss(s); std::istream& stream = iss; @@ -2574,18 +2649,25 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent delete ugcs; //Insert into the db as a BBB model: - auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents`(`id`, `property_id`, `ugc_id`, `lot`, `x`, `y`, `z`, `rx`, `ry`, `rz`, `rw`) VALUES (?,?,?,?,?,?,?,?,?,?,?)"); + auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); stmt->setUInt64(1, newIDL); stmt->setUInt64(2, propertyId); stmt->setUInt(3, blueprintIDSmall); - stmt->setUInt(4, 14); //14 is the lot the BBB models use - stmt->setDouble(5, 0.0f); //x - stmt->setDouble(6, 0.0f); //y - stmt->setDouble(7, 0.0f); //z - stmt->setDouble(8, 0.0f); - stmt->setDouble(9, 0.0f); - stmt->setDouble(10, 0.0f); - stmt->setDouble(11, 0.0f); + stmt->setUInt(4, 14); // 14 is the lot the BBB models use + stmt->setDouble(5, 0.0f); // x + stmt->setDouble(6, 0.0f); // y + stmt->setDouble(7, 0.0f); // z + stmt->setDouble(8, 0.0f); // rx + stmt->setDouble(9, 0.0f); // ry + stmt->setDouble(10, 0.0f); // rz + stmt->setDouble(11, 0.0f); // rw + stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable + stmt->setString(13, ""); // Model description. TODO implement this. + stmt->setDouble(14, 0); // behavior 1. TODO implement this. + stmt->setDouble(15, 0); // behavior 2. TODO implement this. + stmt->setDouble(16, 0); // behavior 3. TODO implement this. + stmt->setDouble(17, 0); // behavior 4. TODO implement this. + stmt->setDouble(18, 0); // behavior 5. TODO implement this. stmt->execute(); delete stmt; @@ -2595,7 +2677,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent */ ////Send off to UGC for processing, if enabled: - //if (Game::config->GetValue("ugc_remote") == "1") { + //if (Game::config->GetValue("ugc_remote") == "1") { // std::string ugcIP = Game::config->GetValue("ugc_ip"); // int ugcPort = std::stoi(Game::config->GetValue("ugc_port")); @@ -2611,38 +2693,21 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent //Tell the client their model is saved: (this causes us to actually pop out of our current state): CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); bitStream.Write(localId); - bitStream.Write(0); - bitStream.Write(1); + bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); + bitStream.Write(1); bitStream.Write(blueprintID); - bitStream.Write(lxfmlSize + 9); + bitStream.Write(sd0Size); - //Write a fake sd0 header: - bitStream.Write(0x73); //s - bitStream.Write(0x64); //d - bitStream.Write(0x30); //0 - bitStream.Write(0x01); //1 - bitStream.Write(0xFF); //end magic - - bitStream.Write(lxfmlSize); - - for (size_t i = 0; i < lxfmlSize; ++i) - bitStream.Write(inData[i]); + for (size_t i = 0; i < sd0Size; ++i) { + bitStream.Write(sd0Data[i]); + } SEND_PACKET; - PacketUtils::SavePacket("MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); //Now we have to construct this object: - /* - * This needs to be sent as config data, but I don't know how to right now. - 'blueprintid': (9, 1152921508346399522), - 'componentWhitelist': (1, 1), - 'modelType': (1, 2), - 'propertyObjectID': (7, True), - 'userModelID': (9, 1152921510759098799) - */ EntityInfo info; info.lot = 14; @@ -2673,13 +2738,13 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent //there was an issue with builds not appearing since it was placed above ConstructEntity. PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), newIDL); } + + }); }); }); - }); } -void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool includeNullAddress{}; bool includeNullDescription{}; bool playerOwn{}; @@ -2701,8 +2766,7 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit inStream->Read(startIndex); inStream->Read(filterTextLength); - for (auto i = 0u; i < filterTextLength; i++) - { + for (auto i = 0u; i < filterTextLength; i++) { char c; inStream->Read(c); filterText.push_back(c); @@ -2728,8 +2792,7 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit ); } -void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t index{}; bool returnToZone{}; @@ -2750,8 +2813,7 @@ void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* enti } } -void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LOT lot; inStream->Read(lot); @@ -2763,24 +2825,23 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* inventory->SetConsumable(lot); } -void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, - int endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, - bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) -{ +void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, + bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, + eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, + bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PLAY_CINEMATIC); + bitStream.Write(eGameMessageType::PLAY_CINEMATIC); bitStream.Write(allowGhostUpdates); bitStream.Write(bCloseMultiInteract); bitStream.Write(bSendServerNotify); bitStream.Write(bUseControlledObjectForAudioListener); - bitStream.Write(endBehavior != 0); - if (endBehavior != 0) bitStream.Write(endBehavior); + bitStream.Write(endBehavior != eEndBehavior::RETURN); + if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior); bitStream.Write(hidePlayerDuringCine); @@ -2806,13 +2867,12 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, } void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - float leadOut, bool leavePlayerLocked) -{ + float leadOut, bool leavePlayerLocked) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_END_CINEMATIC); + bitStream.Write(eGameMessageType::END_CINEMATIC); bitStream.Write(leadOut != -1); if (leadOut != -1) bitStream.Write(leadOut); @@ -2828,65 +2888,64 @@ void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, SEND_PACKET; } -void GameMessages::HandleCinematicUpdate(RakNet::BitStream *inStream, Entity *entity, const SystemAddress &sysAddr) { - eCinematicEvent event; - if (!inStream->ReadBit()) { - event = STARTED; - } else { - inStream->Read(event); - } +void GameMessages::HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + eCinematicEvent event; + if (!inStream->ReadBit()) { + event = eCinematicEvent::STARTED; + } else { + inStream->Read(event); + } - float_t overallTime; - if (!inStream->ReadBit()) { - overallTime = -1.0f; - } else { - inStream->Read(overallTime); - } + float_t overallTime; + if (!inStream->ReadBit()) { + overallTime = -1.0f; + } else { + inStream->Read(overallTime); + } - uint32_t pathNameLength; - inStream->Read(pathNameLength); + uint32_t pathNameLength; + inStream->Read(pathNameLength); - std::u16string pathName; - for (size_t i = 0; i < pathNameLength; i++) { - char16_t character; - inStream->Read(character); - pathName.push_back(character); - } + std::u16string pathName; + for (size_t i = 0; i < pathNameLength; i++) { + char16_t character; + inStream->Read(character); + pathName.push_back(character); + } - float_t pathTime; - if (!inStream->ReadBit()) { - pathTime = -1.0f; - } else { - inStream->Read(pathTime); - } + float_t pathTime; + if (!inStream->ReadBit()) { + pathTime = -1.0f; + } else { + inStream->Read(pathTime); + } - int32_t waypoint; - if (!inStream->ReadBit()) { - waypoint = -1; - } else { - inStream->Read(waypoint); - } + int32_t waypoint; + if (!inStream->ReadBit()) { + waypoint = -1; + } else { + inStream->Read(waypoint); + } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); - for (Entity* scriptEntity : scriptedActs) { - scriptEntity->OnCinematicUpdate(scriptEntity, entity, event, pathName, pathTime, overallTime, waypoint); - } + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); + for (Entity* scriptEntity : scriptedActs) { + scriptEntity->OnCinematicUpdate(scriptEntity, entity, event, pathName, pathTime, overallTime, waypoint); + } } -void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, - LWOOBJID originator, bool bCantAttack, bool bCantEquip, - bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn, - bool bCantUseItem, bool bDontTerminateInteract, bool bIgnoreImmunity, - bool bCantAttackOutChangeWasApplied, bool bCantEquipOutChangeWasApplied, - bool bCantInteractOutChangeWasApplied, bool bCantJumpOutChangeWasApplied, - bool bCantMoveOutChangeWasApplied, bool bCantTurnOutChangeWasApplied, - bool bCantUseItemOutChangeWasApplied) -{ +void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, + LWOOBJID originator, bool bCantAttack, bool bCantEquip, + bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn, + bool bCantUseItem, bool bDontTerminateInteract, bool bIgnoreImmunity, + bool bCantAttackOutChangeWasApplied, bool bCantEquipOutChangeWasApplied, + bool bCantInteractOutChangeWasApplied, bool bCantJumpOutChangeWasApplied, + bool bCantMoveOutChangeWasApplied, bool bCantTurnOutChangeWasApplied, + bool bCantUseItemOutChangeWasApplied) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SET_STUNNED); + bitStream.Write(eGameMessageType::SET_STUNNED); bitStream.Write(originator != LWOOBJID_EMPTY); if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); @@ -2915,21 +2974,83 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, bitStream.Write(bCantUseItemOutChangeWasApplied); bitStream.Write(bDontTerminateInteract); - + bitStream.Write(bIgnoreImmunity); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } +void GameMessages::SendSetStunImmunity(LWOOBJID target, eStateChangeType state, const SystemAddress& sysAddr, + LWOOBJID originator, + bool bImmuneToStunAttack, + bool bImmuneToStunEquip, + bool bImmuneToStunInteract, + bool bImmuneToStunJump, + bool bImmuneToStunMove, + bool bImmuneToStunTurn, + bool bImmuneToStunUseItem) { + CBITSTREAM; + CMSGHEADER; -void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) -{ + bitStream.Write(target); + bitStream.Write(eGameMessageType::SET_STUN_IMMUNITY); + + bitStream.Write(originator != LWOOBJID_EMPTY); + if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); + + bitStream.Write(state); + + bitStream.Write(bImmuneToStunAttack); + bitStream.Write(bImmuneToStunEquip); + bitStream.Write(bImmuneToStunInteract); + bitStream.Write(bImmuneToStunJump); + bitStream.Write(bImmuneToStunMove); + bitStream.Write(bImmuneToStunTurn); + bitStream.Write(bImmuneToStunUseItem); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendSetStatusImmunity(LWOOBJID objectId, eStateChangeType state, const SystemAddress& sysAddr, + bool bImmuneToBasicAttack, + bool bImmuneToDamageOverTime, + bool bImmuneToKnockback, + bool bImmuneToInterrupt, + bool bImmuneToSpeed, + bool bImmuneToImaginationGain, + bool bImmuneToImaginationLoss, + bool bImmuneToQuickbuildInterrupt, + bool bImmuneToPullToPoint) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ORIENT_TO_ANGLE); + bitStream.Write(eGameMessageType::SET_STATUS_IMMUNITY); + + bitStream.Write(state); + + bitStream.Write(bImmuneToBasicAttack); + bitStream.Write(bImmuneToDamageOverTime); + bitStream.Write(bImmuneToKnockback); + bitStream.Write(bImmuneToInterrupt); + bitStream.Write(bImmuneToSpeed); + bitStream.Write(bImmuneToImaginationGain); + bitStream.Write(bImmuneToImaginationLoss); + bitStream.Write(bImmuneToQuickbuildInterrupt); + bitStream.Write(bImmuneToPullToPoint); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::ORIENT_TO_ANGLE); bitStream.Write(bRelativeToCurrent); bitStream.Write(fAngle); @@ -2939,13 +3060,12 @@ void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, } -void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr) -{ +void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ADD_RUN_SPEED_MODIFIER); + bitStream.Write(eGameMessageType::ADD_RUN_SPEED_MODIFIER); bitStream.Write(caster != LWOOBJID_EMPTY); if (caster != LWOOBJID_EMPTY) bitStream.Write(caster); @@ -2957,13 +3077,12 @@ void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, u SEND_PACKET; } -void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifier, const SystemAddress& sysAddr) -{ +void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifier, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_REMOVE_RUN_SPEED_MODIFIER); + bitStream.Write(eGameMessageType::REMOVE_RUN_SPEED_MODIFIER); bitStream.Write(modifier != 500); if (modifier != 500) bitStream.Write(modifier); @@ -2972,25 +3091,23 @@ void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifi SEND_PACKET; } -void GameMessages::SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PROPERTY_ENTRANCE_BEGIN); + bitStream.Write(eGameMessageType::PROPERTY_ENTRANCE_BEGIN); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector& entries, const SystemAddress& sysAddr) -{ +void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector& entries, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PROPERTY_SELECT_QUERY); + bitStream.Write(eGameMessageType::PROPERTY_SELECT_QUERY); bitStream.Write(navOffset); bitStream.Write(thereAreMore); @@ -3000,8 +3117,7 @@ void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bitStream.Write(entries.size()); - for (auto& entry : entries) - { + for (auto& entry : entries) { entry.Serialize(bitStream); } @@ -3009,21 +3125,19 @@ void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, SEND_PACKET; } -void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) -{ +void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_OBJECT); + bitStream.Write(eGameMessageType::NOTIFY_OBJECT); bitStream.Write(objIDSender); bitStream.Write(static_cast(name.size())); - for (const auto character : name) - { + for (const auto character : name) { bitStream.Write(character); } - + bitStream.Write(param1); bitStream.Write(param2); @@ -3031,8 +3145,7 @@ void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std SEND_PACKET; } -void GameMessages::HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bDifferent; std::string sBitStream; uint32_t uiHandle = 0; @@ -3047,42 +3160,38 @@ void GameMessages::HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, sBitStream.push_back(character); } - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(uiHandle); } } -void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) -{ +void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_TEAM_PICKUP_ITEM); + bitStream.Write(eGameMessageType::TEAM_PICKUP_ITEM); bitStream.Write(lootID); bitStream.Write(lootOwnerID); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } //Trading: -void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopUp, LWOOBJID i64Requestor, std::u16string wsName, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopUp, LWOOBJID i64Requestor, std::u16string wsName, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_INVITE); + bitStream.Write(eGameMessageType::SERVER_TRADE_INVITE); bitStream.Write(bNeedInvitePopUp); bitStream.Write(i64Requestor); bitStream.Write(static_cast(wsName.size())); - for (const auto character : wsName) - { + for (const auto character : wsName) { bitStream.Write(character); } @@ -3090,19 +3199,17 @@ void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopU SEND_PACKET; } -void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64Invitee, int32_t resultType, std::u16string wsName, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64Invitee, int32_t resultType, std::u16string wsName, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_INITIAL_REPLY); + bitStream.Write(eGameMessageType::SERVER_TRADE_INITIAL_REPLY); bitStream.Write(i64Invitee); bitStream.Write(resultType); bitStream.Write(static_cast(wsName.size())); - for (const auto character : wsName) - { + for (const auto character : wsName) { bitStream.Write(character); } @@ -3110,19 +3217,17 @@ void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64In SEND_PACKET; } -void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LWOOBJID i64Invitee, std::u16string wsName, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LWOOBJID i64Invitee, std::u16string wsName, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_FINAL_REPLY); + bitStream.Write(eGameMessageType::SERVER_TRADE_FINAL_REPLY); bitStream.Write(bResult); bitStream.Write(i64Invitee); bitStream.Write(static_cast(wsName.size())); - for (const auto character : wsName) - { + for (const auto character : wsName) { bitStream.Write(character); } @@ -3130,13 +3235,12 @@ void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LW SEND_PACKET; } -void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_ACCEPT); + bitStream.Write(eGameMessageType::SERVER_TRADE_ACCEPT); bitStream.Write(bFirst); @@ -3144,32 +3248,29 @@ void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const S SEND_PACKET; } -void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_CANCEL); + bitStream.Write(eGameMessageType::SERVER_TRADE_CANCEL); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector& items, const SystemAddress& sysAddr) -{ +void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector& items, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SERVER_TRADE_UPDATE); + bitStream.Write(eGameMessageType::SERVER_TRADE_UPDATE); bitStream.Write(false); bitStream.Write(coins); bitStream.Write(static_cast(items.size())); - for (const auto& item : items) - { + for (const auto& item : items) { bitStream.Write(item.itemId); bitStream.Write(item.itemId); @@ -3187,13 +3288,11 @@ void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, cons SEND_PACKET; } -void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { // Check if the player has restricted trade access auto* character = entity->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedTradeAccess)) - { + if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -3210,12 +3309,10 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* auto* invitee = EntityManager::Instance()->GetEntity(i64Invitee); - if (invitee != nullptr && invitee->IsPlayer()) - { + if (invitee != nullptr && invitee->IsPlayer()) { character = invitee->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedTradeAccess)) - { + if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -3225,72 +3322,64 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* return; } - Game::logger->Log("GameMessages", "Trade request to (%llu)\n", i64Invitee); + Game::logger->Log("GameMessages", "Trade request to (%llu)", i64Invitee); auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - if (trade != nullptr) - { - if (!trade->IsParticipant(i64Invitee)) - { + if (trade != nullptr) { + if (!trade->IsParticipant(i64Invitee)) { TradingManager::Instance()->CancelTrade(trade->GetTradeId()); TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee); } - } - else - { + } else { TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee); } - + SendServerTradeInvite( i64Invitee, bNeedInvitePopUp, entity->GetObjectID(), - GeneralUtils::ASCIIToUTF16(entity->GetCharacter()->GetName()), + GeneralUtils::UTF8ToUTF16(entity->GetCharacter()->GetName()), invitee->GetSystemAddress() ); } } -void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; - Game::logger->Log("GameMessages", "Trade canceled from (%llu)\n", entity->GetObjectID()); + Game::logger->Log("GameMessages", "Trade canceled from (%llu)", entity->GetObjectID()); TradingManager::Instance()->CancelTrade(trade->GetTradeId()); } -void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bFirst = inStream->ReadBit(); - Game::logger->Log("GameMessages", "Trade accepted from (%llu) -> (%d)\n", entity->GetObjectID(), bFirst); - + Game::logger->Log("GameMessages", "Trade accepted from (%llu) -> (%d)", entity->GetObjectID(), bFirst); + auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; trade->SetAccepted(entity->GetObjectID(), bFirst); } -void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { uint64_t currency; uint32_t itemCount; inStream->Read(currency); inStream->Read(itemCount); - Game::logger->Log("GameMessages", "Trade update from (%llu) -> (%llu), (%i)\n", entity->GetObjectID(), currency, itemCount); + Game::logger->Log("GameMessages", "Trade update from (%llu) -> (%llu), (%i)", entity->GetObjectID(), currency, itemCount); - std::vector items {}; + std::vector items{}; - for (size_t i = 0; i < itemCount; i++) - { + for (size_t i = 0; i < itemCount; i++) { LWOOBJID itemId; LWOOBJID itemId2; @@ -3306,46 +3395,39 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* bool unknown4; inStream->Read(lot); - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(unknown1); } - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(unknown2); } - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(slot); } - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(unknown3); } if (inStream->ReadBit()) // No { inStream->Read(ldfSize); bool compressed = inStream->ReadBit(); - if (compressed) - { + if (compressed) { uint32_t ldfCompressedSize = 0; inStream->Read(ldfCompressedSize); inStream->IgnoreBytes(ldfCompressedSize); - } - else - { + } else { inStream->IgnoreBytes(ldfSize); } } unknown4 = inStream->ReadBit(); - items.push_back({itemId, lot, unknown2}); + items.push_back({ itemId, lot, unknown2 }); - Game::logger->Log("GameMessages", "Trade item from (%llu) -> (%llu)/(%llu), (%i), (%llu), (%i), (%i)\n", entity->GetObjectID(), itemId, itemId2, lot, unknown1, unknown2, unknown3); + Game::logger->Log("GameMessages", "Trade item from (%llu) -> (%llu)/(%llu), (%i), (%llu), (%i), (%i)", entity->GetObjectID(), itemId, itemId2, lot, unknown1, unknown2, unknown3); } - + auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; trade->SetCoins(entity->GetObjectID(), currency); @@ -3355,13 +3437,12 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* //Pets: -void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, uint32_t notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr) -{ +void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, ePetTamingNotifyType notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_PET_TAMING_MINIGAME); + bitStream.Write(eGameMessageType::NOTIFY_PET_TAMING_MINIGAME); bitStream.Write(petId); bitStream.Write(playerTamingId); @@ -3378,29 +3459,26 @@ void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId SEND_PACKET; } -void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER); + bitStream.Write(eGameMessageType::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vector& bricks, const SystemAddress& sysAddr) -{ +void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vector& bricks, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_PET_TAMING_PUZZLE_SELECTED); + bitStream.Write(eGameMessageType::NOTIFY_PET_TAMING_PUZZLE_SELECTED); bitStream.Write(static_cast(bricks.size())); - for (const auto& brick : bricks) - { + for (const auto& brick : bricks) { bitStream.Write(brick.designerID); bitStream.Write(brick.materialID); } @@ -3409,13 +3487,12 @@ void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vec SEND_PACKET; } -void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, int32_t iNumCorrect, const SystemAddress& sysAddr) -{ +void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, int32_t iNumCorrect, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PET_TAMING_TRY_BUILD_RESULT); + bitStream.Write(eGameMessageType::PET_TAMING_TRY_BUILD_RESULT); bitStream.Write(bSuccess); bitStream.Write(iNumCorrect != 0); @@ -3425,13 +3502,12 @@ void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, SEND_PACKET; } -void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t iPetCommandType, int32_t iResponse, int32_t iTypeID, const SystemAddress& sysAddr) -{ +void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t iPetCommandType, int32_t iResponse, int32_t iTypeID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PET_RESPONSE); + bitStream.Write(eGameMessageType::PET_RESPONSE); bitStream.Write(objIDPet); bitStream.Write(iPetCommandType); @@ -3442,21 +3518,19 @@ void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t SEND_PACKET; } -void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, std::u16string name, LWOOBJID petDBID, LOT petLOT, const SystemAddress& sysAddr) -{ +void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, std::u16string name, LWOOBJID petDBID, LOT petLOT, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ADD_PET_TO_PLAYER); + bitStream.Write(eGameMessageType::ADD_PET_TO_PLAYER); bitStream.Write(iElementalType); bitStream.Write(static_cast(name.size())); - for (const auto character : name) - { + for (const auto character : name) { bitStream.Write(character); } - + bitStream.Write(petDBID); bitStream.Write(petLOT); @@ -3464,13 +3538,12 @@ void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, SEND_PACKET; } -void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const SystemAddress& sysAddr) -{ +void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_REGISTER_PET_ID); + bitStream.Write(eGameMessageType::REGISTER_PET_ID); bitStream.Write(objID); @@ -3478,13 +3551,12 @@ void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const Sy SEND_PACKET; } -void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr) -{ +void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_REGISTER_PET_DBID); + bitStream.Write(eGameMessageType::REGISTER_PET_DBID); bitStream.Write(petDBID); @@ -3492,18 +3564,17 @@ void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, cons SEND_PACKET; } -void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr) -{ +void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, eUnequippableActiveType iType, LWOOBJID itemID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE); + bitStream.Write(eGameMessageType::MARK_INVENTORY_ITEM_AS_ACTIVE); bitStream.Write(bActive); - - bitStream.Write(iType != 0); - if (iType != 0) bitStream.Write(iType); + + bitStream.Write(iType != eUnequippableActiveType::INVALID); + if (iType != eUnequippableActiveType::INVALID) bitStream.Write(iType); bitStream.Write(itemID != LWOOBJID_EMPTY); if (itemID != LWOOBJID_EMPTY) bitStream.Write(itemID); @@ -3512,13 +3583,12 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive SEND_PACKET; } -void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr) -{ +void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_CLIENT_EXIT_TAMING_MINIGAME); + bitStream.Write(eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME); bitStream.Write(bVoluntaryExit); @@ -3526,13 +3596,12 @@ void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVolunta SEND_PACKET; } -void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr) -{ +void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SHOW_PET_ACTION_BUTTON); + bitStream.Write(eGameMessageType::SHOW_PET_ACTION_BUTTON); bitStream.Write(buttonLabel); bitStream.Write(bShow); @@ -3541,13 +3610,12 @@ void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabe SEND_PACKET; } -void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr) -{ +void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PLAY_EMOTE); + bitStream.Write(eGameMessageType::PLAY_EMOTE); bitStream.Write(emoteID); bitStream.Write(target); @@ -3556,14 +3624,27 @@ void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID ta SEND_PACKET; } +void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId) { + CBITSTREAM; + CMSGHEADER; -void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, const SystemAddress& sysAddr) -{ + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::REMOVE_BUFF); + + bitStream.Write(false); // bFromRemoveBehavior but setting this to true makes the GM not do anything on the client? + bitStream.Write(fromUnEquip); + bitStream.Write(removeImmunity); + bitStream.Write(buffId); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_BOUNCER_ACTIVE_STATUS); + bitStream.Write(eGameMessageType::BOUNCER_ACTIVE_STATUS); bitStream.Write(bActive); @@ -3572,20 +3653,18 @@ void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, cons } -void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJID petDBID, const SystemAddress& sysAddr) -{ +void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJID petDBID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SET_PET_NAME); + bitStream.Write(eGameMessageType::SET_PET_NAME); bitStream.Write(static_cast(name.size())); - for (const auto character : name) - { + for (const auto character : name) { bitStream.Write(character); } - + bitStream.Write(petDBID != LWOOBJID_EMPTY); if (petDBID != LWOOBJID_EMPTY) bitStream.Write(petDBID); @@ -3594,14 +3673,13 @@ void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJ } -void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, int32_t nModerationStatus, const SystemAddress& sysAddr) -{ +void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, int32_t nModerationStatus, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SET_PET_NAME_MODERATED); - + bitStream.Write(eGameMessageType::SET_PET_NAME_MODERATED); + bitStream.Write(petDBID != LWOOBJID_EMPTY); if (petDBID != LWOOBJID_EMPTY) bitStream.Write(petDBID); @@ -3612,25 +3690,22 @@ void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, } -void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatus, std::u16string name, std::u16string ownerName, const SystemAddress& sysAddr) -{ +void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatus, std::u16string name, std::u16string ownerName, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_PET_NAME_CHANGED); + bitStream.Write(eGameMessageType::PET_NAME_CHANGED); bitStream.Write(moderationStatus); bitStream.Write(static_cast(name.size())); - for (const auto character : name) - { + for (const auto character : name) { bitStream.Write(character); } - + bitStream.Write(static_cast(ownerName.size())); - for (const auto character : ownerName) - { + for (const auto character : ownerName) { bitStream.Write(character); } @@ -3639,34 +3714,29 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu } -void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bVoluntaryExit = inStream->ReadBit(); auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } petComponent->ClientExitTamingMinigame(bVoluntaryExit); } -void GameMessages::HandleStartServerPetMinigameTimer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleStartServerPetMinigameTimer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } petComponent->StartTimer(); } -void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t brickCount; std::vector bricks; bool clientFailed; @@ -3675,8 +3745,7 @@ void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* bricks.reserve(brickCount); - for (uint32_t i = 0; i < brickCount; i++) - { + for (uint32_t i = 0; i < brickCount; i++) { Brick brick; inStream->Read(brick); @@ -3688,52 +3757,45 @@ void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } petComponent->TryBuild(bricks.size(), clientFailed); } -void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 position; inStream->Read(position); auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } petComponent->NotifyTamingBuildSuccess(position); } -void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t nameLength; std::u16string name; inStream->Read(nameLength); - for (size_t i = 0; i < nameLength; i++) - { + for (size_t i = 0; i < nameLength; i++) { char16_t character; inStream->Read(character); name.push_back(character); } - + auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { petComponent = PetComponent::GetActivePet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } } @@ -3741,14 +3803,13 @@ void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* petComponent->RequestSetPetName(name); } -void GameMessages::HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 genericPosInfo; LWOOBJID objIdSource; int32_t iPetCommandType; int32_t iTypeID; bool overrideObey; - + inStream->Read(genericPosInfo); inStream->Read(objIdSource); inStream->Read(iPetCommandType); @@ -3757,39 +3818,32 @@ void GameMessages::HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, auto* petComponent = entity->GetComponent(); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } petComponent->Command(genericPosInfo, objIdSource, iPetCommandType, iTypeID, overrideObey); } -void GameMessages::HandleDespawnPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleDespawnPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bDeletePet; bDeletePet = inStream->ReadBit(); auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID()); - if (petComponent == nullptr) - { + if (petComponent == nullptr) { return; } - if (bDeletePet) - { + if (bDeletePet) { petComponent->Release(); - } - else - { + } else { petComponent->Deactivate(); } } -void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { int32_t iButton; uint32_t identifierLength; std::u16string identifier; @@ -3799,34 +3853,30 @@ void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* inStream->Read(iButton); inStream->Read(identifierLength); - for (size_t i = 0; i < identifierLength; i++) - { + for (size_t i = 0; i < identifierLength; i++) { char16_t character; inStream->Read(character); identifier.push_back(character); } inStream->Read(userDataLength); - for (size_t i = 0; i < userDataLength; i++) - { + for (size_t i = 0; i < userDataLength; i++) { char16_t character; inStream->Read(character); userData.push_back(character); } - - Game::logger->Log("HandleMessageBoxResponse", "Button: " + std::to_string(iButton) + "; LOT: " + std::to_string(entity->GetLOT()) + " identifier: " + GeneralUtils::UTF16ToWTF8(identifier) + "; userData: " + GeneralUtils::UTF16ToWTF8(userData) + "\n"); + + Game::logger->Log("HandleMessageBoxResponse", "Button: %d; LOT: %u identifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(identifier).c_str(), GeneralUtils::UTF16ToWTF8(userData).c_str()); auto* user = UserManager::Instance()->GetUser(sysAddr); - if (user == nullptr) - { + if (user == nullptr) { return; } auto* userEntity = user->GetLastUsedChar()->GetEntity(); - if (userEntity == nullptr) - { + if (userEntity == nullptr) { return; } @@ -3834,26 +3884,22 @@ void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* auto* scriptedActivityComponent = entity->GetComponent(); - if (scriptedActivityComponent != nullptr) - { + if (scriptedActivityComponent != nullptr) { scriptedActivityComponent->HandleMessageBoxResponse(userEntity, GeneralUtils::UTF16ToWTF8(identifier)); } auto* racingControlComponent = entity->GetComponent(); - if (racingControlComponent != nullptr) - { - racingControlComponent->HandleMessageBoxResponse(userEntity, GeneralUtils::UTF16ToWTF8(identifier)); + if (racingControlComponent != nullptr) { + racingControlComponent->HandleMessageBoxResponse(userEntity, iButton, GeneralUtils::UTF16ToWTF8(identifier)); } - for (auto* shootingGallery : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SHOOTING_GALLERY)) - { + for (auto* shootingGallery : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY)) { shootingGallery->OnMessageBoxResponse(userEntity, iButton, identifier, userData); } } -void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { int32_t iButton; uint32_t buttonIdentifierLength; std::u16string buttonIdentifier; @@ -3861,8 +3907,7 @@ void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* e std::u16string identifier; inStream->Read(buttonIdentifierLength); - for (size_t i = 0; i < buttonIdentifierLength; i++) - { + for (size_t i = 0; i < buttonIdentifierLength; i++) { char16_t character; inStream->Read(character); buttonIdentifier.push_back(character); @@ -3871,39 +3916,35 @@ void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* e inStream->Read(iButton); inStream->Read(identifierLength); - for (size_t i = 0; i < identifierLength; i++) - { + for (size_t i = 0; i < identifierLength; i++) { char16_t character; inStream->Read(character); identifier.push_back(character); } - - Game::logger->Log("HandleChoiceBoxRespond", "Button: " + std::to_string(iButton) + "; LOT: " + std::to_string(entity->GetLOT()) + " buttonIdentifier: " + GeneralUtils::UTF16ToWTF8(buttonIdentifier) + "; userData: " + GeneralUtils::UTF16ToWTF8(identifier) + "\n"); + + Game::logger->Log("HandleChoiceBoxRespond", "Button: %d; LOT: %u buttonIdentifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(buttonIdentifier).c_str(), GeneralUtils::UTF16ToWTF8(identifier).c_str()); auto* user = UserManager::Instance()->GetUser(sysAddr); - if (user == nullptr) - { + if (user == nullptr) { return; } auto* userEntity = user->GetLastUsedChar()->GetEntity(); - if (userEntity == nullptr) - { + if (userEntity == nullptr) { return; } entity->OnChoiceBoxResponse(userEntity, iButton, buttonIdentifier, identifier); } -void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) -{ +void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_DISPLAY_ZONE_SUMMARY); + bitStream.Write(eGameMessageType::DISPLAY_ZONE_SUMMARY); bitStream.Write(isPropertyMap); bitStream.Write(isZoneStart); @@ -3916,13 +3957,12 @@ void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress //UI -void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeSlotsNeeded, eInventoryType inventoryType, const SystemAddress& sysAddr) -{ +void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeSlotsNeeded, eInventoryType inventoryType, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE); + bitStream.Write(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE); bitStream.Write(freeSlotsNeeded); bitStream.Write(inventoryType != 0); @@ -3932,34 +3972,30 @@ void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeS SEND_PACKET; } -void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) -{ +void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_DISPLAY_MESSAGE_BOX); + bitStream.Write(eGameMessageType::DISPLAY_MESSAGE_BOX); bitStream.Write(bShow); bitStream.Write(callbackClient); bitStream.Write(static_cast(identifier.size())); - for (const auto character : identifier) - { + for (const auto character : identifier) { bitStream.Write(character); } bitStream.Write(imageID); - + bitStream.Write(static_cast(text.size())); - for (const auto character : text) - { + for (const auto character : text) { bitStream.Write(character); } bitStream.Write(static_cast(userData.size())); - for (const auto character : userData) - { + for (const auto character : userData) { bitStream.Write(character); } @@ -3967,18 +4003,16 @@ void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID SEND_PACKET; } -void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) -{ - // GAME_MSG_DISPLAY_CHAT_BUBBLE +void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) { + // eGameMessageType::DISPLAY_CHAT_BUBBLE CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_DISPLAY_CHAT_BUBBLE); + bitStream.Write(eGameMessageType::DISPLAY_CHAT_BUBBLE); bitStream.Write(static_cast(text.size())); - for (const auto character : text) - { + for (const auto character : text) { bitStream.Write(character); } @@ -3986,55 +4020,125 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string SEND_PACKET; } -//Racing -void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - auto* moduleAssemblyComponent = entity->GetComponent(); +void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; - Game::logger->Log("HandleModuleAssemblyQueryData", "Got Query from %i\n", entity->GetLOT()); + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::CHANGE_IDLE_FLAGS); + bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); + if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); + bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); + if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); - if (moduleAssemblyComponent != nullptr) - { - Game::logger->Log("HandleModuleAssemblyQueryData", "Returning assembly %s\n", GeneralUtils::UTF16ToWTF8(moduleAssemblyComponent->GetAssemblyPartsLOTs()).c_str()); + SEND_PACKET_BROADCAST; +} +// Mounts - SendModuleAssemblyDBDataForClient(entity->GetObjectID(), moduleAssemblyComponent->GetSubKey(), moduleAssemblyComponent->GetAssemblyPartsLOTs(), UNASSIGNED_SYSTEM_ADDRESS); +void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::SET_MOUNT_INVENTORY_ID); + bitStream.Write(objectID); + + SEND_PACKET_BROADCAST; +} + + +void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + // Get the objectID from the bitstream + LWOOBJID objectId{}; + inStream->Read(objectId); + + // If we aren't possessing somethings, the don't do anything + if (objectId != LWOOBJID_EMPTY) { + auto* possessorComponent = entity->GetComponent(); + auto* mount = EntityManager::Instance()->GetEntity(objectId); + // make sure we have the things we need and they aren't null + if (possessorComponent && mount) { + if (!possessorComponent->GetIsDismounting()) return; + possessorComponent->SetIsDismounting(false); + possessorComponent->SetPossessable(LWOOBJID_EMPTY); + possessorComponent->SetPossessableType(ePossessionType::NO_POSSESSION); + + // character related things + auto* character = entity->GetComponent(); + if (character) { + // If we had an active item turn it off + if (possessorComponent->GetMountItemID() != LWOOBJID_EMPTY) GameMessages::SendMarkInventoryItemAsActive(entity->GetObjectID(), false, eUnequippableActiveType::MOUNT, possessorComponent->GetMountItemID(), entity->GetSystemAddress()); + possessorComponent->SetMountItemID(LWOOBJID_EMPTY); + } + + // Set that the controllabel phsyics comp is teleporting + auto* controllablePhysicsComponent = entity->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetIsTeleporting(true); + + // Call dismoint on the possessable comp to let it handle killing the possessable + auto* possessableComponent = mount->GetComponent(); + if (possessableComponent) possessableComponent->Dismount(); + + // Update the entity that was possessing + EntityManager::Instance()->SerializeEntity(entity); + + // We aren't mounted so remove the stun + GameMessages::SendSetStunned(entity->GetObjectID(), eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + } } } -void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + EntityManager::Instance()->SerializeEntity(entity); + LWOOBJID objectId{}; + inStream->Read(objectId); + auto* mount = EntityManager::Instance()->GetEntity(objectId); + if (mount) EntityManager::Instance()->SerializeEntity(mount); +} + +//Racing + +void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + auto* moduleAssemblyComponent = entity->GetComponent(); + + Game::logger->Log("HandleModuleAssemblyQueryData", "Got Query from %i", entity->GetLOT()); + + if (moduleAssemblyComponent != nullptr) { + Game::logger->Log("HandleModuleAssemblyQueryData", "Returning assembly %s", GeneralUtils::UTF16ToWTF8(moduleAssemblyComponent->GetAssemblyPartsLOTs()).c_str()); + + SendModuleAssemblyDBDataForClient(entity->GetObjectID(), moduleAssemblyComponent->GetSubKey(), moduleAssemblyComponent->GetAssemblyPartsLOTs(), UNASSIGNED_SYSTEM_ADDRESS); + } +} + + +void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID objectID; inStream->Read(objectID); } -void GameMessages::HandleVehicleSetWheelLockState(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleVehicleSetWheelLockState(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bExtraFriction = inStream->ReadBit(); bool bLocked = inStream->ReadBit(); } -void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID playerID; inStream->Read(playerID); auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - { + if (player == nullptr) { return; } auto* racingControlComponent = dZoneManager::Instance()->GetZoneControlObject()->GetComponent(); - if (racingControlComponent == nullptr) - { + if (racingControlComponent == nullptr) { return; } @@ -4042,34 +4146,24 @@ void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* } -void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - Game::logger->Log("HandleAcknowledgePossession", "Got AcknowledgePossession from %i\n", entity->GetLOT()); - - EntityManager::Instance()->SerializeEntity(entity); -} - - -void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bClientDeath; bool bSpawnLoot; std::u16string deathType; float directionRelativeAngleXZ; float directionRelativeAngleY; float directionRelativeForce; - int32_t killType = VIOLENT; + eKillType killType = eKillType::VIOLENT; LWOOBJID killerID; LWOOBJID lootOwnerID = LWOOBJID_EMPTY; bClientDeath = inStream->ReadBit(); bSpawnLoot = inStream->ReadBit(); - + uint32_t deathTypeLength = 0; inStream->Read(deathTypeLength); - for (size_t i = 0; i < deathTypeLength; i++) - { + for (size_t i = 0; i < deathTypeLength; i++) { char16_t character; inStream->Read(character); @@ -4080,15 +4174,13 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, inStream->Read(directionRelativeAngleY); inStream->Read(directionRelativeForce); - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(killType); } inStream->Read(killerID); - if (inStream->ReadBit()) - { + if (inStream->ReadBit()) { inStream->Read(lootOwnerID); } @@ -4096,18 +4188,15 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, auto* racingControlComponent = zoneController->GetComponent(); - Game::logger->Log("HandleRequestDie", "Got die request: %i\n", entity->GetLOT()); + Game::logger->Log("HandleRequestDie", "Got die request: %i", entity->GetLOT()); - if (racingControlComponent != nullptr) - { + if (racingControlComponent != nullptr) { auto* possessableComponent = entity->GetComponent(); - if (possessableComponent != nullptr) - { + if (possessableComponent != nullptr) { entity = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (entity == nullptr) - { + if (entity == nullptr) { return; } } @@ -4117,28 +4206,24 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, } -void GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { //SendVehicleAddPassiveBoostAction(entity->GetObjectID(), sysAddr); } -void GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { //SendVehicleRemovePassiveBoostAction(entity->GetObjectID(), sysAddr); } -void GameMessages::HandleRacingPlayerInfoResetFinished(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleRacingPlayerInfoResetFinished(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID playerID; inStream->Read(playerID); auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - { + if (player == nullptr) { return; } @@ -4146,10 +4231,9 @@ void GameMessages::HandleRacingPlayerInfoResetFinished(RakNet::BitStream* inStre auto* racingControlComponent = zoneController->GetComponent(); - Game::logger->Log("HandleRacingPlayerInfoResetFinished", "Got finished: %i\n", entity->GetLOT()); + Game::logger->Log("HandleRacingPlayerInfoResetFinished", "Got finished: %i", entity->GetLOT()); - if (racingControlComponent != nullptr) - { + if (racingControlComponent != nullptr) { racingControlComponent->OnRacingPlayerInfoResetFinished(player); } } @@ -4159,7 +4243,7 @@ void GameMessages::SendUpdateReputation(const LWOOBJID objectId, const int64_t r CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_UPDATE_REPUTATION); + bitStream.Write(eGameMessageType::UPDATE_REPUTATION); bitStream.Write(reputation); @@ -4190,8 +4274,7 @@ void GameMessages::HandleUpdatePropertyPerformanceCost(RakNet::BitStream* inStre updatePerformanceCostQuery = nullptr; } -void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID pickupObjID = LWOOBJID_EMPTY; LWOOBJID pickupSpawnerID = LWOOBJID_EMPTY; int32_t pickupSpawnerIndex = -1; @@ -4204,27 +4287,24 @@ void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* in auto* pickup = EntityManager::Instance()->GetEntity(pickupObjID); - if (pickup == nullptr) - { + if (pickup == nullptr) { return; } auto* possessableComponent = entity->GetComponent(); - if (possessableComponent != nullptr) - { + if (possessableComponent != nullptr) { entity = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (entity == nullptr) - { + if (entity == nullptr) { return; } } - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingImaginationPowerUpsCollected); - } + auto* characterComponent = entity->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingImaginationPowerUpsCollected); + } pickup->OnFireEventServerSide(entity, "powerup"); @@ -4232,19 +4312,17 @@ void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* in } -void GameMessages::SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID assemblyID, const std::u16string& data, const SystemAddress& sysAddr) -{ +void GameMessages::SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID assemblyID, const std::u16string& data, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT); + bitStream.Write(eGameMessageType::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT); bitStream.Write(assemblyID); bitStream.Write(static_cast(data.size())); - for (auto character : data) - { + for (auto character : data) { bitStream.Write(character); } @@ -4253,13 +4331,12 @@ void GameMessages::SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID } -void GameMessages::SendNotifyVehicleOfRacingObject(LWOOBJID objectId, LWOOBJID racingObjectID, const SystemAddress& sysAddr) -{ +void GameMessages::SendNotifyVehicleOfRacingObject(LWOOBJID objectId, LWOOBJID racingObjectID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_VEHICLE_OF_RACING_OBJECT); + bitStream.Write(eGameMessageType::NOTIFY_VEHICLE_OF_RACING_OBJECT); bitStream.Write(racingObjectID != LWOOBJID_EMPTY); if (racingObjectID != LWOOBJID_EMPTY) bitStream.Write(racingObjectID); @@ -4269,13 +4346,12 @@ void GameMessages::SendNotifyVehicleOfRacingObject(LWOOBJID objectId, LWOOBJID r } -void GameMessages::SendRacingPlayerLoaded(LWOOBJID objectId, LWOOBJID playerID, LWOOBJID vehicleID, const SystemAddress& sysAddr) -{ +void GameMessages::SendRacingPlayerLoaded(LWOOBJID objectId, LWOOBJID playerID, LWOOBJID vehicleID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_RACING_PLAYER_LOADED); + bitStream.Write(eGameMessageType::RACING_PLAYER_LOADED); bitStream.Write(playerID); bitStream.Write(vehicleID); @@ -4285,13 +4361,12 @@ void GameMessages::SendRacingPlayerLoaded(LWOOBJID objectId, LWOOBJID playerID, } -void GameMessages::SendVehicleUnlockInput(LWOOBJID objectId, bool bLockWheels, const SystemAddress& sysAddr) -{ +void GameMessages::SendVehicleUnlockInput(LWOOBJID objectId, bool bLockWheels, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_UNLOCK_INPUT); + bitStream.Write(eGameMessageType::VEHICLE_UNLOCK_INPUT); bitStream.Write(bLockWheels); @@ -4300,13 +4375,12 @@ void GameMessages::SendVehicleUnlockInput(LWOOBJID objectId, bool bLockWheels, c } -void GameMessages::SendVehicleSetWheelLockState(LWOOBJID objectId, bool bExtraFriction, bool bLocked, const SystemAddress& sysAddr) -{ +void GameMessages::SendVehicleSetWheelLockState(LWOOBJID objectId, bool bExtraFriction, bool bLocked, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE); + bitStream.Write(eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE); bitStream.Write(bExtraFriction); bitStream.Write(bLocked); @@ -4316,13 +4390,12 @@ void GameMessages::SendVehicleSetWheelLockState(LWOOBJID objectId, bool bExtraFr } -void GameMessages::SendRacingSetPlayerResetInfo(LWOOBJID objectId, int32_t currentLap, uint32_t furthestResetPlane, LWOOBJID playerID, NiPoint3 respawnPos, uint32_t upcomingPlane, const SystemAddress& sysAddr) -{ +void GameMessages::SendRacingSetPlayerResetInfo(LWOOBJID objectId, int32_t currentLap, uint32_t furthestResetPlane, LWOOBJID playerID, NiPoint3 respawnPos, uint32_t upcomingPlane, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_RACING_SET_PLAYER_RESET_INFO); + bitStream.Write(eGameMessageType::RACING_SET_PLAYER_RESET_INFO); bitStream.Write(currentLap); bitStream.Write(furthestResetPlane); @@ -4335,13 +4408,12 @@ void GameMessages::SendRacingSetPlayerResetInfo(LWOOBJID objectId, int32_t curre } -void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID playerID, const SystemAddress& sysAddr) -{ +void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID playerID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_RACING_RESET_PLAYER_TO_LAST_RESET); + bitStream.Write(eGameMessageType::RACING_RESET_PLAYER_TO_LAST_RESET); bitStream.Write(playerID); @@ -4349,14 +4421,43 @@ void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID SEND_PACKET; } +void GameMessages::SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive) { + CBITSTREAM; + CMSGHEADER; -void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) -{ + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(eGameMessageType::VEHICLE_STOP_BOOST); + + bitStream.Write(affectPassive); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(eGameMessageType::SET_RESURRECT_RESTORE_VALUES); + + bitStream.Write(armorRestore != -1); + if (armorRestore != -1) bitStream.Write(armorRestore); + + bitStream.Write(healthRestore != -1); + if (healthRestore != -1) bitStream.Write(healthRestore); + + bitStream.Write(imaginationRestore != -1); + if (imaginationRestore != -1) bitStream.Write(imaginationRestore); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_NOTIFY_RACING_CLIENT); + bitStream.Write(eGameMessageType::NOTIFY_RACING_CLIENT); bitStream.Write(eventType != 0); if (eventType != 0) bitStream.Write(eventType); @@ -4366,8 +4467,7 @@ void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, bitStream.Write(paramObj); bitStream.Write(static_cast(paramStr.size())); - for (auto character : paramStr) - { + for (auto character : paramStr) { bitStream.Write(character); } @@ -4378,52 +4478,48 @@ void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, } -void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ACTIVITY_ENTER); + bitStream.Write(eGameMessageType::ACTIVITY_ENTER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ACTIVITY_START); + bitStream.Write(eGameMessageType::ACTIVITY_START); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ACTIVITY_EXIT); + bitStream.Write(eGameMessageType::ACTIVITY_EXIT); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCancel, const SystemAddress& sysAddr) -{ +void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCancel, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_ACTIVITY_STOP); + bitStream.Write(eGameMessageType::ACTIVITY_STOP); bitStream.Write(bExit); bitStream.Write(bUserCancel); @@ -4433,53 +4529,50 @@ void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCan } -void GameMessages::SendVehicleAddPassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendVehicleAddPassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION); + bitStream.Write(eGameMessageType::VEHICLE_ADD_PASSIVE_BOOST_ACTION); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendVehicleRemovePassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendVehicleRemovePassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION); + bitStream.Write(eGameMessageType::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } -void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const SystemAddress& sysAddr) -{ +void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE); + bitStream.Write(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration, - bool addImmunity, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, - bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, - const SystemAddress& sysAddr) { + bool addImmunity, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, + bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, + const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(GAME_MSG::GAME_MSG_ADD_BUFF); + bitStream.Write(eGameMessageType::ADD_BUFF); bitStream.Write(false); // Added by teammate bitStream.Write(false); // Apply on teammates @@ -4510,15 +4603,14 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin // NT -void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - bool bAllowPartial; +void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + bool bAllowPartial{}; int32_t destSlot = -1; int32_t iStackCount = 1; eInventoryType invTypeDst = ITEMS; eInventoryType invTypeSrc = ITEMS; LWOOBJID itemID = LWOOBJID_EMPTY; - bool showFlyingLoot; + bool showFlyingLoot{}; LWOOBJID subkey = LWOOBJID_EMPTY; LOT itemLOT = 0; @@ -4532,27 +4624,22 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* if (inStream->ReadBit()) inStream->Read(subkey); if (inStream->ReadBit()) inStream->Read(itemLOT); - if (invTypeDst == invTypeSrc) - { + if (invTypeDst == invTypeSrc) { return; } auto* inventoryComponent = entity->GetComponent(); - if (inventoryComponent != nullptr) - { - if (itemID != LWOOBJID_EMPTY) - { + if (inventoryComponent != nullptr) { + if (itemID != LWOOBJID_EMPTY) { auto* item = inventoryComponent->FindItemById(itemID); - if (item == nullptr) - { - return; - } + if (!item) return; - if (inventoryComponent->IsPet(item->GetSubKey()) || !item->GetConfig().empty()) - { - return; + // Despawn the pet if we are moving that pet to the vault. + auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID()); + if (petComponent && petComponent->GetDatabaseId() == item->GetSubKey()) { + inventoryComponent->DespawnPet(); } inventoryComponent->MoveItemToInventory(item, invTypeDst, iStackCount, showFlyingLoot, false, false, destSlot); @@ -4561,21 +4648,19 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* } -void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) -{ +void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(GAME_MSG::GAME_MSG_SHOW_ACTIVITY_COUNTDOWN); + bitStream.Write(eGameMessageType::SHOW_ACTIVITY_COUNTDOWN); bitStream.Write(bPlayAdditionalSound); bitStream.Write(bPlayCountdownSound); bitStream.Write(static_cast(sndName.size())); - for (auto character : sndName) - { + for (auto character : sndName) { bitStream.Write(character); } @@ -4590,33 +4675,29 @@ void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditi //------------------------------------------------------------------- Handlers ------------------------------------------------------------------ //----------------------------------------------------------------------------------------------------------------------------------------------- -void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bOverride = false; inStream->Read(bOverride); auto* player = Player::GetPlayer(sysAddr); - if (player != nullptr) - { + if (player != nullptr) { player->SetGhostOverride(bOverride); - + EntityManager::Instance()->UpdateGhosting(player); } } -void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ +void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 position; inStream->Read(position); auto* player = Player::GetPlayer(sysAddr); - if (player != nullptr) - { + if (player != nullptr) { player->SetGhostOverridePoint(position); EntityManager::Instance()->UpdateGhosting(player); @@ -4640,110 +4721,85 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti Entity* player = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!player) return; - auto* propertyVendorComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_VENDOR)); + auto* propertyVendorComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); - if (propertyVendorComponent != nullptr) - { + if (propertyVendorComponent != nullptr) { propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count); return; } const auto isCommendationVendor = entity->GetLOT() == 13806; - - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend && !isCommendationVendor) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item, COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); Character* character = player->GetCharacter(); if (!character) return; - // Extra currency that needs to be deducted in case of crafting - auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); - for (const auto& craftingCurrency : craftingCurrencies) { - inv->RemoveItem(craftingCurrency.first, craftingCurrency.second * count); - } + // Extra currency that needs to be deducted in case of crafting + auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); + for (const auto& craftingCurrency : craftingCurrencies) { + inv->RemoveItem(craftingCurrency.first, craftingCurrency.second * count); + } - if (isCommendationVendor) - { - if (itemComp.commendationLOT != 13763) - { + if (isCommendationVendor) { + if (itemComp.commendationLOT != 13763) { return; } auto* missionComponent = player->GetComponent(); - if (missionComponent == nullptr) - { + if (missionComponent == nullptr) { return; } LOT tokenId = -1; - if (missionComponent->GetMissionState(545) == MissionState::MISSION_STATE_COMPLETE) // "Join Assembly!" - { - tokenId = 8318; // "Assembly Token" - } - - if (missionComponent->GetMissionState(556) == MissionState::MISSION_STATE_COMPLETE) // "Join Venture League!" - { - tokenId = 8321; // "Venture League Token" - } - - if (missionComponent->GetMissionState(567) == MissionState::MISSION_STATE_COMPLETE) // "Join The Sentinels!" - { - tokenId = 8319; // "Sentinels Token" - } - - if (missionComponent->GetMissionState(578) == MissionState::MISSION_STATE_COMPLETE) // "Join Paradox!" - { - tokenId = 8320; // "Paradox Token" - } + if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) tokenId = 8318; // "Assembly Token" + if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) tokenId = 8321; // "Venture League Token" + if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) tokenId = 8319; // "Sentinels Token" + if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) tokenId = 8320; // "Paradox Token" const uint32_t altCurrencyCost = itemComp.commendationCost * count; - if (inv->GetLotCount(tokenId) < altCurrencyCost) - { + if (inv->GetLotCount(tokenId) < altCurrencyCost) { return; } inv->RemoveItem(tokenId, altCurrencyCost); - inv->AddItem(item, count, eLootSourceType::LOOT_SOURCE_VENDOR); - } - else - { + inv->AddItem(item, count, eLootSourceType::VENDOR); + } else { float buyScalar = vend->GetBuyScalar(); const auto coinCost = static_cast(std::floor((itemComp.baseValue * buyScalar) * count)); - if (character->GetCoins() < coinCost) - { + if (character->GetCoins() < coinCost) { return; } - if (Inventory::IsValidItem(itemComp.currencyLOT)) - { + if (Inventory::IsValidItem(itemComp.currencyLOT)) { const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count; - if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) - { + if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { return; } inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost); } - character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::LOOT_SOURCE_VENDOR); - inv->AddItem(item, count, eLootSourceType::LOOT_SOURCE_VENDOR); + character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR); + inv->AddItem(item, count, eLootSourceType::VENDOR); } GameMessages::SendVendorTransactionResult(entity, sysAddr); @@ -4764,34 +4820,33 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit if (!player) return; Character* character = player->GetCharacter(); if (!character) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend) return; Item* item = inv->FindItemById(iObjID); if (!item) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); // Items with a base value of 0 or max int are special items that should not be sold if they're not sub items if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) return; float sellScalar = vend->GetSellScalar(); - if (Inventory::IsValidItem(itemComp.currencyLOT)) - { - const auto altCurrency = (itemComp.altCurrencyCost * sellScalar) * count; - inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::LOOT_SOURCE_VENDOR); // Return alt currencies like faction tokens. + if (Inventory::IsValidItem(itemComp.currencyLOT)) { + const auto altCurrency = static_cast(itemComp.altCurrencyCost * sellScalar) * count; + inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens. } //inv->RemoveItem(count, -1, iObjID); inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true); - character->SetCoins(std::floor(character->GetCoins() + ((itemComp.baseValue * sellScalar)*count)), eLootSourceType::LOOT_SOURCE_VENDOR); + character->SetCoins(std::floor(character->GetCoins() + (static_cast(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR); //EntityManager::Instance()->SerializeEntity(player); // so inventory updates GameMessages::SendVendorTransactionResult(entity, sysAddr); } @@ -4815,36 +4870,33 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* if (!player) return; Character* character = player->GetCharacter(); if (!character) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend) return; Item* item = inv->FindItemById(iObjID); if (!item) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); float sellScalar = vend->GetSellScalar(); const auto cost = static_cast(std::floor(((itemComp.baseValue * sellScalar) * count))); - if (character->GetCoins() < cost) - { + if (character->GetCoins() < cost) { return; } - if (Inventory::IsValidItem(itemComp.currencyLOT)) - { + if (Inventory::IsValidItem(itemComp.currencyLOT)) { const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count; - if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) - { + if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { return; } @@ -4853,7 +4905,7 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* //inv->RemoveItem(count, -1, iObjID); inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false); - character->SetCoins(character->GetCoins() - cost, eLootSourceType::LOOT_SOURCE_VENDOR); + character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR); //EntityManager::Instance()->SerializeEntity(player); // so inventory updates GameMessages::SendVendorTransactionResult(entity, sysAddr); } @@ -4908,22 +4960,13 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity return; } - if (args == u"toggleMail") { - AMFFalseValue* value = new AMFFalseValue(); - - AMFArrayValue args; - args.InsertValue("visible", value); - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleMail", &args); - delete value; - } - // This should probably get it's own "ServerEvents" system or something at some point if (args == u"ZonePlayer") { // Should probably check to make sure they're using a launcher at some point before someone makes a hack that lets you testmap LWOCLONEID cloneId = 0; LWOMAPID mapId = 0; - + auto* rocketPad = entity->GetComponent(); if (rocketPad == nullptr) return; @@ -4932,23 +4975,20 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity if (param2) { mapId = rocketPad->GetDefaultZone(); - } - else { + } else { mapId = param3; } - if (mapId == 0) - { + if (mapId == 0) { mapId = rocketPad->GetSelectedMapId(player->GetObjectID()); } - if (mapId == 0) - { + if (mapId == 0) { mapId = dZoneManager::Instance()->GetZoneID().GetMapID(); // Fallback to sending the player back to the same zone. } - Game::logger->Log("FireEventServerSide", "Player %llu has requested zone transfer to (%i, %i).\n", sender->GetObjectID(), (int) mapId, (int) cloneId); - + Game::logger->Log("FireEventServerSide", "Player %llu has requested zone transfer to (%i, %i).", sender->GetObjectID(), (int)mapId, (int)cloneId); + auto* character = player->GetCharacter(); if (mapId <= 0) { @@ -4956,8 +4996,8 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity } ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, mapId, cloneId, false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (character) { character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); @@ -4966,10 +5006,10 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); return; - }); + }); } - entity->OnFireEventServerSide(sender, GeneralUtils::UTF16ToWTF8(args), param1, param2, param3); + entity->OnFireEventServerSide(sender, GeneralUtils::UTF16ToWTF8(args), param1, param2, param3); } void GameMessages::HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { @@ -4984,10 +5024,10 @@ void GameMessages::HandleRebuildCancel(RakNet::BitStream* inStream, Entity* enti inStream->Read(bEarlyRelease); inStream->Read(userID); - RebuildComponent* rebComp = static_cast(entity->GetComponent(COMPONENT_TYPE_REBUILD)); + RebuildComponent* rebComp = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD)); if (!rebComp) return; - rebComp->CancelRebuild(EntityManager::Instance()->GetEntity(userID), eFailReason::REASON_CANCELED_EARLY); + rebComp->CancelRebuild(EntityManager::Instance()->GetEntity(userID), eQuickBuildFailReason::CANCELED_EARLY); } void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { @@ -5005,45 +5045,37 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, Entity* interactedObject = EntityManager::Instance()->GetEntity(objectID); - if (interactedObject == nullptr) - { - Game::logger->Log("GameMessages", "Object %llu tried to interact, but doesn't exist!\n", objectID); + if (interactedObject == nullptr) { + Game::logger->Log("GameMessages", "Object %llu tried to interact, but doesn't exist!", objectID); return; } - - if (interactedObject->GetLOT() == 9524) - { + + if (interactedObject->GetLOT() == 9524) { entity->GetCharacter()->SetBuildMode(true); } - - if (bIsMultiInteractUse) - { - if (multiInteractType == 0) - { - auto* missionOfferComponent = static_cast(interactedObject->GetComponent(COMPONENT_TYPE_MISSION_OFFER)); - if (missionOfferComponent != nullptr) - { + if (bIsMultiInteractUse) { + if (multiInteractType == 0) { + auto* missionOfferComponent = static_cast(interactedObject->GetComponent(eReplicaComponentType::MISSION_OFFER)); + + if (missionOfferComponent != nullptr) { missionOfferComponent->OfferMissions(entity, multiInteractID); } - } - else { + } else { interactedObject->OnUse(entity); } - } - else - { + } else { interactedObject->OnUse(entity); } //Perform use task if possible: - auto missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - + auto missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); + if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION, interactedObject->GetLOT(), interactedObject->GetObjectID()); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_NON_MISSION_INTERACTION, interactedObject->GetLOT(), interactedObject->GetObjectID()); + missionComponent->Progress(eMissionTaskType::TALK_TO_NPC, interactedObject->GetLOT(), interactedObject->GetObjectID()); + missionComponent->Progress(eMissionTaskType::INTERACT, interactedObject->GetLOT(), interactedObject->GetObjectID()); } void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) { @@ -5053,44 +5085,40 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) inStream->Read(emoteID); inStream->Read(targetID); - Game::logger->Log("GameMessages", "Emote (%i) (%llu)\n", emoteID, targetID); - + Game::logger->LogDebug("GameMessages", "Emote (%i) (%llu)", emoteID, targetID); + //TODO: If targetID != 0, and we have one of the "perform emote" missions, complete them. if (emoteID == 0) return; std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote - MissionComponent* mission = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - if (mission) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_EMOTE, emoteID, targetID); - } - - if (targetID != LWOOBJID_EMPTY) - { + MissionComponent* missionComponent = entity->GetComponent(); + if (!missionComponent) return; + + if (targetID != LWOOBJID_EMPTY) { auto* targetEntity = EntityManager::Instance()->GetEntity(targetID); - Game::logger->Log("GameMessages", "Emote target found (%d)\n", targetEntity != nullptr); - - if (targetEntity != nullptr) - { + Game::logger->LogDebug("GameMessages", "Emote target found (%d)", targetEntity != nullptr); + + if (targetEntity != nullptr) { targetEntity->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, targetID); } - } - else - { - const auto scriptedEntities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); + } else { + Game::logger->LogDebug("GameMessages", "Target ID is empty, using backup"); + const auto scriptedEntities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); const auto& referencePoint = entity->GetPosition(); - for (auto* scripted : scriptedEntities) - { + for (auto* scripted : scriptedEntities) { if (Vector3::DistanceSquared(scripted->GetPosition(), referencePoint) > 5.0f * 5.0f) continue; scripted->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID()); } } - CDEmoteTableTable* emotes = CDClientManager::Instance()->GetTable("EmoteTable"); + CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable(); if (emotes) { CDEmoteTable* emote = emotes->GetEmote(emoteID); if (emote) sAnimationName = emote->animationName; @@ -5108,24 +5136,23 @@ void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, E if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(modelID); - if (item == nullptr) - { + if (item == nullptr) { return; } item->Disassemble(TEMP_MODELS); - item->SetCount(item->GetCount() - 1, false, false, true, eLootSourceType::LOOT_SOURCE_QUICKBUILD); + item->SetCount(item->GetCount() - 1, false, false, true, eLootSourceType::QUICKBUILD); } void GameMessages::HandleSetFlag(RakNet::BitStream* inStream, Entity* entity) { bool bFlag{}; - int iFlagID{}; + int32_t iFlagID{}; inStream->Read(bFlag); inStream->Read(iFlagID); @@ -5152,24 +5179,23 @@ void GameMessages::HandleRespondToMission(RakNet::BitStream* inStream, Entity* e inStream->Read(isDefaultReward); if (isDefaultReward) inStream->Read(reward); - MissionComponent* missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { - Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle RespondToMission\n", playerID); + Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle RespondToMission", playerID); return; } Mission* mission = missionComponent->GetMission(missionID); if (mission) { mission->SetReward(reward); - } - else { - Game::logger->Log("GameMessages", "Unable to get mission %i for entity %llu to update reward in RespondToMission\n", missionID, playerID); + } else { + Game::logger->Log("GameMessages", "Unable to get mission %i for entity %llu to update reward in RespondToMission", missionID, playerID); } Entity* offerer = EntityManager::Instance()->GetEntity(receiverID); if (offerer == nullptr) { - Game::logger->Log("GameMessages", "Unable to get receiver entity %llu for RespondToMission\n", receiverID); + Game::logger->Log("GameMessages", "Unable to get receiver entity %llu for RespondToMission", receiverID); return; } @@ -5180,7 +5206,7 @@ void GameMessages::HandleRespondToMission(RakNet::BitStream* inStream, Entity* e void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* entity) { bool bIsComplete{}; - MissionState iMissionState{}; + eMissionState iMissionState{}; int missionID{}; LWOOBJID responder{}; Entity* player = nullptr; @@ -5196,16 +5222,15 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* en } // Get the player's mission component - MissionComponent* missionComponent = static_cast(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(player->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { - Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle MissionDialogueOK\n", player->GetObjectID()); + Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle MissionDialogueOK", player->GetObjectID()); return; } - if (iMissionState == MissionState::MISSION_STATE_AVAILABLE || iMissionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) { + if (iMissionState == eMissionState::AVAILABLE || iMissionState == eMissionState::COMPLETE_AVAILABLE) { missionComponent->AcceptMission(missionID); - } - else if (iMissionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || iMissionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { missionComponent->CompleteMission(missionID); } } @@ -5221,10 +5246,9 @@ void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entit auto* player = EntityManager::Instance()->GetEntity(playerId); - auto* missionOfferComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION_OFFER)); - - if (missionOfferComponent != nullptr) - { + auto* missionOfferComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION_OFFER)); + + if (missionOfferComponent != nullptr) { missionOfferComponent->OfferMissions(player, 0); } } @@ -5236,20 +5260,22 @@ void GameMessages::HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* e Entity* player = EntityManager::Instance()->GetEntity(playerID); if (!player || !entity || entity->GetCollectibleID() == 0) return; - MissionComponent* missionComponent = static_cast(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(player->GetComponent(eReplicaComponentType::MISSION)); if (missionComponent) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT, entity->GetLOT(), entity->GetObjectID()); + missionComponent->Progress(eMissionTaskType::COLLECTION, entity->GetLOT(), entity->GetObjectID()); } } void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* inStream, Entity* entity) { - auto* character = static_cast(entity->GetComponent(COMPONENT_TYPE_CHARACTER)); + auto* levelComp = entity->GetComponent(); + if (!levelComp) return; + auto* character = entity->GetComponent(); if (!character) return; - - //Update our character's level in memory: - character->SetLevel(character->GetLevel() + 1); - character->HandleLevelUp(); + //Update our character's level in memory: + levelComp->SetLevel(levelComp->GetLevel() + 1); + + levelComp->HandleLevelUp(); auto* inventoryComponent = entity->GetComponent(); @@ -5267,12 +5293,13 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* //Send a notification in chat: std::stringstream wss; wss << "level=1:"; - wss << character->GetLevel(); + wss << levelComp->GetLevel(); wss << "\n"; wss << "name=0:"; wss << character->GetName(); - std::u16string attrs = GeneralUtils::ASCIIToUTF16(wss.str()); + // FIXME: only really need utf8 conversion for the name, so move that up? + std::u16string attrs = GeneralUtils::UTF8ToUTF16(wss.str()); std::u16string wsText = u"UI_LEVEL_PROGRESSION_LEVELUP_MESSAGE"; GameMessages::SendBroadcastTextToChatbox(entity, UNASSIGNED_SYSTEM_ADDRESS, attrs, wsText); @@ -5281,12 +5308,12 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* void GameMessages::HandlePickupCurrency(RakNet::BitStream* inStream, Entity* entity) { unsigned int currency; inStream->Read(currency); - + if (currency == 0) return; auto* ch = entity->GetCharacter(); if (entity->CanPickupCoins(currency)) { - ch->SetCoins(ch->GetCoins() + currency, eLootSourceType::LOOT_SOURCE_PICKUP); + ch->SetCoins(ch->GetCoins() + currency, eLootSourceType::PICKUP); } } @@ -5306,7 +5333,7 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity) inStream->Read(bClientDeath); inStream->Read(bDieAccepted); inStream->Read(bSpawnLoot); - + bool coinSpawnTimeIsDefault{}; inStream->Read(coinSpawnTimeIsDefault); if (coinSpawnTimeIsDefault != 0) inStream->Read(coinSpawnTime); @@ -5336,16 +5363,16 @@ void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) inStream->Read(immediate); //twice? inStream->Read(objectID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; Item* item = inv->FindItemById(objectID); if (!item) return; - item->Equip(); - - EntityManager::Instance()->SerializeEntity(entity); - } + item->Equip(); + + EntityManager::Instance()->SerializeEntity(entity); +} void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity) { bool immediate; @@ -5355,15 +5382,15 @@ void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity inStream->Read(immediate); inStream->Read(objectID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(objectID); if (!item) return; - + item->UnEquip(); - + EntityManager::Instance()->SerializeEntity(entity); } @@ -5430,22 +5457,20 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En inStream->Read(iTradeIDIsDefault); if (iTradeIDIsDefault) inStream->Read(iTradeID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(iObjID); - if (item == nullptr) - { + if (item == nullptr) { return; } - + iStackCount = std::min(item->GetCount(), iStackCount); - + if (bConfirmed) { for (auto i = 0; i < iStackCount; ++i) { - if (eInvType == eInventoryType::MODELS) - { + if (eInvType == eInventoryType::MODELS) { item->DisassembleModel(); } } @@ -5454,10 +5479,9 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En EntityManager::Instance()->SerializeEntity(entity); auto* missionComponent = entity->GetComponent(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::GATHER, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); } } } @@ -5476,13 +5500,12 @@ void GameMessages::HandleMoveItemInInventory(RakNet::BitStream* inStream, Entity inStream->Read(responseCode); inStream->Read(slot); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(iObjID); - if (!item) - { + if (!item) { return; } @@ -5525,7 +5548,7 @@ void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStre } } } - + if (entity->GetCharacter()) { if (entity->GetCharacter()->GetBuildMode()) { showFlyingLoot = false; @@ -5542,8 +5565,8 @@ void GameMessages::HandleBuildModeSet(RakNet::BitStream* inStream, Entity* entit inStream->Read(bStart); // there's more here but we don't need it (for now?) - Game::logger->Log("GameMessages", "Set build mode to (%d) for (%llu)\n", bStart, entity->GetObjectID()); - + Game::logger->Log("GameMessages", "Set build mode to (%d) for (%llu)", bStart, entity->GetObjectID()); + if (entity->GetCharacter()) { entity->GetCharacter()->SetBuildMode(bStart); } @@ -5554,10 +5577,10 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - Game::logger->Log("GameMessages", "Build finished\n"); + Game::logger->Log("GameMessages", "Build finished"); GameMessages::SendFinishArrangingWithItem(character, entity->GetObjectID()); // kick them from modular build GameMessages::SendModularBuildEnd(character); // i dont know if this does anything but DLUv2 did it @@ -5571,7 +5594,8 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* auto* temp = inv->GetInventory(TEMP_MODELS); std::vector modList; - + auto& oldPartList = character->GetVar(u"currentModifiedBuild"); + bool everyPieceSwapped = !oldPartList.empty(); // If the player didn't put a build in initially, then they should not get this achievement. if (count >= 3) { std::u16string modules; @@ -5579,17 +5603,22 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* uint32_t mod; inStream->Read(mod); modList.push_back(mod); - modules += u"1:" + (GeneralUtils::to_u16string(mod)); + auto modToStr = GeneralUtils::to_u16string(mod); + modules += u"1:" + (modToStr); if (k + 1 != count) modules += u"+"; - if (temp->GetLotCount(mod) > 0) - { + if (temp->GetLotCount(mod) > 0) { inv->RemoveItem(mod, 1, TEMP_MODELS); - } - else - { + } else { inv->RemoveItem(mod, 1); } + + // Doing this check for 1 singular mission that needs to know when you've swapped every part out during a car modular build. + // since all 8129's are the same, skip checking that + if (mod != 8129) { + if (oldPartList.find(GeneralUtils::UTF16ToWTF8(modToStr)) != std::string::npos) everyPieceSwapped = false; + + } } const auto moduleAssembly = new LDFData(u"assemblyPartLOTs", modules); @@ -5597,27 +5626,23 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* std::vector config; config.push_back(moduleAssembly); - if (count == 3) - { - inv->AddItem(6416, 1, eLootSourceType::LOOT_SOURCE_QUICKBUILD, eInventoryType::MODELS, config); - } - else if (count == 7) - { - inv->AddItem(8092, 1, eLootSourceType::LOOT_SOURCE_QUICKBUILD, eInventoryType::MODELS, config); + if (count == 3) { + inv->AddItem(6416, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config); + } else if (count == 7) { + inv->AddItem(8092, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config); } auto* missionComponent = character->GetComponent(); - - if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) - { - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, entity->GetLOT(), entity->GetObjectID()); + + if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) { + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::SCRIPT, entity->GetLOT(), entity->GetObjectID()); + if (count >= 7 && everyPieceSwapped) missionComponent->Progress(eMissionTaskType::RACING, LWOOBJID_EMPTY, (LWOOBJID)eRacingTaskParam::MODULAR_BUILDING); } } } - ScriptComponent* script = static_cast(entity->GetComponent(COMPONENT_TYPE_SCRIPT)); + ScriptComponent* script = static_cast(entity->GetComponent(eReplicaComponentType::SCRIPT)); for (CppScripts::Script* script : CppScripts::GetEntityScripts(entity)) { script->OnModularBuildExit(entity, character, count >= 3, modList); @@ -5626,13 +5651,11 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* // Move remaining temp models back to models std::vector items; - for (const auto& pair : temp->GetItems()) - { + for (const auto& pair : temp->GetItems()) { items.push_back(pair.second); } - for (auto* item : items) - { + for (auto* item : items) { inv->MoveItemToInventory(item, eInventoryType::MODELS, item->GetCount(), false); } } @@ -5642,7 +5665,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; /** @@ -5686,34 +5709,32 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti inStream->Read(oldItemTYPE); /* - Game::logger->Log("GameMessages", - "\nnewSourceBAG: %d\nnewSourceID: %llu\nnewSourceLOT: %d\nnewSourceTYPE: %d\nnewTargetID: %llu\nnewTargetLOT: %d\nnewTargetTYPE: %d\nnewTargetPOS: %f, %f, %f\noldItemBAG: %d\noldItemID: %llu\noldItemLOT: %d\noldItemTYPE: %d\n", + Game::logger->Log("GameMessages", + "\nnewSourceBAG: %d\nnewSourceID: %llu\nnewSourceLOT: %d\nnewSourceTYPE: %d\nnewTargetID: %llu\nnewTargetLOT: %d\nnewTargetTYPE: %d\nnewTargetPOS: %f, %f, %f\noldItemBAG: %d\noldItemID: %llu\noldItemLOT: %d\noldItemTYPE: %d", newSourceBAG, newSourceID, newSourceLOT, newSourceTYPE, newTargetID, newTargetLOT, newTargetTYPE, newTargetPOS.x, newTargetPOS.y, newTargetPOS.z, oldItemBAG, oldItemID, oldItemLOT, oldItemTYPE ); */ if (PropertyManagementComponent::Instance() != nullptr) { - const auto& buildAreas = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_BUILD_BORDER); - + const auto& buildAreas = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::BUILD_BORDER); + const auto& entities = EntityManager::Instance()->GetEntitiesInGroup("PropertyPlaque"); Entity* buildArea; if (!buildAreas.empty()) { buildArea = buildAreas[0]; - } - else if (!entities.empty()) { + } else if (!entities.empty()) { buildArea = entities[0]; - - Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque\n"); - } - else { - Game::logger->Log("BuildBorderComponent", "No build area found\n"); + + Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque"); + } else { + Game::logger->Log("BuildBorderComponent", "No build area found"); return; } - Game::logger->Log("GameMessages", "Build area found: %llu\n", buildArea->GetObjectID()); + Game::logger->Log("GameMessages", "Build area found: %llu", buildArea->GetObjectID()); GameMessages::SendStartArrangingWithItem( character, @@ -5732,7 +5753,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti ); } - Game::logger->Log("GameMessages", "Done Arranging\n"); + Game::logger->Log("GameMessages", "Done Arranging"); //GenericInventory* models = inv->GetGenericInventory(MODELS); //GenericInventory* tempModels = inv->GetGenericInventory(TEMP_MODELS); @@ -5741,13 +5762,11 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti std::vector items; - for (const auto& pair : inventory->GetItems()) - { + for (const auto& pair : inventory->GetItems()) { items.push_back(pair.second); } - for (auto* item : items) - { + for (auto* item : items) { inv->MoveItemToInventory(item, eInventoryType::MODELS, item->GetCount(), false, false); } } @@ -5758,19 +5777,18 @@ void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, E Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - Game::logger->Log("GameMessages", "Build and move\n"); + Game::logger->Log("GameMessages", "Build and move"); LOT templateID; inStream->Read(templateID); - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemByLot(templateID, TEMP_MODELS); - if (item == nullptr) - { + if (item == nullptr) { return; } @@ -5787,10 +5805,8 @@ void GameMessages::HandlePickupItem(RakNet::BitStream* inStream, Entity* entity) auto* team = TeamManager::Instance()->GetTeam(entity->GetObjectID()); - if (team != nullptr) - { - for (const auto memberId : team->members) - { + if (team != nullptr) { + for (const auto memberId : team->members) { auto* member = EntityManager::Instance()->GetEntity(memberId); if (member == nullptr || memberId == playerID) continue; @@ -5801,63 +5817,59 @@ void GameMessages::HandlePickupItem(RakNet::BitStream* inStream, Entity* entity) } void GameMessages::HandleResurrect(RakNet::BitStream* inStream, Entity* entity) { - bool immediate = inStream->ReadBit(); + bool immediate = inStream->ReadBit(); - Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerResurrected(zoneControl, entity); - } + Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { + script->OnPlayerResurrected(zoneControl, entity); + } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); - for (Entity* scriptEntity : scriptedActs) { - if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerResurrected(scriptEntity, entity); - } - } - } + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (Entity* scriptEntity : scriptedActs) { + if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds + for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { + script->OnPlayerResurrected(scriptEntity, entity); + } + } + } } void GameMessages::HandlePushEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PushEquippedItems(); } void GameMessages::HandlePopEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PopEquippedItems(); EntityManager::Instance()->SerializeEntity(entity); // so it updates on client side } -void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* entity) -{ +void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* entity) { LWOOBJID itemConsumed; inStream->Read(itemConsumed); - auto* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - - if (inventory == nullptr) - { + auto* inventory = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); + + if (inventory == nullptr) { return; } auto* item = inventory->FindItemById(itemConsumed); - - if (item == nullptr) - { + if (item == nullptr) { return; } + LOT itemLot = item->GetLot(); item->Consume(); - auto* missions = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - if (missions != nullptr) - { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, item->GetLot()); + auto* missions = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); + if (missions != nullptr) { + missions->Progress(eMissionTaskType::USE_ITEM, itemLot); } } @@ -5866,19 +5878,14 @@ void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity LWOOBJID itemConsumed; inStream->Read(itemConsumed); - - auto* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - + + auto* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); + if (!inv) return; auto* item = inv->FindItemById(itemConsumed); - - if (item == nullptr) - { - return; - } - item->UseNonEquip(); + if (item) item->UseNonEquip(item); } void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity) { @@ -5903,24 +5910,22 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit inStream->Read(type); inStream->Read(value); - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); if (type == 0) { // join if (value != 0) { for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY)); + ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); if (!comp) continue; if (comp->GetActivityID() == value) { comp->PlayerJoin(entity); } } - } - else { + } else { } - } - else if (type == 1) { // ready/unready + } else if (type == 1) { // ready/unready for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY)); + ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); if (!comp) continue; if (comp->PlayerIsInQueue(entity)) { comp->PlayerReady(entity, value); @@ -5929,6 +5934,51 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit } } +void GameMessages::HandleGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + SendGetHotPropertyData(inStream, entity, sysAddr); +} + +void GameMessages::SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + /** + * [u32] - Number of properties + * [objid] - property id + * [objid] - property owner id + * [wstring] - property owner name + * [u64] - total reputation + * [i32] - property template id + * [wstring] - property name + * [wstring] - property description + * [float] - performance cost + * [timestamp] - time last published + * [cloneid] - clone id + * + */ + // TODO This needs to be implemented when reputation is implemented for getting hot properties. + /** + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::SEND_HOT_PROPERTY_DATA); + std::vector t = {25166, 25188, 25191, 25194}; + bitStream.Write(4); + for (uint8_t i = 0; i < 4; i++) { + bitStream.Write(entity->GetObjectID()); + bitStream.Write(entity->GetObjectID()); + bitStream.Write(1); + bitStream.Write('c'); + bitStream.Write(42069); + bitStream.Write(t[i]); + bitStream.Write(1); + bitStream.Write('c'); + bitStream.Write(1); + bitStream.Write('c'); + bitStream.Write(420.69f); + bitStream.Write(1658376385); + bitStream.Write(25166); + } + SEND_PACKET*/ +} + void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) { //Definitely not stolen from autogenerated code, no sir: std::u16string body; @@ -5986,37 +6036,36 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) insertBug->setInt(5, reporterID); insertBug->execute(); delete insertBug; - } - catch (sql::SQLException& e) { - Game::logger->Log("HandleReportBug", "Couldn't save bug report! (%s)\n", e.what()); + } catch (sql::SQLException& e) { + Game::logger->Log("HandleReportBug", "Couldn't save bug report! (%s)", e.what()); } } void -GameMessages::HandleClientRailMovementReady(RakNet::BitStream *inStream, Entity *entity, const SystemAddress &sysAddr) { - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); - for (const auto* possibleRail : possibleRails) { - const auto* rail = possibleRail->GetComponent(); - if (rail != nullptr) { - rail->OnRailMovementReady(entity); - } - } +GameMessages::HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); + for (const auto* possibleRail : possibleRails) { + const auto* rail = possibleRail->GetComponent(); + if (rail != nullptr) { + rail->OnRailMovementReady(entity); + } + } } -void GameMessages::HandleCancelRailMovement(RakNet::BitStream *inStream, Entity *entity, const SystemAddress &sysAddr) { - const auto immediate = inStream->ReadBit(); +void GameMessages::HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + const auto immediate = inStream->ReadBit(); - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); - for (const auto* possibleRail : possibleRails) { - auto* rail = possibleRail->GetComponent(); - if (rail != nullptr) { - rail->OnCancelRailMovement(entity); - } - } + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); + for (const auto* possibleRail : possibleRails) { + auto* rail = possibleRail->GetComponent(); + if (rail != nullptr) { + rail->OnCancelRailMovement(entity); + } + } } -void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream *inStream, Entity *entity, - const SystemAddress &sysAddr) { +void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream* inStream, Entity* entity, + const SystemAddress& sysAddr) { uint32_t pathNameLength; inStream->Read(pathNameLength); @@ -6030,7 +6079,7 @@ void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream *inStre int32_t waypointNumber; inStream->Read(waypointNumber); - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (auto* possibleRail : possibleRails) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(possibleRail)) { script->OnPlayerRailArrived(possibleRail, entity, pathName, waypointNumber); @@ -6038,44 +6087,120 @@ void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream *inStre } } -void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream *inStream, Entity *entity) { - const auto set = inStream->ReadBit(); - const auto statisticsName = GeneralUtils::ReadWString(inStream); +void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream* inStream, Entity* entity) { + const auto set = inStream->ReadBit(); + const auto statisticsName = GeneralUtils::ReadWString(inStream); - int32_t value; - if (inStream->ReadBit()) { - inStream->Read(value); - } else { - value = 0; - } + int32_t value; + if (inStream->ReadBit()) { + inStream->Read(value); + } else { + value = 0; + } - LWOMAPID zone; - if (inStream->ReadBit()) { - inStream->Read(zone); - } else { - zone = LWOMAPID_INVALID; - } + LWOMAPID zone; + if (inStream->ReadBit()) { + inStream->Read(zone); + } else { + zone = LWOMAPID_INVALID; + } - // Notify the character component that something's changed - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->HandleZoneStatisticsUpdate(zone, statisticsName, value); - } + // Notify the character component that something's changed + auto* characterComponent = entity->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->HandleZoneStatisticsUpdate(zone, statisticsName, value); + } } void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Entity* entity) { - int32_t updateID; - inStream->Read(updateID); + int32_t updateID; + inStream->Read(updateID); - int64_t updateValue; - if (inStream->ReadBit()) { - inStream->Read(updateValue); - } else { - updateValue = 1; - } + int64_t updateValue; + if (inStream->ReadBit()) { + inStream->Read(updateValue); + } else { + updateValue = 1; + } - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic((StatisticID) updateID, (uint64_t) std::max(updateValue, int64_t(0))); - } + auto* characterComponent = entity->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic((StatisticID)updateID, (uint64_t)std::max(updateValue, int64_t(0))); + } +} + +void GameMessages::HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + auto controllablePhysicsComponent = entity->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->DeactivateBubbleBuff(); +} + +void GameMessages::HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + bool specialAnimations; + if (!inStream->Read(specialAnimations)) return; + + std::u16string type = GeneralUtils::ReadWString(inStream); + auto bubbleType = eBubbleType::DEFAULT; + if (type == u"skunk") bubbleType = eBubbleType::SKUNK; + else if (type == u"energy") bubbleType = eBubbleType::ENERGY; + + auto controllablePhysicsComponent = entity->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->ActivateBubbleBuff(bubbleType, specialAnimations); +} + +void GameMessages::SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::ACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity) { + LWOOBJID player_id; + inStream->Read(player_id); + auto target = EntityManager::Instance()->GetEntity(player_id); + entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); +}; + +void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::SET_NAME_BILLBOARD_STATE); + + // Technically these bits would be written, however the client does not + // contain a deserialize method to actually deserialize, so we are leaving it out. + // As such this GM only turns the billboard off. + + // bitStream.Write(overrideDefault); + // bitStream.Write(state); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET +} + +void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(eGameMessageType::SHOW_BILLBOARD_INTERACT_ICON); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET } diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 1d42eebc..ce24a105 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -1,35 +1,53 @@ - #ifndef GAMEMESSAGES_H #define GAMEMESSAGES_H #include "dCommonVars.h" -#include "RakNetTypes.h" +#include #include -#include "InventoryComponent.h" -#include "dMessageIdentifiers.h" -#include "AMFFormat.h" -#include "AMFFormat_BitStream.h" -#include "NiQuaternion.h" -#include "PropertySelectQueryProperty.h" -#include "TradingManager.h" -#include "LeaderboardManager.h" -#include "MovingPlatformComponent.h" +#include +#include "eMovementPlatformState.h" +#include "NiPoint3.h" +#include "eEndBehavior.h" +#include "eCyclingMode.h" +#include "eLootSourceType.h" +#include "Brick.h" +class AMFValue; +class Entity; +class Item; class NiQuaternion; class User; -class Entity; -class NiPoint3; +class Leaderboard; +class PropertySelectQueryProperty; +class TradeItem; + +enum class eAnimationFlags : uint32_t; + +enum class eUnequippableActiveType; +enum eInventoryType : uint32_t; +enum class eGameMasterLevel : uint8_t; +enum class eMatchUpdate : int32_t; +enum class eKillType : uint32_t; +enum class eObjectWorldState : uint32_t; +enum class eTerminateType : uint32_t; +enum class eControlScheme : uint32_t; +enum class eStateChangeType : uint32_t; +enum class ePetTamingNotifyType : uint32_t; +enum class eUseItemResponse : uint32_t; +enum class eQuickBuildFailReason : uint32_t; +enum class eRebuildState : uint32_t; namespace GameMessages { class PropertyDataMessage; void SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender); void SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation = false, bool noGravTeleport = true); - void SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority = 0.0f, float fScale = 1.0f); - void SendPlayerReady(Entity * entity, const SystemAddress& sysAddr); + void SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority = 0.0f, float fScale = 1.0f); + void SendPlayerReady(Entity* entity, const SystemAddress& sysAddr); void SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress& systemAddress); - void SendInvalidZoneTransferList(Entity * entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); + void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); void SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caster, const LWOOBJID& originator, int knockBackTimeMS, const NiPoint3& vector); - + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.VehicleStopBoost.html + void SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive); void SendStartArrangingWithItem( Entity* entity, const SystemAddress& sysAddr, @@ -46,33 +64,32 @@ namespace GameMessages { int targetTYPE = 0 ); - void SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, - bool bAllowCyclingWhileDeadOnly = true, eCyclingMode cyclingMode = ALLOW_CYCLE_TEAMMATES); + void SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, bool bAllowCyclingWhileDeadOnly = true, eCyclingMode cyclingMode = eCyclingMode::ALLOW_CYCLE_TEAMMATES); void SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID); void SendStartPathing(Entity* entity); void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint = false, - int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1, - MovementPlatformState movementState = MovementPlatformState::Moving); - - void SendRestoreToPostLoadStats(Entity * entity, const SystemAddress& sysAddr); - void SendServerDoneLoadingAllObjects(Entity * entity, const SystemAddress& sysAddr); - void SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level); - void SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level); - - void SendAddItemToInventoryClientSync(Entity* entity, const SystemAddress& sysAddr, Item* item, const LWOOBJID& objectID, bool showFlyingLoot, int itemCount, LWOOBJID subKey = LWOOBJID_EMPTY, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); - void SendNotifyClientFlagChange(const LWOOBJID& objectID, int iFlagID, bool bFlag, const SystemAddress& sysAddr); - void SendChangeObjectWorldState(const LWOOBJID& objectID, int state, const SystemAddress& sysAddr); - - void SendOfferMission(const LWOOBJID& entity, const SystemAddress& sysAddr, int32_t missionID, const LWOOBJID& offererID); - void SendNotifyMission(Entity * entity, const SystemAddress& sysAddr, int missionID, int missionState, bool sendingRewards); - void SendNotifyMissionTask(Entity * entity, const SystemAddress& sysAddr, int missionID, int taskMask, std::vector updates); + int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1, + eMovementPlatformState movementState = eMovementPlatformState::Moving); + + void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr); + void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr); + void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level); + void SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level); + + void SendAddItemToInventoryClientSync(Entity* entity, const SystemAddress& sysAddr, Item* item, const LWOOBJID& objectID, bool showFlyingLoot, int itemCount, LWOOBJID subKey = LWOOBJID_EMPTY, eLootSourceType lootSourceType = eLootSourceType::NONE); + void SendNotifyClientFlagChange(const LWOOBJID& objectID, uint32_t iFlagID, bool bFlag, const SystemAddress& sysAddr); + void SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr); + + void SendOfferMission(const LWOOBJID& entity, const SystemAddress& sysAddr, int32_t missionID, const LWOOBJID& offererID); + void SendNotifyMission(Entity* entity, const SystemAddress& sysAddr, int missionID, int missionState, bool sendingRewards); + void SendNotifyMissionTask(Entity* entity, const SystemAddress& sysAddr, int missionID, int taskMask, std::vector updates); void NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sysAddr, int level, bool sending_rewards); void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType); - void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args); - void SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args); + void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args); + void SendUIMessageServerToAllClients(const std::string& message, AMFValue* args); void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius); void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority = 1, float scale = 1, bool serialize = true); @@ -81,8 +98,8 @@ namespace GameMessages { void SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText); void SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType); - void SendRebuildNotifyState(Entity* entity, int prevState, int state, const LWOOBJID& playerID); - void SendEnableRebuild(Entity* entity, bool enable, bool fail, bool success, int failReason, float duration, const LWOOBJID& playerID); + void SendRebuildNotifyState(Entity* entity, eRebuildState prevState, eRebuildState state, const LWOOBJID& playerID); + void SendEnableRebuild(Entity* entity, bool enable, bool fail, bool success, eQuickBuildFailReason failReason, float duration, const LWOOBJID& playerID); void AddActivityOwner(Entity* entity, LWOOBJID& ownerID); void SendTerminateInteraction(const LWOOBJID& objectID, eTerminateType type, const LWOOBJID& terminator); @@ -90,16 +107,16 @@ namespace GameMessages { void SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOBJID& lootOwnerID, bool bDieAccepted, eKillType killType, std::u16string deathType, float directionRelative_AngleY, float directionRelative_AngleXZ, float directionRelative_Force, bool bClientDeath, bool bSpawnLoot, float coinSpawnTime); void SendSetInventorySize(Entity* entity, int invType, int size); - + void SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID); - void SendSetJetPackMode(Entity* entity, bool use, bool bypassChecks = false, bool doHover = false, int effectID = -1, float airspeed = 10, float maxAirspeed = 15, float verticalVelocity = 1, int warningEffectID = -1); + void SendSetJetPackMode(Entity* entity, bool use, bool bypassChecks = false, bool doHover = false, int effectID = -1, float airspeed = 10, float maxAirspeed = 15, float verticalVelocity = 1, int warningEffectID = -1); void SendResurrect(Entity* entity); void SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result = false); void SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result = false); void SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data); void SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos = NiPoint3::ZERO, int count = 1); - void SendSetPlayerControlScheme(Entity* entity, eControlSceme controlScheme); + void SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme); void SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPoint3& position, const NiQuaternion& rotation); void SendAddSkill(Entity* entity, TSkillID skillID, int slotID); @@ -118,21 +135,58 @@ namespace GameMessages { void SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, int srcInv, int dstInv, const LWOOBJID& iObjID); void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response); - void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, int type); + void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type); + void HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID); + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.SetResurrectRestoreValues.html + void SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore); + + /** + * Sends a message to an Entity to smash itself, but not delete or destroy itself from the world + * + * @param entity The Entity that will smash itself into bricks + * @param force The force the Entity will be smashed with + * @param ghostOpacity The ghosting opacity of the smashed Entity + * @param killerID The Entity that invoked the smash, if none exists, this should be LWOOBJID_EMPTY + * @param ignoreObjectVisibility Whether or not to ignore the objects visibility + */ + void SendSmash(Entity* entity, float force, float ghostOpacity, LWOOBJID killerID, bool ignoreObjectVisibility = false); + + /** + * Sends a message to an Entity to UnSmash itself (aka rebuild itself over a duration) + * + * @param entity The Entity that will UnSmash itself + * @param builderID The Entity that invoked the build (LWOOBJID_EMPTY if none exists or invoked the rebuild) + * @param duration The duration for the Entity to rebuild over. 3 seconds by default + */ + void SendUnSmash(Entity* entity, LWOOBJID builderID = LWOOBJID_EMPTY, float duration = 3.0f); + + /** + * @brief This GameMessage is the one that handles all of the property behavior incoming messages from the client. + * + * The GameMessage struct can be located here https://lcdruniverse.org/lu_packets/lu_packets/world/gm/server/struct.ControlBehaviors.html + * For information on the AMF3 format can be found here https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf + * For any questions regarding AMF3 you can contact EmosewaMC on GitHub + * + * @param inStream The incoming data sent from the client + * @param entity The Entity that sent the message + * @param sysAddr The SystemAddress that sent the message + */ + void HandleControlBehaviors(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + // Rails stuff void SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, uint32_t pathStart, - const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - int32_t railActivatorComponentID = -1, LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); + const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, + int32_t railActivatorComponentID = -1, LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); void SendStartRailMovement(const LWOOBJID& objectID, std::u16string pathName, std::u16string startSound, - std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - uint32_t pathStart = 0, bool goForward = true, bool damageImmune = true, bool noAggro = true, - bool notifyActor = false, bool showNameBillboard = true, bool cameraLocked = true, - bool collisionEnabled = true, bool useDB = true, int32_t railComponentID = -1, - LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); + std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, + uint32_t pathStart = 0, bool goForward = true, bool damageImmune = true, bool noAggro = true, + bool notifyActor = false, bool showNameBillboard = true, bool cameraLocked = true, + bool collisionEnabled = true, bool useDB = true, int32_t railComponentID = -1, + LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); void HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -142,14 +196,14 @@ namespace GameMessages { void SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, int param2, const LWOOBJID& paramObj, const std::string& paramStr, const SystemAddress& sysAddr); void SendNotifyClientFailedPrecondition(LWOOBJID objectId, const SystemAddress& sysAddr, const std::u16string& failedReason, int preconditionID); - + // The success or failure response sent back to the client will preserve the same value for localID. void SendBBBSaveResponse(const LWOOBJID& objectId, const LWOOBJID& localID, unsigned char* buffer, uint32_t bufferSize, const SystemAddress& sysAddr); void SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration, - bool addImmunity = false, bool cancelOnDamaged = false, bool cancelOnDeath = true, - bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnUi = false, - bool cancelOnUnequip = false, bool cancelOnZone = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); + bool addImmunity = false, bool cancelOnDamaged = false, bool cancelOnDeath = true, + bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnUi = false, + bool cancelOnUnequip = false, bool cancelOnZone = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr); @@ -163,6 +217,16 @@ namespace GameMessages { void SendDownloadPropertyData(LWOOBJID objectId, const PropertyDataMessage& data, const SystemAddress& sysAddr); + /** + * @brief Send an updated item id to the client when they load a blueprint in brick build mode + * + * @param sysAddr SystemAddress to respond to + * @param oldItemId The item ID that was requested to be loaded + * @param newItemId The new item ID of the loaded item + * + */ + void SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId); + void SendPropertyRentalResponse(LWOOBJID objectId, LWOCLONEID cloneId, uint32_t code, LWOOBJID propertyId, int64_t rentDue, const SystemAddress& sysAddr); void SendLockNodeRotation(Entity* entity, std::string nodeName); @@ -176,7 +240,7 @@ namespace GameMessages { void SendPlaceModelResponse(LWOOBJID objectId, const SystemAddress& sysAddr, NiPoint3 position, LWOOBJID plaque, int32_t response, NiQuaternion rotation); void SendUGCEquipPreCreateBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, int modelCount, LWOOBJID model); - + void SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, LWOOBJID inventoryItem, int itemTotal); void HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -186,11 +250,11 @@ namespace GameMessages { void HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - + void HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - + void HandlePropertyEditorEnd(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandlePropertyContentsFromClient(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -213,16 +277,16 @@ namespace GameMessages { void HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, + void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false, - int endBehavior = 0, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, + eEndBehavior endBehavior = eEndBehavior::RETURN, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, bool lockPlayer = true, bool result = false, bool skipIfSamePath = false, float startTimeAdvance = 0); void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - float leadOut = -1.0f, bool leavePlayerLocked = false); + float leadOut = -1.0f, bool leavePlayerLocked = false); void HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, + void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false, bool bCantInteract = false, bool bCantJump = false, bool bCantMove = false, bool bCantTurn = false, bool bCantUseItem = false, bool bDontTerminateInteract = false, bool bIgnoreImmunity = true, @@ -231,6 +295,35 @@ namespace GameMessages { bool bCantMoveOutChangeWasApplied = false, bool bCantTurnOutChangeWasApplied = false, bool bCantUseItemOutChangeWasApplied = false); + void SendSetStunImmunity( + LWOOBJID target, + eStateChangeType state, + const SystemAddress& sysAddr, + LWOOBJID originator = LWOOBJID_EMPTY, + bool bImmuneToStunAttack = false, + bool bImmuneToStunEquip = false, + bool bImmuneToStunInteract = false, + bool bImmuneToStunJump = false, + bool bImmuneToStunMove = false, + bool bImmuneToStunTurn = false, + bool bImmuneToStunUseItem = false + ); + + void SendSetStatusImmunity( + LWOOBJID objectId, + eStateChangeType state, + const SystemAddress& sysAddr, + bool bImmuneToBasicAttack = false, + bool bImmuneToDamageOverTime = false, + bool bImmuneToKnockback = false, + bool bImmuneToInterrupt = false, + bool bImmuneToSpeed = false, + bool bImmuneToImaginationGain = false, + bool bImmuneToImaginationLoss = false, + bool bImmuneToQuickbuildInterrupt = false, + bool bImmuneToPullToPoint = false + ); + void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr); void SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr); @@ -269,7 +362,7 @@ namespace GameMessages { void HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); //Pets: - void SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, uint32_t notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr); + void SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, ePetTamingNotifyType notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr); void SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vector& bricks, const SystemAddress& sysAddr); @@ -285,7 +378,7 @@ namespace GameMessages { void SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr); - void SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr); + void SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, eUnequippableActiveType iType, LWOOBJID itemID, const SystemAddress& sysAddr); void SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr); @@ -328,6 +421,75 @@ namespace GameMessages { void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr); + /** + * @brief + * + * @param objectId ID of the entity to set idle flags + * @param FlagsOn Flag to turn on + * @param FlagsOff Flag to turn off + */ + void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr); + + // Mounts + /** + * @brief Set the Inventory LWOOBJID of the mount + * + * @param entity The entity that is mounting + * @param sysAddr the system address to send game message responses to + * @param objectID LWOOBJID of the item in inventory that is being used + */ + void SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr); + + /** + * @brief Handle client dismounting mount + * + * @param inStream Raknet BitStream of incoming data + * @param entity The Entity that is dismounting + * @param sysAddr the system address to send game message responses to + */ + void HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + + /** + * @brief Handle acknowledging that the client possessed something + * + * @param inStream Raknet BitStream of incoming data + * @param entity The Entity that is possessing + * @param sysAddr the system address to send game message responses to + */ + void HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + + /** + * @brief A request from a client to get the hot properties that would appear on the news feed + * This incoming message has NO DATA and is simply a request that expects to send a reply to the sender. + * + * @param inStream packet of data + * @param entity The Entity that sent the request + * @param sysAddr The SystemAddress of the Entity that sent the request + */ + void HandleGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + + /** + * @brief A request from a client to get the hot properties that would appear on the news feed + * The struct of data to send is as follows + * + * [u32] - Number of properties + * [objid] - property id + * [objid] - property owner id + * [wstring] - property owner name + * [u64] - total reputation + * [i32] - property template id + * [wstring] - property name + * [wstring] - property description + * [float] - performance cost + * [timestamp] - time last published + * [cloneid] - clone id + * + * @param inStream packet of data + * @param entity The Entity that sent the request + * @param sysAddr The SystemAddress of the Entity that sent the request + */ + void SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + //Racing: void HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -337,8 +499,6 @@ namespace GameMessages { void HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -372,7 +532,7 @@ namespace GameMessages { void SendActivityPause(LWOOBJID objectId, bool pause = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendStartActivityTime(LWOOBJID objectId, float_t startTime, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID); - void SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse); + void SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, eUseItemResponse itemResponse); // SG: @@ -400,16 +560,16 @@ namespace GameMessages { void SendUpdateReputation(const LWOOBJID objectId, const int64_t reputation, const SystemAddress& sysAddr); - // Leaderboards - void SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, - const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - void HandleActivitySummaryLeaderboardData(RakNet::BitStream* instream, Entity* entity, const SystemAddress& sysAddr); - void SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, - const SystemAddress& sysAddr, const int32_t& gameID = 0, - const int32_t& queryType = 1, const int32_t& resultsEnd = 10, - const int32_t& resultsStart = 0, bool weekly = false); - void HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity); + // Leaderboards + void SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, + const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); + void HandleActivitySummaryLeaderboardData(RakNet::BitStream* instream, Entity* entity, const SystemAddress& sysAddr); + void SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, + const SystemAddress& sysAddr, const int32_t& gameID = 0, + const int32_t& queryType = 1, const int32_t& resultsEnd = 10, + const int32_t& resultsStart = 0, bool weekly = false); + void HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity); void SendVehicleAddPassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr); @@ -418,33 +578,35 @@ namespace GameMessages { void SendVehicleNotifyFinishedRace(LWOOBJID objectId, const SystemAddress& sysAddr); //NT: - + void HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr); - //Handlers: - + //Handlers: + void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId); + void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId); void HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleToggleGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleFireEventServerSide(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleToggleGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleFireEventServerSide(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleRebuildCancel(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity); + void HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity); void HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetFlag(RakNet::BitStream* inStream, Entity* entity); - void HandleRespondToMission(RakNet::BitStream* inStream, Entity* entity); - void HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity); - void HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* entity); + void HandleSetFlag(RakNet::BitStream* inStream, Entity* entity); + void HandleRespondToMission(RakNet::BitStream* inStream, Entity* entity); + void HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* entity); + void HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity); + void HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* entity); void HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* inStream, Entity* entity); void HandlePickupCurrency(RakNet::BitStream* inStream, Entity* entity); void HandleRequestDie(RakNet::BitStream* inStream, Entity* entity); @@ -467,559 +629,25 @@ namespace GameMessages { void HandlePopEquippedItemsState(RakNet::BitStream* inStream, Entity* entity); void HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* entity); - + void HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity* entity); void HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity); void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); - /* Message to synchronize a skill cast */ - class EchoSyncSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_SYNC_SKILL; + void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); - public: - EchoSyncSkill() { - bDone = false; - } + // bubble + void HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); - EchoSyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } + void HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); - EchoSyncSkill(RakNet::BitStream* stream) { - bDone = false; + void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); - Deserialize(stream); - } + void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); - ~EchoSyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Message to synchronize a skill cast */ - class SyncSkill { - static const GAME_MSG MsgID = GAME_MSG_SYNC_SKILL; - - public: - SyncSkill() { - bDone = false; - } - - SyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } - - SyncSkill(RakNet::BitStream* stream) { - bDone = false; - Deserialize(stream); - } - - ~SyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Notifying the server that a locally owned projectil impacted. Sent to the caster of the projectile - should always be the local char. */ - class RequestServerProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT; - - public: - RequestServerProjectileImpact() { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64LocalID = _i64LocalID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - RequestServerProjectileImpact(RakNet::BitStream* stream) { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~RequestServerProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64LocalID != LWOOBJID_EMPTY); - if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64LocalIDIsDefault{}; - stream->Read(i64LocalIDIsDefault); - if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64LocalID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Tell a client local projectile to impact */ - class DoClientProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT; - - public: - DoClientProjectileImpact() { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64OrgID = _i64OrgID; - i64OwnerID = _i64OwnerID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - DoClientProjectileImpact(RakNet::BitStream* stream) { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~DoClientProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64OrgID != LWOOBJID_EMPTY); - if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); - - stream->Write(i64OwnerID != LWOOBJID_EMPTY); - if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64OrgIDIsDefault{}; - stream->Read(i64OrgIDIsDefault); - if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); - - bool i64OwnerIDIsDefault{}; - stream->Read(i64OwnerIDIsDefault); - if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64OrgID; - LWOOBJID i64OwnerID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ - class EchoStartSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_START_SKILL; - - public: - EchoStartSkill() { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - EchoStartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~EchoStartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse; - float fCasterLatency; - int iCastType; - NiPoint3 lastClickedPosit; - LWOOBJID optionalOriginatorID; - LWOOBJID optionalTargetID; - NiQuaternion originatorRot; - std::string sBitStream; - TSkillID skillID; - unsigned int uiSkillHandle; - }; - - /* Same as sync skill but with different network options. An echo down to other clients that need to play the skill. */ - class StartSkill { - static const GAME_MSG MsgID = GAME_MSG_START_SKILL; - - public: - StartSkill() { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - consumableItemID = _consumableItemID; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - StartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~StartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(consumableItemID != LWOOBJID_EMPTY); - if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool consumableItemIDIsDefault{}; - stream->Read(consumableItemIDIsDefault); - if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse = false; - LWOOBJID consumableItemID{}; - float fCasterLatency{}; - int iCastType{}; - NiPoint3 lastClickedPosit{}; - LWOOBJID optionalOriginatorID{}; - LWOOBJID optionalTargetID{}; - NiQuaternion originatorRot{}; - std::string sBitStream = ""; - TSkillID skillID = 0; - unsigned int uiSkillHandle = 0; - }; + void HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity); }; - - - #endif // GAMEMESSAGES_H diff --git a/dGame/dGameMessages/PropertyDataMessage.cpp b/dGame/dGameMessages/PropertyDataMessage.cpp index 85eb54cb..c3443f31 100644 --- a/dGame/dGameMessages/PropertyDataMessage.cpp +++ b/dGame/dGameMessages/PropertyDataMessage.cpp @@ -1,4 +1,4 @@ -#include "PropertyDataMessage.h" +#include "PropertyDataMessage.h" #include "GeneralUtils.h" @@ -6,8 +6,9 @@ #include "dLogger.h" #include "CDClientManager.h" -void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) const -{ +#include "CDPropertyTemplateTable.h" + +void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) const { stream.Write(0); // - property id stream.Write(TemplateID); // - template id @@ -15,19 +16,19 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con stream.Write(VendorMapId); // - vendor map id stream.Write(cloneId); // clone id - const auto& name = GeneralUtils::ASCIIToUTF16(Name); + const auto& name = GeneralUtils::UTF8ToUTF16(Name); stream.Write(uint32_t(name.size())); for (uint32_t i = 0; i < name.size(); ++i) { stream.Write(uint16_t(name[i])); } - const auto& description = GeneralUtils::ASCIIToUTF16(Description); + const auto& description = GeneralUtils::UTF8ToUTF16(Description); stream.Write(uint32_t(description.size())); for (uint32_t i = 0; i < description.size(); ++i) { stream.Write(uint16_t(description[i])); } - const auto& owner = GeneralUtils::ASCIIToUTF16(OwnerName); + const auto& owner = GeneralUtils::UTF8ToUTF16(OwnerName); stream.Write(uint32_t(owner.size())); for (uint32_t i = 0; i < owner.size(); ++i) { stream.Write(uint16_t(owner[i])); @@ -39,9 +40,9 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con stream.Write(0); // - zone code stream.Write(0); // - minimum price stream.Write(1); // - rent duration - + stream.Write(LastUpdatedTime); // - timestamp - + stream.Write(1); stream.Write(reputation); // Reputation @@ -52,7 +53,7 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con for (uint32_t i = 0; i < spawn.size(); ++i) { stream.Write(uint16_t(spawn[i])); } - + stream.Write(0); // String length stream.Write(0); // String length @@ -69,7 +70,7 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con else stream.Write(REJECTION_STATUS_PENDING); // Does this go here??? - // const auto& rejectionReasonConverted = GeneralUtils::ASCIIToUTF16(rejectionReason); + // const auto& rejectionReasonConverted = GeneralUtils::UTF8ToUTF16(rejectionReason); // stream.Write(uint32_t(rejectionReasonConverted.size())); // for (uint32_t i = 0; i < rejectionReasonConverted.size(); ++i) { // stream.Write(uint16_t(rejectionReasonConverted[i])); @@ -89,13 +90,12 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con stream.Write(MaxBuildHeight); stream.Write(ClaimedTime); // - timestamp - + stream.Write(PrivacyOption); stream.Write(uint32_t(Paths.size())); - for (const auto& path : Paths) - { + for (const auto& path : Paths) { stream.Write(path.x); stream.Write(path.y); stream.Write(path.z); @@ -103,11 +103,10 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con } GameMessages::PropertyDataMessage::PropertyDataMessage(uint32_t mapID) { - const auto propertyTemplate = CDClientManager::Instance()-> - GetTable("PropertyTemplate")->GetByMapID(mapID); + const auto propertyTemplate = CDClientManager::Instance().GetTable()->GetByMapID(mapID); - TemplateID = propertyTemplate.id; - ZoneId = propertyTemplate.mapID; - VendorMapId = propertyTemplate.vendorMapID; - SpawnName = propertyTemplate.spawnName; + TemplateID = propertyTemplate.id; + ZoneId = propertyTemplate.mapID; + VendorMapId = propertyTemplate.vendorMapID; + SpawnName = propertyTemplate.spawnName; } diff --git a/dGame/dGameMessages/PropertyDataMessage.h b/dGame/dGameMessages/PropertyDataMessage.h index 5b5d7d0f..f7c9e2d5 100644 --- a/dGame/dGameMessages/PropertyDataMessage.h +++ b/dGame/dGameMessages/PropertyDataMessage.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -8,12 +8,11 @@ #include "NiPoint3.h" #include "dCommonVars.h" -namespace GameMessages -{ +namespace GameMessages { class PropertyDataMessage final { public: - explicit PropertyDataMessage(uint32_t mapID); + explicit PropertyDataMessage(uint32_t mapID); void Serialize(RakNet::BitStream& stream) const; @@ -47,4 +46,4 @@ namespace GameMessages REJECTION_STATUS_REJECTED = 2 }; }; -} \ No newline at end of file +} diff --git a/dGame/dGameMessages/PropertySelectQueryProperty.cpp b/dGame/dGameMessages/PropertySelectQueryProperty.cpp index 38e7cea2..6e975879 100644 --- a/dGame/dGameMessages/PropertySelectQueryProperty.cpp +++ b/dGame/dGameMessages/PropertySelectQueryProperty.cpp @@ -1,22 +1,21 @@ -#include "PropertySelectQueryProperty.h" +#include "PropertySelectQueryProperty.h" -void PropertySelectQueryProperty::Serialize(RakNet::BitStream& stream) const -{ - stream.Write(CloneId); +void PropertySelectQueryProperty::Serialize(RakNet::BitStream& stream) const { + stream.Write(CloneId); - const auto& owner = GeneralUtils::ASCIIToUTF16(OwnerName); + const auto& owner = GeneralUtils::UTF8ToUTF16(OwnerName); stream.Write(uint32_t(owner.size())); for (uint32_t i = 0; i < owner.size(); ++i) { stream.Write(static_cast(owner[i])); } - const auto& name = GeneralUtils::ASCIIToUTF16(Name); + const auto& name = GeneralUtils::UTF8ToUTF16(Name); stream.Write(uint32_t(name.size())); for (uint32_t i = 0; i < name.size(); ++i) { stream.Write(static_cast(name[i])); } - const auto& description = GeneralUtils::ASCIIToUTF16(Description); + const auto& description = GeneralUtils::UTF8ToUTF16(Description); stream.Write(uint32_t(description.size())); for (uint32_t i = 0; i < description.size(); ++i) { stream.Write(static_cast(description[i])); @@ -34,7 +33,6 @@ void PropertySelectQueryProperty::Serialize(RakNet::BitStream& stream) const stream.Write(PerformanceCost); } -void PropertySelectQueryProperty::Deserialize(RakNet::BitStream& stream) const -{ - // Do we need this? +void PropertySelectQueryProperty::Deserialize(RakNet::BitStream& stream) const { + // Do we need this? } diff --git a/dGame/dGameMessages/PropertySelectQueryProperty.h b/dGame/dGameMessages/PropertySelectQueryProperty.h index e633f41b..47d795a7 100644 --- a/dGame/dGameMessages/PropertySelectQueryProperty.h +++ b/dGame/dGameMessages/PropertySelectQueryProperty.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #ifndef PROPERTYSELECTQUERY_H #define PROPERTYSELECTQUERY_H @@ -12,20 +12,20 @@ public: void Deserialize(RakNet::BitStream& stream) const; - LWOCLONEID CloneId = LWOCLONEID_INVALID; // The cloneID of the property - std::string OwnerName = ""; // The property owners name - std::string Name = ""; // The property name - std::string Description = ""; // The property description - float Reputation = 0; // The reputation of the property - bool IsBestFriend = false; // Whether or not the property belongs to a best friend - bool IsFriend = false; // Whether or not the property belongs to a friend - bool IsModeratorApproved = false; // Whether or not a moderator has approved this property - bool IsAlt = false; // Whether or not the property is owned by an alt of the account owner - bool IsOwned = false; // Whether or not the property is owned - uint32_t AccessType = 0; // The privacy option of the property - uint32_t DateLastPublished = 0; // The last day the property was published - float PerformanceCost = 0; // The performance cost of the property - uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0? + LWOCLONEID CloneId = LWOCLONEID_INVALID; // The cloneID of the property + std::string OwnerName = ""; // The property owners name + std::string Name = ""; // The property name + std::string Description = ""; // The property description + float Reputation = 0; // The reputation of the property + bool IsBestFriend = false; // Whether or not the property belongs to a best friend + bool IsFriend = false; // Whether or not the property belongs to a friend + bool IsModeratorApproved = false; // Whether or not a moderator has approved this property + bool IsAlt = false; // Whether or not the property is owned by an alt of the account owner + bool IsOwned = false; // Whether or not the property is owned + uint32_t AccessType = 0; // The privacy option of the property + uint32_t DateLastPublished = 0; // The last day the property was published + float PerformanceCost = 0; // The performance cost of the property + uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0? }; #endif diff --git a/dGame/dGameMessages/RequestServerProjectileImpact.h b/dGame/dGameMessages/RequestServerProjectileImpact.h new file mode 100644 index 00000000..090d8274 --- /dev/null +++ b/dGame/dGameMessages/RequestServerProjectileImpact.h @@ -0,0 +1,72 @@ +#ifndef __REQUESTSERVERPROJECTILEIMPACT__H__ +#define __REQUESTSERVERPROJECTILEIMPACT__H__ + +#include "dCommonVars.h" +#include "eGameMessageType.h" + +/* Notifying the server that a locally owned projectile impacted. Sent to the caster of the projectile + should always be the local char. */ +class RequestServerProjectileImpact { +public: + RequestServerProjectileImpact() { + i64LocalID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64LocalID = _i64LocalID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + RequestServerProjectileImpact(RakNet::BitStream* stream) : RequestServerProjectileImpact() { + Deserialize(stream); + } + + ~RequestServerProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT); + + stream->Write(i64LocalID != LWOOBJID_EMPTY); + if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64LocalIDIsDefault{}; + stream->Read(i64LocalIDIsDefault); + if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64LocalID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__REQUESTSERVERPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/StartSkill.h b/dGame/dGameMessages/StartSkill.h new file mode 100644 index 00000000..40bc210f --- /dev/null +++ b/dGame/dGameMessages/StartSkill.h @@ -0,0 +1,142 @@ +#ifndef __STARTSKILL__H__ +#define __STARTSKILL__H__ + +#include "dCommonVars.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" +#include "eGameMessageType.h" + +/** + * Same as sync skill but with different network options. An echo down to other clients that need to play the skill. + */ +class StartSkill { +public: + StartSkill() { + bUsedMouse = false; + consumableItemID = LWOOBJID_EMPTY; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + consumableItemID = _consumableItemID; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + StartSkill(RakNet::BitStream* stream) : StartSkill() { + Deserialize(stream); + } + + ~StartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::START_SKILL); + + stream->Write(bUsedMouse); + + stream->Write(consumableItemID != LWOOBJID_EMPTY); + if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool consumableItemIDIsDefault{}; + stream->Read(consumableItemIDIsDefault); + if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse = false; + LWOOBJID consumableItemID{}; + float fCasterLatency{}; + int32_t iCastType{}; + NiPoint3 lastClickedPosit{}; + LWOOBJID optionalOriginatorID{}; + LWOOBJID optionalTargetID{}; + NiQuaternion originatorRot{}; + std::string sBitStream = ""; + TSkillID skillID = 0; + uint32_t uiSkillHandle = 0; +}; + +#endif //!__STARTSKILL__H__ diff --git a/dGame/dGameMessages/SyncSkill.h b/dGame/dGameMessages/SyncSkill.h new file mode 100644 index 00000000..6485199e --- /dev/null +++ b/dGame/dGameMessages/SyncSkill.h @@ -0,0 +1,67 @@ +#ifndef __SYNCSKILL__H__ +#define __SYNCSKILL__H__ + +#include +#include + +#include "BitStream.h" +#include "eGameMessageType.h" + +/* Message to synchronize a skill cast */ +class SyncSkill { +public: + SyncSkill() { + bDone = false; + } + + SyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + SyncSkill(RakNet::BitStream* stream) : SyncSkill() { + Deserialize(stream); + } + + ~SyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(eGameMessageType::SYNC_SKILL); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__SYNCSKILL__H__ diff --git a/dGame/dInventory/CMakeLists.txt b/dGame/dInventory/CMakeLists.txt new file mode 100644 index 00000000..60cfca75 --- /dev/null +++ b/dGame/dInventory/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DGAME_DINVENTORY_SOURCES "EquippedItem.cpp" + "Inventory.cpp" + "Item.cpp" + "ItemSet.cpp" + "ItemSetPassiveAbility.cpp" PARENT_SCOPE) diff --git a/dGame/dInventory/DatabasePet.h b/dGame/dInventory/DatabasePet.h index 068c6195..2dd8649a 100644 --- a/dGame/dInventory/DatabasePet.h +++ b/dGame/dInventory/DatabasePet.h @@ -7,20 +7,20 @@ */ struct DatabasePet { - /** - * The lot of this pet - */ - LOT lot = LOT_NULL; + /** + * The lot of this pet + */ + LOT lot = LOT_NULL; - /** - * The name of the pet - */ - std::string name; + /** + * The name of the pet + */ + std::string name; - /** - * The current moderation state, see PetComponent for more info - */ - int32_t moderationState = 0; + /** + * The current moderation state, see PetComponent for more info + */ + int32_t moderationState = 0; }; const DatabasePet DATABASE_PET_INVALID; diff --git a/dGame/dInventory/EquippedItem.cpp b/dGame/dInventory/EquippedItem.cpp index df5639de..9eaed5fc 100644 --- a/dGame/dInventory/EquippedItem.cpp +++ b/dGame/dInventory/EquippedItem.cpp @@ -1 +1 @@ -#include "EquippedItem.h" +#include "EquippedItem.h" diff --git a/dGame/dInventory/EquippedItem.h b/dGame/dInventory/EquippedItem.h index cf5ba253..78da9e8d 100644 --- a/dGame/dInventory/EquippedItem.h +++ b/dGame/dInventory/EquippedItem.h @@ -8,24 +8,24 @@ */ struct EquippedItem { - /** - * The object ID of the equipped item - */ + /** + * The object ID of the equipped item + */ LWOOBJID id = LWOOBJID_EMPTY; - /** - * The LOT of this equipped item - */ + /** + * The LOT of this equipped item + */ LOT lot = LOT_NULL; - /** - * The number of items that are stored in this slot - */ + /** + * The number of items that are stored in this slot + */ uint32_t count = 0; - /** - * The slot this item is stored in - */ + /** + * The slot this item is stored in + */ uint32_t slot = 0; /** diff --git a/dGame/dInventory/Inventory.cpp b/dGame/dInventory/Inventory.cpp index 6e8be6aa..3d2c82ae 100644 --- a/dGame/dInventory/Inventory.cpp +++ b/dGame/dInventory/Inventory.cpp @@ -1,7 +1,12 @@ -#include "Inventory.h" +#include "Inventory.h" #include "GameMessages.h" #include "Game.h" #include "Item.h" +#include "InventoryComponent.h" +#include "eItemType.h" +#include "eReplicaComponentType.h" + +#include "CDComponentsRegistryTable.h" std::vector Inventory::m_GameMasterRestrictedItems = { 1727, // GM Only - JetPack @@ -13,40 +18,33 @@ std::vector Inventory::m_GameMasterRestrictedItems = { 14442 // The jamesster jetpack }; -Inventory::Inventory(const eInventoryType type, const uint32_t size, const std::vector& items, InventoryComponent* component) -{ +Inventory::Inventory(const eInventoryType type, const uint32_t size, const std::vector& items, InventoryComponent* component) { this->type = type; this->size = size; this->free = size; this->component = component; - for (auto* item : items) - { + for (auto* item : items) { AddManagedItem(item); } } -eInventoryType Inventory::GetType() const -{ +eInventoryType Inventory::GetType() const { return type; } -uint32_t Inventory::GetSize() const -{ +uint32_t Inventory::GetSize() const { return size; } -std::map& Inventory::GetItems() -{ +std::map& Inventory::GetItems() { return items; } -std::map Inventory::GetSlots() const -{ +std::map Inventory::GetSlots() const { std::map slots; - for (const auto& pair : items) - { + for (const auto& pair : items) { auto* item = pair.second; slots.insert_or_assign(item->GetSlot(), item); @@ -55,21 +53,17 @@ std::map Inventory::GetSlots() const return slots; } -InventoryComponent* Inventory::GetComponent() const -{ +InventoryComponent* Inventory::GetComponent() const { return component; } -uint32_t Inventory::GetLotCount(const LOT lot) const -{ +uint32_t Inventory::GetLotCount(const LOT lot) const { uint32_t count = 0; - for (const auto& pair : items) - { + for (const auto& pair : items) { const auto* item = pair.second; - if (item->GetLot() == lot) - { + if (item->GetLot() == lot) { count += item->GetCount(); } } @@ -77,54 +71,42 @@ uint32_t Inventory::GetLotCount(const LOT lot) const return count; } -void Inventory::SetSize(const uint32_t value) -{ +void Inventory::SetSize(const uint32_t value) { free += static_cast(value) - static_cast(size); - + size = value; GameMessages::SendSetInventorySize(component->GetParent(), type, static_cast(size)); } -int32_t Inventory::FindEmptySlot() -{ +int32_t Inventory::FindEmptySlot() { if (free <= 6) // Up from 1 { - if (type != ITEMS && type != VAULT_ITEMS && type != eInventoryType::VAULT_MODELS) - { + if (type != ITEMS && type != VAULT_ITEMS && type != eInventoryType::VAULT_MODELS) { uint32_t newSize = size; - if (type == MODELS) - { + if (type == MODELS) { newSize = 240; - } - else if (type == eInventoryType::VENDOR_BUYBACK) - { + } else if (type == eInventoryType::VENDOR_BUYBACK) { newSize += 9u; - } - else - { + } else { newSize += 10u; } - - if (newSize > GetSize()) - { + + if (newSize > GetSize()) { SetSize(newSize); } } } - if (free == 0) - { + if (free == 0) { return -1; } const auto slots = GetSlots(); - - for (auto i = 0u; i < size; ++i) - { - if (slots.find(i) == slots.end()) - { + + for (auto i = 0u; i < size; ++i) { + if (slots.find(i) == slots.end()) { return i; } } @@ -132,64 +114,53 @@ int32_t Inventory::FindEmptySlot() return -1; } -int32_t Inventory::GetEmptySlots() -{ +int32_t Inventory::GetEmptySlots() { return free; } -bool Inventory::IsSlotEmpty(int32_t slot) -{ +bool Inventory::IsSlotEmpty(int32_t slot) { const auto slots = GetSlots(); - + const auto& index = slots.find(slot); return index == slots.end(); } -Item* Inventory::FindItemById(const LWOOBJID id) const -{ +Item* Inventory::FindItemById(const LWOOBJID id) const { const auto& index = items.find(id); - if (index == items.end()) - { + if (index == items.end()) { return nullptr; } return index->second; } -Item* Inventory::FindItemByLot(const LOT lot, const bool ignoreEquipped, const bool ignoreBound) const -{ +Item* Inventory::FindItemByLot(const LOT lot, const bool ignoreEquipped, const bool ignoreBound) const { Item* smallest = nullptr; - for (const auto& pair : items) - { + for (const auto& pair : items) { auto* item = pair.second; - if (item->GetLot() != lot) - { + if (item->GetLot() != lot) { continue; } - if (ignoreEquipped && item->IsEquipped()) - { + if (ignoreEquipped && item->IsEquipped()) { continue; } - if (ignoreBound && item->GetBound()) - { + if (ignoreBound && item->GetBound()) { continue; } - if (smallest == nullptr) - { + if (smallest == nullptr) { smallest = item; continue; } - if (smallest->GetCount() > item->GetCount()) - { + if (smallest->GetCount() > item->GetCount()) { smallest = item; } } @@ -197,26 +168,21 @@ Item* Inventory::FindItemByLot(const LOT lot, const bool ignoreEquipped, const b return smallest; } -Item* Inventory::FindItemBySlot(const uint32_t slot) const -{ +Item* Inventory::FindItemBySlot(const uint32_t slot) const { const auto slots = GetSlots(); - + const auto index = slots.find(slot); - if (index == slots.end()) - { + if (index == slots.end()) { return nullptr; } return index->second; } -Item* Inventory::FindItemBySubKey(LWOOBJID id) const -{ - for (const auto& item : items) - { - if (item.second->GetSubKey() == id) - { +Item* Inventory::FindItemBySubKey(LWOOBJID id) const { + for (const auto& item : items) { + if (item.second->GetSubKey() == id) { return item.second; } } @@ -224,24 +190,21 @@ Item* Inventory::FindItemBySubKey(LWOOBJID id) const return nullptr; } -void Inventory::AddManagedItem(Item* item) -{ +void Inventory::AddManagedItem(Item* item) { const auto id = item->GetId(); - - if (items.find(id) != items.end()) - { - Game::logger->Log("Inventory", "Attempting to add an item with an already present id (%llu)!\n", id); + + if (items.find(id) != items.end()) { + Game::logger->Log("Inventory", "Attempting to add an item with an already present id (%llu)!", id); return; } - + const auto slots = GetSlots(); const auto slot = item->GetSlot(); - if (slots.find(slot) != slots.end()) - { - Game::logger->Log("Inventory", "Attempting to add an item with an already present slot (%i)!\n", slot); + if (slots.find(slot) != slots.end()) { + Game::logger->Log("Inventory", "Attempting to add an item with an already present slot (%i)!", slot); return; } @@ -251,13 +214,11 @@ void Inventory::AddManagedItem(Item* item) free--; } -void Inventory::RemoveManagedItem(Item* item) -{ +void Inventory::RemoveManagedItem(Item* item) { const auto id = item->GetId(); - if (items.find(id) == items.end()) - { - Game::logger->Log("Inventory", "Attempting to remove an item with an invalid id (%llu), lot (%i)!\n", id, item->GetLot()); + if (items.find(id) == items.end()) { + Game::logger->Log("Inventory", "Attempting to remove an item with an invalid id (%llu), lot (%i)!", id, item->GetLot()); return; } @@ -267,90 +228,90 @@ void Inventory::RemoveManagedItem(Item* item) free++; } -eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot) -{ +eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot) { auto itemComponent = FindItemComponent(lot); const auto itemType = static_cast(itemComponent.itemType); switch (itemType) { - case ITEM_TYPE_BRICK: + case eItemType::BRICK: return BRICKS; - - case ITEM_TYPE_BEHAVIOR: + + case eItemType::BEHAVIOR: return BEHAVIORS; - case ITEM_TYPE_PROPERTY: + case eItemType::PROPERTY: return PROPERTY_DEEDS; - case ITEM_TYPE_MODEL: - case ITEM_TYPE_VEHICLE: - case ITEM_TYPE_LOOT_MODEL: + case eItemType::MODEL: + case eItemType::PET_INVENTORY_ITEM: + case eItemType::LOOT_MODEL: + case eItemType::VEHICLE: + case eItemType::MOUNT: return MODELS; - - case ITEM_TYPE_HAT: - case ITEM_TYPE_HAIR: - case ITEM_TYPE_NECK: - case ITEM_TYPE_LEFT_HAND: - case ITEM_TYPE_RIGHT_HAND: - case ITEM_TYPE_LEGS: - case ITEM_TYPE_LEFT_TRINKET: - case ITEM_TYPE_RIGHT_TRINKET: - case ITEM_TYPE_COLLECTIBLE: - case ITEM_TYPE_CONSUMABLE: - case ITEM_TYPE_CHEST: - case ITEM_TYPE_EGG: - case ITEM_TYPE_PET_FOOD: - case ITEM_TYPE_PET_INVENTORY_ITEM: - case ITEM_TYPE_PACKAGE: - case ITEM_TYPE_CURRENCY: + + case eItemType::HAT: + case eItemType::HAIR: + case eItemType::NECK: + case eItemType::LEFT_HAND: + case eItemType::RIGHT_HAND: + case eItemType::LEGS: + case eItemType::LEFT_TRINKET: + case eItemType::RIGHT_TRINKET: + case eItemType::COLLECTIBLE: + case eItemType::CONSUMABLE: + case eItemType::CHEST: + case eItemType::EGG: + case eItemType::PET_FOOD: + case eItemType::PACKAGE: + case eItemType::LUP_MODEL: return ITEMS; - - case ITEM_TYPE_QUEST_OBJECT: - case ITEM_TYPE_UNKNOWN: + + case eItemType::QUEST_OBJECT: + case eItemType::UNKNOWN: default: - return HIDDEN; + return QUEST; } } -const CDItemComponent& Inventory::FindItemComponent(const LOT lot) -{ - auto* registry = CDClientManager::Instance()->GetTable("ComponentsRegistry"); +const CDItemComponent& Inventory::FindItemComponent(const LOT lot) { + auto* registry = CDClientManager::Instance().GetTable(); - auto* itemComponents = CDClientManager::Instance()->GetTable("ItemComponent"); + auto* itemComponents = CDClientManager::Instance().GetTable(); - const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM); + const auto componentId = registry->GetByIDAndType(lot, eReplicaComponentType::ITEM); - if (componentId == 0) - { - Game::logger->Log("Inventory", "Failed to find item component for (%i)!\n", lot); + if (componentId == 0) { + Game::logger->Log("Inventory", "Failed to find item component for (%i)!", lot); return CDItemComponentTable::Default; } - + const auto& itemComponent = itemComponents->GetItemComponentByID(componentId); return itemComponent; } -bool Inventory::IsValidItem(const LOT lot) -{ - auto* registry = CDClientManager::Instance()->GetTable("ComponentsRegistry"); +bool Inventory::IsValidItem(const LOT lot) { + auto* registry = CDClientManager::Instance().GetTable(); - const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM); + const auto componentId = registry->GetByIDAndType(lot, eReplicaComponentType::ITEM); return componentId != 0; } -const std::vector& Inventory::GetAllGMItems() -{ +const std::vector& Inventory::GetAllGMItems() { return m_GameMasterRestrictedItems; } -Inventory::~Inventory() -{ - for (auto item : items) - { +void Inventory::DeleteAllItems() { + while (!this->items.empty()) { + if (items.begin()->second) items.begin()->second->SetCount(0); + } +} + +Inventory::~Inventory() { + for (auto item : items) { delete item.second; } diff --git a/dGame/dInventory/Inventory.h b/dGame/dInventory/Inventory.h index b65a2040..5e0ac8d6 100644 --- a/dGame/dInventory/Inventory.h +++ b/dGame/dInventory/Inventory.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #ifndef INVENTORY_H #define INVENTORY_H @@ -6,10 +6,11 @@ #include #include - +#include "CDItemComponentTable.h" #include "CDClientManager.h" #include "dCommonVars.h" +enum eInventoryType : uint32_t; class Item; class InventoryComponent; @@ -21,168 +22,173 @@ class Inventory final public: explicit Inventory(eInventoryType type, uint32_t size, const std::vector& items, InventoryComponent* component); - /** - * Returns the type of this inventory - * @return the type of this inventory - */ + /** + * Returns the type of this inventory + * @return the type of this inventory + */ eInventoryType GetType() const; - /** - * Returns the maximum amount of items this inventory can contain - * @return the maximum amount of items this inventory can contain - */ + /** + * Returns the maximum amount of items this inventory can contain + * @return the maximum amount of items this inventory can contain + */ uint32_t GetSize() const; - /** - * Returns all the items that are currently in this inventory, mapped by object ID - * @return all the items that are currently in this inventory, mapped by object ID - */ + /** + * Returns all the items that are currently in this inventory, mapped by object ID + * @return all the items that are currently in this inventory, mapped by object ID + */ std::map& GetItems(); - /** - * Returns all the items that are currently in this inventory, mapped by slot - * @return all the items that are currently in this inventory, mapped by slot - */ + /** + * Returns all the items that are currently in this inventory, mapped by slot + * @return all the items that are currently in this inventory, mapped by slot + */ std::map GetSlots() const; - /** - * Returns the inventory component that this inventory is part of - * @return the inventory component that this inventory is part of - */ + /** + * Returns the inventory component that this inventory is part of + * @return the inventory component that this inventory is part of + */ InventoryComponent* GetComponent() const; - /** - * Returns the amount of items this inventory contains of the specified LOT - * @param lot the lot to find items for - * @return the amount of items this inventory contains of the specified LOT - */ + /** + * Returns the amount of items this inventory contains of the specified LOT + * @param lot the lot to find items for + * @return the amount of items this inventory contains of the specified LOT + */ uint32_t GetLotCount(LOT lot) const; - /** - * Updates the max size of this inventory - * @param value the size to set - */ + /** + * Updates the max size of this inventory + * @param value the size to set + */ void SetSize(uint32_t value); - /** - * Returns the first slot in this inventory that does not contain an item - * @return the first slot in this inventory that does not contain an item - */ + /** + * Returns the first slot in this inventory that does not contain an item + * @return the first slot in this inventory that does not contain an item + */ int32_t FindEmptySlot(); - /** - * Returns the number of empty slots this inventory has left - * @return the number of empty slots this inventory has left - */ + /** + * Returns the number of empty slots this inventory has left + * @return the number of empty slots this inventory has left + */ int32_t GetEmptySlots(); - /** - * Returns if the slot for the specified index is empty - * @param slot the index to check occupation for - * @return if the slot for the specified index is empty - */ + /** + * Returns if the slot for the specified index is empty + * @param slot the index to check occupation for + * @return if the slot for the specified index is empty + */ bool IsSlotEmpty(int32_t slot); - /** - * Finds an item in this inventory by the provided id - * @param id the object ID of the item to find - * @return item in this inventory by the provided id - */ + /** + * Finds an item in this inventory by the provided id + * @param id the object ID of the item to find + * @return item in this inventory by the provided id + */ Item* FindItemById(LWOOBJID id) const; - /** - * Finds an item in the inventory for the provided LOT - * @param lot the lot to find items for - * @param ignoreEquipped ignores equipped items - * @param ignoreBound ignores bound items - * @return item in the inventory for the provided LOT - */ + /** + * Finds an item in the inventory for the provided LOT + * @param lot the lot to find items for + * @param ignoreEquipped ignores equipped items + * @param ignoreBound ignores bound items + * @return item with the lowest stack count in the inventory for the provided LOT + */ Item* FindItemByLot(LOT lot, bool ignoreEquipped = false, bool ignoreBound = false) const; - /** - * Finds an item in the inventory stored on the provied slot - * @param slot to slot to find an item for - * @return item in the inventory stored on the provied slot - */ + /** + * Finds an item in the inventory stored on the provied slot + * @param slot to slot to find an item for + * @return item in the inventory stored on the provied slot + */ Item* FindItemBySlot(uint32_t slot) const; - /** - * Finds an item based on a specified subkey (useful for pets) - * @param id the subkey to look for in the items - * @return item based on a specified subkey - */ + /** + * Finds an item based on a specified subkey (useful for pets) + * @param id the subkey to look for in the items + * @return item based on a specified subkey + */ Item* FindItemBySubKey(LWOOBJID id) const; - /** - * Adds an item to the inventory, finding a slot to place it in - * @param item item to add to the inventory - */ + /** + * Adds an item to the inventory, finding a slot to place it in + * @param item item to add to the inventory + */ void AddManagedItem(Item* item); - /** - * Removes an item from the inventory, clearing its slot - * @param item - */ + /** + * Removes an item from the inventory, clearing its slot + * @param item + */ void RemoveManagedItem(Item* item); - /** - * Returns the inventory type an item of the specified lot should be placed in - * @param lot the lot to find the inventory type for - * @return the inventory type an item of the specified lot should be placed in - */ + /** + * Returns the inventory type an item of the specified lot should be placed in + * @param lot the lot to find the inventory type for + * @return the inventory type an item of the specified lot should be placed in + */ static eInventoryType FindInventoryTypeForLot(LOT lot); - /** - * Finds the database item component for a item of a certain LOT - * @param lot the LOT of the item to get the database item component for - * @return the database item component for a item of a certain LOT - */ + /** + * Finds the database item component for a item of a certain LOT + * @param lot the LOT of the item to get the database item component for + * @return the database item component for a item of a certain LOT + */ static const CDItemComponent& FindItemComponent(LOT lot); - /** - * Cheks if the provided lot has a database item component - * @param lot the LOT to check item validity for - * @return if the provided lot has a database item component - */ + /** + * Cheks if the provided lot has a database item component + * @param lot the LOT to check item validity for + * @return if the provided lot has a database item component + */ static bool IsValidItem(LOT lot); - /** - * Returns all the items that are restricted to GMs - * @return all the items that are restricted to GMs - */ + /** + * Returns all the items that are restricted to GMs + * @return all the items that are restricted to GMs + */ static const std::vector& GetAllGMItems(); - + + /** + * Remove ALL Items from this inventory. + */ + void DeleteAllItems(); + ~Inventory(); private: - /** - * The type of this inventory - */ + /** + * The type of this inventory + */ eInventoryType type; - /** - * The max size of this inventory - */ + /** + * The max size of this inventory + */ uint32_t size; - /** - * The amount of items that can still be stored in this inventroy - */ + /** + * The amount of items that can still be stored in this inventroy + */ uint32_t free; - /** - * The items stored in this inventory - */ + /** + * The items stored in this inventory + */ std::map items; - /** - * The inventory component this inventory belongs to - */ + /** + * The inventory component this inventory belongs to + */ InventoryComponent* component; - /** - * List of items that are GM restricted - */ + /** + * List of items that are GM restricted + */ static std::vector m_GameMasterRestrictedItems; }; diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 0d254e5b..83ac8869 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -1,4 +1,4 @@ -#include "Item.h" +#include "Item.h" #include @@ -10,17 +10,26 @@ #include "dLogger.h" #include "EntityManager.h" #include "RenderComponent.h" +#include "PossessableComponent.h" +#include "CharacterComponent.h" +#include "eItemType.h" +#include "AssetManager.h" +#include "InventoryComponent.h" +#include "Loot.h" +#include "eObjectBits.h" +#include "eReplicaComponentType.h" +#include "eUseItemResponse.h" -class Inventory; +#include "CDBrickIDTableTable.h" +#include "CDObjectSkillsTable.h" +#include "CDComponentsRegistryTable.h" +#include "CDPackageComponentTable.h" - -Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) -{ - if (!Inventory::IsValidItem(lot)) - { +Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) { + if (!Inventory::IsValidItem(lot)) { return; } - + this->id = id; this->lot = lot; this->inventory = inventory; @@ -32,7 +41,7 @@ Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_ this->info = &Inventory::FindItemComponent(lot); this->preconditions = new PreconditionExpression(this->info->reqPrecondition); this->subKey = subKey; - + inventory->AddManagedItem(this); } @@ -47,15 +56,12 @@ Item::Item( bool isModMoveAndEquip, LWOOBJID subKey, bool bound, - eLootSourceType lootSourceType) -{ - if (!Inventory::IsValidItem(lot)) - { + eLootSourceType lootSourceType) { + if (!Inventory::IsValidItem(lot)) { return; } - if (isModMoveAndEquip) - { + if (isModMoveAndEquip) { showFlyingLoot = false; } @@ -73,8 +79,14 @@ Item::Item( LWOOBJID id = ObjectIDManager::GenerateRandomObjectID(); - id = GeneralUtils::SetBit(id, OBJECT_BIT_CHARACTER); - id = GeneralUtils::SetBit(id, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(id, eObjectBits::CHARACTER); + GeneralUtils::SetBit(id, eObjectBits::PERSISTENT); + + const auto type = static_cast(info->itemType); + + if (type == eItemType::MOUNT) { + GeneralUtils::SetBit(id, eObjectBits::CLIENT); + } this->id = id; @@ -83,128 +95,102 @@ Item::Item( auto* entity = inventory->GetComponent()->GetParent(); GameMessages::SendAddItemToInventoryClientSync(entity, entity->GetSystemAddress(), this, id, showFlyingLoot, static_cast(this->count), subKey, lootSourceType); - if (isModMoveAndEquip) - { + if (isModMoveAndEquip) { Equip(); - Game::logger->Log("Item", "Move and equipped (%i) from (%i)\n", this->lot, this->inventory->GetType()); + Game::logger->Log("Item", "Move and equipped (%i) from (%i)", this->lot, this->inventory->GetType()); EntityManager::Instance()->SerializeEntity(inventory->GetComponent()->GetParent()); } } -LWOOBJID Item::GetId() const -{ +LWOOBJID Item::GetId() const { return id; } -LOT Item::GetLot() const -{ +LOT Item::GetLot() const { return lot; } -uint32_t Item::GetCount() const -{ +uint32_t Item::GetCount() const { return count; } -uint32_t Item::GetSlot() const -{ +uint32_t Item::GetSlot() const { return slot; } -std::vector& Item::GetConfig() -{ +std::vector& Item::GetConfig() { return config; } -const CDItemComponent& Item::GetInfo() const -{ +const CDItemComponent& Item::GetInfo() const { return *info; } -bool Item::GetBound() const -{ +bool Item::GetBound() const { return bound; } -Inventory* Item::GetInventory() const -{ +Inventory* Item::GetInventory() const { return inventory; } -LWOOBJID Item::GetParent() const -{ +LWOOBJID Item::GetParent() const { return parent; } -LWOOBJID Item::GetSubKey() const -{ +LWOOBJID Item::GetSubKey() const { return subKey; } -PreconditionExpression* Item::GetPreconditionExpression() const -{ +PreconditionExpression* Item::GetPreconditionExpression() const { return preconditions; } -void Item::SetCount(const uint32_t value, const bool silent, const bool disassemble, const bool showFlyingLoot, eLootSourceType lootSourceType) -{ - if (value == count) - { +void Item::SetCount(const uint32_t value, const bool silent, const bool disassemble, const bool showFlyingLoot, eLootSourceType lootSourceType) { + if (value == count) { return; } - + const auto delta = std::abs(static_cast(value) - static_cast(count)); const auto type = static_cast(info->itemType); - if (disassemble) - { - if (value < count) - { - for (auto i = 0; i < delta; ++i) - { + if (disassemble) { + if (value < count) { + for (auto i = 0; i < delta; ++i) { Disassemble(); } } } - - if (!silent) - { + + if (!silent) { auto* entity = inventory->GetComponent()->GetParent(); - - if (value > count) - { + + if (value > count) { GameMessages::SendAddItemToInventoryClientSync(entity, entity->GetSystemAddress(), this, id, showFlyingLoot, delta, LWOOBJID_EMPTY, lootSourceType); - } - else - { + } else { GameMessages::SendRemoveItemFromInventory(entity, entity->GetSystemAddress(), id, lot, inventory->GetType(), delta, value); } } count = value; - if (count == 0) - { + if (count == 0) { RemoveFromInventory(); } } -void Item::SetSlot(const uint32_t value) -{ - if (slot == value) - { +void Item::SetSlot(const uint32_t value) { + if (slot == value) { return; } - for (const auto& pair : inventory->GetItems()) - { + for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; - if (item->slot == value) - { + if (item->slot == value) { item->slot = slot; } } @@ -212,18 +198,15 @@ void Item::SetSlot(const uint32_t value) slot = value; } -void Item::SetBound(const bool value) -{ +void Item::SetBound(const bool value) { bound = value; } -void Item::SetSubKey(LWOOBJID value) -{ +void Item::SetSubKey(LWOOBJID value) { subKey = value; } -void Item::SetInventory(Inventory* value) -{ +void Item::SetInventory(Inventory* value) { inventory->RemoveManagedItem(this); inventory = value; @@ -231,36 +214,29 @@ void Item::SetInventory(Inventory* value) inventory->AddManagedItem(this); } -void Item::Equip(const bool skipChecks) -{ - if (IsEquipped()) - { +void Item::Equip(const bool skipChecks) { + if (IsEquipped()) { return; } inventory->GetComponent()->EquipItem(this, skipChecks); } -void Item::UnEquip() -{ - if (!IsEquipped()) - { +void Item::UnEquip() { + if (!IsEquipped()) { return; } inventory->GetComponent()->UnEquipItem(this); } -bool Item::IsEquipped() const -{ +bool Item::IsEquipped() const { auto* component = inventory->GetComponent(); - for (const auto& pair : component->GetEquippedItems()) - { + for (const auto& pair : component->GetEquippedItems()) { const auto item = pair.second; - if (item.id == id) - { + if (item.id == id) { return true; } } @@ -268,166 +244,202 @@ bool Item::IsEquipped() const return false; } -bool Item::Consume() -{ - auto* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); - - auto skills = skillsTable->Query([=](const CDObjectSkills entry) - { +bool Item::Consume() { + auto* skillsTable = CDClientManager::Instance().GetTable(); + + auto skills = skillsTable->Query([=](const CDObjectSkills entry) { return entry.objectTemplate == static_cast(lot); - }); + }); auto success = false; - - for (auto& skill : skills) - { + + for (auto& skill : skills) { if (skill.castOnType == 3) // Consumable type { success = true; } } - Game::logger->Log("Item", "Consumed (%i) / (%llu) with (%d)\n", lot, id, success); + Game::logger->LogDebug("Item", "Consumed LOT (%i) itemID (%llu). Success=(%d)", lot, id, success); GameMessages::SendUseItemResult(inventory->GetComponent()->GetParent(), lot, success); - if (success) - { + if (success) { inventory->GetComponent()->RemoveItem(lot, 1); } return success; } -bool Item::UseNonEquip() -{ - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - - const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE); - - auto* packCompTable = CDClientManager::Instance()->GetTable("PackageComponent"); - - auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); - - const auto success = !packages.empty(); - - auto inventoryComponent = inventory->GetComponent(); - - auto playerEntity = inventoryComponent->GetParent(); - - if (subKey != LWOOBJID_EMPTY) - { - const auto& databasePet = GetInventory()->GetComponent()->GetDatabasePet(subKey); - - if (databasePet.lot != LOT_NULL) - { - GetInventory()->GetComponent()->SpawnPet(this); - - return true; - } +void Item::UseNonEquip(Item* item) { + LOT thisLot = this->GetLot(); + if (!GetInventory()) { + Game::logger->LogDebug("Item", "item %i has no inventory??", this->GetLot()); + return; } - if (success && (playerEntity->GetGMLevel() >= eGameMasterLevel::GAME_MASTER_LEVEL_JUNIOR_DEVELOPER || this->GetPreconditionExpression()->Check(playerEntity))) - { - auto* entityParent = inventory->GetComponent()->GetParent(); - for (auto& pack : packages) - { - std::unordered_map result {}; + auto* playerInventoryComponent = GetInventory()->GetComponent(); + if (!playerInventoryComponent) { + Game::logger->LogDebug("Item", "no inventory component attached to item id %llu lot %i", this->GetId(), this->GetLot()); + return; + } - result = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); + auto* playerEntity = playerInventoryComponent->GetParent(); + if (!playerEntity) { + Game::logger->LogDebug("Item", "no player entity attached to inventory? item id is %llu", this->GetId()); + return; + } - if (!inventory->GetComponent()->HasSpaceForLoot(result)) - { - return false; + const auto type = static_cast(info->itemType); + if (type == eItemType::MOUNT) { + playerInventoryComponent->HandlePossession(this); + // TODO Check if mounts are allowed to be spawned + } else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) { + const auto& databasePet = playerInventoryComponent->GetDatabasePet(subKey); + if (databasePet.lot != LOT_NULL) { + playerInventoryComponent->SpawnPet(this); + } + // This precondition response is taken care of in SpawnPet(). + } else { + bool success = false; + auto inventory = item->GetInventory(); + if (inventory && inventory->GetType() == eInventoryType::ITEMS) { + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::PACKAGE); + + if (packageComponentId == 0) return; + + auto* packCompTable = CDClientManager::Instance().GetTable(); + auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); + + auto success = !packages.empty(); + if (success) { + if (this->GetPreconditionExpression()->Check(playerInventoryComponent->GetParent())) { + auto* entityParent = playerInventoryComponent->GetParent(); + // Roll the loot for all the packages then see if it all fits. If it fits, give it to the player, otherwise don't. + std::unordered_map rolledLoot{}; + for (auto& pack : packages) { + auto thisPackage = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); + for (auto& loot : thisPackage) { + // If we already rolled this lot, add it to the existing one, otherwise create a new entry. + auto existingLoot = rolledLoot.find(loot.first); + if (existingLoot == rolledLoot.end()) { + rolledLoot.insert(loot); + } else { + existingLoot->second += loot.second; + } + } + } + if (playerInventoryComponent->HasSpaceForLoot(rolledLoot)) { + LootGenerator::Instance().GiveLoot(playerInventoryComponent->GetParent(), rolledLoot, eLootSourceType::CONSUMPTION); + item->SetCount(item->GetCount() - 1); + } else { + success = false; + } + } else { + GameMessages::SendUseItemRequirementsResponse( + playerInventoryComponent->GetParent()->GetObjectID(), + playerInventoryComponent->GetParent()->GetSystemAddress(), + eUseItemResponse::FailedPrecondition + ); + success = false; + } + } + } + Game::logger->LogDebug("Item", "Player %llu %s used item %i", playerEntity->GetObjectID(), success ? "successfully" : "unsuccessfully", thisLot); + GameMessages::SendUseItemResult(playerInventoryComponent->GetParent(), thisLot, success); + } +} + +void Item::Disassemble(const eInventoryType inventoryType) { + for (auto* data : config) { + if (data->GetKey() == u"assemblyPartLOTs") { + auto modStr = data->GetValueAsString(); + + // This shouldn't be null but always check your pointers. + if (GetInventory()) { + auto inventoryComponent = GetInventory()->GetComponent(); + if (inventoryComponent) { + auto entity = inventoryComponent->GetParent(); + if (entity) entity->SetVar(u"currentModifiedBuild", modStr); + } } - LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION); - } - Game::logger->Log("Item", "Used (%i)\n", lot); - inventory->GetComponent()->RemoveItem(lot, 1); - } - - return success; -} - -void Item::Disassemble(const eInventoryType inventoryType) -{ - for (auto* data : config) - { - if (data->GetKey() == u"assemblyPartLOTs") - { - auto modStr = data->GetValueAsString(); - std::vector modArray; std::stringstream ssData(modStr); - + std::string token; const auto deliminator = '+'; - while (std::getline(ssData, token, deliminator)) - { + while (std::getline(ssData, token, deliminator)) { const auto modLot = std::stoi(token.substr(2, token.size() - 1)); - + modArray.push_back(modLot); } - for (const auto mod : modArray) - { - inventory->GetComponent()->AddItem(mod, 1, eLootSourceType::LOOT_SOURCE_DELETION, inventoryType); + for (const auto mod : modArray) { + inventory->GetComponent()->AddItem(mod, 1, eLootSourceType::DELETION, inventoryType); } } } } -void Item::DisassembleModel() -{ - auto* table = CDClientManager::Instance()->GetTable("ComponentsRegistry"); +void Item::DisassembleModel() { + auto* table = CDClientManager::Instance().GetTable(); - const auto componentId = table->GetByIDAndType(GetLot(), COMPONENT_TYPE_RENDER); + const auto componentId = table->GetByIDAndType(GetLot(), eReplicaComponentType::RENDER); auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT render_asset FROM RenderComponent WHERE id = ?;"); - query.bind(1, (int) componentId); + "SELECT render_asset, LXFMLFolder FROM RenderComponent WHERE id = ?;"); + query.bind(1, (int)componentId); auto result = query.execQuery(); - if (result.eof()) - { + if (result.eof() || result.fieldIsNull(0)) { return; } - - std::string renderAsset = result.fieldIsNull(0) ? "" : std::string(result.getStringField(0)); - std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\'); - std::string lxfmlPath = "res/BrickModels/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.')[0] + ".lxfml"; - std::ifstream file(lxfmlPath); + std::string renderAsset = std::string(result.getStringField(0)); + std::string lxfmlFolderName = std::string(result.getStringField(1)); + + std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\'); + if (renderAssetSplit.size() == 0) return; + + std::string lxfmlPath = "BrickModels/" + lxfmlFolderName + "/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml"; + auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str()); + + if (!buffer.m_Success) { + Game::logger->Log("Item", "Failed to load %s to disassemble model into bricks, check that this file exists", lxfmlPath.c_str()); + return; + } + + std::istream file(&buffer); result.finalize(); - if (!file.good()) - { + if (!file.good()) { + buffer.close(); return; } - + std::stringstream data; data << file.rdbuf(); - if (data.str().empty()) - { + buffer.close(); + + if (data.str().empty()) { return; } auto* doc = new tinyxml2::XMLDocument(); - - if (!doc) - { + + if (!doc) { return; } - if (doc->Parse(data.str().c_str(), data.str().size()) != 0) - { + if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { return; } @@ -436,51 +448,43 @@ void Item::DisassembleModel() auto* lxfml = doc->FirstChildElement("LXFML"); auto* bricks = lxfml->FirstChildElement("Bricks"); std::string searchTerm = "Brick"; - - if (!bricks) - { + + if (!bricks) { searchTerm = "Part"; bricks = lxfml->FirstChildElement("Scene")->FirstChildElement("Model")->FirstChildElement("Group"); - - if (!bricks) - { + + if (!bricks) { return; } } - + auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str()); - while (currentBrick) - { - if (currentBrick->Attribute("designID") != nullptr) - { + while (currentBrick) { + if (currentBrick->Attribute("designID") != nullptr) { parts.push_back(std::stoi(currentBrick->Attribute("designID"))); } - + currentBrick = currentBrick->NextSiblingElement(searchTerm.c_str()); } - auto* brickIDTable = CDClientManager::Instance()->GetTable("BrickIDTable"); + auto* brickIDTable = CDClientManager::Instance().GetTable(); - for (unsigned int part : parts) - { - const auto brickID = brickIDTable->Query([=](const CDBrickIDTable& entry) - { + for (unsigned int part : parts) { + const auto brickID = brickIDTable->Query([=](const CDBrickIDTable& entry) { return entry.LEGOBrickID == part; - }); + }); - if (brickID.empty()) - { + if (brickID.empty()) { continue; } - - GetInventory()->GetComponent()->AddItem(brickID[0].NDObjectID, 1, eLootSourceType::LOOT_SOURCE_DELETION); + + GetInventory()->GetComponent()->AddItem(brickID[0].NDObjectID, 1, eLootSourceType::DELETION); } } -void Item::RemoveFromInventory() -{ +void Item::RemoveFromInventory() { UnEquip(); - + count = 0; inventory->RemoveManagedItem(this); @@ -488,12 +492,10 @@ void Item::RemoveFromInventory() delete this; } -Item::~Item() -{ +Item::~Item() { delete preconditions; - for (auto* value : config) - { + for (auto* value : config) { delete value; } diff --git a/dGame/dInventory/Item.h b/dGame/dInventory/Item.h index 0be9449a..be2359ef 100644 --- a/dGame/dInventory/Item.h +++ b/dGame/dInventory/Item.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "dCommonVars.h" #include "Inventory.h" @@ -6,6 +6,8 @@ #include "CDClientManager.h" #include "dLogger.h" #include "Preconditions.h" +#include "eInventoryType.h" +#include "eLootSourceType.h" /** * An item that can be stored in an inventory and optionally consumed or equipped @@ -15,18 +17,18 @@ class Item final { public: - /** - * Creates an item, should be used if the item is not picked up but already exists - * @param id the object ID of the item to create - * @param lot the LOT of the item - * @param inventory the inventory to add this item to - * @param slot the slot in the inventory to add this item to - * @param count the amount of items to add to the inventory - * @param bound if the item should be bound - * @param config config data for this item, e.g. for rockets - * @param parent optional parent of this item, e.g. for proxy items - * @param subKey optional subkey for this item, e.g. for pets - */ + /** + * Creates an item, should be used if the item is not picked up but already exists + * @param id the object ID of the item to create + * @param lot the LOT of the item + * @param inventory the inventory to add this item to + * @param slot the slot in the inventory to add this item to + * @param count the amount of items to add to the inventory + * @param bound if the item should be bound + * @param config config data for this item, e.g. for rockets + * @param parent optional parent of this item, e.g. for proxy items + * @param subKey optional subkey for this item, e.g. for pets + */ explicit Item( LWOOBJID id, LOT lot, @@ -37,22 +39,22 @@ public: const std::vector& config, LWOOBJID parent, LWOOBJID subKey, - eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE + eLootSourceType lootSourceType = eLootSourceType::NONE ); - /** - * Creates an item, should be used if the item is picked up / added to the inventory after load - * @param lot the LOT of the item - * @param inventory the inventory to add this item to - * @param slot the slot in the inventory to add this item to - * @param count the amount of items to add to the inventory - * @param config config data for this item, e.g. for rockets - * @param parent optional parent of this item, e.g. for proxy items - * @param showFlyingLoot show UI animation of the item being added - * @param isModMoveAndEquip equips the item - * @param subKey optional subkey for this item, e.g. for pets - * @param bound if the item should be bound - */ + /** + * Creates an item, should be used if the item is picked up / added to the inventory after load + * @param lot the LOT of the item + * @param inventory the inventory to add this item to + * @param slot the slot in the inventory to add this item to + * @param count the amount of items to add to the inventory + * @param config config data for this item, e.g. for rockets + * @param parent optional parent of this item, e.g. for proxy items + * @param showFlyingLoot show UI animation of the item being added + * @param isModMoveAndEquip equips the item + * @param subKey optional subkey for this item, e.g. for pets + * @param bound if the item should be bound + */ explicit Item( LOT lot, Inventory* inventory, @@ -64,209 +66,207 @@ public: bool isModMoveAndEquip = false, LWOOBJID subKey = LWOOBJID_EMPTY, bool bound = false, - eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE + eLootSourceType lootSourceType = eLootSourceType::NONE ); - ~Item(); + ~Item(); - /** - * Returns the object ID of this item - * @return the object ID of this item - */ + /** + * Returns the object ID of this item + * @return the object ID of this item + */ LWOOBJID GetId() const; - /** - * Returns the lot of this item - * @return the lot of this item - */ + /** + * Returns the lot of this item + * @return the lot of this item + */ LOT GetLot() const; - /** - * Sets the number of items this item represents - * @param value the number to update by - * @param silent if true, the client will not be notified of the change with GMs - * @param disassemble if items were removed, this returns all the sub parts of the item individually if it had assembly part lots - * @param showFlyingLoot shows flying loot to the client, if not silent - */ - void SetCount(uint32_t value, bool silent = false, bool disassemble = true, bool showFlyingLoot = true, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); + /** + * Sets the number of items this item represents + * @param value the number to update by + * @param silent if true, the client will not be notified of the change with GMs + * @param disassemble if items were removed, this returns all the sub parts of the item individually if it had assembly part lots + * @param showFlyingLoot shows flying loot to the client, if not silent + */ + void SetCount(uint32_t value, bool silent = false, bool disassemble = true, bool showFlyingLoot = true, eLootSourceType lootSourceType = eLootSourceType::NONE); - /** - * Returns the number of items this item represents (e.g. for stacks) - * @return the number of items this item represents - */ + /** + * Returns the number of items this item represents (e.g. for stacks) + * @return the number of items this item represents + */ uint32_t GetCount() const; - /** - * Sets the slot this item is stored in - * @param value the slot this item is stored in - */ - void SetSlot(uint32_t value); + /** + * Sets the slot this item is stored in + * @param value the slot this item is stored in + */ + void SetSlot(uint32_t value); - /** - * Returns the slot this item is in - * @return the slot this item is in - */ + /** + * Returns the slot this item is in + * @return the slot this item is in + */ uint32_t GetSlot() const; - /** - * Returns current config info for this item, e.g. for rockets - * @return current config info for this item - */ + /** + * Returns current config info for this item, e.g. for rockets + * @return current config info for this item + */ std::vector& GetConfig(); - /** - * Returns the database info for this item - * @return the database info for this item - */ + /** + * Returns the database info for this item + * @return the database info for this item + */ const CDItemComponent& GetInfo() const; - /** - * Sets if the item is bound - * @param value if the item is bound - */ - void SetBound(bool value); + /** + * Sets if the item is bound + * @param value if the item is bound + */ + void SetBound(bool value); - /** - * Returns if the item is bound - * @return if the item is bound - */ + /** + * Returns if the item is bound + * @return if the item is bound + */ bool GetBound() const; - /** - * Sets the inventory this item belongs to - * @param value the inventory this item belongs to - */ - void SetInventory(Inventory* value); + /** + * Sets the inventory this item belongs to + * @param value the inventory this item belongs to + */ + void SetInventory(Inventory* value); - /** - * Returns the inventory this item belongs to - * @return the inventory this item belongs to - */ + /** + * Returns the inventory this item belongs to + * @return the inventory this item belongs to + */ Inventory* GetInventory() const; - /** - * Returns the parent of this item, e.g. for proxy items - * @return the parent of this item - */ + /** + * Returns the parent of this item, e.g. for proxy items + * @return the parent of this item + */ LWOOBJID GetParent() const; - /** - * Sets the subkey for this item, e.g. for pets - * @param value the subkey for this item - */ - void SetSubKey(LWOOBJID value); + /** + * Sets the subkey for this item, e.g. for pets + * @param value the subkey for this item + */ + void SetSubKey(LWOOBJID value); - /** - * Returns the sub key this item has, e.g. for pets - * @return the sub key this item has - */ + /** + * Returns the sub key this item has, e.g. for pets + * @return the sub key this item has + */ LWOOBJID GetSubKey() const; - /** - * Returns the preconditions that must be met before this item may be used - * @return the preconditions that must be met before this item may be used - */ + /** + * Returns the preconditions that must be met before this item may be used + * @return the preconditions that must be met before this item may be used + */ PreconditionExpression* GetPreconditionExpression() const; - /** - * Equips this item into the linked inventory - * @param skipChecks skips equip checks for special items like rockets and cars - */ + /** + * Equips this item into the linked inventory + * @param skipChecks skips equip checks for special items like rockets and cars + */ void Equip(bool skipChecks = false); - /** - * Unequps the item from the linked inventory - */ + /** + * Unequps the item from the linked inventory + */ void UnEquip(); - /** - * Returns if the item is equipped in the linked inventory - * @return if the item is equipped - */ + /** + * Returns if the item is equipped in the linked inventory + * @return if the item is equipped + */ bool IsEquipped() const; - /** - * Attempts to consume one of this item, applying its skills - * @return whether the consumption was successful, e.g. the skill was cast - */ + /** + * Attempts to consume one of this item, applying its skills + * @return whether the consumption was successful, e.g. the skill was cast + */ bool Consume(); - /** - * Uses this item if its non equip, essentially an interface for the linked GM - * @return whether the use was successful, e.g. the skill was cast - */ - bool UseNonEquip(); + /** + * Uses this item if its non equip, essentially an interface for the linked GM + */ + void UseNonEquip(Item* item); - /** - * Disassembles the part LOTs of this item back into the inventory, if it has any - * @param inventoryType the inventory to dissassemble into - */ + /** + * Disassembles the part LOTs of this item back into the inventory, if it has any + * @param inventoryType the inventory to dissassemble into + */ void Disassemble(eInventoryType inventoryType = INVALID); - /** - * Disassembles this item into bricks - */ + /** + * Disassembles this item into bricks + */ void DisassembleModel(); - /** - * Removes the item from the linked inventory - */ + /** + * Removes the item from the linked inventory + */ void RemoveFromInventory(); private: - /** - * The object ID of this item - */ + /** + * The object ID of this item + */ LWOOBJID id; - /** - * The LOT of this item - */ + /** + * The LOT of this item + */ LOT lot; - /** - * The number of items this represents - */ + /** + * The number of items this represents + */ uint32_t count; - /** - * The slot this item is stored in - */ + /** + * The slot this item is stored in + */ uint32_t slot; - /** - * If this item is bound - */ + /** + * If this item is bound + */ bool bound; - /** - * A potential parent of this item, if this item is a subitem - */ + /** + * A potential parent of this item, if this item is a subitem + */ LWOOBJID parent; - /** - * A potential subkey of this item, e.g. for pets - */ + /** + * A potential subkey of this item, e.g. for pets + */ LWOOBJID subKey; - /** - * Config data for this item, e.g. for rocket parts and car parts - */ + /** + * Config data for this item, e.g. for rocket parts and car parts + */ std::vector config; - /** - * The inventory this item belongs to - */ + /** + * The inventory this item belongs to + */ Inventory* inventory; - /** - * The database information of this item - */ + /** + * The database information of this item + */ const CDItemComponent* info; - /** - * A precondition to using this item - */ + /** + * A precondition to using this item + */ PreconditionExpression* preconditions = nullptr; }; - \ No newline at end of file diff --git a/dGame/dInventory/ItemSet.cpp b/dGame/dInventory/ItemSet.cpp index feddd757..a8e58739 100644 --- a/dGame/dInventory/ItemSet.cpp +++ b/dGame/dInventory/ItemSet.cpp @@ -1,4 +1,4 @@ -#include "ItemSet.h" +#include "ItemSet.h" #include "InventoryComponent.h" #include "Entity.h" @@ -6,10 +6,12 @@ #include "CDClientDatabase.h" #include "Game.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" #include -ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) -{ +#include "CDSkillBehaviorTable.h" + +ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { this->m_ID = id; this->m_InventoryComponent = inventoryComponent; @@ -17,19 +19,16 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) auto query = CDClientDatabase::CreatePreppedStmt( "SELECT skillSetWith2, skillSetWith3, skillSetWith4, skillSetWith5, skillSetWith6, itemIDs FROM ItemSets WHERE setID = ?;"); - query.bind(1, (int) id); + query.bind(1, (int)id); auto result = query.execQuery(); - if (result.eof()) - { + if (result.eof()) { return; } - for (auto i = 0; i < 5; ++i) - { - if (result.fieldIsNull(i)) - { + for (auto i = 0; i < 5; ++i) { + if (result.fieldIsNull(i)) { continue; } @@ -39,15 +38,12 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) auto skillResult = skillQuery.execQuery(); - if (skillResult.eof()) - { + if (skillResult.eof()) { return; } - while (!skillResult.eof()) - { - if (skillResult.fieldIsNull(0)) - { + while (!skillResult.eof()) { + if (skillResult.fieldIsNull(0)) { skillResult.nextRow(); continue; @@ -55,8 +51,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) const auto skillId = skillResult.getIntField(0); - switch (i) - { + switch (i) { case 0: m_SkillsWith2.push_back(skillId); break; @@ -91,42 +86,34 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) m_Items = {}; - while (std::getline(stream, token, ',')) - { + while (std::getline(stream, token, ',')) { int32_t value; - if (GeneralUtils::TryParse(token, value)) - { + if (GeneralUtils::TryParse(token, value)) { m_Items.push_back(value); } } m_Equipped = {}; - for (const auto item : m_Items) - { - if (inventoryComponent->IsEquipped(item)) - { + for (const auto item : m_Items) { + if (inventoryComponent->IsEquipped(item)) { m_Equipped.push_back(item); } } } -bool ItemSet::Contains(const LOT lot) -{ +bool ItemSet::Contains(const LOT lot) { return std::find(m_Items.begin(), m_Items.end(), lot) != m_Items.end(); } -void ItemSet::OnEquip(const LOT lot) -{ - if (!Contains(lot)) - { +void ItemSet::OnEquip(const LOT lot) { + if (!Contains(lot)) { return; } const auto& index = std::find(m_Equipped.begin(), m_Equipped.end(), lot); - if (index != m_Equipped.end()) - { + if (index != m_Equipped.end()) { return; } @@ -134,37 +121,32 @@ void ItemSet::OnEquip(const LOT lot) const auto& skillSet = GetSkillSet(m_Equipped.size()); - if (skillSet.empty()) - { + if (skillSet.empty()) { return; } auto* skillComponent = m_InventoryComponent->GetParent()->GetComponent(); auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent(); - for (const auto skill : skillSet) - { - auto* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + for (const auto skill : skillSet) { + auto* skillTable = CDClientManager::Instance().GetTable(); const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill); + missionComponent->Progress(eMissionTaskType::USE_SKILL, skill); skillComponent->HandleUnmanaged(behaviorId, m_InventoryComponent->GetParent()->GetObjectID()); } } -void ItemSet::OnUnEquip(const LOT lot) -{ - if (!Contains(lot)) - { +void ItemSet::OnUnEquip(const LOT lot) { + if (!Contains(lot)) { return; } const auto& index = std::find(m_Equipped.begin(), m_Equipped.end(), lot); - if (index == m_Equipped.end()) - { + if (index == m_Equipped.end()) { return; } @@ -172,16 +154,14 @@ void ItemSet::OnUnEquip(const LOT lot) m_Equipped.erase(index); - if (skillSet.empty()) - { + if (skillSet.empty()) { return; } const auto& skillComponent = m_InventoryComponent->GetParent()->GetComponent(); - for (const auto skill : skillSet) - { - auto* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + for (const auto skill : skillSet) { + auto* skillTable = CDClientManager::Instance().GetTable(); const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID; @@ -189,36 +169,28 @@ void ItemSet::OnUnEquip(const LOT lot) } } -uint32_t ItemSet::GetEquippedCount() const -{ +uint32_t ItemSet::GetEquippedCount() const { return m_Equipped.size(); } -uint32_t ItemSet::GetID() const -{ +uint32_t ItemSet::GetID() const { return m_ID; } -void ItemSet::Update(float deltaTime) -{ - for (auto& passiveAbility : m_PassiveAbilities) - { +void ItemSet::Update(float deltaTime) { + for (auto& passiveAbility : m_PassiveAbilities) { passiveAbility.Update(deltaTime); } } -void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger) -{ - for (auto& passiveAbility : m_PassiveAbilities) - { - passiveAbility.Trigger(trigger); +void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { + for (auto& passiveAbility : m_PassiveAbilities) { + passiveAbility.Trigger(trigger, target); } } -std::vector ItemSet::GetSkillSet(const uint32_t itemCount) const -{ - switch (itemCount) - { +std::vector ItemSet::GetSkillSet(const uint32_t itemCount) const { + switch (itemCount) { case 2: return m_SkillsWith2; case 3: diff --git a/dGame/dInventory/ItemSet.h b/dGame/dInventory/ItemSet.h index d443ca06..d167cfaa 100644 --- a/dGame/dInventory/ItemSet.h +++ b/dGame/dInventory/ItemSet.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include @@ -15,100 +15,100 @@ class ItemSet { public: explicit ItemSet(uint32_t id, InventoryComponent* inventoryComponent); - void Update(float deltaTime); + void Update(float deltaTime); - /** - * Returns if this item set contains the LOT specified - * @param lot the lot to check for - * @return if this item set contains the LOT specified - */ + /** + * Returns if this item set contains the LOT specified + * @param lot the lot to check for + * @return if this item set contains the LOT specified + */ bool Contains(LOT lot); - /** - * Equips the item set skill for this LOT (if it's in the item set) - * @param lot the LOT of the item to equip skills for - */ + /** + * Equips the item set skill for this LOT (if it's in the item set) + * @param lot the LOT of the item to equip skills for + */ void OnEquip(LOT lot); - /** - * Unequips the item set skill for this LOT (if it's in the item set) - * @param lot the LOT of the item to unequip skills for - */ + /** + * Unequips the item set skill for this LOT (if it's in the item set) + * @param lot the LOT of the item to unequip skills for + */ void OnUnEquip(LOT lot); - /** - * Returns the number of items in the item set that are currently equipped - * @return the number of items in the item set that are currently equipped - */ + /** + * Returns the number of items in the item set that are currently equipped + * @return the number of items in the item set that are currently equipped + */ uint32_t GetEquippedCount() const; - /** - * Returns the ID of this item set - * @return the ID of this item set - */ + /** + * Returns the ID of this item set + * @return the ID of this item set + */ uint32_t GetID() const; - /** - * Triggers all the passive abilities in this item set that match this trigger - * @param trigger the trigger to use to trigger passive abilities - */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + /** + * Triggers all the passive abilities in this item set that match this trigger + * @param trigger the trigger to use to trigger passive abilities + */ + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); - /** - * Returns the skills that can be equipped for a specified amount of equipped items - * @param itemCount the amount of items equipped to check for - * @return the skills that can be equipped for a specified amount of equipped items - */ + /** + * Returns the skills that can be equipped for a specified amount of equipped items + * @param itemCount the amount of items equipped to check for + * @return the skills that can be equipped for a specified amount of equipped items + */ std::vector GetSkillSet(uint32_t itemCount) const; private: - /** - * The ID of this skill set - */ + /** + * The ID of this skill set + */ uint32_t m_ID; - /** - * The inventory this skill set belongs to - */ + /** + * The inventory this skill set belongs to + */ InventoryComponent* m_InventoryComponent; - /** - * The items in the skill set that are currently equipped - */ + /** + * The items in the skill set that are currently equipped + */ std::vector m_Equipped; - /** - * The total list of items in this skill set - */ + /** + * The total list of items in this skill set + */ std::vector m_Items; - /** - * The skills that can be triggered when 2 items are equipped - */ + /** + * The skills that can be triggered when 2 items are equipped + */ std::vector m_SkillsWith2; - /** - * The skills that can be triggered when 3 items are equipped - */ + /** + * The skills that can be triggered when 3 items are equipped + */ std::vector m_SkillsWith3; - /** - * The skills that can be triggered when 4 items are equipped - */ + /** + * The skills that can be triggered when 4 items are equipped + */ std::vector m_SkillsWith4; - /** - * The skills that can be triggered when 5 items are equipped - */ + /** + * The skills that can be triggered when 5 items are equipped + */ std::vector m_SkillsWith5; - /** - * The skills that can be triggered when 6 items are equipped - */ + /** + * The skills that can be triggered when 6 items are equipped + */ std::vector m_SkillsWith6; - /** - * The passive abilities associated with this skill set - */ + /** + * The passive abilities associated with this skill set + */ std::vector m_PassiveAbilities; -}; \ No newline at end of file +}; diff --git a/dGame/dInventory/ItemSetPassiveAbility.cpp b/dGame/dInventory/ItemSetPassiveAbility.cpp index 9edb671b..bf7c19cb 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.cpp +++ b/dGame/dInventory/ItemSetPassiveAbility.cpp @@ -3,332 +3,318 @@ #include "DestroyableComponent.h" #include "SkillComponent.h" #include "ItemSet.h" -#include "ItemSetPassiveAbilityID.h" +#include "eItemSetPassiveAbilityID.h" -ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet) -{ - m_Trigger = trigger; - m_Parent = parent; - m_ItemSet = itemSet; +ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet) { + m_Trigger = trigger; + m_Parent = parent; + m_ItemSet = itemSet; - m_Cooldown = 0.0f; + m_Cooldown = 0.0f; } -ItemSetPassiveAbility::~ItemSetPassiveAbility() -{ +ItemSetPassiveAbility::~ItemSetPassiveAbility() { } -void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger) -{ - if (m_Trigger != trigger || m_Cooldown > 0.0f) - { - return; - } +void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger, Entity* target) { + if (m_Trigger != trigger || m_Cooldown > 0.0f) { + return; + } - Activate(); + Activate(target); } -void ItemSetPassiveAbility::Update(float deltaTime) -{ - if (m_Cooldown > 0.0f) - { - m_Cooldown -= deltaTime; - } +void ItemSetPassiveAbility::Update(float deltaTime) { + if (m_Cooldown > 0.0f) { + m_Cooldown -= deltaTime; + } } -void ItemSetPassiveAbility::Activate() -{ - if (m_Trigger == PassiveAbilityTrigger::EnemySmashed) - { - OnEnemySmshed(); +void ItemSetPassiveAbility::Activate(Entity* target) { + if (m_Trigger == PassiveAbilityTrigger::EnemySmashed) { + OnEnemySmshed(target); - return; - } + return; + } - auto* destroyableComponent = m_Parent->GetComponent(); - auto* skillComponent = m_Parent->GetComponent(); + auto* destroyableComponent = m_Parent->GetComponent(); + auto* skillComponent = m_Parent->GetComponent(); - if (destroyableComponent == nullptr || skillComponent == nullptr) - { - return; - } + if (destroyableComponent == nullptr || skillComponent == nullptr) { + return; + } - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); - const auto id = static_cast(m_ItemSet->GetID()); - const auto parentID = m_Parent->GetObjectID(); - const auto equippedCount = m_ItemSet->GetEquippedCount(); + const auto id = static_cast(m_ItemSet->GetID()); + const auto parentID = m_Parent->GetObjectID(); + const auto equippedCount = m_ItemSet->GetEquippedCount(); - switch (id) - { - // Assembly - case ItemSetPassiveAbilityID::InventorRank1: - case ItemSetPassiveAbilityID::SummonerRank1: - case ItemSetPassiveAbilityID::EngineerRank1: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(394, 4401, parentID); - break; - } - case ItemSetPassiveAbilityID::InventorRank2: - case ItemSetPassiveAbilityID::SummonerRank2: - case ItemSetPassiveAbilityID::EngineerRank2: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(581, 9433, parentID); - break; - } - case ItemSetPassiveAbilityID::InventorRank3: - case ItemSetPassiveAbilityID::SummonerRank3: - case ItemSetPassiveAbilityID::EngineerRank3: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(582, 9435, parentID); - break; - } + switch (id) { + // Assembly + case eItemSetPassiveAbilityID::InventorRank1: + case eItemSetPassiveAbilityID::SummonerRank1: + case eItemSetPassiveAbilityID::EngineerRank1: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(394, 4401, parentID); + break; + } + case eItemSetPassiveAbilityID::InventorRank2: + case eItemSetPassiveAbilityID::SummonerRank2: + case eItemSetPassiveAbilityID::EngineerRank2: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(581, 9433, parentID); + break; + } + case eItemSetPassiveAbilityID::InventorRank3: + case eItemSetPassiveAbilityID::SummonerRank3: + case eItemSetPassiveAbilityID::EngineerRank3: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(582, 9435, parentID); + break; + } - // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(559, 8884, parentID); - break; - } - case ItemSetPassiveAbilityID::KnightRank2: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(560, 8885, parentID); - break; - } - case ItemSetPassiveAbilityID::KnightRank3: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(561, 8890, parentID); - break; - } + // Sentinel + case eItemSetPassiveAbilityID::KnightRank1: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(559, 8884, parentID); + break; + } + case eItemSetPassiveAbilityID::KnightRank2: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(560, 8885, parentID); + break; + } + case eItemSetPassiveAbilityID::KnightRank3: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(561, 8890, parentID); + break; + } - case ItemSetPassiveAbilityID::SpaceRangerRank1: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(1101, 24612, parentID); - break; - } - case ItemSetPassiveAbilityID::SpaceRangerRank2: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(1102, 24617, parentID); - break; - } - case ItemSetPassiveAbilityID::SpaceRangerRank3: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(1103, 24622, parentID); - break; - } + case eItemSetPassiveAbilityID::SpaceRangerRank1: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(1101, 24612, parentID); + break; + } + case eItemSetPassiveAbilityID::SpaceRangerRank2: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(1102, 24617, parentID); + break; + } + case eItemSetPassiveAbilityID::SpaceRangerRank3: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(1103, 24622, parentID); + break; + } - case ItemSetPassiveAbilityID::SamuraiRank1: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(562, 8899, parentID); - break; - } - case ItemSetPassiveAbilityID::SamuraiRank2: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(563, 8904, parentID); - break; - } - case ItemSetPassiveAbilityID::SamuraiRank3: { - if (equippedCount < 4) return; - m_Cooldown = 11.0f; - skillComponent->CalculateBehavior(564, 8909, parentID); - break; - } + case eItemSetPassiveAbilityID::SamuraiRank1: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(562, 8899, parentID); + break; + } + case eItemSetPassiveAbilityID::SamuraiRank2: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(563, 8904, parentID); + break; + } + case eItemSetPassiveAbilityID::SamuraiRank3: { + if (equippedCount < 4) return; + m_Cooldown = 11.0f; + skillComponent->CalculateBehavior(564, 8909, parentID); + break; + } - default: - break; - } + default: + break; + } } -std::vector ItemSetPassiveAbility::FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet) -{ - std::vector abilities; +std::vector ItemSetPassiveAbility::FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet) { + std::vector abilities; - switch (static_cast(itemSetID)) { - // Assembly - case ItemSetPassiveAbilityID::SummonerRank1: - case ItemSetPassiveAbilityID::SummonerRank2: - case ItemSetPassiveAbilityID::SummonerRank3: - case ItemSetPassiveAbilityID::InventorRank1: - case ItemSetPassiveAbilityID::InventorRank2: - case ItemSetPassiveAbilityID::InventorRank3: - case ItemSetPassiveAbilityID::EngineerRank1: - case ItemSetPassiveAbilityID::EngineerRank2: - case ItemSetPassiveAbilityID::EngineerRank3: { - abilities.emplace_back(PassiveAbilityTrigger::AssemblyImagination, parent, itemSet); + switch (static_cast(itemSetID)) { + // Assembly + case eItemSetPassiveAbilityID::SummonerRank1: + case eItemSetPassiveAbilityID::SummonerRank2: + case eItemSetPassiveAbilityID::SummonerRank3: + case eItemSetPassiveAbilityID::InventorRank1: + case eItemSetPassiveAbilityID::InventorRank2: + case eItemSetPassiveAbilityID::InventorRank3: + case eItemSetPassiveAbilityID::EngineerRank1: + case eItemSetPassiveAbilityID::EngineerRank2: + case eItemSetPassiveAbilityID::EngineerRank3: { + abilities.emplace_back(PassiveAbilityTrigger::AssemblyImagination, parent, itemSet); - break; - } - // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: - case ItemSetPassiveAbilityID::KnightRank2: - case ItemSetPassiveAbilityID::KnightRank3: - case ItemSetPassiveAbilityID::SpaceRangerRank1: - case ItemSetPassiveAbilityID::SpaceRangerRank2: - case ItemSetPassiveAbilityID::SpaceRangerRank3: - case ItemSetPassiveAbilityID::SamuraiRank1: - case ItemSetPassiveAbilityID::SamuraiRank2: - case ItemSetPassiveAbilityID::SamuraiRank3: { - abilities.emplace_back(PassiveAbilityTrigger::SentinelArmor, parent, itemSet); - abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); + break; + } + // Sentinel + case eItemSetPassiveAbilityID::KnightRank1: + case eItemSetPassiveAbilityID::KnightRank2: + case eItemSetPassiveAbilityID::KnightRank3: + case eItemSetPassiveAbilityID::SpaceRangerRank1: + case eItemSetPassiveAbilityID::SpaceRangerRank2: + case eItemSetPassiveAbilityID::SpaceRangerRank3: + case eItemSetPassiveAbilityID::SamuraiRank1: + case eItemSetPassiveAbilityID::SamuraiRank2: + case eItemSetPassiveAbilityID::SamuraiRank3: { + abilities.emplace_back(PassiveAbilityTrigger::SentinelArmor, parent, itemSet); + abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); - break; - } - // Paradox - case ItemSetPassiveAbilityID::BatLord: - case ItemSetPassiveAbilityID::SpaceMarauderRank1: - case ItemSetPassiveAbilityID::SpaceMarauderRank2: - case ItemSetPassiveAbilityID::SpaceMarauderRank3: - case ItemSetPassiveAbilityID::SorcererRank1: - case ItemSetPassiveAbilityID::SorcererRank2: - case ItemSetPassiveAbilityID::SorcererRank3: - case ItemSetPassiveAbilityID::ShinobiRank1: - case ItemSetPassiveAbilityID::ShinobiRank2: - case ItemSetPassiveAbilityID::ShinobiRank3: { - abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); + break; + } + // Paradox + case eItemSetPassiveAbilityID::BatLord: + case eItemSetPassiveAbilityID::SpaceMarauderRank1: + case eItemSetPassiveAbilityID::SpaceMarauderRank2: + case eItemSetPassiveAbilityID::SpaceMarauderRank3: + case eItemSetPassiveAbilityID::SorcererRank1: + case eItemSetPassiveAbilityID::SorcererRank2: + case eItemSetPassiveAbilityID::SorcererRank3: + case eItemSetPassiveAbilityID::ShinobiRank1: + case eItemSetPassiveAbilityID::ShinobiRank2: + case eItemSetPassiveAbilityID::ShinobiRank3: { + abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); - break; - } - default: - break; - } - - return abilities; + break; + } + default: + break; + } + + return abilities; } -void ItemSetPassiveAbility::OnEnemySmshed() -{ - auto* destroyableComponent = m_Parent->GetComponent(); - auto* skillComponent = m_Parent->GetComponent(); +void ItemSetPassiveAbility::OnEnemySmshed(Entity* target) { + auto* destroyableComponent = m_Parent->GetComponent(); + auto* skillComponent = m_Parent->GetComponent(); - if (destroyableComponent == nullptr || skillComponent == nullptr) - { - return; - } + if (destroyableComponent == nullptr || skillComponent == nullptr) { + return; + } - EntityManager::Instance()->SerializeEntity(m_Parent); + EntityManager::Instance()->SerializeEntity(m_Parent); - const auto id = static_cast(m_ItemSet->GetID()); - const auto parentID = m_Parent->GetObjectID(); - const auto equippedCount = m_ItemSet->GetEquippedCount(); + const auto id = static_cast(m_ItemSet->GetID()); + const auto parentID = m_Parent->GetObjectID(); + const auto equippedCount = m_ItemSet->GetEquippedCount(); - switch (id) - { - // Bat Lord - case ItemSetPassiveAbilityID::BatLord: { - if(equippedCount < 5) return; - destroyableComponent->Heal(3); - break; - } - // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::KnightRank2: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::KnightRank3: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } + switch (id) { + // Bat Lord + case eItemSetPassiveAbilityID::BatLord: { + if (equippedCount < 5) return; + destroyableComponent->Heal(3); + break; + } + // Sentinel + case eItemSetPassiveAbilityID::KnightRank1: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::KnightRank2: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::KnightRank3: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } - case ItemSetPassiveAbilityID::SpaceRangerRank1: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::SpaceRangerRank2: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::SpaceRangerRank3: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } + case eItemSetPassiveAbilityID::SpaceRangerRank1: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::SpaceRangerRank2: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::SpaceRangerRank3: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } - case ItemSetPassiveAbilityID::SamuraiRank1: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::SamuraiRank2: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } - case ItemSetPassiveAbilityID::SamuraiRank3: { - if (equippedCount < 5) return; - destroyableComponent->Repair(1); - break; - } + case eItemSetPassiveAbilityID::SamuraiRank1: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::SamuraiRank2: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } + case eItemSetPassiveAbilityID::SamuraiRank3: { + if (equippedCount < 5) return; + destroyableComponent->Repair(1); + break; + } - // Paradox - case ItemSetPassiveAbilityID::SpaceMarauderRank1: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(1); - break; - } - case ItemSetPassiveAbilityID::SpaceMarauderRank2: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(2); - break; - } - case ItemSetPassiveAbilityID::SpaceMarauderRank3: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(3); - break; - } - - case ItemSetPassiveAbilityID::ShinobiRank1: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(1); - break; - } - case ItemSetPassiveAbilityID::ShinobiRank2: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(2); - break; - } - case ItemSetPassiveAbilityID::ShinobiRank3: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(3); - break; - } + // Paradox + case eItemSetPassiveAbilityID::SpaceMarauderRank1: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(1); + break; + } + case eItemSetPassiveAbilityID::SpaceMarauderRank2: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(2); + break; + } + case eItemSetPassiveAbilityID::SpaceMarauderRank3: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(3); + break; + } - case ItemSetPassiveAbilityID::SorcererRank1: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(1); - break; - } - case ItemSetPassiveAbilityID::SorcererRank2: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(2); - break; - } - case ItemSetPassiveAbilityID::SorcererRank3: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(3); - break; - } + case eItemSetPassiveAbilityID::ShinobiRank1: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(1); + break; + } + case eItemSetPassiveAbilityID::ShinobiRank2: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(2); + break; + } + case eItemSetPassiveAbilityID::ShinobiRank3: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(3); + break; + } - default: - break; - } + case eItemSetPassiveAbilityID::SorcererRank1: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(1); + break; + } + case eItemSetPassiveAbilityID::SorcererRank2: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(2); + break; + } + case eItemSetPassiveAbilityID::SorcererRank3: { + if (equippedCount < 4) return; + destroyableComponent->Imagine(3); + break; + } + + default: + break; + } } diff --git a/dGame/dInventory/ItemSetPassiveAbility.h b/dGame/dInventory/ItemSetPassiveAbility.h index 151ce341..8735e695 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.h +++ b/dGame/dInventory/ItemSetPassiveAbility.h @@ -9,11 +9,11 @@ class ItemSet; enum class PassiveAbilityTrigger { - AssemblyImagination, // Less than 1 imagination - ParadoxHealth, // Less or equal to 1 health - SentinelArmor, // Less than 1 armor - VentureHealth, // Less than 3 health - EnemySmashed, // Enemy is smashed + AssemblyImagination, // Less than 1 imagination + ParadoxHealth, // Less or equal to 1 health + SentinelArmor, // Less than 1 armor + VentureHealth, // Less than 3 health + EnemySmashed, // Enemy is smashed }; /** @@ -22,50 +22,50 @@ enum class PassiveAbilityTrigger class ItemSetPassiveAbility { public: - ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet); - ~ItemSetPassiveAbility(); - void Update(float deltaTime); + ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet); + ~ItemSetPassiveAbility(); + void Update(float deltaTime); - /** - * Attempts to trigger a passive ability for this item set, if this is the wrong trigger this is a no-op - * @param trigger the trigger to attempt to fire - */ - void Trigger(PassiveAbilityTrigger trigger); + /** + * Attempts to trigger a passive ability for this item set, if this is the wrong trigger this is a no-op + * @param trigger the trigger to attempt to fire + */ + void Trigger(PassiveAbilityTrigger trigger, Entity* target = nullptr); - /** - * Activates the passive ability - */ - void Activate(); + /** + * Activates the passive ability + */ + void Activate(Entity* target = nullptr); - /** - * Finds all the passive abilities associated with a certain item set - * @param itemSetID the item set to find abilities for - * @param parent the parent to add to the passive abilities - * @param itemSet the item set to add to the passive abilities - * @return the passive abilities for the provided item set - */ - static std::vector FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet); + /** + * Finds all the passive abilities associated with a certain item set + * @param itemSetID the item set to find abilities for + * @param parent the parent to add to the passive abilities + * @param itemSet the item set to add to the passive abilities + * @return the passive abilities for the provided item set + */ + static std::vector FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet); private: - void OnEnemySmshed(); + void OnEnemySmshed(Entity* target = nullptr); - /** - * The means of triggering this ability - */ - PassiveAbilityTrigger m_Trigger; + /** + * The means of triggering this ability + */ + PassiveAbilityTrigger m_Trigger; - /** - * The owner of this ability - */ - Entity* m_Parent; + /** + * The owner of this ability + */ + Entity* m_Parent; - /** - * The item set this ability belongs to - */ - ItemSet* m_ItemSet; + /** + * The item set this ability belongs to + */ + ItemSet* m_ItemSet; - /** - * The cooldown on this ability until it can be activated again - */ - float m_Cooldown; + /** + * The cooldown on this ability until it can be activated again + */ + float m_Cooldown; }; diff --git a/dGame/dInventory/ItemSetPassiveAbilityID.h b/dGame/dInventory/ItemSetPassiveAbilityID.h deleted file mode 100644 index 12ba8409..00000000 --- a/dGame/dInventory/ItemSetPassiveAbilityID.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -/** -2 Engineer (Rank 1) Item Set -3 Engineer (Rank 2) Item Set -4 Engineer (Rank 3) Item Set -7 Knight (Rank 1) Item Set -8 Knight (Rank 2) Item Set -9 Knight (Rank 3) Item Set -10 Space Ranger (Rank 1) Item Set -11 Space Ranger (Rank 2) Item Set -12 Space Ranger (Rank 3) Item Set -13 Samurai (Rank 1) Item Set -14 Samurai (Rank 2) Item Set -15 Samurai (Rank 3) Item Set -16 Sorcerer (Rank 1) Item Set -17 Sorcerer (Rank 2) Item Set -18 Sorcerer (Rank 3) Item Set -19 Space Marauder (Rank 1) Item Set -20 Space Marauder (Rank 2) Item Set -21 Space Marauder (Rank 3) Item Set -22 Shinobi (Rank 1) Item Set -23 Shinobi (Rank 2) Item Set -24 Shinobi (Rank 3) Item Set -25 Inventor (Rank 1) Item Set -26 Inventor (Rank 2) Item Set -27 Inventor (Rank 3) Item Set -28 Summoner (Rank 1) Item Set -29 Summoner (Rank 2) Item Set -30 Summoner (Rank 3) Item Set -31 Adventurer (Rank 1) Item Set -32 Adventurer (Rank 2) Item Set -33 Adventurer (Rank 3) Item Set -34 Daredevil (Rank 1) Item Set -35 Daredevil (Rank 2) Item Set -36 Daredevil (Rank 3) Item Set -37 Buccaneer (Rank 1) Item Set -38 Buccaneer (Rank 2) Item Set -39 Buccaneer (Rank 3) Item Set -40 Bone Suit Item Set -41 Imagination Spinjitzu Item Set -42 Bat Lord Item Set -43 Mosaic Jester Item Set -44 Explorien Bot Item Set -45 [Unnamed] Item Set -46 [Unnamed] Item Set -47 [Unnamed] Item Set -48 Earth Spinjitzu Item Set -49 [Unnamed] Item Set -50 Fire Spinjitzu Item Set -51 Ice Spinjitzu Item Set -52 Lightning Spinjitzu Item Set - */ -enum class ItemSetPassiveAbilityID -{ - EngineerRank1 = 2, - EngineerRank2 = 3, - EngineerRank3 = 4, - KnightRank1 = 7, - KnightRank2 = 8, - KnightRank3 = 9, - SpaceRangerRank1 = 10, - SpaceRangerRank2 = 11, - SpaceRangerRank3 = 12, - SamuraiRank1 = 13, - SamuraiRank2 = 14, - SamuraiRank3 = 15, - SorcererRank1 = 16, - SorcererRank2 = 17, - SorcererRank3 = 18, - SpaceMarauderRank1 = 19, - SpaceMarauderRank2 = 20, - SpaceMarauderRank3 = 21, - ShinobiRank1 = 22, - ShinobiRank2 = 23, - ShinobiRank3 = 24, - InventorRank1 = 25, - InventorRank2 = 26, - InventorRank3 = 27, - SummonerRank1 = 28, - SummonerRank2 = 29, - SummonerRank3 = 30, - AdventurerRank1 = 31, - AdventurerRank2 = 32, - AdventurerRank3 = 33, - DaredevilRank1 = 34, - DaredevilRank2 = 35, - DaredevilRank3 = 36, - BuccaneerRank1 = 37, - BuccaneerRank2 = 38, - BuccaneerRank3 = 39, - BoneSuit = 40, - ImaginationSpinjitzu = 41, - BatLord = 42, - MosaicJester = 43, - ExplorienBot = 44, - Unnamed1 = 45, - Unnamed2 = 46, - Unnamed3 = 47, - EarthSpinjitzu = 48, - Unnamed4 = 49, - FireSpinjitzu = 50, - IceSpinjitzu = 51, - LightningSpinjitzu = 52 -}; diff --git a/dGame/dMission/CMakeLists.txt b/dGame/dMission/CMakeLists.txt new file mode 100644 index 00000000..652c3cb2 --- /dev/null +++ b/dGame/dMission/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DGAME_DMISSION_SOURCES "Mission.cpp" + "MissionPrerequisites.cpp" + "MissionTask.cpp" PARENT_SCOPE) diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index aeb26838..32a930e4 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -1,613 +1,623 @@ -#include "Mission.h" +#include "Mission.h" #include #include "CDClientManager.h" #include "Character.h" #include "CharacterComponent.h" +#include "LevelProgressionComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" #include "Game.h" #include "GameMessages.h" #include "Mail.h" #include "MissionComponent.h" -#include "RacingTaskParam.h" -#include "dLocale.h" +#include "eRacingTaskParam.h" #include "dLogger.h" #include "dServer.h" #include "dZoneManager.h" +#include "InventoryComponent.h" +#include "User.h" #include "Database.h" +#include "WorldConfig.h" +#include "eMissionState.h" +#include "eMissionTaskType.h" +#include "eMissionLockState.h" +#include "eReplicaComponentType.h" + +#include "CDMissionEmailTable.h" Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { - m_MissionComponent = missionComponent; + m_MissionComponent = missionComponent; - m_Completions = 0; + m_Completions = 0; - m_Timestamp = 0; + m_Timestamp = 0; - m_Reward = 0; + m_UniqueMissionID = dZoneManager::Instance()->GetUniqueMissionIdStartingValue(); - m_State = MissionState::MISSION_STATE_UNKNOWN; + m_Reward = 0; - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + m_State = eMissionState::UNKNOWN; - info = missionsTable->GetPtrByMissionID(missionId); + auto* missionsTable = CDClientManager::Instance().GetTable(); - if (info == &CDMissionsTable::Default) { - Game::logger->Log("Missions", "Failed to find mission (%i)!\n", missionId); + info = missionsTable->GetPtrByMissionID(missionId); - return; - } + if (info == &CDMissionsTable::Default) { + Game::logger->Log("Missions", "Failed to find mission (%i)!", missionId); - auto* tasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); + return; + } - auto tasks = tasksTable->GetByMissionID(missionId); + auto* tasksTable = CDClientManager::Instance().GetTable(); - for (auto i = 0U; i < tasks.size(); ++i) { - auto* info = tasks[i]; + auto tasks = tasksTable->GetByMissionID(missionId); - auto* task = new MissionTask(this, info, i); + for (auto i = 0U; i < tasks.size(); ++i) { + auto* info = tasks[i]; - m_Tasks.push_back(task); - } + auto* task = new MissionTask(this, info, i); + + m_Tasks.push_back(task); + } } void Mission::LoadFromXml(tinyxml2::XMLElement* element) { - // Start custom XML - if (element->Attribute("state") != nullptr) { - m_State = static_cast(std::stoul(element->Attribute("state"))); - } - // End custom XML + // Start custom XML + if (element->Attribute("state") != nullptr) { + m_State = static_cast(std::stoul(element->Attribute("state"))); + } + // End custom XML - if (element->Attribute("cct") != nullptr) { - m_Completions = std::stoul(element->Attribute("cct")); + if (element->Attribute("cct") != nullptr) { + m_Completions = std::stoul(element->Attribute("cct")); - m_Timestamp = std::stoul(element->Attribute("cts")); + m_Timestamp = std::stoul(element->Attribute("cts")); - if (IsComplete()) { - return; - } - } + if (IsComplete()) { + return; + } + } - auto* task = element->FirstChildElement(); + auto* task = element->FirstChildElement(); - auto index = 0U; + auto index = 0U; - while (task != nullptr) { - if (index >= m_Tasks.size()) { - break; - } + while (task != nullptr) { + if (index >= m_Tasks.size()) { + break; + } - const auto type = m_Tasks[index]->GetType(); + const auto type = m_Tasks[index]->GetType(); - if (type == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT || - type == MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY) { - std::vector uniques; + if (type == eMissionTaskType::COLLECTION || + type == eMissionTaskType::VISIT_PROPERTY) { + std::vector uniques; - const auto value = std::stoul(task->Attribute("v")); + const auto value = std::stoul(task->Attribute("v")); - m_Tasks[index]->SetProgress(value, false); + m_Tasks[index]->SetProgress(value, false); - task = task->NextSiblingElement(); + task = task->NextSiblingElement(); - while (task != nullptr) { - const auto unique = std::stoul(task->Attribute("v")); + while (task != nullptr) { + const auto unique = std::stoul(task->Attribute("v")); - uniques.push_back(unique); + uniques.push_back(unique); - if (m_MissionComponent != nullptr && type == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT) { - m_MissionComponent->AddCollectible(unique); - } + if (m_MissionComponent != nullptr && type == eMissionTaskType::COLLECTION) { + m_MissionComponent->AddCollectible(unique); + } - task = task->NextSiblingElement(); - } + task = task->NextSiblingElement(); + } - m_Tasks[index]->SetUnique(uniques); + m_Tasks[index]->SetUnique(uniques); - m_Tasks[index]->SetProgress(uniques.size(), false); + m_Tasks[index]->SetProgress(uniques.size(), false); - break; - } else { - const auto value = std::stoul(task->Attribute("v")); + break; + } else { + const auto value = std::stoul(task->Attribute("v")); - m_Tasks[index]->SetProgress(value, false); + m_Tasks[index]->SetProgress(value, false); - task = task->NextSiblingElement(); - } + task = task->NextSiblingElement(); + } - index++; - } + index++; + } } void Mission::UpdateXml(tinyxml2::XMLElement* element) { - // Start custom XML - element->SetAttribute("state", static_cast(m_State)); - // End custom XML + // Start custom XML + element->SetAttribute("state", static_cast(m_State)); + // End custom XML - element->DeleteChildren(); + element->DeleteChildren(); - element->SetAttribute("id", static_cast(info->id)); + element->SetAttribute("id", static_cast(info->id)); - if (m_Completions > 0) { - element->SetAttribute("cct", static_cast(m_Completions)); + if (m_Completions > 0) { + element->SetAttribute("cct", static_cast(m_Completions)); - element->SetAttribute("cts", static_cast(m_Timestamp)); + element->SetAttribute("cts", static_cast(m_Timestamp)); - if (IsComplete()) { - return; - } - } + if (IsComplete()) { + return; + } + } - for (auto* task : m_Tasks) { - if (task->GetType() == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT || - task->GetType() == MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY) { + for (auto* task : m_Tasks) { + if (task->GetType() == eMissionTaskType::COLLECTION || + task->GetType() == eMissionTaskType::VISIT_PROPERTY) { - auto* child = element->GetDocument()->NewElement("sv"); + auto* child = element->GetDocument()->NewElement("sv"); - child->SetAttribute("v", static_cast(task->GetProgress())); + child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); + element->LinkEndChild(child); - for (auto unique : task->GetUnique()) { - auto* uniqueElement = element->GetDocument()->NewElement("sv"); + for (auto unique : task->GetUnique()) { + auto* uniqueElement = element->GetDocument()->NewElement("sv"); - uniqueElement->SetAttribute("v", static_cast(unique)); + uniqueElement->SetAttribute("v", static_cast(unique)); - element->LinkEndChild(uniqueElement); - } + element->LinkEndChild(uniqueElement); + } - break; - } - auto* child = element->GetDocument()->NewElement("sv"); + break; + } + auto* child = element->GetDocument()->NewElement("sv"); - child->SetAttribute("v", static_cast(task->GetProgress())); + child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); - } + element->LinkEndChild(child); + } } bool Mission::IsValidMission(const uint32_t missionId) { - auto* table = CDClientManager::Instance()->GetTable("Missions"); + auto* table = CDClientManager::Instance().GetTable(); - const auto missions = table->Query([=](const CDMissions& entry) { - return entry.id == static_cast(missionId); - }); + const auto missions = table->Query([=](const CDMissions& entry) { + return entry.id == static_cast(missionId); + }); - return !missions.empty(); + return !missions.empty(); } bool Mission::IsValidMission(const uint32_t missionId, CDMissions& info) { - auto* table = CDClientManager::Instance()->GetTable("Missions"); + auto* table = CDClientManager::Instance().GetTable(); - const auto missions = table->Query([=](const CDMissions& entry) { - return entry.id == static_cast(missionId); - }); + const auto missions = table->Query([=](const CDMissions& entry) { + return entry.id == static_cast(missionId); + }); - if (missions.empty()) { - return false; - } + if (missions.empty()) { + return false; + } - info = missions[0]; + info = missions[0]; - return true; + return true; } Entity* Mission::GetAssociate() const { - return m_MissionComponent->GetParent(); + return m_MissionComponent->GetParent(); } User* Mission::GetUser() const { - return GetAssociate()->GetParentUser(); + return GetAssociate()->GetParentUser(); } uint32_t Mission::GetMissionId() const { - return info->id; + return info->id; } const CDMissions& Mission::GetClientInfo() const { - return *info; + return *info; } uint32_t Mission::GetCompletions() const { - return m_Completions; + return m_Completions; } uint32_t Mission::GetTimestamp() const { - return m_Timestamp; + return m_Timestamp; } LOT Mission::GetReward() const { - return m_Reward; + return m_Reward; } std::vector Mission::GetTasks() const { - return m_Tasks; + return m_Tasks; } -MissionState Mission::GetMissionState() const { - return m_State; +eMissionState Mission::GetMissionState() const { + return m_State; } bool Mission::IsAchievement() const { - return !info->isMission; + return !info->isMission; } bool Mission::IsMission() const { - return info->isMission; + return info->isMission; } bool Mission::IsRepeatable() const { - return info->repeatable; + return info->repeatable; } bool Mission::IsComplete() const { - return m_State == MissionState::MISSION_STATE_COMPLETE; + return m_State == eMissionState::COMPLETE; } bool Mission::IsActive() const { - return m_State == MissionState::MISSION_STATE_ACTIVE || m_State == MissionState::MISSION_STATE_COMPLETE_AVAILABLE; + return m_State == eMissionState::ACTIVE || m_State == eMissionState::COMPLETE_AVAILABLE; } void Mission::MakeActive() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_ACTIVE : MissionState::MISSION_STATE_COMPLETE_ACTIVE); + SetMissionState(m_Completions == 0 ? eMissionState::ACTIVE : eMissionState::COMPLETE_ACTIVE); } bool Mission::IsReadyToComplete() const { - return m_State == MissionState::MISSION_STATE_READY_TO_COMPLETE || m_State == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE; + return m_State == eMissionState::READY_TO_COMPLETE || m_State == eMissionState::COMPLETE_READY_TO_COMPLETE; } void Mission::MakeReadyToComplete() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_READY_TO_COMPLETE : MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE); + SetMissionState(m_Completions == 0 ? eMissionState::READY_TO_COMPLETE : eMissionState::COMPLETE_READY_TO_COMPLETE); } bool Mission::IsAvalible() const { - return m_State == MissionState::MISSION_STATE_AVAILABLE || m_State == MissionState::MISSION_STATE_COMPLETE_AVAILABLE; + return m_State == eMissionState::AVAILABLE || m_State == eMissionState::COMPLETE_AVAILABLE; } bool Mission::IsFetchMission() const { - return m_Tasks.size() == 1 && m_Tasks[0]->GetType() == MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION; + return m_Tasks.size() == 1 && m_Tasks[0]->GetType() == eMissionTaskType::TALK_TO_NPC; } void Mission::MakeAvalible() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_AVAILABLE : MissionState::MISSION_STATE_COMPLETE_AVAILABLE); + SetMissionState(m_Completions == 0 ? eMissionState::AVAILABLE : eMissionState::COMPLETE_AVAILABLE); } void Mission::Accept() { - SetMissionTypeState(MissionLockState::MISSION_LOCK_NEW, info->defined_type, info->defined_subtype); + SetMissionTypeState(eMissionLockState::NEW, info->defined_type, info->defined_subtype); - SetMissionState(m_Completions > 0 ? MissionState::MISSION_STATE_COMPLETE_ACTIVE : MissionState::MISSION_STATE_ACTIVE); + SetMissionState(m_Completions > 0 ? eMissionState::COMPLETE_ACTIVE : eMissionState::ACTIVE); - Catchup(); + Catchup(); } void Mission::Complete(const bool yieldRewards) { - if (m_State != MissionState::MISSION_STATE_ACTIVE && m_State != MissionState::MISSION_STATE_COMPLETE_ACTIVE) { - Accept(); - } + if (m_State != eMissionState::ACTIVE && m_State != eMissionState::COMPLETE_ACTIVE) { + // If we are accepting a mission here there is no point to giving it a unique ID since we just complete it immediately. + Accept(); + } - for (auto* task : m_Tasks) { - task->Complete(); - } + for (auto* task : m_Tasks) { + task->Complete(); + } - SetMissionState(MissionState::MISSION_STATE_REWARDING, true); + SetMissionState(eMissionState::REWARDING, true); - if (yieldRewards) { - YieldRewards(); - } + if (yieldRewards) { + YieldRewards(); + } - SetMissionState(MissionState::MISSION_STATE_COMPLETE); + SetMissionState(eMissionState::COMPLETE); - m_Completions++; + m_Completions++; - m_Timestamp = std::time(nullptr); + m_Timestamp = std::time(nullptr); - auto* entity = GetAssociate(); + auto* entity = GetAssociate(); - if (entity == nullptr) { - return; - } + if (entity == nullptr) { + return; + } - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->TrackMissionCompletion(!info->isMission); - } + auto* characterComponent = entity->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->TrackMissionCompletion(!info->isMission); + } - auto* missionComponent = entity->GetComponent(); + auto* missionComponent = entity->GetComponent(); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MISSION_COMPLETE, info->id); + missionComponent->Progress(eMissionTaskType::META, info->id); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, info->id, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPLETE_ANY_RACING_TASK); + missionComponent->Progress(eMissionTaskType::RACING, info->id, (LWOOBJID)eRacingTaskParam::COMPLETE_ANY_RACING_TASK); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, info->id, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPLETE_TRACK_TASKS); + missionComponent->Progress(eMissionTaskType::RACING, info->id, (LWOOBJID)eRacingTaskParam::COMPLETE_TRACK_TASKS); - auto* missionEmailTable = CDClientManager::Instance()->GetTable("MissionEmail"); + auto* missionEmailTable = CDClientManager::Instance().GetTable(); - const auto missionId = GetMissionId(); + const auto missionId = GetMissionId(); - const auto missionEmails = missionEmailTable->Query([missionId](const CDMissionEmail& entry) { - return entry.missionID == missionId; - }); + const auto missionEmails = missionEmailTable->Query([missionId](const CDMissionEmail& entry) { + return entry.missionID == missionId; + }); - for (const auto& email : missionEmails) { - const auto missionEmailBase = "MissionEmail_" + std::to_string(email.ID) + "_"; + for (const auto& email : missionEmails) { + const auto missionEmailBase = "MissionEmail_" + std::to_string(email.ID) + "_"; - const auto senderLocale = missionEmailBase + "senderName"; - const auto announceLocale = missionEmailBase + "announceText"; + if (email.messageType == 1) { + const auto subject = "%[" + missionEmailBase + "subjectText]"; + const auto body = "%[" + missionEmailBase + "bodyText]"; + const auto sender = "%[" + missionEmailBase + "senderName]"; - if (email.messageType == 1 && Game::locale->HasPhrase(senderLocale)) { - const auto subject = dLocale::GetTemplate(missionEmailBase + "subjectText"); - const auto body = dLocale::GetTemplate(missionEmailBase + "bodyText"); - const auto sender = dLocale::GetTemplate(senderLocale); - - Mail::SendMail(LWOOBJID_EMPTY, sender, GetAssociate(), subject, body, email.attachmentLOT, 1); - } - } + Mail::SendMail(LWOOBJID_EMPTY, sender, GetAssociate(), subject, body, email.attachmentLOT, 1); + } + } } void Mission::CheckCompletion() { - for (auto* task : m_Tasks) { - if (!task->IsComplete()) { - return; - } - } + for (auto* task : m_Tasks) { + if (!task->IsComplete()) { + return; + } + } - if (IsAchievement()) { - Complete(); + if (IsAchievement()) { + Complete(); - return; - } + return; + } - MakeReadyToComplete(); + MakeReadyToComplete(); } void Mission::Catchup() { - auto* entity = GetAssociate(); + auto* entity = GetAssociate(); - auto* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inventory = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); - for (auto* task : m_Tasks) { - const auto type = task->GetType(); + for (auto* task : m_Tasks) { + const auto type = task->GetType(); - if (type == MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { - for (auto target : task->GetAllTargets()) { - const auto count = inventory->GetLotCountNonTransfer(target); + if (type == eMissionTaskType::GATHER) { + for (auto target : task->GetAllTargets()) { + const auto count = inventory->GetLotCountNonTransfer(target); - for (auto i = 0U; i < count; ++i) { - task->Progress(target); - } - } - } + for (auto i = 0U; i < count; ++i) { + task->Progress(target); + } + } + } - if (type == MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG) { - for (auto target : task->GetAllTargets()) { - const auto flag = GetUser()->GetLastUsedChar()->GetPlayerFlag(target); + if (type == eMissionTaskType::PLAYER_FLAG) { + for (int32_t target : task->GetAllTargets()) { + const auto flag = GetUser()->GetLastUsedChar()->GetPlayerFlag(target); - if (!flag) { - continue; - } + if (!flag) { + continue; + } - task->Progress(target); + task->Progress(target); - if (task->IsComplete()) { - break; - } - } - } - } + if (task->IsComplete()) { + break; + } + } + } + } } void Mission::YieldRewards() { - auto* entity = GetAssociate(); + auto* entity = GetAssociate(); - if (entity == nullptr) { - return; - } + if (entity == nullptr) { + return; + } - auto* character = GetUser()->GetLastUsedChar(); + auto* character = GetUser()->GetLastUsedChar(); - auto* inventoryComponent = entity->GetComponent(); - auto* characterComponent = entity->GetComponent(); - auto* destroyableComponent = entity->GetComponent(); - auto* missionComponent = entity->GetComponent(); + auto* inventoryComponent = entity->GetComponent(); + auto* levelComponent = entity->GetComponent(); + auto* characterComponent = entity->GetComponent(); + auto* destroyableComponent = entity->GetComponent(); + auto* missionComponent = entity->GetComponent(); - // Remove mission items - for (auto* task : m_Tasks) { - if (task->GetType() != MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { - continue; - } + // Remove mission items + for (auto* task : m_Tasks) { + if (task->GetType() != eMissionTaskType::GATHER) { + continue; + } - const auto& param = task->GetParameters(); + const auto& param = task->GetParameters(); - if (param.empty() || (param[0] & 1) == 0) // Should items be removed? - { - for (const auto target : task->GetAllTargets()) { - // This is how live did it. ONLY remove item collection items from the items and hidden inventories and none of the others. - inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::ITEMS); - inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::HIDDEN); + if (param.empty() || (param[0] & 1) == 0) // Should items be removed? + { + for (const auto target : task->GetAllTargets()) { + // This is how live did it. ONLY remove item collection items from the items and hidden inventories and none of the others. + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::ITEMS); + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::QUEST); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); - } - } - } + missionComponent->Progress(eMissionTaskType::GATHER, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); + } + } + } - int32_t coinsToSend = 0; - if (info->LegoScore > 0) { - eLootSourceType lootSource = info->isMission ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT; - if(characterComponent->GetLevel() >= dZoneManager::Instance()->GetMaxLevel()) { - // Since the character is at the level cap we reward them with coins instead of UScore. - coinsToSend += info->LegoScore * dZoneManager::Instance()->GetLevelCapCurrencyConversion(); - } else { - characterComponent->SetUScore(characterComponent->GetUScore() + info->LegoScore); - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), info->LegoScore, lootSource); - } - } + int32_t coinsToSend = 0; + if (info->LegoScore > 0) { + eLootSourceType lootSource = info->isMission ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT; + if (levelComponent->GetLevel() >= dZoneManager::Instance()->GetWorldConfig()->levelCap) { + // Since the character is at the level cap we reward them with coins instead of UScore. + coinsToSend += info->LegoScore * dZoneManager::Instance()->GetWorldConfig()->levelCapCurrencyConversion; + } else { + characterComponent->SetUScore(characterComponent->GetUScore() + info->LegoScore); + GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), info->LegoScore, lootSource); + } + } - if (m_Completions > 0) { - std::vector> items; + if (m_Completions > 0) { + std::vector> items; - items.emplace_back(info->reward_item1_repeatable, info->reward_item1_repeat_count); - items.emplace_back(info->reward_item2_repeatable, info->reward_item2_repeat_count); - items.emplace_back(info->reward_item3_repeatable, info->reward_item3_repeat_count); - items.emplace_back(info->reward_item4_repeatable, info->reward_item4_repeat_count); + items.emplace_back(info->reward_item1_repeatable, info->reward_item1_repeat_count); + items.emplace_back(info->reward_item2_repeatable, info->reward_item2_repeat_count); + items.emplace_back(info->reward_item3_repeatable, info->reward_item3_repeat_count); + items.emplace_back(info->reward_item4_repeatable, info->reward_item4_repeat_count); - for (const auto& pair : items) { - // Some missions reward zero of an item and so they must be allowed through this clause, - // hence pair.second < 0 instead of pair.second <= 0. - if (pair.second < 0 || (m_Reward > 0 && pair.first != m_Reward)) { - continue; - } + for (const auto& pair : items) { + // Some missions reward zero of an item and so they must be allowed through this clause, + // hence pair.second < 0 instead of pair.second <= 0. + if (pair.second < 0 || (m_Reward > 0 && pair.first != m_Reward)) { + continue; + } - // If a mission rewards zero of an item, make it reward 1. - auto count = pair.second > 0 ? pair.second : 1; + // If a mission rewards zero of an item, make it reward 1. + auto count = pair.second > 0 ? pair.second : 1; - // Sanity check, 6 is the max any mission yields - if (count > 6) { - count = 0; - } + // Sanity check, 6 is the max any mission yields + if (count > 6) { + count = 0; + } - inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT); - } + inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT); + } - if (info->reward_currency_repeatable > 0 || coinsToSend > 0) { - eLootSourceType lootSource = info->isMission ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT; - character->SetCoins(character->GetCoins() + info->reward_currency_repeatable + coinsToSend, lootSource); - } + if (info->reward_currency_repeatable > 0 || coinsToSend > 0) { + eLootSourceType lootSource = info->isMission ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT; + character->SetCoins(character->GetCoins() + info->reward_currency_repeatable + coinsToSend, lootSource); + } - return; - } + return; + } - std::vector> items; + std::vector> items; - items.emplace_back(info->reward_item1, info->reward_item1_count); - items.emplace_back(info->reward_item2, info->reward_item2_count); - items.emplace_back(info->reward_item3, info->reward_item3_count); - items.emplace_back(info->reward_item4, info->reward_item4_count); + items.emplace_back(info->reward_item1, info->reward_item1_count); + items.emplace_back(info->reward_item2, info->reward_item2_count); + items.emplace_back(info->reward_item3, info->reward_item3_count); + items.emplace_back(info->reward_item4, info->reward_item4_count); - for (const auto& pair : items) { - // Some missions reward zero of an item and so they must be allowed through this clause, - // hence pair.second < 0 instead of pair.second <= 0. - if (pair.second < 0 || (m_Reward > 0 && pair.first != m_Reward)) { - continue; - } - - // If a mission rewards zero of an item, make it reward 1. - auto count = pair.second > 0 ? pair.second : 1; + for (const auto& pair : items) { + // Some missions reward zero of an item and so they must be allowed through this clause, + // hence pair.second < 0 instead of pair.second <= 0. + if (pair.second < 0 || (m_Reward > 0 && pair.first != m_Reward)) { + continue; + } - // Sanity check, 6 is the max any mission yields - if (count > 6) { - count = 0; - } + // If a mission rewards zero of an item, make it reward 1. + auto count = pair.second > 0 ? pair.second : 1; - inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT); - } + // Sanity check, 6 is the max any mission yields + if (count > 6) { + count = 0; + } - if (info->reward_currency > 0 || coinsToSend > 0) { - eLootSourceType lootSource = info->isMission ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT; - character->SetCoins(character->GetCoins() + info->reward_currency + coinsToSend, lootSource); - } + inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT); + } - if (info->reward_maxinventory > 0) { - auto* inventory = inventoryComponent->GetInventory(ITEMS); + if (info->reward_currency > 0 || coinsToSend > 0) { + eLootSourceType lootSource = info->isMission ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT; + character->SetCoins(character->GetCoins() + info->reward_currency + coinsToSend, lootSource); + } - inventory->SetSize(inventory->GetSize() + info->reward_maxinventory); - } + if (info->reward_maxinventory > 0) { + auto* inventory = inventoryComponent->GetInventory(ITEMS); - if (info->reward_bankinventory > 0) { - auto* inventory = inventoryComponent->GetInventory(eInventoryType::VAULT_ITEMS); - auto modelInventory = inventoryComponent->GetInventory(eInventoryType::VAULT_MODELS); + inventory->SetSize(inventory->GetSize() + info->reward_maxinventory); + } - inventory->SetSize(inventory->GetSize() + info->reward_bankinventory); - modelInventory->SetSize(modelInventory->GetSize() + info->reward_bankinventory); - } + if (info->reward_bankinventory > 0) { + auto* inventory = inventoryComponent->GetInventory(eInventoryType::VAULT_ITEMS); + auto modelInventory = inventoryComponent->GetInventory(eInventoryType::VAULT_MODELS); - if (info->reward_reputation > 0) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_EARN_REPUTATION, 0, 0L, "", info->reward_reputation); - auto character = entity->GetComponent(); - if (character) { - character->SetReputation(character->GetReputation() + info->reward_reputation); - GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress()); - } - } + inventory->SetSize(inventory->GetSize() + info->reward_bankinventory); + modelInventory->SetSize(modelInventory->GetSize() + info->reward_bankinventory); + } - if (info->reward_maxhealth > 0) { - destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast(info->reward_maxhealth), true); - } + if (info->reward_reputation > 0) { + missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, 0L, "", info->reward_reputation); + auto character = entity->GetComponent(); + if (character) { + character->SetReputation(character->GetReputation() + info->reward_reputation); + GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress()); + } + } - if (info->reward_maximagination > 0) { - destroyableComponent->SetMaxImagination(destroyableComponent->GetMaxImagination() + static_cast(info->reward_maximagination), true); - } + if (info->reward_maxhealth > 0) { + destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast(info->reward_maxhealth), true); + } - EntityManager::Instance()->SerializeEntity(entity); + if (info->reward_maximagination > 0) { + destroyableComponent->SetMaxImagination(destroyableComponent->GetMaxImagination() + static_cast(info->reward_maximagination), true); + } - if (info->reward_emote > 0) { - character->UnlockEmote(info->reward_emote); - } + EntityManager::Instance()->SerializeEntity(entity); - if (info->reward_emote2 > 0) { - character->UnlockEmote(info->reward_emote2); - } + if (info->reward_emote > 0) { + character->UnlockEmote(info->reward_emote); + } - if (info->reward_emote3 > 0) { - character->UnlockEmote(info->reward_emote3); - } + if (info->reward_emote2 > 0) { + character->UnlockEmote(info->reward_emote2); + } - if (info->reward_emote4 > 0) { - character->UnlockEmote(info->reward_emote4); - } + if (info->reward_emote3 > 0) { + character->UnlockEmote(info->reward_emote3); + } + + if (info->reward_emote4 > 0) { + character->UnlockEmote(info->reward_emote4); + } } -void Mission::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) { - const auto isRemoval = count < 0; +void Mission::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) { + const auto isRemoval = count < 0; - if (isRemoval && (IsComplete() || IsAchievement())) { - return; - } + if (isRemoval && (IsComplete() || IsAchievement())) { + return; + } - for (auto* task : m_Tasks) { - if (task->IsComplete() && !isRemoval) { - continue; - } + for (auto* task : m_Tasks) { + if (task->IsComplete() && !isRemoval) { + continue; + } - if (task->GetType() != type) { - continue; - } + if (task->GetType() != type) { + continue; + } - if (isRemoval && !task->InAllTargets(value)) { - continue; - } + if (isRemoval && !task->InAllTargets(value)) { + continue; + } - task->Progress(value, associate, targets, count); - } + task->Progress(value, associate, targets, count); + } } -void Mission::SetMissionState(const MissionState state, const bool sendingRewards) { - this->m_State = state; +void Mission::SetMissionState(const eMissionState state, const bool sendingRewards) { + this->m_State = state; - auto* entity = GetAssociate(); + auto* entity = GetAssociate(); - if (entity == nullptr) { - return; - } + if (entity == nullptr) { + return; + } - GameMessages::SendNotifyMission(entity, entity->GetParentUser()->GetSystemAddress(), info->id, static_cast(state), sendingRewards); + GameMessages::SendNotifyMission(entity, entity->GetParentUser()->GetSystemAddress(), info->id, static_cast(state), sendingRewards); } -void Mission::SetMissionTypeState(MissionLockState state, const std::string& type, const std::string& subType) { - // TODO +void Mission::SetMissionTypeState(eMissionLockState state, const std::string& type, const std::string& subType) { + // TODO } void Mission::SetCompletions(const uint32_t value) { - m_Completions = value; + m_Completions = value; } void Mission::SetReward(const LOT lot) { - m_Reward = lot; + m_Reward = lot; } Mission::~Mission() { - for (auto* task : m_Tasks) { - delete task; - } + for (auto* task : m_Tasks) { + delete task; + } - m_Tasks.clear(); -} \ No newline at end of file + m_Tasks.clear(); +} diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index 4fb6c60f..b04c3548 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #ifndef MISSION_H #define MISSION_H @@ -10,9 +10,12 @@ #include "MissionTask.h" #include "dCommonVars.h" #include "Entity.h" -#include "MissionState.h" -#include "MissionLockState.h" +namespace tinyxml2 { + class XMLElement; +}; +enum class eMissionState : int; +enum class eMissionLockState : int; class MissionComponent; /** @@ -22,245 +25,262 @@ class Mission final { public: Mission(MissionComponent* missionComponent, uint32_t missionId); - ~Mission(); + ~Mission(); - void LoadFromXml(tinyxml2::XMLElement* element); - void UpdateXml(tinyxml2::XMLElement* element); + void LoadFromXml(tinyxml2::XMLElement* element); + void UpdateXml(tinyxml2::XMLElement* element); - /** - * Returns the ID of this mission - * @return the ID of this mission - */ + /** + * Returns the ID of this mission + * @return the ID of this mission + */ uint32_t GetMissionId() const; - /** - * Returns the entity that is currently progressing this mission - * @return the entity that is currently progressing this mission - */ + /** + * Returns the entity that is currently progressing this mission + * @return the entity that is currently progressing this mission + */ Entity* GetAssociate() const; - /** - * Returns the account owns the entity that is currently progressing this mission - * @return the account owns the entity that is currently progressing this mission - */ + /** + * Returns the account owns the entity that is currently progressing this mission + * @return the account owns the entity that is currently progressing this mission + */ User* GetUser() const; - /** - * Returns the current state of this mission - * @return the current state of this mission - */ - MissionState GetMissionState() const; + /** + * Returns the current state of this mission + * @return the current state of this mission + */ + eMissionState GetMissionState() const; - /** - * Returns the database information that represents to this mission. - * @return the database information that represents to this mission. - */ + /** + * Returns the database information that represents to this mission. + * @return the database information that represents to this mission. + */ const CDMissions& GetClientInfo() const; - /** - * Returns the number of times the entity has completed this mission, can only be > 0 for dailies. - * @return the number of thimes the entity has completed this mission - */ + /** + * Returns the number of times the entity has completed this mission, can only be > 0 for dailies. + * @return the number of thimes the entity has completed this mission + */ uint32_t GetCompletions() const; - /** - * Sets the number of times this mission has been completed - * @param value the number of times this mission should be completed - */ - void SetCompletions(uint32_t value); + /** + * Sets the number of times this mission has been completed + * @param value the number of times this mission should be completed + */ + void SetCompletions(uint32_t value); - /** - * Returns the last timestamp at which the entity completed this mission - * @return the last timestamp at which the entity completed this mission - */ + /** + * Returns the last timestamp at which the entity completed this mission + * @return the last timestamp at which the entity completed this mission + */ uint32_t GetTimestamp() const; - /** - * Returns some specific reward that should be returned from the possible rewards indicated by the client - * @return some specific reward that should be returned from the possible rewards indicated by the client - */ + /** + * Returns some specific reward that should be returned from the possible rewards indicated by the client + * @return some specific reward that should be returned from the possible rewards indicated by the client + */ LOT GetReward() const; - /** - * Sets an some specific reward that should be returned from the possible rewards indicated by the client - * @param lot the reward to set - */ - void SetReward(LOT lot); + /** + * Sets an some specific reward that should be returned from the possible rewards indicated by the client + * @param lot the reward to set + */ + void SetReward(LOT lot); - /** - * Returns all the tasks that must be completed to mark this mission as complete - * @return all the tasks that must be completed to mark this mission as complete - */ + /** + * Returns all the tasks that must be completed to mark this mission as complete + * @return all the tasks that must be completed to mark this mission as complete + */ std::vector GetTasks() const; - /** - * Updates the mission state to the one provided - * @param state the mission state to set - * @param sendingRewards a flag indicating to the client that rewards wil lfollow - */ - void SetMissionState(MissionState state, bool sendingRewards = false); + /** + * Updates the mission state to the one provided + * @param state the mission state to set + * @param sendingRewards a flag indicating to the client that rewards wil lfollow + */ + void SetMissionState(eMissionState state, bool sendingRewards = false); - /** - * Currently unimplemented - */ - void SetMissionTypeState(MissionLockState state, const std::string& type, const std::string& subType); + /** + * Currently unimplemented + */ + void SetMissionTypeState(eMissionLockState state, const std::string& type, const std::string& subType); - /** - * Returns whether this mission is an achievement - * @return true if this mission is an achievement, false otherwise - */ + /** + * Returns whether this mission is an achievement + * @return true if this mission is an achievement, false otherwise + */ bool IsAchievement() const; - /** - * Returns whether this mission is a mission (e.g.: not an achievement) - * @return true if this mission is not an achievement, false otherwise - */ + /** + * Returns whether this mission is a mission (e.g.: not an achievement) + * @return true if this mission is not an achievement, false otherwise + */ bool IsMission() const; - /** - * Returns whether this mission can be repeated (mostly used for dailies) - * @return true if this mission can be repeated, false otherwise - */ + /** + * Returns whether this mission can be repeated (mostly used for dailies) + * @return true if this mission can be repeated, false otherwise + */ bool IsRepeatable() const; - /** - * Returns whether the entity has completed this mission before - * @return true if the mission has been completed before, false otherwise - */ + /** + * Returns whether the entity has completed this mission before + * @return true if the mission has been completed before, false otherwise + */ bool IsComplete() const; - /** - * Returns whether the mission is currently active - * @return true if the mission is currently active, false otherwise - */ + /** + * Returns whether the mission is currently active + * @return true if the mission is currently active, false otherwise + */ bool IsActive() const; - /** - * Sets the mission state to active, takes into account if this is a repeatable mission. - */ + /** + * Sets the mission state to active, takes into account if this is a repeatable mission. + */ void MakeActive(); - /** - * Returns whether the entity has completed all tasks and can hand the mission in for rewards. - * @return true if the entity can hand the mission in, false otherwise - */ + /** + * Returns whether the entity has completed all tasks and can hand the mission in for rewards. + * @return true if the entity can hand the mission in, false otherwise + */ bool IsReadyToComplete() const; - /** - * Sets the mission state to ready to complete, takes into account if this is a repeatable mission - */ + /** + * Sets the mission state to ready to complete, takes into account if this is a repeatable mission + */ void MakeReadyToComplete(); - /** - * Returns whether this mission can be accepted by the entity - * @return true if the mission can be accepted by the entity, false otherwise - */ + /** + * Returns whether this mission can be accepted by the entity + * @return true if the mission can be accepted by the entity, false otherwise + */ bool IsAvalible() const; - /** - * Sets the mission state to available, takes into account if this mission is repeatable - */ - void MakeAvalible(); + /** + * Sets the mission state to available, takes into account if this mission is repeatable + */ + void MakeAvalible(); - /** - * Returns whether this mission is one where an entity simply has to go somewhere, but doesn't have to turn in the - * mission tasks at the original mission giver (called a fetch mission). - * @return true if this is a fetch mission, false otherwise - */ + /** + * Returns whether this mission is one where an entity simply has to go somewhere, but doesn't have to turn in the + * mission tasks at the original mission giver (called a fetch mission). + * @return true if this is a fetch mission, false otherwise + */ bool IsFetchMission() const; - /** - * Accepts this mission, setting it to available. Also progresses any of the tasks if the entity has already - * progressed for them (for example "collect X bricks", will fast track for the amount of bricks the entity - * already has). - */ + /** + * Accepts this mission, setting it to available. Also progresses any of the tasks if the entity has already + * progressed for them (for example "collect X bricks", will fast track for the amount of bricks the entity + * already has). + */ void Accept(); - /** - * Completes the mission and handles all logistics regarding that: checking all tasks, handing out rewards, - * emailing them if the inventory is full, etc. If the mission tasks have not all been completed this is a no-op. - * @param yieldRewards if true, rewards will be given to the entity - */ + /** + * Completes the mission and handles all logistics regarding that: checking all tasks, handing out rewards, + * emailing them if the inventory is full, etc. If the mission tasks have not all been completed this is a no-op. + * @param yieldRewards if true, rewards will be given to the entity + */ void Complete(bool yieldRewards = true); - /** - * Checks if this mission is ready to be completed and updates the state if so. If this is an achievement, the - * state will automatically be updated to completed as there's nobody to hand achievements in to. - */ + /** + * Checks if this mission is ready to be completed and updates the state if so. If this is an achievement, the + * state will automatically be updated to completed as there's nobody to hand achievements in to. + */ void CheckCompletion(); - /** - * Gives all the rewards (items, score, stats, etc.) to the entity. Takes into account if the entity has completed - * the mission before. - */ + /** + * Gives all the rewards (items, score, stats, etc.) to the entity. Takes into account if the entity has completed + * the mission before. + */ void YieldRewards(); - /** - * Attempts to progress tasks of a certain type for this mission. Note that the interpretation of any of these - * arguments is up to the mission task at hand. - * @param type the mission task type to progress - * @param value the value to progress the mission task with - * @param associate optional object ID that was related to the progression - * @param targets optional multiple targets that need to be met for progression - * @param count optional count to progress with - */ - void Progress(MissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1); + /** + * Attempts to progress tasks of a certain type for this mission. Note that the interpretation of any of these + * arguments is up to the mission task at hand. + * @param type the mission task type to progress + * @param value the value to progress the mission task with + * @param associate optional object ID that was related to the progression + * @param targets optional multiple targets that need to be met for progression + * @param count optional count to progress with + */ + void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1); - /** - * Returns if the mission ID that's given belongs to an existing mission - * @param missionId the mission ID to check for - * @return true if the mission exists, false otherwise - */ + /** + * Returns if the mission ID that's given belongs to an existing mission + * @param missionId the mission ID to check for + * @return true if the mission exists, false otherwise + */ static bool IsValidMission(uint32_t missionId); - /** - * Returns if the mission ID that's given belongs to an existing mission - * @param missionId the mission ID to check for - * @param info variable to store the queried mission information in - * @return true if the mission exists, false otherwise - */ + /** + * Returns if the mission ID that's given belongs to an existing mission + * @param missionId the mission ID to check for + * @param info variable to store the queried mission information in + * @return true if the mission exists, false otherwise + */ static bool IsValidMission(uint32_t missionId, CDMissions& info); + + /** + * @brief Returns the unique mission order ID + * + * @return The unique order ID + */ + uint32_t GetUniqueMissionOrderID() { return m_UniqueMissionID; }; + + /** + * Sets the unique mission order ID of this mission + */ + void SetUniqueMissionOrderID(uint32_t value) { m_UniqueMissionID = value; }; private: - /** - * Progresses all the newly accepted tasks for this mission after it has been accepted to reflect the state of the - * inventory of the entity. - */ + /** + * Progresses all the newly accepted tasks for this mission after it has been accepted to reflect the state of the + * inventory of the entity. + */ void Catchup(); - /** - * The database information that corresponds to this mission - */ + /** + * The database information that corresponds to this mission + */ const CDMissions* info; - /** - * The current state this mission is in - */ - MissionState m_State; + /** + * The current state this mission is in + */ + eMissionState m_State; - /** - * The number of times the entity has completed this mission - */ + /** + * The number of times the entity has completed this mission + */ uint32_t m_Completions; - /** - * The last time the entity completed this mission - */ + /** + * The last time the entity completed this mission + */ uint32_t m_Timestamp; - /** - * The mission component of the entity that owns this mission - */ + /** + * The mission component of the entity that owns this mission + */ MissionComponent* m_MissionComponent; - /** - * Optionally specific reward that should be returned from the possible rewards indicated by the client - */ + /** + * Optionally specific reward that should be returned from the possible rewards indicated by the client + */ LOT m_Reward; - /** - * All the tasks that can be progressed for this mission - */ + /** + * All the tasks that can be progressed for this mission + */ std::vector m_Tasks; + + /** + * The unique ID what order this mission was accepted in. + */ + uint32_t m_UniqueMissionID; }; #endif diff --git a/dGame/dMission/MissionLockState.h b/dGame/dMission/MissionLockState.h deleted file mode 100644 index e2dcedd7..00000000 --- a/dGame/dMission/MissionLockState.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#ifndef MISSIONLOCKSTATE_H -#define MISSIONLOCKSTATE_H - -enum class MissionLockState : int -{ - MISSION_LOCK_LOCKED, - MISSION_LOCK_NEW, - MISSION_LOCK_UNLOCKED, -}; - -#endif diff --git a/dGame/dMission/MissionPrerequisites.cpp b/dGame/dMission/MissionPrerequisites.cpp index 93d55437..ec4522b9 100644 --- a/dGame/dMission/MissionPrerequisites.cpp +++ b/dGame/dMission/MissionPrerequisites.cpp @@ -1,4 +1,4 @@ -#include "MissionPrerequisites.h" +#include "MissionPrerequisites.h" #include #include @@ -52,8 +52,7 @@ PrerequisiteExpression::PrerequisiteExpression(const std::string& str) { case '9': if (sub) { s << character; - } - else { + } else { a << character; } break; @@ -71,8 +70,7 @@ PrerequisiteExpression::PrerequisiteExpression(const std::string& str) { if (!aString.empty()) { this->a = std::stoul(a.str()); - } - else { + } else { this->a = 0; } @@ -80,8 +78,7 @@ PrerequisiteExpression::PrerequisiteExpression(const std::string& str) { if (!subString.empty()) { this->sub = std::stoul(s.str()); - } - else { + } else { this->sub = 0; } @@ -89,8 +86,7 @@ PrerequisiteExpression::PrerequisiteExpression(const std::string& str) { if (!bString.empty()) { this->b = new PrerequisiteExpression(bString); - } - else { + } else { this->b = nullptr; } } @@ -109,11 +105,10 @@ bool PrerequisiteExpression::Execute(const std::unordered_mapsub != 0) { // Special case for one Wisp Lee repeatable mission. - a = mission->GetClientInfo().id == 1883 ? - mission->GetMissionState() == static_cast(this->sub) : - mission->GetMissionState() >= static_cast(this->sub); - } - else if (mission->IsComplete()) { + a = mission->GetClientInfo().id == 1883 ? + mission->GetMissionState() == static_cast(this->sub) : + mission->GetMissionState() >= static_cast(this->sub); + } else if (mission->IsComplete()) { a = true; } } @@ -144,42 +139,42 @@ bool MissionPrerequisites::CanAccept(const uint32_t missionId, const std::unorde const auto& info = mission->GetClientInfo(); if (info.repeatable) { - const auto prerequisitesMet = CheckPrerequisites(missionId, missions); + const auto prerequisitesMet = CheckPrerequisites(missionId, missions); - // Checked by client + // Checked by client const time_t time = std::time(nullptr); const time_t lock = mission->GetTimestamp() + info.cooldownTime * 60; - // If there's no time limit, just check the prerequisites, otherwise make sure both conditions are met + // If there's no time limit, just check the prerequisites, otherwise make sure both conditions are met return (info.cooldownTime == -1 ? prerequisitesMet : (lock - time < 0)) && prerequisitesMet; } - // Mission is already accepted and cannot be repeatedly accepted + // Mission is already accepted and cannot be repeatedly accepted return false; } - // Mission is not yet accepted, check the prerequisites + // Mission is not yet accepted, check the prerequisites return CheckPrerequisites(missionId, missions); } bool MissionPrerequisites::CheckPrerequisites(uint32_t missionId, const std::unordered_map& missions) { - const auto& index = expressions.find(missionId); - if (index != expressions.end()) { - return index->second->Execute(missions); - } + const auto& index = expressions.find(missionId); + if (index != expressions.end()) { + return index->second->Execute(missions); + } - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); - const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { - return entry.id == static_cast(missionId); - }); + auto* missionsTable = CDClientManager::Instance().GetTable(); + const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { + return entry.id == static_cast(missionId); + }); - if (missionEntries.empty()) - return false; + if (missionEntries.empty()) + return false; - auto* expression = new PrerequisiteExpression(missionEntries[0].prereqMissionID); - expressions.insert_or_assign(missionId, expression); + auto* expression = new PrerequisiteExpression(missionEntries[0].prereqMissionID); + expressions.insert_or_assign(missionId, expression); - return expression->Execute(missions); + return expression->Execute(missions); } std::unordered_map MissionPrerequisites::expressions = {}; diff --git a/dGame/dMission/MissionPrerequisites.h b/dGame/dMission/MissionPrerequisites.h index f426e916..13b8e903 100644 --- a/dGame/dMission/MissionPrerequisites.h +++ b/dGame/dMission/MissionPrerequisites.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include #include @@ -16,11 +16,11 @@ class PrerequisiteExpression final PrerequisiteExpression* b; public: - /** - * Executes the prerequisite, checking its contents and returning whether or not the mission may be accepted - * @param missions the list of missions to check the prerequisites against (f.e. whether they're completed) - * @return whether or not all the prerequisites are met - */ + /** + * Executes the prerequisite, checking its contents and returning whether or not the mission may be accepted + * @param missions the list of missions to check the prerequisites against (f.e. whether they're completed) + * @return whether or not all the prerequisites are met + */ bool Execute(const std::unordered_map& missions) const; explicit PrerequisiteExpression(const std::string& str); @@ -33,26 +33,26 @@ public: class MissionPrerequisites final { public: - /** - * Checks whether or not the mission identified by the specified ID can be accepted based on the mission inventory passed. - * Also performs checks for daily missions (e.g. if the time out is valid). - * @param missionId the mission ID to check prerequisites for - * @param missions the mission inventory to check the prerequisites against - * @return whether or not the mission identified by the specified ID can be accepted - */ + /** + * Checks whether or not the mission identified by the specified ID can be accepted based on the mission inventory passed. + * Also performs checks for daily missions (e.g. if the time out is valid). + * @param missionId the mission ID to check prerequisites for + * @param missions the mission inventory to check the prerequisites against + * @return whether or not the mission identified by the specified ID can be accepted + */ static bool CanAccept(uint32_t missionId, const std::unordered_map& missions); private: - /** - * Cache of all the executed prerequisites - */ + /** + * Cache of all the executed prerequisites + */ static std::unordered_map expressions; - /** - * Checks the prerequisites for a mission - * @param missionId the mission ID to check prerequisites for - * @param missions the mission inventory to check the prerequisites against - * @return whether or not the mission identified by the specified ID can be accepted - */ - static bool CheckPrerequisites(uint32_t missionId, const std::unordered_map& missions); + /** + * Checks the prerequisites for a mission + * @param missionId the mission ID to check prerequisites for + * @param missions the mission inventory to check the prerequisites against + * @return whether or not the mission identified by the specified ID can be accepted + */ + static bool CheckPrerequisites(uint32_t missionId, const std::unordered_map& missions); }; diff --git a/dGame/dMission/MissionState.h b/dGame/dMission/MissionState.h deleted file mode 100644 index c189c708..00000000 --- a/dGame/dMission/MissionState.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#ifndef __MISSIONSTATE__H__ -#define __MISSIONSTATE__H__ - -/** - * Represents the possible states a mission can be in - */ -enum class MissionState : int { - /** - * The mission state is unknown - */ - MISSION_STATE_UNKNOWN = -1, - - /** - * The mission is yielding rewards - */ - MISSION_STATE_REWARDING = 0, - - /** - * The mission can be accepted - */ - MISSION_STATE_AVAILABLE = 1, - - /** - * The mission has been accepted but not yet completed - */ - MISSION_STATE_ACTIVE = 2, - - /** - * All the tasks for the mission have been completed and the entity can turn the mission in to complete it - */ - MISSION_STATE_READY_TO_COMPLETE = 4, //!< The mission is ready to complete - - /** - * The mission has been completed - */ - MISSION_STATE_COMPLETE = 8, - - /** - * The mission is available again and has been completed before. Used for daily missions. - */ - MISSION_STATE_COMPLETE_AVAILABLE = 9, - - /** - * The mission is active and has been completed before. Used for daily missions. - */ - MISSION_STATE_COMPLETE_ACTIVE = 10, - - /** - * The mission has been completed before and has now been completed again. Used for daily missions. - */ - MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12 -}; - -#endif //!__MISSIONSTATE__H__ diff --git a/dGame/dMission/MissionTask.cpp b/dGame/dMission/MissionTask.cpp index 2dd59887..344427c6 100644 --- a/dGame/dMission/MissionTask.cpp +++ b/dGame/dMission/MissionTask.cpp @@ -1,4 +1,4 @@ -#include +#include #include "MissionTask.h" @@ -11,11 +11,12 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "dZoneManager.h" +#include "InventoryComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" - -MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) -{ +MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) { this->info = info; this->mission = mission; this->mask = mask; @@ -31,7 +32,7 @@ MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) parameters.push_back(parameter); } } - + stream = std::istringstream(info->targetGroup); while (std::getline(stream, token, ',')) { @@ -43,36 +44,30 @@ MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) } -MissionTaskType MissionTask::GetType() const -{ - return static_cast(info->taskType); +eMissionTaskType MissionTask::GetType() const { + return static_cast(info->taskType); } -uint32_t MissionTask::GetProgress() const -{ +uint32_t MissionTask::GetProgress() const { return progress; } -void MissionTask::SetProgress(const uint32_t value, const bool echo) -{ - if (progress == value) - { +void MissionTask::SetProgress(const uint32_t value, const bool echo) { + if (progress == value) { return; } - + progress = value; - if (!echo) - { + if (!echo) { return; } - + auto* entity = mission->GetAssociate(); - if (entity == nullptr) - { + if (entity == nullptr) { return; } @@ -82,74 +77,62 @@ void MissionTask::SetProgress(const uint32_t value, const bool echo) } -void MissionTask::SetUnique(const std::vector& value) -{ +void MissionTask::SetUnique(const std::vector& value) { unique = value; } -void MissionTask::AddProgress(int32_t value) -{ +void MissionTask::AddProgress(int32_t value) { value += progress; - if (value > info->targetValue) - { + if (value > info->targetValue) { value = info->targetValue; } - if (value < 0) - { + if (value < 0) { value = 0; } - + SetProgress(value); } -Mission* MissionTask::GetMission() const -{ +Mission* MissionTask::GetMission() const { return mission; } -uint32_t MissionTask::GetTarget() const -{ +uint32_t MissionTask::GetTarget() const { return info->target; } -const CDMissionTasks& MissionTask::GetClientInfo() const -{ +const CDMissionTasks& MissionTask::GetClientInfo() const { return *info; } -uint32_t MissionTask::GetMask() const -{ +uint32_t MissionTask::GetMask() const { return mask; } -const std::vector& MissionTask::GetUnique() const -{ +const std::vector& MissionTask::GetUnique() const { return unique; } -const std::vector& MissionTask::GetTargets() const -{ +const std::vector& MissionTask::GetTargets() const { return targets; } -const std::vector& MissionTask::GetParameters() const -{ +const std::vector& MissionTask::GetParameters() const { return parameters; } -std::vector MissionTask::GetAllTargets() const -{ +std::vector MissionTask::GetAllTargets() const { auto targets = GetTargets(); targets.push_back(GetTarget()); @@ -158,83 +141,68 @@ std::vector MissionTask::GetAllTargets() const } -bool MissionTask::InTargets(const uint32_t value) const -{ +bool MissionTask::InTargets(const uint32_t value) const { auto targets = GetTargets(); return std::find(targets.begin(), targets.end(), value) != targets.end(); } -bool MissionTask::InAllTargets(const uint32_t value) const -{ +bool MissionTask::InAllTargets(const uint32_t value) const { auto targets = GetAllTargets(); return std::find(targets.begin(), targets.end(), value) != targets.end(); } -bool MissionTask::InParameters(const uint32_t value) const -{ +bool MissionTask::InParameters(const uint32_t value) const { auto parameters = GetParameters(); return std::find(parameters.begin(), parameters.end(), value) != parameters.end(); } -bool MissionTask::IsComplete() const -{ +bool MissionTask::IsComplete() const { // Mission 668 has task uid 984 which is a bit mask. Its completion value is 3. if (info->uid == 984) { return progress >= 3; - } - else { + } else { return progress >= info->targetValue; } } -void MissionTask::Complete() -{ +void MissionTask::Complete() { SetProgress(info->targetValue); } -void MissionTask::CheckCompletion() const -{ - if (IsComplete()) - { +void MissionTask::CheckCompletion() const { + if (IsComplete()) { mission->CheckCompletion(); } } -void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) -{ +void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) { if (IsComplete() && count > 0) return; - + const auto type = GetType(); - if (count < 0) - { - if (mission->IsMission() && type == MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION && InAllTargets(value)) - { - if (parameters.size() > 0 && (parameters[0] & 1) != 0) - { + if (count < 0) { + if (mission->IsMission() && type == eMissionTaskType::GATHER && InAllTargets(value)) { + if (parameters.size() > 0 && (parameters[0] & 1) != 0) { return; } auto* inventoryComponent = mission->GetAssociate()->GetComponent(); - if (inventoryComponent != nullptr) - { + if (inventoryComponent != nullptr) { int32_t itemCount = inventoryComponent->GetLotCountNonTransfer(value); - if (itemCount < info->targetValue) - { + if (itemCount < info->targetValue) { SetProgress(itemCount); - if (mission->IsReadyToComplete()) - { + if (mission->IsReadyToComplete()) { mission->MakeActive(); } } @@ -250,12 +218,12 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& uint32_t lot; uint32_t collectionId; std::vector settings; - + switch (type) { - case MissionTaskType::MISSION_TASK_TYPE_UNKNOWN: + case eMissionTaskType::UNKNOWN: break; - - case MissionTaskType::MISSION_TASK_TYPE_ACTIVITY: + + case eMissionTaskType::ACTIVITY: { if (InAllTargets(value)) { AddProgress(count); @@ -265,14 +233,13 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& entity = EntityManager::Instance()->GetEntity(associate); if (entity == nullptr) { if (associate != LWOOBJID_EMPTY) { - Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!\n", associate); + Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!", associate); } break; } - activity = static_cast(entity->GetComponent(COMPONENT_TYPE_REBUILD)); - if (activity == nullptr) - { + activity = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD)); + if (activity == nullptr) { break; } @@ -280,8 +247,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& const auto activityIdOverride = entity->GetVar(u"activityID"); - if (activityIdOverride != 0) - { + if (activityIdOverride != 0) { activityId = activityIdOverride; } @@ -292,8 +258,8 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_FOOD: - case MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION: + case eMissionTaskType::USE_ITEM: + case eMissionTaskType::TALK_TO_NPC: { if (GetTarget() != value) break; @@ -302,15 +268,14 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_EMOTE: + case eMissionTaskType::EMOTE: { if (!InParameters(value)) break; - + entity = EntityManager::Instance()->GetEntity(associate); - if (entity == nullptr) - { - Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!\n", associate); + if (entity == nullptr) { + Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!", associate); break; } @@ -320,26 +285,26 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& if (GetTarget() != lot) break; AddProgress(count); - + break; } - - case MissionTaskType::MISSION_TASK_TYPE_SKILL: + + case eMissionTaskType::USE_SKILL: { // This is a complicated check because for some missions we need to check for the associate being in the parameters instead of the value being in the parameters. if (associate == LWOOBJID_EMPTY && GetAllTargets().size() == 1 && GetAllTargets()[0] == -1) { if (InParameters(value)) AddProgress(count); } else { if (InParameters(associate) && InAllTargets(value)) AddProgress(count); - } + } break; } - case MissionTaskType::MISSION_TASK_TYPE_MINIGAME: + case eMissionTaskType::PERFORM_ACTIVITY: { auto* minigameManager = EntityManager::Instance()->GetEntity(associate); if (minigameManager == nullptr) - break; + break; int32_t gameID = minigameManager->GetLOT(); @@ -353,18 +318,18 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& } // This special case is for shooting gallery missions that want their // progress value set to 1 instead of being set to the target value. - if(info->targetGroup == targets && value >= info->targetValue && GetMission()->IsMission() && info->target == 1864 && info->targetGroup == "performact_score") { + if (info->targetGroup == targets && value >= info->targetValue && GetMission()->IsMission() && info->target == 1864 && info->targetGroup == "performact_score") { SetProgress(1); break; } - if(info->targetGroup == targets && value >= info->targetValue) { + if (info->targetGroup == targets && value >= info->targetValue) { SetProgress(info->targetValue); break; } break; } - case MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY: + case eMissionTaskType::VISIT_PROPERTY: { if (!InAllTargets(value)) break; @@ -373,19 +338,18 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& AddProgress(count); unique.push_back(associate); - + break; } - case MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT: + case eMissionTaskType::COLLECTION: { if (!InAllTargets(value)) break; - + entity = EntityManager::Instance()->GetEntity(associate); - if (entity == nullptr) - { - Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!\n", associate); + if (entity == nullptr) { + Game::logger->Log("MissionTask", "Failed to find associated entity (%llu)!", associate); break; } @@ -397,7 +361,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& if (std::find(unique.begin(), unique.end(), collectionId) != unique.end()) break; unique.push_back(collectionId); - + SetProgress(unique.size()); auto* entity = mission->GetAssociate(); @@ -409,30 +373,29 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& if (missionComponent == nullptr) break; missionComponent->AddCollectible(collectionId); - + break; } - case MissionTaskType::MISSION_TASK_TYPE_LOCATION: + case eMissionTaskType::EXPLORE: { if (info->targetGroup != targets) break; AddProgress(count); - + break; } - - case MissionTaskType::MISSION_TASK_TYPE_RACING: + + case eMissionTaskType::RACING: { - // The meaning of associate can be found in RacingTaskParam.h + // The meaning of associate can be found in eRacingTaskParam.h if (parameters.empty()) break; if (!InAllTargets(dZoneManager::Instance()->GetZone()->GetWorldID()) && !(parameters[0] == 4 || parameters[0] == 5) && !InAllTargets(value)) break; if (parameters[0] != associate) break; - if (associate == 1 || associate == 2 || associate == 3) - { + if (associate == 1 || associate == 2 || associate == 3) { if (value > info->targetValue) break; AddProgress(info->targetValue); @@ -447,41 +410,33 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& // If we won at Gnarled Forest, set bit 1 else if (value == 1303) SetProgress(tempProgress |= 1 << 1); // If both bits are set, then the client sees the mission as complete. - } - else if (associate == 10) - { + } else if (associate == 10) { // If the player did not crash during the race, progress this task by count. if (value != 0) break; - + AddProgress(count); - } - else if (associate == 4 || associate == 5 || associate == 14) - { + } else if (associate == 4 || associate == 5 || associate == 14) { if (!InAllTargets(value)) break; AddProgress(count); - } - else if (associate == 17) - { + } else if (associate == 17) { if (!InAllTargets(value)) break; AddProgress(count); - } - else - { + } else { AddProgress(count); } break; } - case MissionTaskType::MISSION_TASK_TYPE_PET_TAMING: - case MissionTaskType::MISSION_TASK_TYPE_SCRIPT: - case MissionTaskType::MISSION_TASK_TYPE_NON_MISSION_INTERACTION: - case MissionTaskType::MISSION_TASK_TYPE_MISSION_COMPLETE: - case MissionTaskType::MISSION_TASK_TYPE_POWERUP: - case MissionTaskType::MISSION_TASK_TYPE_SMASH: - case MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION: - case MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG: - case MissionTaskType::MISSION_TASK_TYPE_EARN_REPUTATION: + case eMissionTaskType::PET_TAMING: + case eMissionTaskType::SCRIPT: + case eMissionTaskType::INTERACT: + case eMissionTaskType::META: + case eMissionTaskType::POWERUP: + case eMissionTaskType::SMASH: + case eMissionTaskType::GATHER: + case eMissionTaskType::PLAYER_FLAG: + case eMissionTaskType::EARN_REPUTATION: { if (!InAllTargets(value)) break; @@ -489,13 +444,13 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL: + case eMissionTaskType::PLACE_MODEL: { AddProgress(count); break; } default: - Game::logger->Log("MissionTask", "Invalid mission task type (%i)!\n", static_cast(type)); + Game::logger->Log("MissionTask", "Invalid mission task type (%i)!", static_cast(type)); return; } @@ -503,8 +458,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& } -MissionTask::~MissionTask() -{ +MissionTask::~MissionTask() { targets.clear(); parameters.clear(); diff --git a/dGame/dMission/MissionTask.h b/dGame/dMission/MissionTask.h index 3fcbbe3d..f867b632 100644 --- a/dGame/dMission/MissionTask.h +++ b/dGame/dMission/MissionTask.h @@ -1,12 +1,12 @@ -#pragma once +#pragma once #ifndef MISSIONTASK_H #define MISSIONTASK_H #include "CDMissionTasksTable.h" -#include "MissionTaskType.h" #include "dCommonVars.h" +enum class eMissionTaskType : int; class Mission; /** @@ -16,172 +16,172 @@ class MissionTask final { public: MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask); - ~MissionTask(); + ~MissionTask(); - /** - * Attempts to progress this task using the provided parameters. Note that the behavior of this method is different - * for each mission task type. - * @param value the value to progress by - * @param associate optional object ID of an entity that was related to the progression - * @param targets optional multiple targets that need to be met to progress - * @param count a number that indicates the times to progress - */ + /** + * Attempts to progress this task using the provided parameters. Note that the behavior of this method is different + * for each mission task type. + * @param value the value to progress by + * @param associate optional object ID of an entity that was related to the progression + * @param targets optional multiple targets that need to be met to progress + * @param count a number that indicates the times to progress + */ void Progress(int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1); - /** - * Returns the current progression of this task - * @return the current progression of this task - */ + /** + * Returns the current progression of this task + * @return the current progression of this task + */ uint32_t GetProgress() const; - /** - * Progresses the progress of this task by the provided value. Does not exceed the target progress. - * @param value the value to progress by - */ - void AddProgress(int32_t value); + /** + * Progresses the progress of this task by the provided value. Does not exceed the target progress. + * @param value the value to progress by + */ + void AddProgress(int32_t value); - /** - * Sets the progress of the task and optionally notifies the client - * @param value the value to set for the progress - * @param echo if true, this will notify the client of the change - */ - void SetProgress(uint32_t value, bool echo = true); + /** + * Sets the progress of the task and optionally notifies the client + * @param value the value to set for the progress + * @param echo if true, this will notify the client of the change + */ + void SetProgress(uint32_t value, bool echo = true); - /** - * Returns the mission this task belongs to - * @return the mission this task belongs to - */ + /** + * Returns the mission this task belongs to + * @return the mission this task belongs to + */ Mission* GetMission() const; - /** - * Returns the type of this task - * @return the type of this task - */ - MissionTaskType GetType() const; + /** + * Returns the type of this task + * @return the type of this task + */ + eMissionTaskType GetType() const; - /** - * Returns the value that should be progressed to, to complete the mission (the target value) - * @return the target value - */ + /** + * Returns the value that should be progressed to, to complete the mission (the target value) + * @return the target value + */ uint32_t GetTarget() const; - /** - * Returns the database information for this mission - * @return the database information for this mission - */ + /** + * Returns the database information for this mission + * @return the database information for this mission + */ const CDMissionTasks& GetClientInfo() const; - /** - * Returns the mask for this mission, used for communicating updates - * @return the mask for this mission, used for communicating updates - */ + /** + * Returns the mask for this mission, used for communicating updates + * @return the mask for this mission, used for communicating updates + */ uint32_t GetMask() const; - /** - * Returns the currently visited list of unique locations (only used for visiting mission types) - * @return the currently visited list of unique locations - */ + /** + * Returns the currently visited list of unique locations (only used for visiting mission types) + * @return the currently visited list of unique locations + */ const std::vector& GetUnique() const; - /** - * Sets the uniquely visited list of locations - * @param value the uniquely visited list of locations - */ - void SetUnique(const std::vector& value); + /** + * Sets the uniquely visited list of locations + * @param value the uniquely visited list of locations + */ + void SetUnique(const std::vector& value); - /** - * Returns the possibly target values for this mission task for progression - * @return the possibly target values for this mission task for progression - */ + /** + * Returns the possibly target values for this mission task for progression + * @return the possibly target values for this mission task for progression + */ const std::vector& GetTargets() const; - /** - * Returns the parameters for this task: meta information that determines if the task can be progressed. Note: - * not used by all task types. - * @return the parameters for this task - */ + /** + * Returns the parameters for this task: meta information that determines if the task can be progressed. Note: + * not used by all task types. + * @return the parameters for this task + */ const std::vector& GetParameters() const; - /** - * Returns all the target values for this mission, including the target value concatenated by the optional list of - * targets parsed as ints. - * @return all the targets for this task - */ + /** + * Returns all the target values for this mission, including the target value concatenated by the optional list of + * targets parsed as ints. + * @return all the targets for this task + */ std::vector GetAllTargets() const; - /** - * Returns whether the value is in the list of target values of this task - * @param value the value to check for - * @return true if the value is in the target list, false otherwise - */ + /** + * Returns whether the value is in the list of target values of this task + * @param value the value to check for + * @return true if the value is in the target list, false otherwise + */ bool InTargets(uint32_t value) const; - /** - * Returns whether the value is in one of the target values or equals the individual target value of this task - * @param value the value to check for - * @return true if the value is one of the targets, false otherwise - */ + /** + * Returns whether the value is in one of the target values or equals the individual target value of this task + * @param value the value to check for + * @return true if the value is one of the targets, false otherwise + */ bool InAllTargets(uint32_t value) const; - /** - * Checks if the provided is one of the parameters for this task - * @param value the value to check for - * @return true if the value is one of the parameters, false otherwise - */ + /** + * Checks if the provided is one of the parameters for this task + * @param value the value to check for + * @return true if the value is one of the parameters, false otherwise + */ bool InParameters(uint32_t value) const; - /** - * Checks if this task has been completed by comparing its progress against the target value - * @return true if the task has been completed, false otherwise - */ + /** + * Checks if this task has been completed by comparing its progress against the target value + * @return true if the task has been completed, false otherwise + */ bool IsComplete() const; - /** - * Completes the mission by setting the progress to the required value - */ + /** + * Completes the mission by setting the progress to the required value + */ void Complete(); private: - /** - * Datbase information about this task - */ + /** + * Datbase information about this task + */ CDMissionTasks* info; - /** - * The mission this task belongs to - */ + /** + * The mission this task belongs to + */ Mission* mission; - /** - * Mask used for communicating mission updates - */ + /** + * Mask used for communicating mission updates + */ uint32_t mask; - /** - * The current progression towards the target - */ + /** + * The current progression towards the target + */ uint32_t progress; - /** - * The list of target values for progressing this task - */ + /** + * The list of target values for progressing this task + */ std::vector targets; - /** - * The list of parameters for progressing this task (not used by all task types) - */ + /** + * The list of parameters for progressing this task (not used by all task types) + */ std::vector parameters; - /** - * The unique places visited for progression (not used by all task types) - */ + /** + * The unique places visited for progression (not used by all task types) + */ std::vector unique; - /** - * Checks if the task is complete, and if so checks if the parent mission is complete - */ + /** + * Checks if the task is complete, and if so checks if the parent mission is complete + */ void CheckCompletion() const; }; -#endif +#endif diff --git a/dGame/dMission/MissionTaskType.h b/dGame/dMission/MissionTaskType.h deleted file mode 100644 index 345f8fff..00000000 --- a/dGame/dMission/MissionTaskType.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#ifndef MISSIONTASKTYPE_H -#define MISSIONTASKTYPE_H - -//! An enum for mission task types -enum class MissionTaskType : int { - MISSION_TASK_TYPE_UNKNOWN = -1, //!< The task type is unknown - MISSION_TASK_TYPE_SMASH = 0, //!< A task for smashing something - MISSION_TASK_TYPE_SCRIPT = 1, //!< A task handled by a server LUA script - MISSION_TASK_TYPE_ACTIVITY = 2, //!< A task for completing a quickbuild - MISSION_TASK_TYPE_ENVIRONMENT = 3, //!< A task for something in the environment - MISSION_TASK_TYPE_MISSION_INTERACTION = 4, //!< A task for interacting with a mission - MISSION_TASK_TYPE_EMOTE = 5, //!< A task for playing an emote - MISSION_TASK_TYPE_FOOD = 9, //!< A task for eating food - MISSION_TASK_TYPE_SKILL = 10, //!< A task for performing a skill - MISSION_TASK_TYPE_ITEM_COLLECTION = 11, //!< A task for collecting an item - MISSION_TASK_TYPE_LOCATION = 12, //!< A task for finding a location - MISSION_TASK_TYPE_MINIGAME = 14, //!< A task for doing something in a minigame - MISSION_TASK_TYPE_NON_MISSION_INTERACTION = 15, //!< A task for interacting with a non-mission - MISSION_TASK_TYPE_MISSION_COMPLETE = 16, //!< A task for completing a mission - MISSION_TASK_TYPE_EARN_REPUTATION = 17, //!< A task for earning reputation - MISSION_TASK_TYPE_POWERUP = 21, //!< A task for collecting a powerup - MISSION_TASK_TYPE_PET_TAMING = 22, //!< A task for taming a pet - MISSION_TASK_TYPE_RACING = 23, //!< A task for racing - MISSION_TASK_TYPE_PLAYER_FLAG = 24, //!< A task for setting a player flag - MISSION_TASK_TYPE_PLACE_MODEL = 25, //!< A task for picking up a model - MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property -}; - -#endif diff --git a/dGame/dMission/RacingTaskParam.h b/dGame/dMission/RacingTaskParam.h deleted file mode 100644 index 38f8dd8e..00000000 --- a/dGame/dMission/RacingTaskParam.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -enum class RacingTaskParam : int32_t { - RACING_TASK_PARAM_FINISH_WITH_PLACEMENT = 1, // + +enum class BehaviorState : uint32_t { + HOME_STATE = 0, //!< The HOME behavior state + CIRCLE_STATE, //!< The CIRCLE behavior state + SQUARE_STATE, //!< The SQUARE behavior state + DIAMOND_STATE, //!< The DIAMOND behavior state + TRIANGLE_STATE, //!< The TRIANGLE behavior state + STAR_STATE //!< The STAR behavior state +}; + +#endif //!__BEHAVIORSTATES__H__ diff --git a/dGame/dPropertyBehaviors/BlockDefinition.cpp b/dGame/dPropertyBehaviors/BlockDefinition.cpp new file mode 100644 index 00000000..2950ac82 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.cpp @@ -0,0 +1,9 @@ +#include "BlockDefinition.h" + +BlockDefinition BlockDefinition::blockDefinitionDefault{}; + +BlockDefinition::BlockDefinition(std::string defaultValue, float minimumValue, float maximumValue) { + this->defaultValue = defaultValue; + this->minimumValue = minimumValue; + this->maximumValue = maximumValue; +} diff --git a/dGame/dPropertyBehaviors/BlockDefinition.h b/dGame/dPropertyBehaviors/BlockDefinition.h new file mode 100644 index 00000000..3a5a6bf1 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.h @@ -0,0 +1,25 @@ +#ifndef __BLOCKDEFINITION__H__ +#define __BLOCKDEFINITION__H__ + +#include + +class AMFArrayValue; + +class BlockDefinition { +public: + BlockDefinition(std::string defaultValue = "", float minimumValue = 0.0f, float maximumValue = 0.0f); + static BlockDefinition blockDefinitionDefault; + + std::string& GetDefaultValue() { return defaultValue; }; + float GetMinimumValue() { return minimumValue; }; + float GetMaximumValue() { return maximumValue; }; + void SetDefaultValue(std::string value) { defaultValue = value; }; + void SetMinimumValue(float value) { minimumValue = value; }; + void SetMaximumValue(float value) { maximumValue = value; }; +private: + std::string defaultValue; + float minimumValue; + float maximumValue; +}; + +#endif //!__BLOCKDEFINITION__H__ diff --git a/dGame/dPropertyBehaviors/CMakeLists.txt b/dGame/dPropertyBehaviors/CMakeLists.txt new file mode 100644 index 00000000..5e33a5f5 --- /dev/null +++ b/dGame/dPropertyBehaviors/CMakeLists.txt @@ -0,0 +1,12 @@ +set(DGAME_DPROPERTYBEHAVIORS_SOURCES + "BlockDefinition.cpp" + "ControlBehaviors.cpp" +) + +add_subdirectory(ControlBehaviorMessages) + +foreach(file ${DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES}) + set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} "ControlBehaviorMessages/${file}") +endforeach() + +set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} PARENT_SCOPE) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp new file mode 100644 index 00000000..7da286b0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp @@ -0,0 +1,31 @@ +#include "Action.h" + +Action::Action() { + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; +} + +Action::Action(AMFArrayValue* arguments) { + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; + for (auto& typeValueMap : arguments->GetAssociativeMap()) { + if (typeValueMap.first == "Type") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + type = static_cast(typeValueMap.second)->GetStringValue(); + } else { + valueParameterName = typeValueMap.first; + // Message is the only known string parameter + if (valueParameterName == "Message") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); + } else { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; + valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); + } + } + } +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h new file mode 100644 index 00000000..c97b4050 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h @@ -0,0 +1,25 @@ +#ifndef __ACTION__H__ +#define __ACTION__H__ + +#include "BehaviorMessageBase.h" + +/** + * @brief Sent if a ControlBehavior message has an Action associated with it + * + */ +class Action { +public: + Action(); + Action(AMFArrayValue* arguments); + const std::string& GetType() { return type; }; + const std::string& GetValueParameterName() { return valueParameterName; }; + const std::string& GetValueParameterString() { return valueParameterString; }; + const double GetValueParameterDouble() { return valueParameterDouble; }; +private: + std::string type; + std::string valueParameterName; + std::string valueParameterString; + double valueParameterDouble; +}; + +#endif //!__ACTION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp new file mode 100644 index 00000000..480eef45 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp @@ -0,0 +1,31 @@ +#include "ActionContext.h" + +#include + +#include "AMFFormat.h" + +ActionContext::ActionContext() { + stripId = 0; + stateId = BehaviorState::HOME_STATE; +} + +ActionContext::ActionContext(AMFArrayValue* arguments, std::string customStateKey, std::string customStripKey) { + stripId = 0; + stateId = BehaviorState::HOME_STATE; + stripId = GetStripIdFromArgument(arguments, customStripKey); + stateId = GetBehaviorStateFromArgument(arguments, customStateKey); +} + +BehaviorState ActionContext::GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key) { + auto* stateIDValue = arguments->FindValue(key); + if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\""); + + return static_cast(stateIDValue->GetDoubleValue()); +} + +StripId ActionContext::GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key) { + auto* stripIdValue = arguments->FindValue(key); + if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\""); + + return static_cast(stripIdValue->GetDoubleValue()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h new file mode 100644 index 00000000..5f46fd8c --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h @@ -0,0 +1,26 @@ +#ifndef __ACTIONCONTEXT__H__ +#define __ACTIONCONTEXT__H__ + +#include "BehaviorStates.h" +#include "dCommonVars.h" + +class AMFArrayValue; + +/** + * @brief Sent if contextual State and Strip informationis needed for a ControlBehaviors message + * + */ +class ActionContext { +public: + ActionContext(); + ActionContext(AMFArrayValue* arguments, std::string customStateKey = "stateID", std::string customStripKey = "stripID"); + const StripId GetStripId() { return stripId; }; + const BehaviorState GetStateId() { return stateId; }; +private: + BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key); + StripId GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key); + StripId stripId; + BehaviorState stateId; +}; + +#endif //!__ACTIONCONTEXT__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp new file mode 100644 index 00000000..4fc7f82b --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp @@ -0,0 +1,13 @@ +#include "AddActionMessage.h" + +AddActionMessage::AddActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + actionIndex = GetActionIndexFromArgument(arguments); + + auto* actionValue = arguments->FindValue("action"); + if (!actionValue) return; + + action = Action(actionValue); + + Game::logger->LogDebug("AddActionMessage", "actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i", actionIndex, actionContext.GetStripId(), actionContext.GetStateId(), action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h new file mode 100644 index 00000000..4faf6a53 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h @@ -0,0 +1,26 @@ +#ifndef __ADDACTIONMESSAGE__H__ +#define __ADDACTIONMESSAGE__H__ + +#include "Action.h" +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Send if a player takes an Action A from the toolbox and adds it to an already existing strip + * + */ +class AddActionMessage : public BehaviorMessageBase { +public: + AddActionMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + Action GetAction() { return action; }; + ActionContext GetActionContext() { return actionContext; }; +private: + uint32_t actionIndex; + ActionContext actionContext; + Action action; +}; + +#endif //!__ADDACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp new file mode 100644 index 00000000..4f2123b4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp @@ -0,0 +1,11 @@ +#include "AddMessage.h" + +AddMessage::AddMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + behaviorIndex = 0; + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("AddMessage", "behaviorId %i index %i", behaviorId, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h new file mode 100644 index 00000000..a46d5f98 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h @@ -0,0 +1,18 @@ +#ifndef __ADDMESSAGE__H__ +#define __ADDMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player adds a Behavior A from their inventory to a model. + * + */ +class AddMessage : public BehaviorMessageBase { +public: + AddMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; +private: + uint32_t behaviorIndex; +}; + +#endif //!__ADDMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp new file mode 100644 index 00000000..c4729c57 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp @@ -0,0 +1,25 @@ +#include "AddStripMessage.h" + +#include "Action.h" + +AddStripMessage::AddStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + position = StripUiPosition(arguments); + + auto* strip = arguments->FindValue("strip"); + if (!strip) return; + + auto* actions = strip->FindValue("actions"); + if (!actions) return; + + for (uint32_t actionNumber = 0; actionNumber < actions->GetDenseValueSize(); actionNumber++) { + auto* actionValue = actions->GetValueAt(actionNumber); + if (!actionValue) continue; + + actionsToAdd.push_back(Action(actionValue)); + + Game::logger->LogDebug("AddStripMessage", "xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId, actionsToAdd.back().GetType().c_str(), actionsToAdd.back().GetValueParameterName().c_str(), actionsToAdd.back().GetValueParameterString().c_str(), actionsToAdd.back().GetValueParameterDouble()); + } + Game::logger->Log("AddStripMessage", "number of actions %i", actionsToAdd.size()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h new file mode 100644 index 00000000..db75aef7 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h @@ -0,0 +1,31 @@ +#ifndef __ADDSTRIPMESSAGE__H__ +#define __ADDSTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +#include + +class Action; +class AMFArrayValue; + +/** + * @brief Sent in 2 contexts: + * A player adds an Action A from their toolbox without attaching it to an existing Strip. In this case, only 1 action is sent. + * A player moves a Strip from BehaviorState A directly to BehaviorState B. In this case, a list of actions are sent. + * + */ +class AddStripMessage : public BehaviorMessageBase { +public: + AddStripMessage(AMFArrayValue* arguments); + StripUiPosition GetPosition() { return position; }; + ActionContext GetActionContext() { return actionContext; }; + std::vector GetActionsToAdd() { return actionsToAdd; }; +private: + StripUiPosition position; + ActionContext actionContext; + std::vector actionsToAdd; +}; + +#endif //!__ADDSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp new file mode 100644 index 00000000..b3d98d51 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp @@ -0,0 +1,33 @@ +#include "BehaviorMessageBase.h" + +#include "AMFFormat.h" +#include "BehaviorStates.h" +#include "dCommonVars.h" + +BehaviorMessageBase::BehaviorMessageBase(AMFArrayValue* arguments) { + behaviorId = 0; + behaviorId = GetBehaviorIdFromArgument(arguments); +} + +int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(AMFArrayValue* arguments) { + const auto* key = "BehaviorID"; + auto* behaviorIDValue = arguments->FindValue(key); + int32_t behaviorID = -1; + + if (behaviorIDValue) { + behaviorID = std::stoul(behaviorIDValue->GetStringValue()); + } else if (!arguments->FindValue(key)) { + throw std::invalid_argument("Unable to find behavior ID"); + } + + return behaviorID; +} + +uint32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName) { + auto* actionIndexAmf = arguments->FindValue(keyName); + if (!actionIndexAmf) { + throw std::invalid_argument("Unable to find actionIndex"); + } + + return static_cast(actionIndexAmf->GetDoubleValue()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h new file mode 100644 index 00000000..13b00a35 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h @@ -0,0 +1,29 @@ +#ifndef __BEHAVIORMESSAGEBASE__H__ +#define __BEHAVIORMESSAGEBASE__H__ + +#include +#include + +#include "AMFFormat.h" +#include "dCommonVars.h" + +#include "Game.h" +#include "dLogger.h" + +enum class BehaviorState : uint32_t; + +/** + * @brief The behaviorID target of this ControlBehaviors message + * + */ +class BehaviorMessageBase { +public: + const uint32_t GetBehaviorId() { return behaviorId; }; +protected: + BehaviorMessageBase(AMFArrayValue* arguments); + int32_t GetBehaviorIdFromArgument(AMFArrayValue* arguments); + uint32_t GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName = "actionIndex"); + int32_t behaviorId = -1; +}; + +#endif //!__BEHAVIORMESSAGEBASE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt new file mode 100644 index 00000000..49b0f460 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt @@ -0,0 +1,20 @@ +set(DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES + "Action.cpp" + "ActionContext.cpp" + "AddActionMessage.cpp" + "AddMessage.cpp" + "AddStripMessage.cpp" + "BehaviorMessageBase.cpp" + "MergeStripsMessage.cpp" + "MigrateActionsMessage.cpp" + "MoveToInventoryMessage.cpp" + "RearrangeStripMessage.cpp" + "RemoveActionsMessage.cpp" + "RemoveStripMessage.cpp" + "RenameMessage.cpp" + "SplitStripMessage.cpp" + "StripUiPosition.cpp" + "UpdateActionMessage.cpp" + "UpdateStripUiMessage.cpp" + PARENT_SCOPE +) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp new file mode 100644 index 00000000..df50641a --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp @@ -0,0 +1,11 @@ +#include "MergeStripsMessage.h" + +MergeStripsMessage::MergeStripsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("MergeStripsMessage", "srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), dstActionIndex, behaviorId); +} + diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h new file mode 100644 index 00000000..0aff7f3a --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h @@ -0,0 +1,25 @@ +#ifndef __MERGESTRIPSMESSAGE__H__ +#define __MERGESTRIPSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player adds the first Action of Strip A to a Strip B + * + */ +class MergeStripsMessage : public BehaviorMessageBase { +public: + MergeStripsMessage(AMFArrayValue* arguments); + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t dstActionIndex; +}; + +#endif //!__MERGESTRIPSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp new file mode 100644 index 00000000..08f830a4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp @@ -0,0 +1,11 @@ +#include "MigrateActionsMessage.h" + +MigrateActionsMessage::MigrateActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("MigrateActionsMessage", "srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", srcActionIndex, dstActionIndex, sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h new file mode 100644 index 00000000..f60e8748 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h @@ -0,0 +1,27 @@ +#ifndef __MIGRATEACTIONSMESSAGE__H__ +#define __MIGRATEACTIONSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves an Action after the first Action to a different Strip + * + */ +class MigrateActionsMessage : public BehaviorMessageBase { +public: + MigrateActionsMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t srcActionIndex; + uint32_t dstActionIndex; +}; + +#endif //!__MIGRATEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp new file mode 100644 index 00000000..92700076 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp @@ -0,0 +1,9 @@ +#include "MoveToInventoryMessage.h" + +MoveToInventoryMessage::MoveToInventoryMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("MoveToInventoryMessage", "behaviorId %i behaviorIndex %i", behaviorId, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h new file mode 100644 index 00000000..c48f7d17 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h @@ -0,0 +1,21 @@ +#ifndef __MOVETOINVENTORYMESSAGE__H__ +#define __MOVETOINVENTORYMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves a Behavior A at position B to their inventory. + * + */ +#pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.") +class MoveToInventoryMessage : public BehaviorMessageBase { +public: + MoveToInventoryMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; +private: + uint32_t behaviorIndex; +}; + +#endif //!__MOVETOINVENTORYMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp new file mode 100644 index 00000000..4018a423 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp @@ -0,0 +1,10 @@ +#include "RearrangeStripMessage.h" + +RearrangeStripMessage::RearrangeStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("RearrangeStripMessage", "srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", srcActionIndex, dstActionIndex, actionContext.GetStripId(), behaviorId, actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h new file mode 100644 index 00000000..46819404 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h @@ -0,0 +1,23 @@ +#ifndef __REARRANGESTRIPMESSAGE__H__ +#define __REARRANGESTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player moves an Action around in the same strip + * + */ +class RearrangeStripMessage : public BehaviorMessageBase { +public: + RearrangeStripMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; + uint32_t srcActionIndex; + uint32_t dstActionIndex; +}; + +#endif //!__REARRANGESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp new file mode 100644 index 00000000..8f00d2b0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp @@ -0,0 +1,8 @@ +#include "RemoveActionsMessage.h" + +RemoveActionsMessage::RemoveActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + actionIndex = GetActionIndexFromArgument(arguments); + + Game::logger->LogDebug("RemoveActionsMessage", "behaviorId %i actionIndex %i stripId %i stateId %i", behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h new file mode 100644 index 00000000..457ddba8 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h @@ -0,0 +1,23 @@ +#ifndef __REMOVEACTIONSMESSAGE__H__ +#define __REMOVEACTIONSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player removes any Action after the first one from a Strip + * + */ +class RemoveActionsMessage : public BehaviorMessageBase { +public: + RemoveActionsMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; + uint32_t actionIndex; +}; + +#endif //!__REMOVEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp new file mode 100644 index 00000000..40288b07 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp @@ -0,0 +1,7 @@ +#include "RemoveStripMessage.h" + +RemoveStripMessage::RemoveStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + Game::logger->LogDebug("RemoveStripMessage", "stripId %i stateId %i behaviorId %i", actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h new file mode 100644 index 00000000..36e2e401 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h @@ -0,0 +1,19 @@ +#ifndef __REMOVESTRIPMESSAGE__H__ +#define __REMOVESTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player removes the first Action from a strip. + * + */ +class RemoveStripMessage : public BehaviorMessageBase { +public: + RemoveStripMessage(AMFArrayValue* arguments); + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; +}; + +#endif //!__REMOVESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp new file mode 100644 index 00000000..0ea3b6d6 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp @@ -0,0 +1,9 @@ +#include "RenameMessage.h" + +RenameMessage::RenameMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + auto* nameAmf = arguments->FindValue("Name"); + if (!nameAmf) return; + + name = nameAmf->GetStringValue(); + Game::logger->LogDebug("RenameMessage", "behaviorId %i n %s", behaviorId, name.c_str()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h new file mode 100644 index 00000000..ba181f63 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h @@ -0,0 +1,20 @@ +#ifndef __RENAMEMESSAGE__H__ +#define __RENAMEMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player renames this behavior + * + */ +class RenameMessage : public BehaviorMessageBase { +public: + RenameMessage(AMFArrayValue* arguments); + const std::string& GetName() { return name; }; +private: + std::string name; +}; + +#endif //!__RENAMEMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp new file mode 100644 index 00000000..b4601a17 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp @@ -0,0 +1,11 @@ +#include "SplitStripMessage.h" + +SplitStripMessage::SplitStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + destinationPosition = StripUiPosition(arguments, "dstStripUI"); + + Game::logger->LogDebug("SplitStripMessage", "behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", behaviorId, destinationPosition.GetX(), destinationPosition.GetY(), sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), srcActionIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h new file mode 100644 index 00000000..9210efb0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h @@ -0,0 +1,28 @@ +#ifndef __SPLITSTRIPMESSAGE__H__ +#define __SPLITSTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player takes an Action from Strip A and does not add it to an existing strip + * + */ +class SplitStripMessage : public BehaviorMessageBase { +public: + SplitStripMessage(AMFArrayValue* arguments); + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + StripUiPosition GetPosition() { return destinationPosition; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t srcActionIndex; + StripUiPosition destinationPosition; +}; + +#endif //!__SPLITSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp new file mode 100644 index 00000000..4ddccc55 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp @@ -0,0 +1,22 @@ +#include "StripUiPosition.h" + +#include "AMFFormat.h" + +StripUiPosition::StripUiPosition() { + xPosition = 0.0; + yPosition = 0.0; +} + +StripUiPosition::StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName) { + xPosition = 0.0; + yPosition = 0.0; + auto* uiArray = arguments->FindValue(uiKeyName); + if (!uiArray) return; + + auto* xPositionValue = uiArray->FindValue("x"); + auto* yPositionValue = uiArray->FindValue("y"); + if (!xPositionValue || !yPositionValue) return; + + yPosition = yPositionValue->GetDoubleValue(); + xPosition = xPositionValue->GetDoubleValue(); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h new file mode 100644 index 00000000..809f8890 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h @@ -0,0 +1,21 @@ +#ifndef __STRIPUIPOSITION__H__ +#define __STRIPUIPOSITION__H__ + +class AMFArrayValue; + +/** + * @brief The position of the first Action in a Strip + * + */ +class StripUiPosition { +public: + StripUiPosition(); + StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName = "ui"); + double GetX() { return xPosition; }; + double GetY() { return yPosition; }; +private: + double xPosition; + double yPosition; +}; + +#endif //!__STRIPUIPOSITION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp new file mode 100644 index 00000000..53e2d570 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp @@ -0,0 +1,15 @@ +#include "UpdateActionMessage.h" + +#include "Action.h" + +UpdateActionMessage::UpdateActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + auto* actionValue = arguments->FindValue("action"); + if (!actionValue) return; + + action = Action(actionValue); + actionIndex = GetActionIndexFromArgument(arguments); + + Game::logger->LogDebug("UpdateActionMessage", "type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h new file mode 100644 index 00000000..0a03ce9e --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h @@ -0,0 +1,26 @@ +#ifndef __UPDATEACTIONMESSAGE__H__ +#define __UPDATEACTIONMESSAGE__H__ + +#include "Action.h" +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player updates the value in an Action + * + */ +class UpdateActionMessage : public BehaviorMessageBase { +public: + UpdateActionMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + ActionContext GetActionContext() { return actionContext; }; + Action GetAction() { return action; }; +private: + uint32_t actionIndex; + ActionContext actionContext; + Action action; +}; + +#endif //!__UPDATEACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp new file mode 100644 index 00000000..073db9b4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp @@ -0,0 +1,8 @@ +#include "UpdateStripUiMessage.h" + +UpdateStripUiMessage::UpdateStripUiMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + position = StripUiPosition(arguments); + actionContext = ActionContext(arguments); + + Game::logger->LogDebug("UpdateStripUIMessage", "xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h new file mode 100644 index 00000000..6d96f90c --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h @@ -0,0 +1,24 @@ +#ifndef __UPDATESTRIPUIMESSAGE__H__ +#define __UPDATESTRIPUIMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves the first Action in a Strip + * + */ +class UpdateStripUiMessage : public BehaviorMessageBase { +public: + UpdateStripUiMessage(AMFArrayValue* arguments); + StripUiPosition GetPosition() { return position; }; + ActionContext GetActionContext() { return actionContext; }; +private: + StripUiPosition position; + ActionContext actionContext; +}; + +#endif //!__UPDATESTRIPUIMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp new file mode 100644 index 00000000..dfb22b59 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -0,0 +1,462 @@ +#include "ControlBehaviors.h" + +#include "AMFFormat.h" +#include "Entity.h" +#include "Game.h" +#include "GameMessages.h" +#include "ModelComponent.h" +#include "../../dWorldServer/ObjectIDManager.h" +#include "dLogger.h" +#include "BehaviorStates.h" +#include "AssetManager.h" +#include "BlockDefinition.h" +#include "User.h" +#include "tinyxml2.h" +#include "CDClientDatabase.h" + +// Message includes +#include "Action.h" +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" + +void ControlBehaviors::RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr) { + // auto behavior = modelComponent->FindBehavior(behaviorID); + // if (behavior->GetBehaviorID() == -1 || behavior->GetShouldSetNewID()) { + // ObjectIDManager::Instance()->RequestPersistentID( + // [behaviorID, behavior, modelComponent, modelOwner, sysAddr](uint32_t persistentId) { + // behavior->SetShouldGetNewID(false); + // behavior->SetIsTemplated(false); + // behavior->SetBehaviorID(persistentId); + + // // This updates the behavior ID of the behavior should this be a new behavior + // AMFArrayValue args; + + // AMFStringValue* behaviorIDString = new AMFStringValue(); + // behaviorIDString->SetStringValue(std::to_string(persistentId)); + // args.InsertValue("behaviorID", behaviorIDString); + + // AMFStringValue* objectIDAsString = new AMFStringValue(); + // objectIDAsString->SetStringValue(std::to_string(modelComponent->GetParent()->GetObjectID())); + // args.InsertValue("objectID", objectIDAsString); + + // GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorID", &args); + // ControlBehaviors::SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner); + // }); + // } +} + +void ControlBehaviors::SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner) { + auto* modelComponent = modelEntity->GetComponent(); + + if (!modelComponent) return; + + AMFArrayValue behaviorsToSerialize; + + AMFArrayValue* behaviors = new AMFArrayValue(); // Empty for now + + /** + * The behaviors AMFArray will have up to 5 elements in the dense portion. + * Each element in the dense portion will be made up of another AMFArray + * with the following information mapped in the associative portion + * "id": Behavior ID cast to an AMFString + * "isLocked": AMFTrue or AMFFalse of whether or not the behavior is locked + * "isLoot": AMFTrue or AMFFalse of whether or not the behavior is a custom behavior (true if custom) + * "name": The name of the behavior formatted as an AMFString + */ + + behaviorsToSerialize.InsertValue("behaviors", behaviors); + + AMFStringValue* amfStringValueForObjectID = new AMFStringValue(); + amfStringValueForObjectID->SetStringValue(std::to_string(modelComponent->GetParent()->GetObjectID())); + + behaviorsToSerialize.InsertValue("objectID", amfStringValueForObjectID); + GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorList", &behaviorsToSerialize); +} + +void ControlBehaviors::ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) { + auto* modelTypeAmf = arguments->FindValue("ModelType"); + if (!modelTypeAmf) return; + + uint32_t modelType = static_cast(modelTypeAmf->GetDoubleValue()); + + //TODO Update the model type here +} + +void ControlBehaviors::ToggleExecutionUpdates() { + //TODO do something with this info +} + +void ControlBehaviors::AddStrip(AMFArrayValue* arguments) { + AddStripMessage addStripMessage(arguments); +} + +void ControlBehaviors::RemoveStrip(AMFArrayValue* arguments) { + RemoveStripMessage removeStrip(arguments); +} + +void ControlBehaviors::MergeStrips(AMFArrayValue* arguments) { + MergeStripsMessage mergeStripsMessage(arguments); +} + +void ControlBehaviors::SplitStrip(AMFArrayValue* arguments) { + SplitStripMessage splitStripMessage(arguments); +} + +void ControlBehaviors::UpdateStripUI(AMFArrayValue* arguments) { + UpdateStripUiMessage updateStripUiMessage(arguments); +} + +void ControlBehaviors::AddAction(AMFArrayValue* arguments) { + AddActionMessage addActionMessage(arguments); +} + +void ControlBehaviors::MigrateActions(AMFArrayValue* arguments) { + MigrateActionsMessage migrateActionsMessage(arguments); +} + +void ControlBehaviors::RearrangeStrip(AMFArrayValue* arguments) { + RearrangeStripMessage rearrangeStripMessage(arguments); +} + +void ControlBehaviors::Add(AMFArrayValue* arguments) { + AddMessage addMessage(arguments); +} + +void ControlBehaviors::RemoveActions(AMFArrayValue* arguments) { + RemoveActionsMessage removeActionsMessage(arguments); +} + +void ControlBehaviors::Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + RenameMessage renameMessage(arguments); +} + +// TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet +void ControlBehaviors::SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + // uint32_t behaviorID = ControlBehaviors::GetBehaviorIDFromArgument(arguments); + + // auto modelBehavior = modelComponent->FindBehavior(behaviorID); + + // if (!modelBehavior) return; + + // modelBehavior->VerifyStates(); + + // auto states = modelBehavior->GetBehaviorStates(); + + // // Begin serialization. + + // /** + // * for each state + // * strip id + // * ui info + // * x + // * y + // * actions + // * action1 + // * action2 + // * ... + // * behaviorID of strip + // * objectID of strip + // */ + // LWOOBJID targetObjectID = LWOOBJID_EMPTY; + // behaviorID = 0; + // AMFArrayValue behaviorInfo; + + // AMFArrayValue* stateSerialize = new AMFArrayValue(); + + // for (auto it = states.begin(); it != states.end(); it++) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of state %i!\n", it->first); + // AMFArrayValue* state = new AMFArrayValue(); + + // AMFDoubleValue* stateAsDouble = new AMFDoubleValue(); + // stateAsDouble->SetDoubleValue(it->first); + // state->InsertValue("id", stateAsDouble); + + // AMFArrayValue* strips = new AMFArrayValue(); + // auto stripsInState = it->second->GetStrips(); + // for (auto strip = stripsInState.begin(); strip != stripsInState.end(); strip++) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of strip %i!\n", strip->first); + // AMFArrayValue* thisStrip = new AMFArrayValue(); + + // AMFDoubleValue* stripID = new AMFDoubleValue(); + // stripID->SetDoubleValue(strip->first); + // thisStrip->InsertValue("id", stripID); + + // AMFArrayValue* uiArray = new AMFArrayValue(); + // AMFDoubleValue* yPosition = new AMFDoubleValue(); + // yPosition->SetDoubleValue(strip->second->GetYPosition()); + // uiArray->InsertValue("y", yPosition); + + // AMFDoubleValue* xPosition = new AMFDoubleValue(); + // xPosition->SetDoubleValue(strip->second->GetXPosition()); + // uiArray->InsertValue("x", xPosition); + + // thisStrip->InsertValue("ui", uiArray); + // targetObjectID = modelComponent->GetParent()->GetObjectID(); + // behaviorID = modelBehavior->GetBehaviorID(); + + // AMFArrayValue* stripSerialize = new AMFArrayValue(); + // for (auto behaviorAction : strip->second->GetActions()) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of action %s!\n", behaviorAction->actionName.c_str()); + // AMFArrayValue* thisAction = new AMFArrayValue(); + + // AMFStringValue* actionName = new AMFStringValue(); + // actionName->SetStringValue(behaviorAction->actionName); + // thisAction->InsertValue("Type", actionName); + + // if (behaviorAction->parameterValueString != "") + // { + // AMFStringValue* valueAsString = new AMFStringValue(); + // valueAsString->SetStringValue(behaviorAction->parameterValueString); + // thisAction->InsertValue(behaviorAction->parameterName, valueAsString); + // } + // else if (behaviorAction->parameterValueDouble != 0.0) + // { + // AMFDoubleValue* valueAsDouble = new AMFDoubleValue(); + // valueAsDouble->SetDoubleValue(behaviorAction->parameterValueDouble); + // thisAction->InsertValue(behaviorAction->parameterName, valueAsDouble); + // } + // stripSerialize->PushBackValue(thisAction); + // } + // thisStrip->InsertValue("actions", stripSerialize); + // strips->PushBackValue(thisStrip); + // } + // state->InsertValue("strips", strips); + // stateSerialize->PushBackValue(state); + // } + // behaviorInfo.InsertValue("states", stateSerialize); + + // AMFStringValue* objectidAsString = new AMFStringValue(); + // objectidAsString->SetStringValue(std::to_string(targetObjectID)); + // behaviorInfo.InsertValue("objectID", objectidAsString); + + // AMFStringValue* behaviorIDAsString = new AMFStringValue(); + // behaviorIDAsString->SetStringValue(std::to_string(behaviorID)); + // behaviorInfo.InsertValue("BehaviorID", behaviorIDAsString); + + // GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorBlocks", &behaviorInfo); +} + +void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) { + UpdateActionMessage updateActionMessage(arguments); + auto* blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType()); + + if (!blockDefinition) { + Game::logger->Log("ControlBehaviors", "Received undefined block type %s. Ignoring.", updateActionMessage.GetAction().GetType().c_str()); + return; + } + + if (updateActionMessage.GetAction().GetValueParameterString().size() > 0) { + if (updateActionMessage.GetAction().GetValueParameterString().size() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetAction().GetValueParameterString().size() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str()); + return; + } + } else { + if (updateActionMessage.GetAction().GetValueParameterDouble() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetAction().GetValueParameterDouble() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str()); + return; + } + } +} + +void ControlBehaviors::MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + // This closes the UI menu should it be open while the player is removing behaviors + AMFArrayValue args; + + AMFFalseValue* stateToPop = new AMFFalseValue(); + args.InsertValue("visible", stateToPop); + + GameMessages::SendUIMessageServerToSingleClient(modelOwner, modelOwner->GetParentUser()->GetSystemAddress(), "ToggleBehaviorEditor", &args); + + MoveToInventoryMessage moveToInventoryMessage(arguments); + + SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner); +} + +void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) { + if (!isInitialized || !modelEntity || !modelOwner || !arguments) return; + auto* modelComponent = modelEntity->GetComponent(); + + if (!modelComponent) return; + + if (command == "sendBehaviorListToClient") + SendBehaviorListToClient(modelEntity, sysAddr, modelOwner); + else if (command == "modelTypeChanged") + ModelTypeChanged(arguments, modelComponent); + else if (command == "toggleExecutionUpdates") + ToggleExecutionUpdates(); + else if (command == "addStrip") + AddStrip(arguments); + else if (command == "removeStrip") + RemoveStrip(arguments); + else if (command == "mergeStrips") + MergeStrips(arguments); + else if (command == "splitStrip") + SplitStrip(arguments); + else if (command == "updateStripUI") + UpdateStripUI(arguments); + else if (command == "addAction") + AddAction(arguments); + else if (command == "migrateActions") + MigrateActions(arguments); + else if (command == "rearrangeStrip") + RearrangeStrip(arguments); + else if (command == "add") + Add(arguments); + else if (command == "removeActions") + RemoveActions(arguments); + else if (command == "rename") + Rename(modelEntity, sysAddr, modelOwner, arguments); + else if (command == "sendBehaviorBlocksToClient") + SendBehaviorBlocksToClient(modelComponent, sysAddr, modelOwner, arguments); + else if (command == "moveToInventory") + MoveToInventory(modelComponent, sysAddr, modelOwner, arguments); + else if (command == "updateAction") + UpdateAction(arguments); + else + Game::logger->Log("ControlBehaviors", "Unknown behavior command (%s)\n", command.c_str()); +} + +ControlBehaviors::ControlBehaviors() { + auto blocksDefStreamBuffer = Game::assetManager->GetFileAsBuffer("ui\\ingame\\blocksdef.xml"); + if (!blocksDefStreamBuffer.m_Success) { + Game::logger->Log("ControlBehaviors", "failed to open blocksdef"); + return; + } + std::istream blocksBuffer(&blocksDefStreamBuffer); + if (!blocksBuffer.good()) { + Game::logger->Log("ControlBehaviors", "Blocks buffer is not good!"); + return; + } + + tinyxml2::XMLDocument m_Doc; + + std::string read{}; + + std::string buffer{}; + bool commentBlockStart = false; + while (std::getline(blocksBuffer, read)) { + // tinyxml2 should handle comment blocks but the client has one that fails the processing. + // This preprocessing just removes all comments from the read file out of an abundance of caution. + if (read.find("") != std::string::npos) { + commentBlockStart = false; + continue; + } + if (!commentBlockStart) buffer += read; + } + + auto ret = m_Doc.Parse(buffer.c_str()); + if (ret == tinyxml2::XML_SUCCESS) { + Game::logger->LogDebug("ControlBehaviors", "Successfully parsed the blocksdef file!"); + } else { + Game::logger->Log("Character", "Failed to parse BlocksDef xmlData due to error %i!", ret); + return; + } + auto* blockLibrary = m_Doc.FirstChildElement(); + if (!blockLibrary) { + Game::logger->Log("ControlBehaviors", "No Block Library child element found."); + return; + } + + // Now parse the blocksdef for the cheat detection server side. + // The client does these checks, but a bad actor can bypass the client checks + auto* blockSections = blockLibrary->FirstChildElement(); + while (blockSections) { + auto* block = blockSections->FirstChildElement(); + std::string blockName{}; + while (block) { + blockName = block->Name(); + + BlockDefinition* blockDefinition = new BlockDefinition(); + std::string name{}; + std::string typeName{}; + + auto* argument = block->FirstChildElement("Argument"); + if (argument) { + auto* defaultDefinition = argument->FirstChildElement("DefaultValue"); + if (defaultDefinition) blockDefinition->SetDefaultValue(defaultDefinition->GetText()); + + auto* typeDefinition = argument->FirstChildElement("Type"); + if (typeDefinition) typeName = typeDefinition->GetText(); + + auto* nameDefinition = argument->FirstChildElement("Name"); + if (nameDefinition) name = nameDefinition->GetText(); + + // Now we parse the blocksdef file for the relevant information + if (typeName == "String") { + blockDefinition->SetMaximumValue(50); // The client has a hardcoded limit of 50 characters in a string field + } else if (typeName == "Float" || typeName == "Integer") { + auto* maximumDefinition = argument->FirstChildElement("Maximum"); + if (maximumDefinition) blockDefinition->SetMaximumValue(std::stof(maximumDefinition->GetText())); + + auto* minimumDefinition = argument->FirstChildElement("Minimum"); + if (minimumDefinition) blockDefinition->SetMinimumValue(std::stof(minimumDefinition->GetText())); + } else if (typeName == "Enumeration") { + auto* values = argument->FirstChildElement("Values"); + if (values) { + auto* value = values->FirstChildElement("Value"); + while (value) { + if (value->GetText() == blockDefinition->GetDefaultValue()) blockDefinition->GetDefaultValue() = std::to_string(blockDefinition->GetMaximumValue()); + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() + 1); + value = value->NextSiblingElement("Value"); + } + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() - 1); // Maximum value is 0 indexed + } else { + values = argument->FirstChildElement("EnumerationSource"); + if (!values) { + Game::logger->Log("ControlBehaviors", "Failed to parse EnumerationSource from block (%s)", blockName.c_str()); + continue; + } + + auto* serviceNameNode = values->FirstChildElement("ServiceName"); + if (!serviceNameNode) { + Game::logger->Log("ControlBehaviors", "Failed to parse ServiceName from block (%s)", blockName.c_str()); + continue; + } + + std::string serviceName = serviceNameNode->GetText(); + if (serviceName == "GetBehaviorSoundList") { + auto res = CDClientDatabase::ExecuteQuery("SELECT MAX(id) as countSounds FROM UGBehaviorSounds;"); + blockDefinition->SetMaximumValue(res.getIntField("countSounds")); + blockDefinition->SetDefaultValue("0"); + } else { + Game::logger->Log("ControlBehaviors", "Unsupported Enumeration ServiceType (%s)", serviceName.c_str()); + continue; + } + } + } else { + Game::logger->Log("ControlBehaviors", "Unsupported block value type (%s)!", typeName.c_str()); + continue; + } + } + blockTypes.insert(std::make_pair(blockName, blockDefinition)); + block = block->NextSiblingElement(); + } + blockSections = blockSections->NextSiblingElement(); + } + isInitialized = true; + Game::logger->LogDebug("ControlBehaviors", "Created all base block classes"); + for (auto b : blockTypes) { + Game::logger->LogDebug("ControlBehaviors", "block name is %s default %s min %f max %f", b.first.c_str(), b.second->GetDefaultValue().c_str(), b.second->GetMinimumValue(), b.second->GetMaximumValue()); + } +} + +BlockDefinition* ControlBehaviors::GetBlockInfo(const BlockName& blockName) { + auto blockDefinition = blockTypes.find(blockName); + return blockDefinition != blockTypes.end() ? blockDefinition->second : nullptr; +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.h b/dGame/dPropertyBehaviors/ControlBehaviors.h new file mode 100644 index 00000000..a562aafe --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviors.h @@ -0,0 +1,68 @@ +#pragma once + +#ifndef __CONTROLBEHAVIORS__H__ +#define __CONTROLBEHAVIORS__H__ + +#include +#include + +#include "Singleton.h" + +class AMFArrayValue; +class BlockDefinition; +class Entity; +class ModelComponent; +class SystemAddress; + +// Type definition to clarify what is used where +typedef std::string BlockName; //! A block name + +class ControlBehaviors: public Singleton { +public: + ControlBehaviors(); + /** + * @brief Main driver for processing Property Behavior commands + * + * @param modelEntity The model that sent this command + * @param sysAddr The SystemAddress to respond to + * @param arguments The arguments formatted as an AMFArrayValue + * @param command The command to perform + * @param modelOwner The owner of the model which sent this command + */ + void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner); + + /** + * @brief Gets a blocks parameter values by the name + * No exception will be thrown in this function. + * + * @param blockName The block name to get the parameters of + * + * @return A pair of the block parameter name to its typing + */ + BlockDefinition* GetBlockInfo(const BlockName& blockName); +private: + void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr); + void SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner); + void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent); + void ToggleExecutionUpdates(); + void AddStrip(AMFArrayValue* arguments); + void RemoveStrip(AMFArrayValue* arguments); + void MergeStrips(AMFArrayValue* arguments); + void SplitStrip(AMFArrayValue* arguments); + void UpdateStripUI(AMFArrayValue* arguments); + void AddAction(AMFArrayValue* arguments); + void MigrateActions(AMFArrayValue* arguments); + void RearrangeStrip(AMFArrayValue* arguments); + void Add(AMFArrayValue* arguments); + void RemoveActions(AMFArrayValue* arguments); + void Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void UpdateAction(AMFArrayValue* arguments); + void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + std::map blockTypes{}; + + // If false, property behaviors will not be able to be edited. + bool isInitialized = false; +}; + +#endif //!__CONTROLBEHAVIORS__H__ diff --git a/dGame/dUtilities/BrickDatabase.cpp b/dGame/dUtilities/BrickDatabase.cpp index e0687503..a6c43d52 100644 --- a/dGame/dUtilities/BrickDatabase.cpp +++ b/dGame/dUtilities/BrickDatabase.cpp @@ -3,32 +3,42 @@ #include "BrickDatabase.h" #include "Game.h" +#include "AssetManager.h" +#include "tinyxml2.h" -std::vector BrickDatabase::emptyCache {}; +std::vector BrickDatabase::emptyCache{}; BrickDatabase* BrickDatabase::m_Address = nullptr; BrickDatabase::BrickDatabase() = default; BrickDatabase::~BrickDatabase() = default; -std::vector& BrickDatabase::GetBricks(const std::string& lxfmlPath) -{ - const auto cached = m_Cache.find(lxfmlPath); +std::vector& BrickDatabase::GetBricks(const std::string& lxfmlPath) { + const auto cached = m_Cache.find(lxfmlPath); - if (cached != m_Cache.end()) { - return cached->second; - } + if (cached != m_Cache.end()) { + return cached->second; + } - std::ifstream file(lxfmlPath); + AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer((lxfmlPath).c_str()); + + if (!buffer.m_Success) { + return emptyCache; + } + + std::istream file(&buffer); if (!file.good()) { return emptyCache; } - + std::stringstream data; data << file.rdbuf(); if (data.str().empty()) { + buffer.close(); return emptyCache; } + buffer.close(); + auto* doc = new tinyxml2::XMLDocument(); if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { delete doc; @@ -40,53 +50,53 @@ std::vector& BrickDatabase::GetBricks(const std::string& lxfmlPath) auto* lxfml = doc->FirstChildElement("LXFML"); auto* bricks = lxfml->FirstChildElement("Bricks"); std::string searchTerm = "Brick"; - + if (!bricks) { searchTerm = "Part"; bricks = lxfml->FirstChildElement("Scene")->FirstChildElement("Model")->FirstChildElement("Group"); - + if (!bricks) { - return emptyCache; + return emptyCache; } } - + auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str()); while (currentBrick != nullptr) { - auto* part = currentBrick->FirstChildElement("Part"); + auto* part = currentBrick->FirstChildElement("Part"); if (part == nullptr) part = currentBrick; if (part->Attribute("designID") != nullptr) { - Brick brick { static_cast(part->IntAttribute("designID")) }; + Brick brick{ static_cast(part->IntAttribute("designID")) }; - // Depends on the file, some don't specify a list but just a single material - const auto* materialList = part->Attribute("materials"); - const auto* materialID = part->Attribute("materialID"); + // Depends on the file, some don't specify a list but just a single material + const auto* materialList = part->Attribute("materials"); + const auto* materialID = part->Attribute("materialID"); - if (materialList != nullptr) { - std::string materialString(materialList); - const auto materials = GeneralUtils::SplitString(materialString, ','); + if (materialList != nullptr) { + std::string materialString(materialList); + const auto materials = GeneralUtils::SplitString(materialString, ','); - if (!materials.empty()) { - brick.materialID = std::stoi(materials[0]); - } else { - brick.materialID = 0; - } - } else if (materialID != nullptr) { - brick.materialID = std::stoi(materialID); - } else { - brick.materialID = 0; // This is bad, makes it so the minigame can't be played - } + if (!materials.empty()) { + brick.materialID = std::stoi(materials[0]); + } else { + brick.materialID = 0; + } + } else if (materialID != nullptr) { + brick.materialID = std::stoi(materialID); + } else { + brick.materialID = 0; // This is bad, makes it so the minigame can't be played + } parts.push_back(brick); } - + currentBrick = currentBrick->NextSiblingElement(searchTerm.c_str()); } - m_Cache[lxfmlPath] = parts; + m_Cache[lxfmlPath] = parts; delete doc; - return m_Cache[lxfmlPath]; + return m_Cache[lxfmlPath]; } diff --git a/dGame/dUtilities/BrickDatabase.h b/dGame/dUtilities/BrickDatabase.h index 7e16c2ea..589d46ae 100644 --- a/dGame/dUtilities/BrickDatabase.h +++ b/dGame/dUtilities/BrickDatabase.h @@ -4,28 +4,26 @@ class BrickDatabase { public: - static BrickDatabase* Instance() - { - if (m_Address == nullptr) - { - m_Address = new BrickDatabase(); - } + static BrickDatabase* Instance() { + if (m_Address == nullptr) { + m_Address = new BrickDatabase(); + } - return m_Address; - } + return m_Address; + } - std::vector& GetBricks(const std::string& lxfmlPath); + std::vector& GetBricks(const std::string& lxfmlPath); - explicit BrickDatabase(); + explicit BrickDatabase(); + + ~BrickDatabase(); - ~BrickDatabase(); - private: - std::unordered_map> m_Cache; + std::unordered_map> m_Cache; - static std::vector emptyCache; + static std::vector emptyCache; - static BrickDatabase* m_Address; //For singleton method + static BrickDatabase* m_Address; //For singleton method - /* data */ + /* data */ }; diff --git a/dGame/dUtilities/CMakeLists.txt b/dGame/dUtilities/CMakeLists.txt new file mode 100644 index 00000000..55ca5797 --- /dev/null +++ b/dGame/dUtilities/CMakeLists.txt @@ -0,0 +1,7 @@ +set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp" + "GUID.cpp" + "Loot.cpp" + "Mail.cpp" + "Preconditions.cpp" + "SlashCommandHandler.cpp" + "VanityUtilities.cpp" PARENT_SCOPE) diff --git a/dGame/dUtilities/GUID.cpp b/dGame/dUtilities/GUID.cpp index fb87139a..57f76a81 100644 --- a/dGame/dUtilities/GUID.cpp +++ b/dGame/dUtilities/GUID.cpp @@ -1,27 +1,27 @@ #include "GUID.h" -GUID::GUID(const std::string &guid) { - sscanf(guid.c_str(), - "{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx}", - &this->data1, &this->data2, &this->data3, - &this->data4[0], &this->data4[1], &this->data4[2], &this->data4[3], - &this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]); +GUID::GUID(const std::string& guid) { + sscanf(guid.c_str(), + "{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx}", + &this->data1, &this->data2, &this->data3, + &this->data4[0], &this->data4[1], &this->data4[2], &this->data4[3], + &this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]); } uint32_t GUID::GetData1() const { - return data1; + return data1; } uint16_t GUID::GetData2() const { - return data2; + return data2; } uint16_t GUID::GetData3() const { - return data3; + return data3; } std::array GUID::GetData4() const { - return data4; + return data4; } GUID::GUID() = default; diff --git a/dGame/dUtilities/GUID.h b/dGame/dUtilities/GUID.h index 24518785..2d958c10 100644 --- a/dGame/dUtilities/GUID.h +++ b/dGame/dUtilities/GUID.h @@ -5,15 +5,15 @@ class GUID { public: - explicit GUID(); - explicit GUID(const std::string& guid); - uint32_t GetData1() const; - uint16_t GetData2() const; - uint16_t GetData3() const; - std::array GetData4() const; + explicit GUID(); + explicit GUID(const std::string& guid); + uint32_t GetData1() const; + uint16_t GetData2() const; + uint16_t GetData3() const; + std::array GetData4() const; private: - uint32_t data1 = 0; - uint16_t data2 = 0; - uint16_t data3 = 0; - std::array data4 = { 0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t data1 = 0; + uint16_t data2 = 0; + uint16_t data3 = 0; + std::array data4 = { 0, 0, 0, 0, 0, 0, 0, 0 }; }; diff --git a/dGame/dUtilities/GameConfig.cpp b/dGame/dUtilities/GameConfig.cpp deleted file mode 100644 index bd57ee65..00000000 --- a/dGame/dUtilities/GameConfig.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "GameConfig.h" -#include - -std::map GameConfig::m_Config {}; -std::string GameConfig::m_EmptyString {}; - -void GameConfig::Load(const std::string& filepath) { - m_EmptyString = ""; - std::ifstream in(filepath); - if (!in.good()) return; - - std::string line; - while (std::getline(in, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } - } -} - -const std::string& GameConfig::GetValue(const std::string& key) { - const auto& it = m_Config.find(key); - - if (it != m_Config.end()) { - return it->second; - } - - return m_EmptyString; -} - -void GameConfig::SetValue(const std::string& key, const std::string& value) { - m_Config.insert_or_assign(key, value); -} - -void GameConfig::ProcessLine(const std::string& line) { - std::stringstream ss(line); - std::string segment; - std::vector seglist; - - while (std::getline(ss, segment, '=')) { - seglist.push_back(segment); - } - - if (seglist.size() != 2) return; - - //Make sure that on Linux, we remove special characters: - if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r') - seglist[1].erase(seglist[1].size() - 1); - - m_Config.insert_or_assign(seglist[0], seglist[1]); -} \ No newline at end of file diff --git a/dGame/dUtilities/GameConfig.h b/dGame/dUtilities/GameConfig.h deleted file mode 100644 index e5fc3987..00000000 --- a/dGame/dUtilities/GameConfig.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "GeneralUtils.h" - -class GameConfig { -public: - static void Load(const std::string& filepath); - - static const std::string& GetValue(const std::string& key); - - static void SetValue(const std::string& key, const std::string& value); - - template - static T GetValue(const std::string& key) { - T value; - - if (GeneralUtils::TryParse(GetValue(key), value)) { - return value; - } - - return T(); - } - - template - static void SetValue(const std::string& key, const T& value) { - SetValue(key, std::to_string(value)); - } - -private: - static void ProcessLine(const std::string& line); - - static std::map m_Config; - static std::string m_EmptyString; -}; \ No newline at end of file diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index 8305e152..c788c016 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -7,383 +7,387 @@ #include "CDLootMatrixTable.h" #include "CDLootTableTable.h" #include "CDRarityTableTable.h" +#include "CDActivityRewardsTable.h" +#include "CDCurrencyTableTable.h" #include "Character.h" #include "Entity.h" #include "GameMessages.h" #include "GeneralUtils.h" #include "InventoryComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" LootGenerator::LootGenerator() { - CDLootTableTable* lootTableTable = CDClientManager::Instance()->GetTable("LootTable"); - CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); - CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance()->GetTable("LootMatrix"); - CDRarityTableTable* rarityTableTable = CDClientManager::Instance()->GetTable("RarityTable"); + CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable(); + CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); + CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable(); + CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable(); - // ============================== - // Cache Item Rarities - // ============================== + // ============================== + // Cache Item Rarities + // ============================== - std::vector uniqueItems; + std::vector uniqueItems; - for (const CDLootTable& loot : lootTableTable->GetEntries()) { - uniqueItems.push_back(loot.itemid); - } + for (const CDLootTable& loot : lootTableTable->GetEntries()) { + uniqueItems.push_back(loot.itemid); + } - // filter out duplicates - std::sort(uniqueItems.begin(), uniqueItems.end()); - uniqueItems.erase(std::unique(uniqueItems.begin(), uniqueItems.end()), uniqueItems.end()); + // filter out duplicates + std::sort(uniqueItems.begin(), uniqueItems.end()); + uniqueItems.erase(std::unique(uniqueItems.begin(), uniqueItems.end()), uniqueItems.end()); - for (const uint32_t itemID : uniqueItems) { - uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, COMPONENT_TYPE_ITEM); - const CDItemComponent& item = itemComponentTable->GetItemComponentByID(itemComponentID); + for (const uint32_t itemID : uniqueItems) { + uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, eReplicaComponentType::ITEM); + const CDItemComponent& item = itemComponentTable->GetItemComponentByID(itemComponentID); - m_ItemRarities.insert({itemID, item.rarity}); - } + m_ItemRarities.insert({ itemID, item.rarity }); + } - // ============================== - // Cache Rarity Tables - // ============================== + // ============================== + // Cache Rarity Tables + // ============================== - std::vector uniqueRarityIndices; + std::vector uniqueRarityIndices; - for (const CDRarityTable& rarity : rarityTableTable->GetEntries()) { - uniqueRarityIndices.push_back(rarity.RarityTableIndex); - } + for (const CDRarityTable& rarity : rarityTableTable->GetEntries()) { + uniqueRarityIndices.push_back(rarity.RarityTableIndex); + } - // filter out duplicates - std::sort(uniqueRarityIndices.begin(), uniqueRarityIndices.end()); - uniqueRarityIndices.erase(std::unique(uniqueRarityIndices.begin(), uniqueRarityIndices.end()), uniqueRarityIndices.end()); + // filter out duplicates + std::sort(uniqueRarityIndices.begin(), uniqueRarityIndices.end()); + uniqueRarityIndices.erase(std::unique(uniqueRarityIndices.begin(), uniqueRarityIndices.end()), uniqueRarityIndices.end()); - for (const uint32_t index : uniqueRarityIndices) { - std::vector table = rarityTableTable->Query([index](const CDRarityTable& entry) { return entry.RarityTableIndex == index; }); + for (const uint32_t index : uniqueRarityIndices) { + std::vector table = rarityTableTable->Query([index](const CDRarityTable& entry) { return entry.RarityTableIndex == index; }); - RarityTable rarityTable; + RarityTable rarityTable; - for (const CDRarityTable& entry : table) { - RarityTableEntry rarity{entry.rarity, entry.randmax}; - rarityTable.push_back(rarity); - } + for (const CDRarityTable& entry : table) { + RarityTableEntry rarity{ entry.rarity, entry.randmax }; + rarityTable.push_back(rarity); + } - // sort in descending order based on randMax - std::sort(rarityTable.begin(), rarityTable.end(), [](const RarityTableEntry& x, const RarityTableEntry& y) { return x.randMax > y.randMax; }); + // sort in descending order based on randMax + std::sort(rarityTable.begin(), rarityTable.end(), [](const RarityTableEntry& x, const RarityTableEntry& y) { return x.randMax > y.randMax; }); - m_RarityTables.insert({index, rarityTable}); - } + m_RarityTables.insert({ index, rarityTable }); + } - // ============================== - // Cache Loot Matrices - // ============================== + // ============================== + // Cache Loot Matrices + // ============================== - std::vector uniqueMatrixIndices; + std::vector uniqueMatrixIndices; - for (const CDLootMatrix& matrix : lootMatrixTable->GetEntries()) { - uniqueMatrixIndices.push_back(matrix.LootMatrixIndex); - } + for (const CDLootMatrix& matrix : lootMatrixTable->GetEntries()) { + uniqueMatrixIndices.push_back(matrix.LootMatrixIndex); + } - // filter out duplicates - std::sort(uniqueMatrixIndices.begin(), uniqueMatrixIndices.end()); - uniqueMatrixIndices.erase(std::unique(uniqueMatrixIndices.begin(), uniqueMatrixIndices.end()), uniqueMatrixIndices.end()); + // filter out duplicates + std::sort(uniqueMatrixIndices.begin(), uniqueMatrixIndices.end()); + uniqueMatrixIndices.erase(std::unique(uniqueMatrixIndices.begin(), uniqueMatrixIndices.end()), uniqueMatrixIndices.end()); - for (const uint32_t index : uniqueMatrixIndices) { - std::vector matrix = lootMatrixTable->Query([index](const CDLootMatrix& entry) { return entry.LootMatrixIndex == index; }); + for (const uint32_t index : uniqueMatrixIndices) { + std::vector matrix = lootMatrixTable->Query([index](const CDLootMatrix& entry) { return entry.LootMatrixIndex == index; }); - LootMatrix lootMatrix; + LootMatrix lootMatrix; - for (const CDLootMatrix& entry : matrix) { - LootMatrixEntry matrixEntry{entry.LootTableIndex, entry.RarityTableIndex, entry.percent, entry.minToDrop, entry.maxToDrop}; - lootMatrix.push_back(matrixEntry); - } + for (const CDLootMatrix& entry : matrix) { + LootMatrixEntry matrixEntry{ entry.LootTableIndex, entry.RarityTableIndex, entry.percent, entry.minToDrop, entry.maxToDrop }; + lootMatrix.push_back(matrixEntry); + } - m_LootMatrices.insert({index, lootMatrix}); - } + m_LootMatrices.insert({ index, lootMatrix }); + } - // ============================== - // Cache Loot Tables - // ============================== + // ============================== + // Cache Loot Tables + // ============================== - std::vector uniqueTableIndices; + std::vector uniqueTableIndices; - for (const CDLootTable& entry : lootTableTable->GetEntries()) { - uniqueTableIndices.push_back(entry.LootTableIndex); - } + for (const CDLootTable& entry : lootTableTable->GetEntries()) { + uniqueTableIndices.push_back(entry.LootTableIndex); + } - // filter out duplicates - std::sort(uniqueTableIndices.begin(), uniqueTableIndices.end()); - uniqueTableIndices.erase(std::unique(uniqueTableIndices.begin(), uniqueTableIndices.end()), uniqueTableIndices.end()); + // filter out duplicates + std::sort(uniqueTableIndices.begin(), uniqueTableIndices.end()); + uniqueTableIndices.erase(std::unique(uniqueTableIndices.begin(), uniqueTableIndices.end()), uniqueTableIndices.end()); - for (const uint32_t index : uniqueTableIndices) { - std::vector entries = lootTableTable->Query([index](const CDLootTable& entry) { return entry.LootTableIndex == index; }); + for (const uint32_t index : uniqueTableIndices) { + std::vector entries = lootTableTable->Query([index](const CDLootTable& entry) { return entry.LootTableIndex == index; }); - LootTable lootTable; + LootTable lootTable; - for (const CDLootTable& entry : entries) { - LootTableEntry tableEntry{(LOT)entry.itemid, entry.MissionDrop}; - lootTable.push_back(tableEntry); - } + for (const CDLootTable& entry : entries) { + LootTableEntry tableEntry{ (LOT)entry.itemid, entry.MissionDrop }; + lootTable.push_back(tableEntry); + } - // sort by item rarity descending - std::sort(lootTable.begin(), lootTable.end(), [&](const LootTableEntry& x, const LootTableEntry& y) { - return m_ItemRarities[x.itemID] > m_ItemRarities[y.itemID]; - }); + // sort by item rarity descending + std::sort(lootTable.begin(), lootTable.end(), [&](const LootTableEntry& x, const LootTableEntry& y) { + return m_ItemRarities[x.itemID] > m_ItemRarities[y.itemID]; + }); - m_LootTables.insert({index, lootTable}); - } + m_LootTables.insert({ index, lootTable }); + } } std::unordered_map LootGenerator::RollLootMatrix(Entity* player, uint32_t matrixIndex) { - auto* missionComponent = player->GetComponent(); + auto* missionComponent = player->GetComponent(); - std::unordered_map drops; + std::unordered_map drops; - if (missionComponent == nullptr) { - return drops; - } + if (missionComponent == nullptr) { + return drops; + } - const LootMatrix& matrix = m_LootMatrices[matrixIndex]; + const LootMatrix& matrix = m_LootMatrices[matrixIndex]; - for (const LootMatrixEntry& entry : matrix) { - if (GeneralUtils::GenerateRandomNumber(0, 1) < entry.percent) { - const LootTable& lootTable = m_LootTables[entry.lootTableIndex]; - const RarityTable& rarityTable = m_RarityTables[entry.rarityTableIndex]; + for (const LootMatrixEntry& entry : matrix) { + if (GeneralUtils::GenerateRandomNumber(0, 1) < entry.percent) { + const LootTable& lootTable = m_LootTables[entry.lootTableIndex]; + const RarityTable& rarityTable = m_RarityTables[entry.rarityTableIndex]; - uint32_t dropCount = GeneralUtils::GenerateRandomNumber(entry.minDrop, entry.maxDrop); - for (uint32_t i = 0; i < dropCount; ++i) { - uint32_t maxRarity = 1; + uint32_t dropCount = GeneralUtils::GenerateRandomNumber(entry.minDrop, entry.maxDrop); + for (uint32_t i = 0; i < dropCount; ++i) { + uint32_t maxRarity = 1; - float rarityRoll = GeneralUtils::GenerateRandomNumber(0, 1); + float rarityRoll = GeneralUtils::GenerateRandomNumber(0, 1); - for (const RarityTableEntry& rarity : rarityTable) { - if (rarity.randMax >= rarityRoll) { - maxRarity = rarity.rarity; - } else { - break; - } - } + for (const RarityTableEntry& rarity : rarityTable) { + if (rarity.randMax >= rarityRoll) { + maxRarity = rarity.rarity; + } else { + break; + } + } - bool rarityFound = false; - std::vector possibleDrops; + bool rarityFound = false; + std::vector possibleDrops; - for (const LootTableEntry& loot : lootTable) { - uint32_t rarity = m_ItemRarities[loot.itemID]; + for (const LootTableEntry& loot : lootTable) { + uint32_t rarity = m_ItemRarities[loot.itemID]; - if (rarity == maxRarity) { - possibleDrops.push_back(loot); - rarityFound = true; - } else if (rarity < maxRarity && !rarityFound) { - possibleDrops.push_back(loot); - maxRarity = rarity; - } - } + if (rarity == maxRarity) { + possibleDrops.push_back(loot); + rarityFound = true; + } else if (rarity < maxRarity && !rarityFound) { + possibleDrops.push_back(loot); + maxRarity = rarity; + } + } - if (possibleDrops.size() > 0) { - LootTableEntry drop = possibleDrops[GeneralUtils::GenerateRandomNumber(0, possibleDrops.size() - 1)]; + if (possibleDrops.size() > 0) { + LootTableEntry drop = possibleDrops[GeneralUtils::GenerateRandomNumber(0, possibleDrops.size() - 1)]; - // filter out uneeded mission items - if (drop.isMissionDrop && !missionComponent->RequiresItem(drop.itemID)) - continue; + // filter out uneeded mission items + if (drop.isMissionDrop && !missionComponent->RequiresItem(drop.itemID)) + continue; - // convert faction token proxy - if (drop.itemID == 13763) { - if (missionComponent->GetMissionState(545) == MissionState::MISSION_STATE_COMPLETE) - drop.itemID = 8318; // "Assembly Token" - else if (missionComponent->GetMissionState(556) == MissionState::MISSION_STATE_COMPLETE) - drop.itemID = 8321; // "Venture League Token" - else if (missionComponent->GetMissionState(567) == MissionState::MISSION_STATE_COMPLETE) - drop.itemID = 8319; // "Sentinels Token" - else if (missionComponent->GetMissionState(578) == MissionState::MISSION_STATE_COMPLETE) - drop.itemID = 8320; // "Paradox Token" - } + // convert faction token proxy + if (drop.itemID == 13763) { + if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) + drop.itemID = 8318; // "Assembly Token" + else if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) + drop.itemID = 8321; // "Venture League Token" + else if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) + drop.itemID = 8319; // "Sentinels Token" + else if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) + drop.itemID = 8320; // "Paradox Token" + } - if (drop.itemID == 13763) { - continue; - } // check if we aren't in faction + if (drop.itemID == 13763) { + continue; + } // check if we aren't in faction - if (drops.find(drop.itemID) == drops.end()) { - drops.insert({drop.itemID, 1}); - } else { - ++drops[drop.itemID]; - } - } - } - } - } + if (drops.find(drop.itemID) == drops.end()) { + drops.insert({ drop.itemID, 1 }); + } else { + ++drops[drop.itemID]; + } + } + } + } + } - return drops; + return drops; } std::unordered_map LootGenerator::RollLootMatrix(uint32_t matrixIndex) { - std::unordered_map drops; + std::unordered_map drops; - const LootMatrix& matrix = m_LootMatrices[matrixIndex]; + const LootMatrix& matrix = m_LootMatrices[matrixIndex]; - for (const LootMatrixEntry& entry : matrix) { - if (GeneralUtils::GenerateRandomNumber(0, 1) < entry.percent) { - const LootTable& lootTable = m_LootTables[entry.lootTableIndex]; - const RarityTable& rarityTable = m_RarityTables[entry.rarityTableIndex]; + for (const LootMatrixEntry& entry : matrix) { + if (GeneralUtils::GenerateRandomNumber(0, 1) < entry.percent) { + const LootTable& lootTable = m_LootTables[entry.lootTableIndex]; + const RarityTable& rarityTable = m_RarityTables[entry.rarityTableIndex]; - uint32_t dropCount = GeneralUtils::GenerateRandomNumber(entry.minDrop, entry.maxDrop); - for (uint32_t i = 0; i < dropCount; ++i) { - uint32_t maxRarity = 1; + uint32_t dropCount = GeneralUtils::GenerateRandomNumber(entry.minDrop, entry.maxDrop); + for (uint32_t i = 0; i < dropCount; ++i) { + uint32_t maxRarity = 1; - float rarityRoll = GeneralUtils::GenerateRandomNumber(0, 1); + float rarityRoll = GeneralUtils::GenerateRandomNumber(0, 1); - for (const RarityTableEntry& rarity : rarityTable) { - if (rarity.randMax >= rarityRoll) { - maxRarity = rarity.rarity; - } else { - break; - } - } + for (const RarityTableEntry& rarity : rarityTable) { + if (rarity.randMax >= rarityRoll) { + maxRarity = rarity.rarity; + } else { + break; + } + } - bool rarityFound = false; - std::vector possibleDrops; + bool rarityFound = false; + std::vector possibleDrops; - for (const LootTableEntry& loot : lootTable) { - uint32_t rarity = m_ItemRarities[loot.itemID]; + for (const LootTableEntry& loot : lootTable) { + uint32_t rarity = m_ItemRarities[loot.itemID]; - if (rarity == maxRarity) { - possibleDrops.push_back(loot); - rarityFound = true; - } else if (rarity < maxRarity && !rarityFound) { - possibleDrops.push_back(loot); - maxRarity = rarity; - } - } + if (rarity == maxRarity) { + possibleDrops.push_back(loot); + rarityFound = true; + } else if (rarity < maxRarity && !rarityFound) { + possibleDrops.push_back(loot); + maxRarity = rarity; + } + } - if (possibleDrops.size() > 0) { - const LootTableEntry& drop = possibleDrops[GeneralUtils::GenerateRandomNumber(0, possibleDrops.size() - 1)]; + if (possibleDrops.size() > 0) { + const LootTableEntry& drop = possibleDrops[GeneralUtils::GenerateRandomNumber(0, possibleDrops.size() - 1)]; - if (drops.find(drop.itemID) == drops.end()) { - drops.insert({drop.itemID, 1}); - } else { - ++drops[drop.itemID]; - } - } - } - } - } + if (drops.find(drop.itemID) == drops.end()) { + drops.insert({ drop.itemID, 1 }); + } else { + ++drops[drop.itemID]; + } + } + } + } + } - return drops; + return drops; } void LootGenerator::GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType) { - player = player->GetOwner(); // If the owner is overwritten, we collect that here + player = player->GetOwner(); // If the owner is overwritten, we collect that here - std::unordered_map result = RollLootMatrix(player, matrixIndex); + std::unordered_map result = RollLootMatrix(player, matrixIndex); - GiveLoot(player, result, lootSourceType); + GiveLoot(player, result, lootSourceType); } void LootGenerator::GiveLoot(Entity* player, std::unordered_map& result, eLootSourceType lootSourceType) { - player = player->GetOwner(); // if the owner is overwritten, we collect that here + player = player->GetOwner(); // if the owner is overwritten, we collect that here - auto* inventoryComponent = player->GetComponent(); + auto* inventoryComponent = player->GetComponent(); - if (!inventoryComponent) - return; + if (!inventoryComponent) + return; - for (const auto& pair : result) { - inventoryComponent->AddItem(pair.first, pair.second, lootSourceType); - } + for (const auto& pair : result) { + inventoryComponent->AddItem(pair.first, pair.second, lootSourceType); + } } void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) { - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); - std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); + std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); - const CDActivityRewards* selectedReward = nullptr; - for (const auto& activityReward : activityRewards) { - if (activityReward.activityRating <= rating && (selectedReward == nullptr || activityReward.activityRating > selectedReward->activityRating)) { - selectedReward = &activityReward; - } - } + const CDActivityRewards* selectedReward = nullptr; + for (const auto& activityReward : activityRewards) { + if (activityReward.activityRating <= rating && (selectedReward == nullptr || activityReward.activityRating > selectedReward->activityRating)) { + selectedReward = &activityReward; + } + } - if (!selectedReward) - return; + if (!selectedReward) + return; - uint32_t minCoins = 0; - uint32_t maxCoins = 0; + uint32_t minCoins = 0; + uint32_t maxCoins = 0; - CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); - std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); + CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable(); + std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); - if (currencyTable.size() > 0) { - minCoins = currencyTable[0].minvalue; - maxCoins = currencyTable[0].maxvalue; - } + if (currencyTable.size() > 0) { + minCoins = currencyTable[0].minvalue; + maxCoins = currencyTable[0].maxvalue; + } - GiveLoot(player, selectedReward->LootMatrixIndex, eLootSourceType::LOOT_SOURCE_ACTIVITY); + GiveLoot(player, selectedReward->LootMatrixIndex, eLootSourceType::ACTIVITY); - uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber(0, 1) * (maxCoins - minCoins)); + uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber(0, 1) * (maxCoins - minCoins)); - auto* character = player->GetCharacter(); + auto* character = player->GetCharacter(); - character->SetCoins(character->GetCoins() + coins, eLootSourceType::LOOT_SOURCE_ACTIVITY); + character->SetCoins(character->GetCoins() + coins, eLootSourceType::ACTIVITY); } void LootGenerator::DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { - player = player->GetOwner(); // if the owner is overwritten, we collect that here + player = player->GetOwner(); // if the owner is overwritten, we collect that here - auto* inventoryComponent = player->GetComponent(); + auto* inventoryComponent = player->GetComponent(); - if (!inventoryComponent) - return; + if (!inventoryComponent) + return; - std::unordered_map result = RollLootMatrix(player, matrixIndex); + std::unordered_map result = RollLootMatrix(player, matrixIndex); - DropLoot(player, killedObject, result, minCoins, maxCoins); + DropLoot(player, killedObject, result, minCoins, maxCoins); } void LootGenerator::DropLoot(Entity* player, Entity* killedObject, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins) { - player = player->GetOwner(); // if the owner is overwritten, we collect that here + player = player->GetOwner(); // if the owner is overwritten, we collect that here - auto* inventoryComponent = player->GetComponent(); + auto* inventoryComponent = player->GetComponent(); - if (!inventoryComponent) - return; + if (!inventoryComponent) + return; - const auto spawnPosition = killedObject->GetPosition(); + const auto spawnPosition = killedObject->GetPosition(); - const auto source = killedObject->GetObjectID(); + const auto source = killedObject->GetObjectID(); - for (const auto& pair : result) { - for (int i = 0; i < pair.second; ++i) { - GameMessages::SendDropClientLoot(player, source, pair.first, 0, spawnPosition, 1); - } - } + for (const auto& pair : result) { + for (int i = 0; i < pair.second; ++i) { + GameMessages::SendDropClientLoot(player, source, pair.first, 0, spawnPosition, 1); + } + } - uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber(0, 1) * (maxCoins - minCoins)); + uint32_t coins = (int)(minCoins + GeneralUtils::GenerateRandomNumber(0, 1) * (maxCoins - minCoins)); - GameMessages::SendDropClientLoot(player, source, LOT_NULL, coins, spawnPosition); + GameMessages::SendDropClientLoot(player, source, LOT_NULL, coins, spawnPosition); } void LootGenerator::DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) { - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); - std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); + std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); - const CDActivityRewards* selectedReward = nullptr; - for (const auto& activityReward : activityRewards) { - if (activityReward.activityRating <= rating && (selectedReward == nullptr || activityReward.activityRating > selectedReward->activityRating)) { - selectedReward = &activityReward; - } - } + const CDActivityRewards* selectedReward = nullptr; + for (const auto& activityReward : activityRewards) { + if (activityReward.activityRating <= rating && (selectedReward == nullptr || activityReward.activityRating > selectedReward->activityRating)) { + selectedReward = &activityReward; + } + } - if (selectedReward == nullptr) { - return; - } + if (selectedReward == nullptr) { + return; + } - uint32_t minCoins = 0; - uint32_t maxCoins = 0; + uint32_t minCoins = 0; + uint32_t maxCoins = 0; - CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); - std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); + CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable(); + std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); - if (currencyTable.size() > 0) { - minCoins = currencyTable[0].minvalue; - maxCoins = currencyTable[0].maxvalue; - } + if (currencyTable.size() > 0) { + minCoins = currencyTable[0].minvalue; + maxCoins = currencyTable[0].maxvalue; + } - DropLoot(player, source, selectedReward->LootMatrixIndex, minCoins, maxCoins); + DropLoot(player, source, selectedReward->LootMatrixIndex, minCoins, maxCoins); } diff --git a/dGame/dUtilities/Loot.h b/dGame/dUtilities/Loot.h index b16c834a..a1c52b63 100644 --- a/dGame/dUtilities/Loot.h +++ b/dGame/dUtilities/Loot.h @@ -8,55 +8,55 @@ class Entity; struct RarityTableEntry { - uint32_t rarity; - float randMax; + uint32_t rarity; + float randMax; }; typedef std::vector RarityTable; struct LootMatrixEntry { - uint32_t lootTableIndex; - uint32_t rarityTableIndex; - float percent; - uint32_t minDrop; - uint32_t maxDrop; + uint32_t lootTableIndex; + uint32_t rarityTableIndex; + float percent; + uint32_t minDrop; + uint32_t maxDrop; }; typedef std::vector LootMatrix; struct LootTableEntry { - LOT itemID; - bool isMissionDrop; + LOT itemID; + bool isMissionDrop; }; typedef std::vector LootTable; // used for glue code with Entity and Player classes namespace Loot { - struct Info { - LWOOBJID id; - LOT lot; - uint32_t count; - }; + struct Info { + LWOOBJID id; + LOT lot; + uint32_t count; + }; } class LootGenerator : public Singleton { - public: - LootGenerator(); +public: + LootGenerator(); - std::unordered_map RollLootMatrix(Entity* player, uint32_t matrixIndex); - std::unordered_map RollLootMatrix(uint32_t matrixIndex); - void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); - void GiveLoot(Entity* player, std::unordered_map& result, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); - void GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); - void DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins); - void DropLoot(Entity* player, Entity* killedObject, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins); - void DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); + std::unordered_map RollLootMatrix(Entity* player, uint32_t matrixIndex); + std::unordered_map RollLootMatrix(uint32_t matrixIndex); + void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::NONE); + void GiveLoot(Entity* player, std::unordered_map& result, eLootSourceType lootSourceType = eLootSourceType::NONE); + void GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); + void DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins); + void DropLoot(Entity* player, Entity* killedObject, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins); + void DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); - private: - std::unordered_map m_ItemRarities; - std::unordered_map m_RarityTables; - std::unordered_map m_LootMatrices; - std::unordered_map m_LootTables; +private: + std::unordered_map m_ItemRarities; + std::unordered_map m_RarityTables; + std::unordered_map m_LootMatrices; + std::unordered_map m_LootTables; }; diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 7e77cd77..5dc55765 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -13,7 +13,6 @@ #include "Entity.h" #include "Character.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "dLogger.h" #include "EntityManager.h" #include "InventoryComponent.h" @@ -22,10 +21,14 @@ #include "MissionComponent.h" #include "ChatPackets.h" #include "Character.h" +#include "dZoneManager.h" +#include "WorldConfig.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" +#include "eConnectionType.h" void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment, - const uint16_t attachmentCount) -{ + const uint16_t attachmentCount) { SendMail( LWOOBJID_EMPTY, ServerName, @@ -40,8 +43,7 @@ void Mail::SendMail(const Entity* recipient, const std::string& subject, const s } void Mail::SendMail(const LWOOBJID recipient, const std::string& recipientName, const std::string& subject, - const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) -{ + const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) { SendMail( LWOOBJID_EMPTY, ServerName, @@ -56,8 +58,7 @@ void Mail::SendMail(const LWOOBJID recipient, const std::string& recipientName, } void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, const Entity* recipient, const std::string& subject, - const std::string& body, const LOT attachment, const uint16_t attachmentCount) -{ + const std::string& body, const LOT attachment, const uint16_t attachmentCount) { SendMail( sender, senderName, @@ -72,18 +73,17 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, const } void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJID recipient, - const std::string& recipientName, const std::string& subject, const std::string& body, const LOT attachment, - const uint16_t attachmentCount, const SystemAddress& sysAddr) -{ + const std::string& recipientName, const std::string& subject, const std::string& body, const LOT attachment, + const uint16_t attachmentCount, const SystemAddress& sysAddr) { auto* ins = Database::CreatePreppedStmt("INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)"); ins->setUInt(1, sender); - ins->setString(2, senderName); + ins->setString(2, senderName.c_str()); ins->setUInt(3, recipient); ins->setString(4, recipientName.c_str()); ins->setUInt64(5, time(nullptr)); - ins->setString(6, subject); - ins->setString(7, body); + ins->setString(6, subject.c_str()); + ins->setString(7, body.c_str()); ins->setUInt(8, 0); ins->setInt(9, attachment); ins->setInt(10, 0); @@ -93,7 +93,7 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ delete ins; if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server - + SendNotification(sysAddr, 1); //Show the "one new mail" message } @@ -130,7 +130,7 @@ void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAd int mailStuffID = 0; packet->Read(mailStuffID); - std::async(std::launch::async, [packet, &sysAddr, entity, mailStuffID]() { + auto returnVal = std::async(std::launch::async, [packet, &sysAddr, entity, mailStuffID]() { Mail::MailMessageID stuffID = MailMessageID(mailStuffID); switch (stuffID) { case MailMessageID::AttachmentCollect: @@ -152,9 +152,9 @@ void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAd Mail::HandleSendMail(packet, sysAddr, entity); break; default: - Game::logger->Log("Mail", "Unhandled and possibly undefined MailStuffID: %i\n", int(stuffID)); + Game::logger->Log("Mail", "Unhandled and possibly undefined MailStuffID: %i", int(stuffID)); } - }); + }); } void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity) { @@ -167,8 +167,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd if (!character) return; - if (character->HasPermission(PermissionMap::RestrictedMailAccess)) - { + if (character->HasPermission(ePermissionMap::RestrictedMailAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -196,15 +195,15 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd uint32_t itemID = static_cast(attachmentID); LOT itemLOT = 0; //Inventory::InventoryType itemType; - int mailCost = 25; + int mailCost = dZoneManager::Instance()->GetWorldConfig()->mailBaseFee; int stackSize = 0; - auto inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); Item* item = nullptr; if (itemID > 0 && attachmentCount > 0 && inv) { item = inv->FindItemById(attachmentID); if (item) { - mailCost += (item->GetInfo().baseValue * 0.1f); + mailCost += (item->GetInfo().baseValue * dZoneManager::Instance()->GetWorldConfig()->mailPercentAttachmentFee); stackSize = item->GetCount(); itemLOT = item->GetLot(); } else { @@ -227,8 +226,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd if (res->rowsCount() > 0) { while (res->next()) receiverID = res->getUInt(1); - } - else { + } else { Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound); delete stmt; delete res; @@ -242,8 +240,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID == character->GetObjectID()) { Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf); return; - } - else { + } else { uint64_t currentTime = time(NULL); sql::PreparedStatement* ins = Database::CreatePreppedStmt("INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)"); ins->setUInt(1, character->GetObjectID()); @@ -262,19 +259,18 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd } Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::Success); - entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::LOOT_SOURCE_MAIL); + entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL); - Game::logger->Log("Mail", "Seeing if we need to remove item with ID/count/LOT: %i %i %i\n", itemID, attachmentCount, itemLOT); + Game::logger->Log("Mail", "Seeing if we need to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT); if (inv && itemLOT != 0 && attachmentCount > 0 && item) { - Game::logger->Log("Mail", "Trying to remove item with ID/count/LOT: %i %i %i\n", itemID, attachmentCount, itemLOT); + Game::logger->Log("Mail", "Trying to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT); inv->RemoveItem(itemLOT, attachmentCount, INVALID, true); auto* missionCompoent = entity->GetComponent(); - if (missionCompoent != nullptr) - { - missionCompoent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount); + if (missionCompoent != nullptr) { + missionCompoent->Progress(eMissionTaskType::GATHER, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount); } } @@ -287,7 +283,7 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys sql::ResultSet* res = stmt->executeQuery(); RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::MailData)); bitStream.Write(int(0)); @@ -298,9 +294,9 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys while (res->next()) { bitStream.Write(res->getUInt64(1)); //MailID - /*std::u16string subject = GeneralUtils::ASCIIToUTF16(res->getString(7)); - std::u16string body = GeneralUtils::ASCIIToUTF16(res->getString(8)); - std::u16string sender = GeneralUtils::ASCIIToUTF16(res->getString(3)); + /*std::u16string subject = GeneralUtils::UTF8ToUTF16(res->getString(7)); + std::u16string body = GeneralUtils::UTF8ToUTF16(res->getString(8)); + std::u16string sender = GeneralUtils::UTF8ToUTF16(res->getString(3)); WriteToPacket(&bitStream, subject, 50); WriteToPacket(&bitStream, body, 400); @@ -360,10 +356,10 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres attachmentCount = res->getInt(2); } - auto inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::LOOT_SOURCE_MAIL); + inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL); Mail::SendAttachmentRemoveConfirm(sysAddr, mailID); @@ -397,7 +393,7 @@ void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAdd } void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) { - std::async(std::launch::async, [&]() { + auto returnVal = std::async(std::launch::async, [&]() { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM mail WHERE receiver_id=? AND was_read=0"); stmt->setUInt(1, objectID); sql::ResultSet* res = stmt->executeQuery(); @@ -405,12 +401,12 @@ void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t obje if (res->rowsCount() > 0) Mail::SendNotification(sysAddr, res->rowsCount()); delete res; delete stmt; - }); + }); } void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::SendResponse)); bitStream.Write(int(response)); Game::server->Send(&bitStream, sysAddr, false); @@ -418,7 +414,7 @@ void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse respo void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); uint64_t messageType = 2; uint64_t s1 = 0; uint64_t s2 = 0; @@ -437,7 +433,7 @@ void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::AttachmentCollectConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); @@ -446,7 +442,7 @@ void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t ma void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::MailDeleteConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); @@ -460,7 +456,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAIL); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::MailReadConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); diff --git a/dGame/dUtilities/Mail.h b/dGame/dUtilities/Mail.h index 4853db18..c8eabe6b 100644 --- a/dGame/dUtilities/Mail.h +++ b/dGame/dUtilities/Mail.h @@ -56,7 +56,7 @@ namespace Mail { uint16_t attachmentCount, const SystemAddress& sysAddr ); - + void SendMail( LWOOBJID sender, const std::string& senderName, @@ -92,4 +92,4 @@ namespace Mail { void SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID); void SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID); void SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID); -}; \ No newline at end of file +}; diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index bd10b814..8602586c 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -1,4 +1,4 @@ -#include "Preconditions.h" +#include "Preconditions.h" #include "Game.h" #include "dLogger.h" @@ -9,42 +9,39 @@ #include "MissionComponent.h" #include "Character.h" #include "CharacterComponent.h" +#include "LevelProgressionComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" - +#include "eMissionState.h" std::map Preconditions::cache = {}; Precondition::Precondition(const uint32_t condition) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT type, targetLOT, targetCount FROM Preconditions WHERE id = ?;"); - query.bind(1, (int) condition); + query.bind(1, (int)condition); auto result = query.execQuery(); - if (result.eof()) - { + if (result.eof()) { this->type = PreconditionType::ItemEquipped; this->count = 1; this->values = { 0 }; - Game::logger->Log("Precondition", "Failed to find precondition of id (%i)!\n", condition); + Game::logger->Log("Precondition", "Failed to find precondition of id (%i)!", condition); return; } this->type = static_cast(result.fieldIsNull(0) ? 0 : result.getIntField(0)); - if (!result.fieldIsNull(1)) - { + if (!result.fieldIsNull(1)) { std::istringstream stream(result.getStringField(1)); std::string token; - while (std::getline(stream, token, ',')) - { + while (std::getline(stream, token, ',')) { uint32_t value; - if (GeneralUtils::TryParse(token, value)) - { + if (GeneralUtils::TryParse(token, value)) { this->values.push_back(value); } } @@ -56,10 +53,8 @@ Precondition::Precondition(const uint32_t condition) { } -bool Precondition::Check(Entity* player, bool evaluateCosts) const -{ - if (values.empty()) - { +bool Precondition::Check(Entity* player, bool evaluateCosts) const { + if (values.empty()) { return true; // There are very few of these } @@ -99,22 +94,18 @@ bool Precondition::Check(Entity* player, bool evaluateCosts) const auto passedAny = false; - for (const auto value : values) - { + for (const auto value : values) { const auto passed = CheckValue(player, value, evaluateCosts); - if (passed && any) - { + if (passed && any) { return true; } - if (!passed && !any) - { + if (!passed && !any) { return false; } - if (passed) - { + if (passed) { passedAny = true; } } @@ -123,18 +114,16 @@ bool Precondition::Check(Entity* player, bool evaluateCosts) const } -bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluateCosts) const -{ +bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluateCosts) const { auto* missionComponent = player->GetComponent(); auto* inventoryComponent = player->GetComponent(); auto* destroyableComponent = player->GetComponent(); - auto* characterComponent = player->GetComponent(); + auto* levelComponent = player->GetComponent(); auto* character = player->GetCharacter(); Mission* mission; - switch (type) - { + switch (type) { case PreconditionType::ItemEquipped: return inventoryComponent->IsEquipped(value); case PreconditionType::ItemNotEquipped: @@ -153,19 +142,19 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat case PreconditionType::HasAchievement: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::COMPLETE; case PreconditionType::MissionAvailable: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_AVAILABLE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::AVAILABLE; case PreconditionType::OnMission: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_ACTIVE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::ACTIVE; case PreconditionType::MissionComplete: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE; + return mission == nullptr ? false : mission->GetMissionState() >= eMissionState::COMPLETE; case PreconditionType::PetDeployed: return false; // TODO case PreconditionType::HasFlag: @@ -179,20 +168,16 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat case PreconditionType::IsPetTaming: return false; // TODO case PreconditionType::HasFaction: - for (const auto faction : destroyableComponent->GetFactionIDs()) - { - if (faction == static_cast(value)) - { + for (const auto faction : destroyableComponent->GetFactionIDs()) { + if (faction == static_cast(value)) { return true; } } return false; case PreconditionType::DoesNotHaveFaction: - for (const auto faction : destroyableComponent->GetFactionIDs()) - { - if (faction == static_cast(value)) - { + for (const auto faction : destroyableComponent->GetFactionIDs()) { + if (faction == static_cast(value)) { return false; } } @@ -207,16 +192,14 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat case PreconditionType::NoInteraction: return false; // TODO case PreconditionType::HasLevel: - return characterComponent->GetLevel() >= value; + return levelComponent->GetLevel() >= value; default: return true; // There are a couple more unknown preconditions. Always return true in this case. } } -PreconditionExpression::PreconditionExpression(const std::string& conditions) -{ - if (conditions.empty()) - { +PreconditionExpression::PreconditionExpression(const std::string& conditions) { + if (conditions.empty()) { empty = true; return; @@ -229,17 +212,14 @@ PreconditionExpression::PreconditionExpression(const std::string& conditions) auto done = false; - for (auto i = 0u; i < conditions.size(); ++i) - { - if (done) - { + for (auto i = 0u; i < conditions.size(); ++i) { + if (done) { break; } const auto character = conditions[i]; - switch (character) - { + switch (character) { case '|': bor = true; b << conditions.substr(i + 1); @@ -276,44 +256,30 @@ PreconditionExpression::PreconditionExpression(const std::string& conditions) const auto aString = a.str(); - if (!aString.empty()) - { + if (!aString.empty()) { this->condition = std::stoul(a.str()); - } - else - { + } else { this->condition = 0; } const auto bString = b.str(); - if (!bString.empty()) - { + if (!bString.empty()) { this->next = new PreconditionExpression(bString); - } - else - { + } else { this->next = nullptr; } } -bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const -{ - if (empty) - { - return true; - } - - if (player->GetGMLevel() >= 9) // Developers can skip this for testing - { +bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const { + if (empty) { return true; } const auto a = Preconditions::Check(player, condition, evaluateCosts); - if (!a) - { + if (!a) { GameMessages::SendNotifyClientFailedPrecondition(player->GetObjectID(), player->GetSystemAddress(), u"", condition); } @@ -322,24 +288,19 @@ bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const return m_or ? a || b : a && b; } -PreconditionExpression::~PreconditionExpression() -{ +PreconditionExpression::~PreconditionExpression() { delete next; } -bool Preconditions::Check(Entity* player, const uint32_t condition, bool evaluateCosts) -{ +bool Preconditions::Check(Entity* player, const uint32_t condition, bool evaluateCosts) { Precondition* precondition; const auto& index = cache.find(condition); - if (index != cache.end()) - { + if (index != cache.end()) { precondition = index->second; - } - else - { + } else { precondition = new Precondition(condition); cache.insert_or_assign(condition, precondition); @@ -349,16 +310,13 @@ bool Preconditions::Check(Entity* player, const uint32_t condition, bool evaluat } -PreconditionExpression Preconditions::CreateExpression(const std::string& conditions) -{ +PreconditionExpression Preconditions::CreateExpression(const std::string& conditions) { return PreconditionExpression(conditions); } -Preconditions::~Preconditions() -{ - for (const auto& condition : cache) - { +Preconditions::~Preconditions() { + for (const auto& condition : cache) { delete condition.second; } diff --git a/dGame/dUtilities/Preconditions.h b/dGame/dUtilities/Preconditions.h index 0ceeb32a..2b6e1216 100644 --- a/dGame/dUtilities/Preconditions.h +++ b/dGame/dUtilities/Preconditions.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include "Entity.h" @@ -6,26 +6,26 @@ enum class PreconditionType { - ItemEquipped, - ItemNotEquipped, - HasItem, - DoesNotHaveItem, - HasAchievement, - MissionAvailable, - OnMission, - MissionComplete, - PetDeployed, - HasFlag, - WithinShape, - InBuild, - TeamCheck, - IsPetTaming, - HasFaction, - DoesNotHaveFaction, - HasRacingLicence, - DoesNotHaveRacingLicence, - LegoClubMember, - NoInteraction, + ItemEquipped, + ItemNotEquipped, + HasItem, + DoesNotHaveItem, + HasAchievement, + MissionAvailable, + OnMission, + MissionComplete, + PetDeployed, + HasFlag, + WithinShape, + InBuild, + TeamCheck, + IsPetTaming, + HasFaction, + DoesNotHaveFaction, + HasRacingLicence, + DoesNotHaveRacingLicence, + LegoClubMember, + NoInteraction, HasLevel = 22 }; @@ -33,49 +33,49 @@ enum class PreconditionType class Precondition final { public: - explicit Precondition(uint32_t condition); - - bool Check(Entity* player, bool evaluateCosts = false) const; - + explicit Precondition(uint32_t condition); + + bool Check(Entity* player, bool evaluateCosts = false) const; + private: - bool CheckValue(Entity* player, uint32_t value, bool evaluateCosts = false) const; - - PreconditionType type; + bool CheckValue(Entity* player, uint32_t value, bool evaluateCosts = false) const; - std::vector values; + PreconditionType type; - uint32_t count; + std::vector values; + + uint32_t count; }; class PreconditionExpression final { public: - explicit PreconditionExpression(const std::string& conditions); + explicit PreconditionExpression(const std::string& conditions); + + bool Check(Entity* player, bool evaluateCosts = false) const; + + ~PreconditionExpression(); - bool Check(Entity* player, bool evaluateCosts = false) const; - - ~PreconditionExpression(); - private: - uint32_t condition = 0; + uint32_t condition = 0; - bool m_or = false; + bool m_or = false; - bool empty = false; + bool empty = false; - PreconditionExpression* next = nullptr; + PreconditionExpression* next = nullptr; }; class Preconditions final { public: - static bool Check(Entity* player, uint32_t condition, bool evaluateCosts = false); + static bool Check(Entity* player, uint32_t condition, bool evaluateCosts = false); - static PreconditionExpression CreateExpression(const std::string& conditions); + static PreconditionExpression CreateExpression(const std::string& conditions); ~Preconditions(); - + private: - static std::map cache; + static std::map cache; }; diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 8631f760..16db62a6 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -50,6 +50,9 @@ #include "Item.h" #include "PropertyManagementComponent.h" #include "PacketUtils.h" +#include "Loot.h" +#include "EntityInfo.h" +#include "LUTriggers.h" #include "Player.h" #include "PhantomPhysicsComponent.h" #include "ProximityMonitorComponent.h" @@ -60,100 +63,93 @@ #include "BuffComponent.h" #include "SkillComponent.h" #include "VanityUtilities.h" -#include "GameConfig.h" #include "ScriptedActivityComponent.h" +#include "LevelProgressionComponent.h" +#include "AssetManager.h" +#include "BinaryPathFinder.h" +#include "dConfig.h" +#include "eBubbleType.h" +#include "AMFFormat.h" +#include "MovingPlatformComponent.h" +#include "eMissionState.h" +#include "TriggerComponent.h" +#include "eServerDisconnectIdentifiers.h" +#include "eObjectBits.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" +#include "eControlScheme.h" +#include "eConnectionType.h" +#include "eChatInternalMessageType.h" +#include "eMasterMessageType.h" + +#include "CDObjectsTable.h" +#include "CDZoneTableTable.h" void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) { - std::string chatCommand; - std::vector args; + auto commandCopy = command; + // Sanity check that a command was given + if (command.empty() || command.front() != u'/') return; + commandCopy.erase(commandCopy.begin()); - uint32_t breakIndex = 0; - for (uint32_t i = 1; i < command.size(); ++i) { - if (command[i] == L' ') { - breakIndex = i; - break; - } + // Split the command by spaces + std::string chatCommand; + std::vector args; + auto wideCommand = GeneralUtils::SplitString(commandCopy, u' '); + if (wideCommand.empty()) return; - chatCommand.push_back(static_cast(command[i])); - breakIndex++; - } + // Convert the command to lowercase + chatCommand = GeneralUtils::UTF16ToWTF8(wideCommand.front()); + std::transform(chatCommand.begin(), chatCommand.end(), chatCommand.begin(), ::tolower); + wideCommand.erase(wideCommand.begin()); - uint32_t index = ++breakIndex; - while (true) { - std::string arg; + // Convert the arguements to not u16strings + for (auto wideArg : wideCommand) args.push_back(GeneralUtils::UTF16ToWTF8(wideArg)); - while (index < command.size()) { - if (command[index] == L' ') { - args.push_back(arg); - arg = ""; - index++; - continue; - } + User* user = UserManager::Instance()->GetUser(sysAddr); + if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > eGameMasterLevel::CIVILIAN) { + if (args.size() != 1) return; - arg.push_back(static_cast(command[index])); - index++; - } + uint32_t level_intermed = 0; - if (arg != "") { - args.push_back(arg); - } - - break; - } - - //Game::logger->Log("SlashCommandHandler", "Received chat command \"%s\"\n", GeneralUtils::UTF16ToWTF8(command).c_str()); - - User* user = UserManager::Instance()->GetUser(sysAddr); - if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { - if (args.size() != 1) return; - - uint32_t level; - - if (!GeneralUtils::TryParse(args[0], level)) - { + if (!GeneralUtils::TryParse(args[0], level_intermed)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid gm level."); return; } + eGameMasterLevel level = static_cast(level_intermed); #ifndef DEVELOPER_SERVER - if (user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) - { - level = GAME_MASTER_LEVEL_CIVILIAN; + if (user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER) { + level = eGameMasterLevel::CIVILIAN; } #endif - if (level > user->GetMaxGMLevel()) - { + if (level > user->GetMaxGMLevel()) { level = user->GetMaxGMLevel(); } - if (level == entity->GetGMLevel()) return; - bool success = user->GetMaxGMLevel() >= level; + if (level == entity->GetGMLevel()) return; + bool success = user->GetMaxGMLevel() >= level; - if (success) { + if (success) { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && level == GAME_MASTER_LEVEL_CIVILIAN) - { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && level == eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - } - else if (entity->GetGMLevel() == GAME_MASTER_LEVEL_CIVILIAN && level > GAME_MASTER_LEVEL_CIVILIAN) - { + } else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN && level > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); } WorldPackets::SendGMLevelChange(sysAddr, success, user->GetMaxGMLevel(), entity->GetGMLevel(), level); GameMessages::SendChatModeUpdate(entity->GetObjectID(), level); entity->SetGMLevel(level); - Game::logger->Log("SlashCommandHandler", "User %s (%i) has changed their GM level to %i for charID %llu\n", user->GetUsername().c_str(), user->GetAccountID(), level, entity->GetObjectID()); + Game::logger->Log("SlashCommandHandler", "User %s (%i) has changed their GM level to %i for charID %llu", user->GetUsername().c_str(), user->GetAccountID(), level, entity->GetObjectID()); } } #ifndef DEVELOPER_SERVER - if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER)) - { - WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), GAME_MASTER_LEVEL_CIVILIAN); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), GAME_MASTER_LEVEL_CIVILIAN); - entity->SetGMLevel(GAME_MASTER_LEVEL_CIVILIAN); + if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER)) { + WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), eGameMasterLevel::CIVILIAN); + GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); + entity->SetGMLevel(eGameMasterLevel::CIVILIAN); GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); @@ -161,6 +157,19 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #endif + if (chatCommand == "togglenameplate" && (Game::config->GetValue("allow_nameplate_off") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) { + auto* character = entity->GetCharacter(); + + if (character && character->GetBillboardVisible()) { + character->SetBillboardVisible(false); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate has been turned off and is not visible to players currently in this zone."); + } else { + character->SetBillboardVisible(true); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate is now on and visible to all players."); + } + return; + } + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -169,7 +178,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit auto* character = entity->GetComponent(); if (character == nullptr) { - Game::logger->Log("SlashCommandHandler", "Failed to find character component!\n"); + Game::logger->Log("SlashCommandHandler", "Failed to find character component!"); return; } @@ -179,39 +188,34 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::stringstream message; message << character->GetName() << " changed their PVP flag to " << std::to_string(character->GetPvpEnabled()) << "!"; - ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::ASCIIToUTF16(message.str()), true); + ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::UTF8ToUTF16(message.str()), true); return; } - if (chatCommand == "who") - { + if (chatCommand == "who") { ChatPackets::SendSystemMessage( sysAddr, u"Players in this instance: (" + GeneralUtils::to_u16string(Player::GetAllPlayers().size()) + u")" ); - for (auto* player : Player::GetAllPlayers()) - { + for (auto* player : Player::GetAllPlayers()) { const auto& name = player->GetCharacter()->GetName(); ChatPackets::SendSystemMessage( sysAddr, - GeneralUtils::ASCIIToUTF16(player == entity ? name + " (you)" : name) + GeneralUtils::UTF8ToUTF16(player == entity ? name + " (you)" : name) ); } } if (chatCommand == "ping") { - if (!args.empty() && args[0] == "-l") - { + if (!args.empty() && args[0] == "-l") { std::stringstream message; message << "Your latest ping: " << std::to_string(Game::server->GetLatestPing(sysAddr)) << "ms"; ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); - } - else - { + } else { std::stringstream message; message << "Your average ping: " << std::to_string(Game::server->GetPing(sysAddr)) << "ms"; @@ -220,36 +224,14 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "skip-ags") - { - auto* missionComponent = entity->GetComponent(); - - if (missionComponent != nullptr && missionComponent->HasMission(479)) - { - missionComponent->CompleteMission(479); - } - } - - if (chatCommand == "skip-sg") - { - auto* missionComponent = entity->GetComponent(); - - if (missionComponent != nullptr && missionComponent->HasMission(229)) - { - missionComponent->CompleteMission(229); - } - } - - if (chatCommand == "fix-stats") - { + if (chatCommand == "fix-stats") { // Reset skill component and buff component auto* skillComponent = entity->GetComponent(); auto* buffComponent = entity->GetComponent(); auto* destroyableComponent = entity->GetComponent(); // If any of the components are nullptr, return - if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) - { + if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) { return; } @@ -263,9 +245,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit destroyableComponent->FixStats(); } - if (chatCommand == "credits" || chatCommand == "info") - { - const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown("./vanity/CREDITS.md") : VanityUtilities::ParseMarkdown("./vanity/INFO.md"); + if (chatCommand == "credits" || chatCommand == "info") { + const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); { AMFArrayValue args; @@ -276,28 +257,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit args.InsertValue("state", state); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); - - delete state; } - entity->AddCallbackTimer(0.5f, [customText, entity] () - { + entity->AddCallbackTimer(0.5f, [customText, entity]() { AMFArrayValue args; - auto* visiable = new AMFTrueValue(); auto* text = new AMFStringValue(); text->SetStringValue(customText); - args.InsertValue("visible", visiable); + args.InsertValue("visible", new AMFTrueValue()); args.InsertValue("text", text); - Game::logger->Log("SlashCommandHandler", "Sending \n%s\n", customText.c_str()); + Game::logger->Log("SlashCommandHandler", "Sending %s", customText.c_str()); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", &args); - - delete visiable; - delete text; - }); + }); return; } @@ -305,7 +279,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (chatCommand == "leave-zone") { const auto currentZone = dZoneManager::Instance()->GetZone()->GetZoneID().GetMapID(); - auto newZone = 0; + LWOMAPID newZone = 0; if (currentZone % 100 == 0) { ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone."); return; @@ -313,33 +287,32 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit newZone = (currentZone / 100) * 100; } // If new zone would be inaccessible, then default to Avant Gardens. - if (!CheckIfAccessibleZone(newZone)) newZone = 1100; + if (!dZoneManager::Instance()->CheckIfAccessibleZone(newZone)) newZone = 1100; ChatPackets::SendSystemMessage(sysAddr, u"Leaving zone..."); const auto objid = entity->GetObjectID(); - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) - { - auto* entity = EntityManager::Instance()->GetEntity(objid); + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + auto* entity = EntityManager::Instance()->GetEntity(objid); - if (entity == nullptr) { - return; - } + if (entity == nullptr) { + return; + } - const auto sysAddr = entity->GetSystemAddress(); + const auto sysAddr = entity->GetSystemAddress(); - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", entity->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - if (entity->GetCharacter()) { - entity->GetCharacter()->SetZoneID(zoneID); - entity->GetCharacter()->SetZoneInstance(zoneInstance); - entity->GetCharacter()->SetZoneClone(zoneClone); - } + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + } - entity->GetCharacter()->SaveXMLToDatabase(); + entity->GetCharacter()->SaveXMLToDatabase(); - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); }); } @@ -347,23 +320,22 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); const auto& password = args[0]; - ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) - { - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - if (entity->GetCharacter()) { - entity->GetCharacter()->SetZoneID(zoneID); - entity->GetCharacter()->SetZoneInstance(zoneInstance); - entity->GetCharacter()->SetZoneClone(zoneClone); - } + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + } - entity->GetCharacter()->SaveXMLToDatabase(); + entity->GetCharacter()->SaveXMLToDatabase(); - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); }); } - if (user->GetMaxGMLevel() == 0 || entity->GetGMLevel() >= 0) { + if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) { if (chatCommand == "die") { entity->Smash(entity->GetObjectID()); } @@ -389,17 +361,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); } - if (entity->GetGMLevel() == 0) return; + if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return; } // Log command to database auto stmt = Database::CreatePreppedStmt("INSERT INTO command_log (character_id, command) VALUES (?, ?);"); stmt->setInt(1, entity->GetCharacter()->GetID()); stmt->setString(2, GeneralUtils::UTF16ToWTF8(command).c_str()); - stmt->execute(); - delete stmt; + stmt->execute(); + delete stmt; - if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { // could break characters so only allow if GM > 0 + if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 int32_t minifigItemId; if (!GeneralUtils::TryParse(args[1], minifigItemId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); @@ -443,12 +415,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character } - if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size()); GameMessages::SendPlayAnimation(entity, anim); + auto* possessorComponent = entity->GetComponent(); + if (possessorComponent) { + auto* possessedComponent = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + if (possessedComponent) GameMessages::SendPlayAnimation(possessedComponent, anim); + } } - if (chatCommand == "list-spawns" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "list-spawns" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { for (const auto& pair : EntityManager::Instance()->GetSpawnPointEntities()) { ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); } @@ -458,11 +435,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t emoteID; - if (!GeneralUtils::TryParse(args[0], emoteID)) - { + if (!GeneralUtils::TryParse(args[0], emoteID)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid emote ID."); return; } @@ -470,11 +446,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->UnlockEmote(emoteID); } - if (chatCommand == "force-save" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "force-save" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { entity->GetCharacter()->SaveXMLToDatabase(); } - if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); auto* user = UserManager::Instance()->GetUser(args[0]); @@ -489,64 +465,71 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { float boost; - if (!GeneralUtils::TryParse(args[0], boost)) - { + if (!GeneralUtils::TryParse(args[0], boost)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost."); return; } auto* controllablePhysicsComponent = entity->GetComponent(); - if (controllablePhysicsComponent == nullptr) - { - return; - } - + if (!controllablePhysicsComponent) return; controllablePhysicsComponent->SetSpeedMultiplier(boost); + // speedboost possesables + auto possessor = entity->GetComponent(); + if (possessor) { + auto possessedID = possessor->GetPossessable(); + if (possessedID != LWOOBJID_EMPTY) { + auto possessable = EntityManager::Instance()->GetEntity(possessedID); + if (possessable) { + auto* possessControllablePhysicsComponent = possessable->GetComponent(); + if (possessControllablePhysicsComponent) { + possessControllablePhysicsComponent->SetSpeedMultiplier(boost); + } + } + } + } + EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "freecam" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "freecam" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto state = !entity->GetVar(u"freecam"); entity->SetVar(u"freecam", state); - GameMessages::SendSetPlayerControlScheme(entity, static_cast(state ? 9 : 1)); + GameMessages::SendSetPlayerControlScheme(entity, static_cast(state ? 9 : 1)); ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); return; } - if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { uint32_t scheme; - if (!GeneralUtils::TryParse(args[0], scheme)) - { + if (!GeneralUtils::TryParse(args[0], scheme)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid control scheme."); return; } - GameMessages::SendSetPlayerControlScheme(entity, static_cast(scheme)); + GameMessages::SendSetPlayerControlScheme(entity, static_cast(scheme)); ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); return; } - if (chatCommand == "approveproperty" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { + if (chatCommand == "approveproperty" && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { - if (PropertyManagementComponent::Instance() != nullptr) - { + if (PropertyManagementComponent::Instance() != nullptr) { PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); } return; } - if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFStringValue* value = new AMFStringValue(); value->SetStringValue(args[0]); @@ -556,12 +539,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); - delete value; - return; } - if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFTrueValue* value = new AMFTrueValue(); AMFArrayValue amfArgs; @@ -570,93 +551,114 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); - delete value; - return; } - if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - if (args.size() != 1) return; - + if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { uint32_t size; - if (!GeneralUtils::TryParse(args[0], size)) - { + if (!GeneralUtils::TryParse(args.at(0), size)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); return; } - InventoryComponent* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - if (inventory) - { - auto* items = inventory->GetInventory(ITEMS); + eInventoryType selectedInventory = eInventoryType::ITEMS; - items->SetSize(size); + // a possible inventory was provided if we got more than 1 argument + if (args.size() >= 2) { + selectedInventory = eInventoryType::INVALID; + if (!GeneralUtils::TryParse(args.at(1), selectedInventory)) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(args.at(1).begin(), args.at(1).end(), args.at(1).begin(), ::toupper); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(args.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast(index)))) selectedInventory = static_cast(index); + } + } + if (selectedInventory == eInventoryType::INVALID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + + GeneralUtils::ASCIIToUTF16(args.at(1)) + + u" to size " + + GeneralUtils::to_u16string(size)); + } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(selectedInventory); + + inventory->SetSize(size); } return; } - if (chatCommand == "runmacro" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "runmacro" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() != 1) return; // Only process if input does not contain separator charaters if (args[0].find("/") != std::string::npos) return; if (args[0].find("\\") != std::string::npos) return; - std::ifstream infile("./res/macros/" + args[0] + ".scm"); + auto buf = Game::assetManager->GetFileAsBuffer(("macros/" + args[0] + ".scm").c_str()); + + if (!buf.m_Success) { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + return; + } + + std::istream infile(&buf); if (infile.good()) { std::string line; while (std::getline(infile, line)) { SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr); } - } - else { + } else { ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); } + buf.close(); + return; } - if (chatCommand == "addmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "addmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; - if (!GeneralUtils::TryParse(args[0], missionID)) - { + if (!GeneralUtils::TryParse(args[0], missionID)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); return; } - auto comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp) comp->AcceptMission(missionID, true); return; } - if (chatCommand == "completemission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "completemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; - if (!GeneralUtils::TryParse(args[0], missionID)) - { + if (!GeneralUtils::TryParse(args[0], missionID)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); return; } - auto comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp) comp->CompleteMission(missionID, true); return; } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) - { - uint32_t flagId; + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { + int32_t flagId; - if (!GeneralUtils::TryParse(args[0], flagId)) - { + if (!GeneralUtils::TryParse(args[0], flagId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); return; } @@ -664,12 +666,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, true); } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 2) - { - uint32_t flagId; + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 2) { + int32_t flagId; std::string onOffFlag = args[0]; - if (!GeneralUtils::TryParse(args[1], flagId)) - { + if (!GeneralUtils::TryParse(args[1], flagId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); return; } @@ -679,12 +679,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } entity->GetCharacter()->SetPlayerFlag(flagId, onOffFlag == "on"); } - if (chatCommand == "clearflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) - { - uint32_t flagId; + if (chatCommand == "clearflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { + int32_t flagId; - if (!GeneralUtils::TryParse(args[0], flagId)) - { + if (!GeneralUtils::TryParse(args[0], flagId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); return; } @@ -692,18 +690,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, false); } - if (chatCommand == "resetmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "resetmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; - if (!GeneralUtils::TryParse(args[0], missionID)) - { + if (!GeneralUtils::TryParse(args[0], missionID)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); return; } - auto* comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto* comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp == nullptr) { return; @@ -715,26 +712,27 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - mission->SetMissionState(MissionState::MISSION_STATE_ACTIVE); + mission->SetMissionState(eMissionState::ACTIVE); return; } - if (chatCommand == "playeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "playeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { int32_t effectID = 0; if (!GeneralUtils::TryParse(args[0], effectID)) { return; } + // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID, GeneralUtils::ASCIIToUTF16(args[1]), args[2]); } - if (chatCommand == "stopeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "stopeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { GameMessages::SendStopFXEffect(entity, true, args[0]); } - if (chatCommand == "setanntitle" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setanntitle" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -745,7 +743,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setannmsg" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setannmsg" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -756,7 +754,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "announce" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "announce" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (entity->GetCharacter()->GetAnnouncementTitle().size() == 0 || entity->GetCharacter()->GetAnnouncementMessage().size() == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle & /setannmsg <msg> first!"); return; @@ -766,10 +764,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == GAME_MASTER_LEVEL_OPERATOR) { + if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == eGameMasterLevel::OPERATOR) { //Tell the master server that we're going to be shutting down whole "universe": CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_UNIVERSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_UNIVERSE); Game::server->SendToMaster(&bitStream); ChatPackets::SendSystemMessage(sysAddr, u"Sent universe shutdown notification to master."); @@ -778,55 +776,51 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!control) return; - float y = dpWorld::Instance().GetHeightAtPoint(control->GetPosition()); + float y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(control->GetPosition()); std::u16string msg = u"Navmesh height: " + (GeneralUtils::to_u16string(y)); ChatPackets::SendSystemMessage(sysAddr, msg); } - if (chatCommand == "gmadditem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gmadditem" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 1) { uint32_t itemLOT; - if (!GeneralUtils::TryParse(args[0], itemLOT)) - { + if (!GeneralUtils::TryParse(args[0], itemLOT)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); return; } - InventoryComponent * inventory = static_cast<InventoryComponent*>(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - inventory->AddItem(itemLOT, 1, eLootSourceType::LOOT_SOURCE_MODERATION); - } else if(args.size() == 2) { + inventory->AddItem(itemLOT, 1, eLootSourceType::MODERATION); + } else if (args.size() == 2) { uint32_t itemLOT; - if (!GeneralUtils::TryParse(args[0], itemLOT)) - { + if (!GeneralUtils::TryParse(args[0], itemLOT)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); return; } uint32_t count; - if (!GeneralUtils::TryParse(args[1], count)) - { + if (!GeneralUtils::TryParse(args[1], count)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item count."); return; } - InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - inventory->AddItem(itemLOT, count, eLootSourceType::LOOT_SOURCE_MODERATION); - } - else { + inventory->AddItem(itemLOT, count, eLootSourceType::MODERATION); + } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /gmadditem <lot>"); } } - if (chatCommand == "mailitem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_MODERATOR && args.size() >= 2) { + if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { const auto& playerName = args[0]; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;"); @@ -841,8 +835,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit delete stmt; delete res; - if (receiverID == 0) - { + if (receiverID == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); return; @@ -850,8 +843,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit uint32_t lot; - if (!GeneralUtils::TryParse(args[1], lot)) - { + if (!GeneralUtils::TryParse(args[1], lot)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); return; } @@ -877,72 +869,63 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setname" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "setname" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = ""; - for (const auto& arg : args) - { + for (const auto& arg : args) { name += arg + " "; } - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if (chatCommand == "title" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "title" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = entity->GetCharacter()->GetName() + " - "; - for (const auto& arg : args) - { + for (const auto& arg : args) { name += arg + " "; } - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { - NiPoint3 pos {}; + if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { + NiPoint3 pos{}; if (args.size() == 3) { float x, y, z; - if (!GeneralUtils::TryParse(args[0], x)) - { + if (!GeneralUtils::TryParse(args[0], x)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); return; } - if (!GeneralUtils::TryParse(args[1], y)) - { + if (!GeneralUtils::TryParse(args[1], y)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid y."); return; } - if (!GeneralUtils::TryParse(args[2], z)) - { + if (!GeneralUtils::TryParse(args[2], z)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); return; } - pos.SetX(x); - pos.SetY(y); - pos.SetZ(z); + pos.SetX(x); + pos.SetY(y); + pos.SetZ(z); - Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to %f, %f, %f\n", entity->GetObjectID(), pos.x, pos.y, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else if (args.size() == 2) { + Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else if (args.size() == 2) { float x, z; - if (!GeneralUtils::TryParse(args[0], x)) - { + if (!GeneralUtils::TryParse(args[0], x)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); return; } - if (!GeneralUtils::TryParse(args[1], z)) - { + if (!GeneralUtils::TryParse(args[1], z)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); return; } @@ -951,106 +934,119 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit pos.SetY(0.0f); pos.SetZ(z); - Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to X: %f, Z: %f\n", entity->GetObjectID(), pos.x, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); - } + Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); + } + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - - if (possessorComponent != nullptr) - { + if (possessorComponent) { auto* possassableEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - if (possassableEntity != nullptr) - { + if (possassableEntity != nullptr) { auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>(); - - if (vehiclePhysicsComponent != nullptr) - { + if (vehiclePhysicsComponent) { vehiclePhysicsComponent->SetPosition(pos); - EntityManager::Instance()->SerializeEntity(possassableEntity); - - Game::logger->Log("ClientPackets", "Forced updated vehicle position\n"); - } + } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr); } } } - if (chatCommand == "tpall" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "tpall" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto pos = entity->GetPosition(); - const auto characters = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); + const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); - for (auto* character : characters) - { + for (auto* character : characters) { GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); } return; } - if (chatCommand == "dismount" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { - PossessorComponent* possessorComponent; - if (entity->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { - Entity* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - if (!vehicle) return; + if (chatCommand == "dismount" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto possessableId = possessorComponent->GetPossessable(); + if (possessableId != LWOOBJID_EMPTY) { + auto* possessableEntity = EntityManager::Instance()->GetEntity(possessableId); + if (possessableEntity) possessorComponent->Dismount(possessableEntity, true); + } + } + } - PossessableComponent* possessableComponent; - if (vehicle->TryGetComponent(COMPONENT_TYPE_POSSESSABLE, possessableComponent)) { - possessableComponent->SetPossessor(LWOOBJID_EMPTY); - possessorComponent->SetPossessable(LWOOBJID_EMPTY); + if (chatCommand == "fly" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { + auto* character = entity->GetCharacter(); - EntityManager::Instance()->SerializeEntity(vehicle); - EntityManager::Instance()->SerializeEntity(entity); + if (character) { + bool isFlying = character->GetIsFlying(); + + if (isFlying) { + GameMessages::SendSetJetPackMode(entity, false); + + character->SetIsFlying(false); + } else { + float speedScale = 1.0f; + + if (args.size() >= 1) { + float tempScaleStore; + + if (GeneralUtils::TryParse<float>(args[0], tempScaleStore)) { + speedScale = tempScaleStore; + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to parse speed scale argument."); + } + } + + float airSpeed = 20 * speedScale; + float maxAirSpeed = 30 * speedScale; + float verticalVelocity = 1.5 * speedScale; + + GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); + + character->SetIsFlying(true); } } } //------- GM COMMANDS TO ACTUALLY MODERATE -------- - if (chatCommand == "mute" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { + if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { if (args.size() >= 1) { auto* player = Player::GetPlayer(args[0]); uint32_t accountId = 0; LWOOBJID characterId = 0; - if (player == nullptr) - { + if (player == nullptr) { auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id, id FROM charinfo WHERE name=? LIMIT 1;"); accountQuery->setString(1, args[0]); auto result = accountQuery->executeQuery(); - if (result->rowsCount() > 0) - { + if (result->rowsCount() > 0) { while (result->next()) { accountId = result->getUInt(1); characterId = result->getUInt64(2); - characterId = GeneralUtils::SetBit(characterId, OBJECT_BIT_CHARACTER); - characterId = GeneralUtils::SetBit(characterId, OBJECT_BIT_PERSISTENT); + GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); + GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); } } delete accountQuery; delete result; - if (accountId == 0) - { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::ASCIIToUTF16(args[0])); + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); return; } - } - else - { + } else { accountId = player->GetParentUser()->GetAccountID(); characterId = player->GetCharacter()->GetID(); } @@ -1059,21 +1055,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit time_t expire = 1; // Default to indefinate mute - if (args.size() >= 2) - { + if (args.size() >= 2) { uint32_t days = 0; uint32_t hours = 0; - if (!GeneralUtils::TryParse(args[1], days)) - { + if (!GeneralUtils::TryParse(args[1], days)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); return; } - if (args.size() >= 3) - { - if (!GeneralUtils::TryParse(args[2], hours)) - { + if (args.size() >= 3) { + if (!GeneralUtils::TryParse(args[2], hours)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid hours."); return; @@ -1094,82 +1086,73 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit char buffer[32] = "brought up for review.\0"; - if (expire != 1) - { - std::tm * ptm = std::localtime(&expire); + if (expire != 1) { + std::tm* ptm = std::localtime(&expire); // Format: Mo, 15.06.2009 20:20:00 std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); } const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); - ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::ASCIIToUTF16(args[0]) + u" until " + timeStr); + ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(args[0]) + u" until " + timeStr); //Notify chat about it CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); bitStream.Write(characterId); bitStream.Write(expire); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); - } - else { + } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>"); } } - if (chatCommand == "kick" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { + if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); - if (player == nullptr) - { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::ASCIIToUTF16(args[0])); - + std::u16string username = GeneralUtils::UTF8ToUTF16(args[0]); + if (player == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); return; } - Game::server->Disconnect(player->GetSystemAddress(), SERVER_DISCON_KICK); + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); - ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + GeneralUtils::ASCIIToUTF16(args[0])); - } - else { + ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); + } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick <username>"); } } - if (chatCommand == "ban" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_SENIOR_MODERATOR) { + if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); uint32_t accountId = 0; - if (player == nullptr) - { + if (player == nullptr) { auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id FROM charinfo WHERE name=? LIMIT 1;"); accountQuery->setString(1, args[0]); auto result = accountQuery->executeQuery(); - if (result->rowsCount() > 0) - { + if (result->rowsCount() > 0) { while (result->next()) accountId = result->getUInt(1); } delete accountQuery; delete result; - if (accountId == 0) - { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::ASCIIToUTF16(args[0])); + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); return; } - } - else - { + } else { accountId = player->GetParentUser()->GetAccountID(); } @@ -1181,22 +1164,20 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit delete userUpdate; - if (player != nullptr) - { - Game::server->Disconnect(player->GetSystemAddress(), SERVER_DISCON_KICK); + if (player != nullptr) { + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); } ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(args[0])); - } - else { + } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban <username>"); } } //------------------------------------------------- - if (chatCommand == "buffme" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + if (chatCommand == "buffme" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(999); dest->SetMaxHealth(999.0f); @@ -1205,14 +1186,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit dest->SetImagination(999); dest->SetMaxImagination(999.0f); } - EntityManager::Instance()->SerializeEntity(entity); - } + EntityManager::Instance()->SerializeEntity(entity); + } - if (chatCommand == "startcelebration" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "startcelebration" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { int32_t celebration; - if (!GeneralUtils::TryParse(args[0], celebration)) - { + if (!GeneralUtils::TryParse(args[0], celebration)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid celebration."); return; } @@ -1220,8 +1200,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration); } - if (chatCommand == "buffmed" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + if (chatCommand == "buffmed" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(9); dest->SetMaxHealth(9.0f); @@ -1230,45 +1210,50 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit dest->SetImagination(9); dest->SetMaxImagination(9.0f); } - EntityManager::Instance()->SerializeEntity(entity); - } + EntityManager::Instance()->SerializeEntity(entity); + } - if (chatCommand == "refillstats" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "refillstats" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth((int)dest->GetMaxHealth()); dest->SetArmor((int)dest->GetMaxArmor()); dest->SetImagination((int)dest->GetMaxImagination()); } - EntityManager::Instance()->SerializeEntity(entity); - } + EntityManager::Instance()->SerializeEntity(entity); + } - if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "lookup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); + // Concatenate all of the arguments into a single query so a multi word query can be used properly. + std::string conditional = args[0]; + args.erase(args.begin()); + for (auto& argument : args) { + conditional += ' ' + argument; + } - const std::string query_text = "%" + args[0] + "%"; + const std::string query_text = "%" + conditional + "%"; query.bind(1, query_text.c_str()); auto tables = query.execQuery(); - while (!tables.eof()) { - std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message, message.size())); - tables.nextRow(); - } - } + while (!tables.eof()) { + std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size())); + tables.nextRow(); + } + } - if (chatCommand == "spawn" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { - ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); - if (!comp) return; + if (chatCommand == "spawn" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + if (!comp) return; uint32_t lot; - if (!GeneralUtils::TryParse(args[0], lot)) - { + if (!GeneralUtils::TryParse(args[0], lot)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); return; } @@ -1288,26 +1273,95 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } + auto vehiclePhysicsComponent = newEntity->GetComponent<VehiclePhysicsComponent>(); + if (vehiclePhysicsComponent) { + auto newRot = newEntity->GetRotation(); + auto angles = newRot.GetEulerAngles(); + // make it right side up + angles.x -= PI; + // make it going in the direction of the player + angles.y -= PI; + newRot = NiQuaternion::FromEulerAngles(angles); + newEntity->SetRotation(newRot); + } + EntityManager::Instance()->ConstructEntity(newEntity); } - if ((chatCommand == "giveuscore") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "spawngroup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { + auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + if (!controllablePhysicsComponent) return; + + LOT lot{}; + uint32_t numberToSpawn{}; + float radiusToSpawnWithin{}; + + if (!GeneralUtils::TryParse(args[0], lot)) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + if (!GeneralUtils::TryParse(args[1], numberToSpawn) && numberToSpawn > 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); + return; + } + + // Must spawn within a radius of at least 0.0f + if (!GeneralUtils::TryParse(args[2], radiusToSpawnWithin) && radiusToSpawnWithin < 0.0f) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); + return; + } + + EntityInfo info; + info.lot = lot; + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + auto playerPosition = controllablePhysicsComponent->GetPosition(); + while (numberToSpawn > 0) { + auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); + auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); + + // Set the position to the generated random position plus the player position. This will + // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. + info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); + info.rot = NiQuaternion(); + + auto newEntity = EntityManager::Instance()->CreateEntity(info); + if (newEntity == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); + return; + } + + EntityManager::Instance()->ConstructEntity(newEntity); + numberToSpawn--; + } + } + + if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t uscore; - if (!GeneralUtils::TryParse(args[0], uscore)) - { + if (!GeneralUtils::TryParse(args[0], uscore)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid uscore."); return; } CharacterComponent* character = entity->GetComponent<CharacterComponent>(); if (character) character->SetUScore(character->GetUScore() + uscore); - // LOOT_SOURCE_MODERATION should work but it doesn't. Relog to see uscore changes - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MODERATION); + // MODERATION should work but it doesn't. Relog to see uscore changes + + eLootSourceType lootType = eLootSourceType::MODERATION; + + int32_t type; + if (args.size() >= 2 && GeneralUtils::TryParse(args[1], type)) { + lootType = (eLootSourceType)type; + } + + GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); } - if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { // We may be trying to set a specific players level to a level. If so override the entity with the requested players. std::string requestedPlayerToSetLevelOf = ""; if (args.size() > 1) { @@ -1316,12 +1370,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit auto requestedPlayer = Player::GetPlayer(requestedPlayerToSetLevelOf); if (!requestedPlayer) { - ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::ASCIIToUTF16(requestedPlayerToSetLevelOf) + u")."); + ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); return; } if (!requestedPlayer->GetOwner()) { - ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::ASCIIToUTF16(requestedPlayerToSetLevelOf) + u")."); + ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); return; } @@ -1331,14 +1385,15 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit uint32_t oldLevel; // first check the level is valid - if (!GeneralUtils::TryParse(args[0], requestedLevel)) - { + if (!GeneralUtils::TryParse(args[0], requestedLevel)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); return; } // query to set our uscore to the correct value for this level auto characterComponent = entity->GetComponent<CharacterComponent>(); + if (!characterComponent) return; + auto levelComponent = entity->GetComponent<LevelProgressionComponent>(); auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); query.bind(1, (int)requestedLevel); auto result = query.execQuery(); @@ -1346,171 +1401,157 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (result.eof()) return; // Set the UScore first - oldLevel = characterComponent->GetLevel(); + oldLevel = levelComponent->GetLevel(); characterComponent->SetUScore(result.getIntField(0, characterComponent->GetUScore())); // handle level up for each level we have passed if we set our level to be higher than the current one. if (oldLevel < requestedLevel) { while (oldLevel < requestedLevel) { - oldLevel+=1; - characterComponent->SetLevel(oldLevel); - characterComponent->HandleLevelUp(); + oldLevel += 1; + levelComponent->SetLevel(oldLevel); + levelComponent->HandleLevelUp(); } } else { - characterComponent->SetLevel(requestedLevel); + levelComponent->SetLevel(requestedLevel); } if (requestedPlayerToSetLevelOf != "") { - ChatPackets::SendSystemMessage( - sysAddr, u"Set " + GeneralUtils::ASCIIToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + - u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - u". Relog to see changes."); + ChatPackets::SendSystemMessage( + sysAddr, u"Set " + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); } else { - ChatPackets::SendSystemMessage( - sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + - u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - u". Relog to see changes."); + ChatPackets::SendSystemMessage( + sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); } return; } - if (chatCommand == "pos" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "pos" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); - ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); + ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); std::cout << position.x << ", " << position.y << ", " << position.z << std::endl; } - if (chatCommand == "rot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto rotation = entity->GetRotation(); - ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); + ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl; } - if (chatCommand == "locrow" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); const auto rotation = entity->GetRotation(); std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl; } - if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if ((chatCommand == "freemoney" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) && args.size() == 1) { + if ((chatCommand == "freemoney" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) && args.size() == 1) { int32_t money; - if (!GeneralUtils::TryParse(args[0], money)) - { + if (!GeneralUtils::TryParse(args[0], money)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); return; } auto* ch = entity->GetCharacter(); - ch->SetCoins(ch->GetCoins() + money, eLootSourceType::LOOT_SOURCE_MODERATION); + ch->SetCoins(ch->GetCoins() + money, eLootSourceType::MODERATION); } - if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t money; - if (!GeneralUtils::TryParse(args[0], money)) - { + if (!GeneralUtils::TryParse(args[0], money)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); return; } auto* ch = entity->GetCharacter(); - ch->SetCoins(money, eLootSourceType::LOOT_SOURCE_MODERATION); + ch->SetCoins(money, eLootSourceType::MODERATION); } // Allow for this on even while not a GM, as it sometimes toggles incorrrectly. - if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); return; } - if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); int32_t state = false; - if (!GeneralUtils::TryParse(args[0], state)) - { + if (!GeneralUtils::TryParse(args[0], state)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); return; } - if (destroyableComponent != nullptr) - { + if (destroyableComponent != nullptr) { destroyableComponent->SetIsGMImmune(state); } return; } - if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { + if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* buffComponent = entity->GetComponent<BuffComponent>(); int32_t id = 0; int32_t duration = 0; - if (!GeneralUtils::TryParse(args[0], id)) - { + if (!GeneralUtils::TryParse(args[0], id)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff id."); return; } - if (!GeneralUtils::TryParse(args[1], duration)) - { + if (!GeneralUtils::TryParse(args[1], duration)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff duration."); return; } - if (buffComponent != nullptr) - { + if (buffComponent != nullptr) { buffComponent->ApplyBuff(id, duration, entity->GetObjectID()); } return; } - if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { + if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); uint32_t reqZone; LWOCLONEID cloneId = 0; bool force = false; - if (!GeneralUtils::TryParse(args[0], reqZone)) - { + if (!GeneralUtils::TryParse(args[0], reqZone)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); return; } - if (args.size() > 1) - { + if (args.size() > 1) { auto index = 1; - if (args[index] == "force") - { + if (args[index] == "force") { index++; force = true; } - if (args.size() > index && !GeneralUtils::TryParse(args[index], cloneId)) - { + if (args.size() > index && !GeneralUtils::TryParse(args[index], cloneId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id."); return; } @@ -1518,76 +1559,48 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit const auto objid = entity->GetObjectID(); - if (force || CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery - bool darwin = true; //Putting this on true, as I'm sick of having to wait 3-4 seconds on a transfer while trying to quickly moderate properties + if (force || dZoneManager::Instance()->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery - Character* character = entity->GetCharacter(); - if (character) { - std::string lowerName = character->GetName(); - std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - // feel free to add your name to the list - if (lowerName.find("max") != std::string::npos || lowerName.find("darwin") != std::string::npos || lowerName.find("gie") != std::string::npos) { - darwin = true; - } - } + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - if (!darwin) { - GameMessages::SendPlayAnimation(entity, u"lup-teleport"); - GameMessages::SendSetStunned(objid, PUSH, user->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true, true - ); - } - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid, darwin](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { auto* entity = EntityManager::Instance()->GetEntity(objid); + if (!entity) return; - if (entity == nullptr) { - return; + const auto sysAddr = entity->GetSystemAddress(); + + ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); + + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u""); } - float transferTime = 3.32999992370605f; - if (darwin) transferTime = 0.0f; + entity->GetCharacter()->SaveXMLToDatabase(); - entity->AddCallbackTimer(transferTime, [=] { - const auto sysAddr = entity->GetSystemAddress(); - - ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); - - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - if (entity->GetCharacter()) { - entity->GetCharacter()->SetZoneID(zoneID); - entity->GetCharacter()->SetZoneInstance(zoneInstance); - entity->GetCharacter()->SetZoneClone(zoneClone); - entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u""); - } - - entity->GetCharacter()->SaveXMLToDatabase(); - - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + return; }); - return; - }); - } else { - std::string msg = "ZoneID not found or allowed: "; - msg.append(args[0]); - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(msg, msg.size())); - } - } + } else { + std::string msg = "ZoneID not found or allowed: "; + msg.append(args[0]); // FIXME: unnecessary utf16 re-encoding just for error + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(msg, msg.size())); + } + } - if (chatCommand == "createprivate" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) - { + if (chatCommand == "createprivate" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { uint32_t zone; - if (!GeneralUtils::TryParse(args[0], zone)) - { + if (!GeneralUtils::TryParse(args[0], zone)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); return; } uint32_t clone; - if (!GeneralUtils::TryParse(args[1], clone)) - { + if (!GeneralUtils::TryParse(args[1], clone)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone."); return; } @@ -1601,64 +1614,82 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "debugui") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "debugui") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); - AMFStringValue* value = new AMFStringValue(); - value->SetStringValue("ToggleUIDebugger;"); AMFArrayValue args; - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, value->GetStringValue(), &args); - delete value; + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", nullptr); } - if ((chatCommand == "boost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "boost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - if (possessorComponent == nullptr) - { + if (possessorComponent == nullptr) { return; } auto* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - if (vehicle == nullptr) - { + if (vehicle == nullptr) { return; } - GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + if (args.size() >= 1) { + float time; + + if (!GeneralUtils::TryParse(args[0], time)) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time."); + return; + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + entity->AddCallbackTimer(time, [vehicle]() { + if (!vehicle) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + }); + } + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + } - if (chatCommand == "activatespawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) - { + if ((chatCommand == "unboost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) return; + auto* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + + if (chatCommand == "activatespawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Activate(); } spawners = dZoneManager::Instance()->GetSpawnersInGroup(args[0]); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Activate(); } } - if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= 6) { + if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { //Go tell physics to spawn all the vertices: - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PHANTOM_PHYSICS); + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); for (auto en : entities) { - auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (phys) phys->SpawnVertices(); } } - if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= 6) { - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROXIMITY_MONITOR); + if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); for (auto en : entities) { - auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(COMPONENT_TYPE_PROXIMITY_MONITOR)); + auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); if (phys) { for (auto prox : phys->GetProximitiesData()) { if (!prox.second) continue; @@ -1671,25 +1702,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) - { + if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Spawn(); } spawners = dZoneManager::Instance()->GetSpawnersInGroup(args[0]); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Spawn(); } } - if (chatCommand == "reforge" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) - { + if (chatCommand == "reforge" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { LOT baseItem; LOT reforgedItem; @@ -1700,14 +1727,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (inventoryComponent == nullptr) return; - std::vector<LDFBaseData*> data {}; + std::vector<LDFBaseData*> data{}; data.push_back(new LDFData<int32_t>(u"reforgedLOT", reforgedItem)); - inventoryComponent->AddItem(baseItem, 1, eLootSourceType::LOOT_SOURCE_MODERATION, eInventoryType::INVALID, data); + inventoryComponent->AddItem(baseItem, 1, eLootSourceType::MODERATION, eInventoryType::INVALID, data); } - if (chatCommand == "crash" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR) - { + if (chatCommand == "crash" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); int* badPtr = nullptr; @@ -1716,37 +1742,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "config-set" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) - { - GameConfig::SetValue(args[0], args[1]); - - ChatPackets::SendSystemMessage( - sysAddr, u"Set config value: " + GeneralUtils::ASCIIToUTF16(args[0]) + u" to " + GeneralUtils::ASCIIToUTF16(args[1]) - ); - } - - if (chatCommand == "config-get" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) - { - const auto& value = GameConfig::GetValue(args[0]); - - if (value.empty()) - { - ChatPackets::SendSystemMessage(sysAddr, u"No value found for " + GeneralUtils::ASCIIToUTF16(args[0])); - } - else - { - ChatPackets::SendSystemMessage(sysAddr, u"Value for " + GeneralUtils::ASCIIToUTF16(args[0]) + u": " + GeneralUtils::ASCIIToUTF16(value)); - } - } - - if (chatCommand == "metrics" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) - { - for (const auto variable : Metrics::GetAllMetrics()) - { + if (chatCommand == "metrics" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + for (const auto variable : Metrics::GetAllMetrics()) { auto* metric = Metrics::GetMetric(variable); - if (metric == nullptr) - { + if (metric == nullptr) { continue; } @@ -1761,13 +1761,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage( sysAddr, - u"Peak RSS: " + GeneralUtils::to_u16string((float) ((double) Metrics::GetPeakRSS() / 1.024e6)) + + u"Peak RSS: " + GeneralUtils::to_u16string((float)((double)Metrics::GetPeakRSS() / 1.024e6)) + u"MB" ); ChatPackets::SendSystemMessage( sysAddr, - u"Current RSS: " + GeneralUtils::to_u16string((float) ((double) Metrics::GetCurrentRSS() / 1.024e6)) + + u"Current RSS: " + GeneralUtils::to_u16string((float)((double)Metrics::GetCurrentRSS() / 1.024e6)) + u"MB" ); @@ -1779,7 +1779,23 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "rollloot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && args.size() >= 3) { + if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + Game::config->ReloadConfig(); + VanityUtilities::SpawnVanity(); + dpWorld::Instance().Reload(); + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (auto entity : entities) { + auto* scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); + if (!scriptedActivityComponent) continue; + + scriptedActivityComponent->ReloadConfig(); + } + Game::server->UpdateMaximumMtuSize(); + Game::server->UpdateBandwidthLimit(); + ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); + } + + if (chatCommand == "rollloot" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR && args.size() >= 3) { uint32_t lootMatrixIndex = 0; uint32_t targetLot = 0; uint32_t loops = 1; @@ -1811,26 +1827,51 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit + u" times. It ran " + GeneralUtils::to_u16string(totalRuns) + u" times. Averaging out at " - + GeneralUtils::to_u16string((float) totalRuns / loops); + + GeneralUtils::to_u16string((float)totalRuns / loops); ChatPackets::SendSystemMessage(sysAddr, message); } - if (chatCommand == "inspect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) - { + if (chatCommand == "deleteinven" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { + eInventoryType inventoryType = eInventoryType::INVALID; + if (!GeneralUtils::TryParse(args[0], inventoryType)) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(args[0].begin(), args[0].end(), args[0].begin(), ::toupper); + Game::logger->Log("SlashCommandHandler", "looking for inventory %s", args[0].c_str()); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(args[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); + } + } + + if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); + return; + } + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); + if (!inventoryToDelete) return; + + inventoryToDelete->DeleteAllItems(); + Game::logger->Log("SlashCommandHandler", "Deleted inventory %s for user %llu", args[0].c_str(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); + } + + if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { Entity* closest = nullptr; - int32_t component; + eReplicaComponentType component; std::u16string ldf; bool isLDF = false; - if (!GeneralUtils::TryParse(args[0], component)) - { - component = -1; + if (!GeneralUtils::TryParse(args[0], component)) { + component = eReplicaComponentType::INVALID; - ldf = GeneralUtils::ASCIIToUTF16(args[0]); + ldf = GeneralUtils::UTF8ToUTF16(args[0]); isLDF = true; } @@ -1841,20 +1882,16 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit const auto candidates = EntityManager::Instance()->GetEntitiesByComponent(component); - for (auto* candidate : candidates) - { - if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) - { + for (auto* candidate : candidates) { + if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) { continue; } - if (isLDF && !candidate->HasVar(ldf)) - { + if (isLDF && !candidate->HasVar(ldf)) { continue; } - if (closest == nullptr) - { + if (closest == nullptr) { closest = candidate; closestDistance = NiPoint3::Distance(candidate->GetPosition(), reference); @@ -1864,22 +1901,20 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit const auto distance = NiPoint3::Distance(candidate->GetPosition(), reference); - if (distance < closestDistance) - { + if (distance < closestDistance) { closest = candidate; closestDistance = distance; } } - if (closest == nullptr) - { + if (closest == nullptr) { return; } EntityManager::Instance()->SerializeEntity(closest); - auto* table = CDClientManager::Instance()->GetTable<CDObjectsTable>("Objects"); + auto* table = CDClientManager::Instance().GetTable<CDObjectsTable>(); const auto& info = table->GetByID(closest->GetLOT()); @@ -1889,72 +1924,55 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str())); - for (const auto& pair : closest->GetComponents()) - { + for (const auto& pair : closest->GetComponents()) { auto id = pair.first; std::stringstream stream; - stream << "Component [" << std::to_string(id) << "]"; + stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); } - if (args.size() >= 2) - { - if (args[1] == "-m" && args.size() >= 3) - { + if (args.size() >= 2) { + if (args[1] == "-m" && args.size() >= 3) { auto* movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>(); int32_t value = 0; - if (movingPlatformComponent == nullptr || !GeneralUtils::TryParse(args[2], value)) - { + if (movingPlatformComponent == nullptr || !GeneralUtils::TryParse(args[2], value)) { return; } movingPlatformComponent->SetSerialized(true); - if (value == -1) - { + if (value == -1) { movingPlatformComponent->StopPathing(); - } - else - { + } else { movingPlatformComponent->GotoWaypoint(value); } EntityManager::Instance()->SerializeEntity(closest); - } - else if (args[1] == "-a" && args.size() >= 3) - { - GameMessages::SendPlayAnimation(closest, GeneralUtils::ASCIIToUTF16(args[2])); - } - else if (args[1] == "-s") - { - for (auto* entry : closest->GetSettings()) - { - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(entry->GetString())); + } else if (args[1] == "-a" && args.size() >= 3) { + GameMessages::SendPlayAnimation(closest, GeneralUtils::UTF8ToUTF16(args[2])); + } else if (args[1] == "-s") { + for (auto* entry : closest->GetSettings()) { + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString())); } ChatPackets::SendSystemMessage(sysAddr, u"------"); ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID())); - } - else if (args[1] == "-p") - { + } else if (args[1] == "-p") { const auto postion = closest->GetPosition(); ChatPackets::SendSystemMessage( sysAddr, GeneralUtils::ASCIIToUTF16("< " + std::to_string(postion.x) + ", " + std::to_string(postion.y) + ", " + std::to_string(postion.z) + " >") ); - } - else if (args[1] == "-f") - { + } else if (args[1] == "-f") { auto* destuctable = closest->GetComponent<DestroyableComponent>(); - if (destuctable == nullptr) - { + if (destuctable == nullptr) { ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); return; } @@ -1962,65 +1980,47 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Smashable: " + (GeneralUtils::to_u16string(destuctable->GetIsSmashable()))); ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); - for (const auto entry : destuctable->GetFactionIDs()) - { + for (const auto entry : destuctable->GetFactionIDs()) { ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); } ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); - for (const auto entry : destuctable->GetEnemyFactionsIDs()) - { + for (const auto entry : destuctable->GetEnemyFactionsIDs()) { ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); } - if (args.size() >= 3) - { + if (args.size() >= 3) { int32_t faction; - if (!GeneralUtils::TryParse(args[2], faction)) - { + if (!GeneralUtils::TryParse(args[2], faction)) { return; } destuctable->SetFaction(-1); destuctable->AddFaction(faction, true); } - } - else if (args[1] == "-t") - { + } else if (args[1] == "-t") { auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); - if (phantomPhysicsComponent != nullptr) - { - ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetEffectType()))); + if (phantomPhysicsComponent != nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType())))); const auto dir = phantomPhysicsComponent->GetDirection(); - ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", "+ (GeneralUtils::to_u16string(dir.z)) + u">"); + ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">"); ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier()))); ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); } - if (closest->GetTrigger() != nullptr) - { - ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(closest->GetTrigger()->id))); + auto* triggerComponent = closest->GetComponent<TriggerComponent>(); + if (triggerComponent) { + auto trigger = triggerComponent->GetTrigger(); + if (trigger) { + ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); + } } } } } } -bool SlashCommandHandler::CheckIfAccessibleZone(const unsigned int zoneID) { - //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable * zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); - const CDZoneTable* zone = zoneTable->Query(zoneID); - if (zone != nullptr) { - std::string zonePath = "./res/maps/" + zone->zoneName; - std::transform(zonePath.begin(), zonePath.end(), zonePath.begin(), ::tolower); - std::ifstream f(zonePath.c_str()); - return f.good(); - } else { - return false; - } -} - void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::string& message) { AMFArrayValue args; auto* titleValue = new AMFStringValue(); @@ -2033,20 +2033,19 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std:: GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args); - delete titleValue; - delete messageValue; - titleValue = nullptr; - messageValue = nullptr; - //Notify chat about it CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ANNOUNCEMENT); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ANNOUNCEMENT); - RakNet::RakString rsTitle(title.c_str()); - RakNet::RakString rsMsg(message.c_str()); + bitStream.Write<uint32_t>(title.size()); + for (auto character : title) { + bitStream.Write<char>(character); + } - bitStream.Write(rsTitle); - bitStream.Write(rsMsg); + bitStream.Write<uint32_t>(message.size()); + for (auto character : message) { + bitStream.Write<char>(character); + } Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } diff --git a/dGame/dUtilities/SlashCommandHandler.h b/dGame/dUtilities/SlashCommandHandler.h index 32b267ef..85b7c697 100644 --- a/dGame/dUtilities/SlashCommandHandler.h +++ b/dGame/dUtilities/SlashCommandHandler.h @@ -12,10 +12,8 @@ class Entity; namespace SlashCommandHandler { - void HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr); - bool CheckIfAccessibleZone(const unsigned int zoneID); - - void SendAnnouncement(const std::string& title, const std::string& message); + void HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr); + void SendAnnouncement(const std::string& title, const std::string& message); }; #endif // SLASHCOMMANDHANDLER_H diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index c3f8f6b4..7fabfbce 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -13,6 +13,8 @@ #include "tinyxml2.h" #include "Game.h" #include "dLogger.h" +#include "BinaryPathFinder.h" +#include "EntityInfo.h" #include <fstream> @@ -20,520 +22,522 @@ std::vector<VanityNPC> VanityUtilities::m_NPCs = {}; std::vector<VanityParty> VanityUtilities::m_Parties = {}; std::vector<std::string> VanityUtilities::m_PartyPhrases = {}; -void VanityUtilities::SpawnVanity() -{ - if (Game::config->GetValue("disable_vanity") == "1") { - return; - } +void VanityUtilities::SpawnVanity() { + if (Game::config->GetValue("disable_vanity") == "1") { + return; + } - const uint32_t zoneID = Game::server->GetZoneID(); + const uint32_t zoneID = Game::server->GetZoneID(); - ParseXML("./vanity/NPC.xml"); + ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string()); - // Loop through all parties - for (const auto& party : m_Parties) { - const auto chance = party.m_Chance; - const auto zone = party.m_Zone; + // Loop through all parties + for (const auto& party : m_Parties) { + const auto chance = party.m_Chance; + const auto zone = party.m_Zone; - if (zone != Game::server->GetZoneID()) { - continue; - } + if (zone != Game::server->GetZoneID()) { + continue; + } - float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (chance < rate) { - continue; - } + float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); + if (chance < rate) { + continue; + } - // Copy m_NPCs into a new vector - std::vector<VanityNPC> npcList = m_NPCs; - std::vector<uint32_t> taken = {}; + // Copy m_NPCs into a new vector + std::vector<VanityNPC> npcList = m_NPCs; + std::vector<uint32_t> taken = {}; - Game::logger->Log("VanityUtilities", "Spawning party with %i locations\n", party.m_Locations.size()); + Game::logger->Log("VanityUtilities", "Spawning party with %i locations", party.m_Locations.size()); - // Loop through all locations - for (const auto& location : party.m_Locations) { - rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (0.75f < rate) { - continue; - } + // Loop through all locations + for (const auto& location : party.m_Locations) { + rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); + if (0.75f < rate) { + continue; + } - // Get a random NPC - auto npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); + // Get a random NPC + auto npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); - while (std::find(taken.begin(), taken.end(), npcIndex) != taken.end()) { - npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); - } + while (std::find(taken.begin(), taken.end(), npcIndex) != taken.end()) { + npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); + } - const auto& npc = npcList[npcIndex]; + auto& npc = npcList[npcIndex]; - taken.push_back(npcIndex); + taken.push_back(npcIndex); - // Spawn the NPC - std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>( - u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") }; + // Spawn the NPC + Game::logger->Log("VanityUtilities", "ldf size is %i", npc.ldf.size()); + if (npc.ldf.empty()) { + npc.ldf = { + new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), + new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") + }; + } - // Spawn the NPC - auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, data); + // Spawn the NPC + auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); - npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases); + npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases); - SetupNPCTalk(npcEntity); - } + SetupNPCTalk(npcEntity); + } - return; - } + return; + } - // Loop through all NPCs - for (const auto& pair : m_NPCs) { - if (pair.m_Locations.find(Game::server->GetZoneID()) == pair.m_Locations.end()) - continue; + // Loop through all NPCs + for (auto& npc : m_NPCs) { + if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end()) + continue; - const std::vector<VanityNPCLocation>& locations = pair.m_Locations.at(Game::server->GetZoneID()); + const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID()); - // Pick a random location - const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>( - static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))]; + // Pick a random location + const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>( + static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))]; - float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (location.m_Chance < rate) { - continue; - } + float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); + if (location.m_Chance < rate) { + continue; + } - std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>( - u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") }; + if (npc.ldf.empty()) { + npc.ldf = { + new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), + new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") + }; + } - // Spawn the NPC - auto* npc = SpawnNPC(pair.m_LOT, pair.m_Name, location.m_Position, location.m_Rotation, pair.m_Equipment, data); + // Spawn the NPC + auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); - npc->SetVar<std::vector<std::string>>(u"chats", pair.m_Phrases); + npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases); - auto* scriptComponent = npc->GetComponent<ScriptComponent>(); + auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>(); - if (scriptComponent != nullptr) { - scriptComponent->SetScript(pair.m_Script); - scriptComponent->SetSerialized(false); + if (scriptComponent != nullptr) { + scriptComponent->SetScript(npc.m_Script); + scriptComponent->SetSerialized(false); - for (const auto& pair : pair.m_Flags) { - npc->SetVar<bool>(GeneralUtils::ASCIIToUTF16(pair.first), pair.second); - } - } + for (const auto& npc : npc.m_Flags) { + npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second); + } + } - SetupNPCTalk(npc); - } + SetupNPCTalk(npcEntity); + } - if (zoneID == 1200) { - { - EntityInfo info; - info.lot = 8139; - info.pos = { 259.5f, 246.4f, -705.2f }; - info.rot = { 0.0f, 0.0f, 1.0f, 0.0f }; - info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); + if (zoneID == 1200) { + { + EntityInfo info; + info.lot = 8139; + info.pos = { 259.5f, 246.4f, -705.2f }; + info.rot = { 0.0f, 0.0f, 1.0f, 0.0f }; + info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); - info.settings = { new LDFData<bool>(u"hasCustomText", true), - new LDFData<std::string>(u"customText", ParseMarkdown("./vanity/TESTAMENT.md")) }; + info.settings = { new LDFData<bool>(u"hasCustomText", true), + new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) }; - auto* entity = EntityManager::Instance()->CreateEntity(info); + auto* entity = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(entity); - } - } + EntityManager::Instance()->ConstructEntity(entity); + } + } } Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoint3& position, - const NiQuaternion& rotation, const std::vector<LOT>& inventory, const std::vector<LDFBaseData*>& ldf) -{ - EntityInfo info; - info.lot = lot; - info.pos = position; - info.rot = rotation; - info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); - info.settings = ldf; + const NiQuaternion& rotation, const std::vector<LOT>& inventory, const std::vector<LDFBaseData*>& ldf) { + EntityInfo info; + info.lot = lot; + info.pos = position; + info.rot = rotation; + info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); + info.settings = ldf; - auto* entity = EntityManager::Instance()->CreateEntity(info); - entity->SetVar(u"npcName", name); + auto* entity = EntityManager::Instance()->CreateEntity(info); + entity->SetVar(u"npcName", name); - auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - if (inventoryComponent != nullptr) { - inventoryComponent->SetNPCItems(inventory); - } + if (inventoryComponent != nullptr) { + inventoryComponent->SetNPCItems(inventory); + } - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetIsGMImmune(true); - destroyableComponent->SetMaxHealth(0); - destroyableComponent->SetHealth(0); - } + if (destroyableComponent != nullptr) { + destroyableComponent->SetIsGMImmune(true); + destroyableComponent->SetMaxHealth(0); + destroyableComponent->SetHealth(0); + } - EntityManager::Instance()->ConstructEntity(entity); + EntityManager::Instance()->ConstructEntity(entity); - return entity; + return entity; } -void VanityUtilities::ParseXML(const std::string& file) -{ - // Read the entire file - std::ifstream xmlFile(file); - std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>()); +void VanityUtilities::ParseXML(const std::string& file) { + // Read the entire file + std::ifstream xmlFile(file); + std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>()); - // Parse the XML - tinyxml2::XMLDocument doc; - doc.Parse(xml.c_str(), xml.size()); + // Parse the XML + tinyxml2::XMLDocument doc; + doc.Parse(xml.c_str(), xml.size()); - // Read the NPCs - auto* npcs = doc.FirstChildElement("npcs"); + // Read the NPCs + auto* npcs = doc.FirstChildElement("npcs"); - if (npcs == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPCs\n"); - return; - } + if (npcs == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPCs"); + return; + } - for (auto* party = npcs->FirstChildElement("party"); party != nullptr; party = party->NextSiblingElement("party")) { - // Get 'zone' as uint32_t and 'chance' as float - uint32_t zone = 0; - float chance = 0.0f; + for (auto* party = npcs->FirstChildElement("party"); party != nullptr; party = party->NextSiblingElement("party")) { + // Get 'zone' as uint32_t and 'chance' as float + uint32_t zone = 0; + float chance = 0.0f; - if (party->Attribute("zone") != nullptr) { - zone = std::stoul(party->Attribute("zone")); - } + if (party->Attribute("zone") != nullptr) { + zone = std::stoul(party->Attribute("zone")); + } - if (party->Attribute("chance") != nullptr) { - chance = std::stof(party->Attribute("chance")); - } + if (party->Attribute("chance") != nullptr) { + chance = std::stof(party->Attribute("chance")); + } - VanityParty partyInfo; - partyInfo.m_Zone = zone; - partyInfo.m_Chance = chance; + VanityParty partyInfo; + partyInfo.m_Zone = zone; + partyInfo.m_Chance = chance; - auto* locations = party->FirstChildElement("locations"); + auto* locations = party->FirstChildElement("locations"); - if (locations == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse party locations\n"); - continue; - } + if (locations == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse party locations"); + continue; + } - for (auto* location = locations->FirstChildElement("location"); location != nullptr; - location = location->NextSiblingElement("location")) { - // Get the location data - auto* x = location->Attribute("x"); - auto* y = location->Attribute("y"); - auto* z = location->Attribute("z"); - auto* rw = location->Attribute("rw"); - auto* rx = location->Attribute("rx"); - auto* ry = location->Attribute("ry"); - auto* rz = location->Attribute("rz"); + for (auto* location = locations->FirstChildElement("location"); location != nullptr; + location = location->NextSiblingElement("location")) { + // Get the location data + auto* x = location->Attribute("x"); + auto* y = location->Attribute("y"); + auto* z = location->Attribute("z"); + auto* rw = location->Attribute("rw"); + auto* rx = location->Attribute("rx"); + auto* ry = location->Attribute("ry"); + auto* rz = location->Attribute("rz"); - if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr - || rz == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse party location data\n"); - continue; - } + if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr + || rz == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse party location data"); + continue; + } - VanityNPCLocation locationData; - locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) }; - locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) }; - locationData.m_Chance = 1.0f; + VanityNPCLocation locationData; + locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) }; + locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) }; + locationData.m_Chance = 1.0f; - partyInfo.m_Locations.push_back(locationData); - } + partyInfo.m_Locations.push_back(locationData); + } - m_Parties.push_back(partyInfo); - } + m_Parties.push_back(partyInfo); + } - auto* partyPhrases = npcs->FirstChildElement("partyphrases"); + auto* partyPhrases = npcs->FirstChildElement("partyphrases"); - if (partyPhrases == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse party phrases\n"); - return; - } + if (partyPhrases == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse party phrases"); + return; + } - for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr; - phrase = phrase->NextSiblingElement("phrase")) { - // Get the phrase - auto* text = phrase->GetText(); + for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr; + phrase = phrase->NextSiblingElement("phrase")) { + // Get the phrase + auto* text = phrase->GetText(); - if (text == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse party phrase\n"); - continue; - } + if (text == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse party phrase"); + continue; + } - m_PartyPhrases.push_back(text); - } + m_PartyPhrases.push_back(text); + } - for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) { - // Get the NPC name - auto* name = npc->Attribute("name"); + for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) { + // Get the NPC name + auto* name = npc->Attribute("name"); - if (name == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC name\n"); - continue; - } + if (!name) name = ""; - // Get the NPC lot - auto* lot = npc->Attribute("lot"); + // Get the NPC lot + auto* lot = npc->Attribute("lot"); - if (lot == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC lot\n"); - continue; - } + if (lot == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC lot"); + continue; + } - // Get the equipment - auto* equipment = npc->FirstChildElement("equipment"); + // Get the equipment + auto* equipment = npc->FirstChildElement("equipment"); + std::vector<LOT> inventory; - if (equipment == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC equipment\n"); - continue; - } + if (equipment) { + auto* text = equipment->GetText(); - auto* text = equipment->GetText(); + if (text != nullptr) { + std::string equipmentString(text); - std::vector<LOT> inventory; + std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); - if (text != nullptr) { - std::string equipmentString(text); + for (auto& item : splitEquipment) { + inventory.push_back(std::stoi(item)); + } + } + } - std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); - for (auto& item : splitEquipment) { - inventory.push_back(std::stoi(item)); - } - } + // Get the phrases + auto* phrases = npc->FirstChildElement("phrases"); - // Get the phrases - auto* phrases = npc->FirstChildElement("phrases"); + std::vector<std::string> phraseList = {}; - if (phrases == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC phrases\n"); - continue; - } + if (phrases) { + for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; + phrase = phrase->NextSiblingElement("phrase")) { + // Get the phrase + auto* text = phrase->GetText(); + if (text == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase"); + continue; + } + phraseList.push_back(text); + } + } - std::vector<std::string> phraseList; + // Get the script + auto* scriptElement = npc->FirstChildElement("script"); - for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; - phrase = phrase->NextSiblingElement("phrase")) { - // Get the phrase - auto* text = phrase->GetText(); + std::string scriptName = ""; - if (text == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase\n"); - continue; - } + if (scriptElement != nullptr) { + auto* scriptNameAttribute = scriptElement->Attribute("name"); + if (scriptNameAttribute) scriptName = scriptNameAttribute; + } - phraseList.push_back(text); - } + auto* ldfElement = npc->FirstChildElement("ldf"); + std::vector<std::u16string> keys = {}; - // Get the script - auto* scriptElement = npc->FirstChildElement("script"); + std::vector<LDFBaseData*> ldf = {}; + if(ldfElement) { + for (auto* entry = ldfElement->FirstChildElement("entry"); entry != nullptr; + entry = entry->NextSiblingElement("entry")) { + // Get the ldf data + auto* data = entry->Attribute("data"); + if (!data) continue; - std::string scriptName; + LDFBaseData* ldfData = LDFBaseData::DataFromString(data); + keys.push_back(ldfData->GetKey()); + ldf.push_back(ldfData); + } + } + if (!keys.empty()) ldf.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys)); - if (scriptElement != nullptr) { - auto* scriptNameAttribute = scriptElement->Attribute("name"); + VanityNPC npcData; + npcData.m_Name = name; + npcData.m_LOT = std::stoi(lot); + npcData.m_Equipment = inventory; + npcData.m_Phrases = phraseList; + npcData.m_Script = scriptName; + npcData.ldf = ldf; - if (scriptNameAttribute == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC script name\n"); - continue; - } + // Get flags + auto* flags = npc->FirstChildElement("flags"); - scriptName = scriptNameAttribute; - } + if (flags != nullptr) { + for (auto* flag = flags->FirstChildElement("flag"); flag != nullptr; + flag = flag->NextSiblingElement("flag")) { + // Get the flag name + auto* name = flag->Attribute("name"); - VanityNPC npcData; - npcData.m_Name = name; - npcData.m_LOT = std::stoi(lot); - npcData.m_Equipment = inventory; - npcData.m_Phrases = phraseList; - npcData.m_Script = scriptName; + if (name == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC flag name"); + continue; + } - // Get flags - auto* flags = npc->FirstChildElement("flags"); + // Get the flag value + auto* value = flag->Attribute("value"); - if (flags != nullptr) { - for (auto* flag = flags->FirstChildElement("flag"); flag != nullptr; - flag = flag->NextSiblingElement("flag")) { - // Get the flag name - auto* name = flag->Attribute("name"); + if (value == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC flag value"); + continue; + } - if (name == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC flag name\n"); - continue; - } + npcData.m_Flags[name] = std::stoi(value); + } + } - // Get the flag value - auto* value = flag->Attribute("value"); + // Get the zones + for (auto* zone = npc->FirstChildElement("zone"); zone != nullptr; zone = zone->NextSiblingElement("zone")) { + // Get the zone ID + auto* zoneID = zone->Attribute("id"); - if (value == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC flag value\n"); - continue; - } + if (zoneID == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC zone ID"); + continue; + } - npcData.m_Flags[name] = std::stoi(value); - } - } + // Get the locations + auto* locations = zone->FirstChildElement("locations"); - // Get the zones - for (auto* zone = npc->FirstChildElement("zone"); zone != nullptr; zone = zone->NextSiblingElement("zone")) { - // Get the zone ID - auto* zoneID = zone->Attribute("id"); + if (locations == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC locations"); + continue; + } - if (zoneID == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC zone ID\n"); - continue; - } + for (auto* location = locations->FirstChildElement("location"); location != nullptr; + location = location->NextSiblingElement("location")) { + // Get the location data + auto* x = location->Attribute("x"); + auto* y = location->Attribute("y"); + auto* z = location->Attribute("z"); + auto* rw = location->Attribute("rw"); + auto* rx = location->Attribute("rx"); + auto* ry = location->Attribute("ry"); + auto* rz = location->Attribute("rz"); - // Get the locations - auto* locations = zone->FirstChildElement("locations"); + if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr + || rz == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC location data"); + continue; + } - if (locations == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC locations\n"); - continue; - } + VanityNPCLocation locationData; + locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) }; + locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) }; + locationData.m_Chance = 1.0f; - for (auto* location = locations->FirstChildElement("location"); location != nullptr; - location = location->NextSiblingElement("location")) { - // Get the location data - auto* x = location->Attribute("x"); - auto* y = location->Attribute("y"); - auto* z = location->Attribute("z"); - auto* rw = location->Attribute("rw"); - auto* rx = location->Attribute("rx"); - auto* ry = location->Attribute("ry"); - auto* rz = location->Attribute("rz"); + if (location->Attribute("chance") != nullptr) { + locationData.m_Chance = std::stof(location->Attribute("chance")); + } - if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr - || rz == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC location data\n"); - continue; - } + const auto& it = npcData.m_Locations.find(std::stoi(zoneID)); - VanityNPCLocation locationData; - locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) }; - locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) }; - locationData.m_Chance = 1.0f; + if (it != npcData.m_Locations.end()) { + it->second.push_back(locationData); + } else { + std::vector<VanityNPCLocation> locations; + locations.push_back(locationData); + npcData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations)); + } + } + } - if (location->Attribute("chance") != nullptr) { - locationData.m_Chance = std::stof(location->Attribute("chance")); - } - - const auto& it = npcData.m_Locations.find(std::stoi(zoneID)); - - if (it != npcData.m_Locations.end()) { - it->second.push_back(locationData); - } else { - std::vector<VanityNPCLocation> locations; - locations.push_back(locationData); - npcData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations)); - } - } - } - - m_NPCs.push_back(npcData); - } + m_NPCs.push_back(npcData); + } } -VanityNPC* VanityUtilities::GetNPC(const std::string& name) -{ - for (size_t i = 0; i < m_NPCs.size(); i++) { - if (m_NPCs[i].m_Name == name) { - return &m_NPCs[i]; - } - } +VanityNPC* VanityUtilities::GetNPC(const std::string& name) { + for (size_t i = 0; i < m_NPCs.size(); i++) { + if (m_NPCs[i].m_Name == name) { + return &m_NPCs[i]; + } + } - return nullptr; + return nullptr; } -std::string VanityUtilities::ParseMarkdown(const std::string& file) -{ - // This function will read the file and return the content formatted as ASCII text. +std::string VanityUtilities::ParseMarkdown(const std::string& file) { + // This function will read the file and return the content formatted as ASCII text. - // Read the file into a string - std::ifstream t(file); + // Read the file into a string + std::ifstream t(file); - // If the file does not exist, return an empty string. - if (!t.good()) { - return ""; - } + // If the file does not exist, return an empty string. + if (!t.good()) { + return ""; + } - std::stringstream buffer; - buffer << t.rdbuf(); - std::string fileContents = buffer.str(); + std::stringstream buffer; + buffer << t.rdbuf(); + std::string fileContents = buffer.str(); - // Loop through all lines in the file. - // Replace all instances of the markdown syntax with the corresponding HTML. - // Only care about headers - std::stringstream output; - std::string line; - std::stringstream ss; - ss << fileContents; - while (std::getline(ss, line)) { + // Loop through all lines in the file. + // Replace all instances of the markdown syntax with the corresponding HTML. + // Only care about headers + std::stringstream output; + std::string line; + std::stringstream ss; + ss << fileContents; + while (std::getline(ss, line)) { #define TOSTRING(x) #x #define STRINGIFY(x) TOSTRING(x) - // Replace "__TIMESTAMP__" with the __TIMESTAMP__ - GeneralUtils::ReplaceInString(line, "__TIMESTAMP__", __TIMESTAMP__); - // Replace "__VERSION__" wit'h the PROJECT_VERSION - GeneralUtils::ReplaceInString(line, "__VERSION__", STRINGIFY(PROJECT_VERSION)); - // Replace "__SOURCE__" with SOURCE - GeneralUtils::ReplaceInString(line, "__SOURCE__", Game::config->GetValue("source")); - // Replace "__LICENSE__" with LICENSE - GeneralUtils::ReplaceInString(line, "__LICENSE__", STRINGIFY(LICENSE)); + // Replace "__TIMESTAMP__" with the __TIMESTAMP__ + GeneralUtils::ReplaceInString(line, "__TIMESTAMP__", __TIMESTAMP__); + // Replace "__VERSION__" wit'h the PROJECT_VERSION + GeneralUtils::ReplaceInString(line, "__VERSION__", STRINGIFY(PROJECT_VERSION)); + // Replace "__SOURCE__" with SOURCE + GeneralUtils::ReplaceInString(line, "__SOURCE__", Game::config->GetValue("source")); + // Replace "__LICENSE__" with LICENSE + GeneralUtils::ReplaceInString(line, "__LICENSE__", STRINGIFY(LICENSE)); - if (line.find("##") != std::string::npos) { - // Add "<font size='18' color='#000000'>" before the header - output << "<font size=\"14\" color=\"#000000\">"; - // Add the header without the markdown syntax - output << line.substr(3); + if (line.find("##") != std::string::npos) { + // Add "<font size='18' color='#000000'>" before the header + output << "<font size=\"14\" color=\"#000000\">"; + // Add the header without the markdown syntax + output << line.substr(3); - output << "</font>"; - } else if (line.find("#") != std::string::npos) { - // Add "<font size='18' color='#000000'>" before the header - output << "<font size=\"18\" color=\"#000000\">"; - // Add the header without the markdown syntax - output << line.substr(2); + output << "</font>"; + } else if (line.find("#") != std::string::npos) { + // Add "<font size='18' color='#000000'>" before the header + output << "<font size=\"18\" color=\"#000000\">"; + // Add the header without the markdown syntax + output << line.substr(2); - output << "</font>"; - } else { - output << line; - } + output << "</font>"; + } else { + output << line; + } - output << "\n"; - } + output << "\n"; + } - return output.str(); + return output.str(); } -void VanityUtilities::SetupNPCTalk(Entity* npc) -{ - npc->AddCallbackTimer(15.0f, [npc]() { NPCTalk(npc); }); +void VanityUtilities::SetupNPCTalk(Entity* npc) { + npc->AddCallbackTimer(15.0f, [npc]() { NPCTalk(npc); }); - npc->SetProximityRadius(20.0f, "talk"); + npc->SetProximityRadius(20.0f, "talk"); } -void VanityUtilities::NPCTalk(Entity* npc) -{ - auto* proximityMonitorComponent = npc->GetComponent<ProximityMonitorComponent>(); +void VanityUtilities::NPCTalk(Entity* npc) { + auto* proximityMonitorComponent = npc->GetComponent<ProximityMonitorComponent>(); - if (!proximityMonitorComponent->GetProximityObjects("talk").empty()) { - const auto& chats = npc->GetVar<std::vector<std::string>>(u"chats"); + if (!proximityMonitorComponent->GetProximityObjects("talk").empty()) { + const auto& chats = npc->GetVar<std::vector<std::string>>(u"chats"); - if (chats.empty()) { - return; - } + if (chats.empty()) { + return; + } - const auto& selected - = chats[GeneralUtils::GenerateRandomNumber<int32_t>(0, static_cast<int32_t>(chats.size() - 1))]; + const auto& selected + = chats[GeneralUtils::GenerateRandomNumber<int32_t>(0, static_cast<int32_t>(chats.size() - 1))]; - GameMessages::SendNotifyClientZoneObject( - npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS); - } + GameMessages::SendNotifyClientZoneObject( + npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS); + } - EntityManager::Instance()->SerializeEntity(npc); + EntityManager::Instance()->SerializeEntity(npc); - const float nextTime = GeneralUtils::GenerateRandomNumber<float>(15, 60); + const float nextTime = GeneralUtils::GenerateRandomNumber<float>(15, 60); - npc->AddCallbackTimer(nextTime, [npc]() { NPCTalk(npc); }); + npc->AddCallbackTimer(nextTime, [npc]() { NPCTalk(npc); }); } diff --git a/dGame/dUtilities/VanityUtilities.h b/dGame/dUtilities/VanityUtilities.h index b8462421..0cca0aba 100644 --- a/dGame/dUtilities/VanityUtilities.h +++ b/dGame/dUtilities/VanityUtilities.h @@ -6,61 +6,62 @@ struct VanityNPCLocation { - float m_Chance = 1.0f; - NiPoint3 m_Position; - NiQuaternion m_Rotation; + float m_Chance = 1.0f; + NiPoint3 m_Position; + NiQuaternion m_Rotation; }; struct VanityNPC { - std::string m_Name; - LOT m_LOT; - std::vector<LOT> m_Equipment; - std::vector<std::string> m_Phrases; - std::string m_Script; - std::map<std::string, bool> m_Flags; - std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations; + std::string m_Name; + LOT m_LOT; + std::vector<LOT> m_Equipment; + std::vector<std::string> m_Phrases; + std::string m_Script; + std::map<std::string, bool> m_Flags; + std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations; + std::vector<LDFBaseData*> ldf; }; struct VanityParty { - uint32_t m_Zone; - float m_Chance = 1.0f; - std::vector<VanityNPCLocation> m_Locations; + uint32_t m_Zone; + float m_Chance = 1.0f; + std::vector<VanityNPCLocation> m_Locations; }; class VanityUtilities { public: - static void SpawnVanity(); + static void SpawnVanity(); - static Entity* SpawnNPC( - LOT lot, - const std::string& name, - const NiPoint3& position, - const NiQuaternion& rotation, - const std::vector<LOT>& inventory, - const std::vector<LDFBaseData*>& ldf - ); + static Entity* SpawnNPC( + LOT lot, + const std::string& name, + const NiPoint3& position, + const NiQuaternion& rotation, + const std::vector<LOT>& inventory, + const std::vector<LDFBaseData*>& ldf + ); - static std::string ParseMarkdown( - const std::string& file - ); + static std::string ParseMarkdown( + const std::string& file + ); - static void ParseXML( - const std::string& file - ); + static void ParseXML( + const std::string& file + ); - static VanityNPC* GetNPC(const std::string& name); + static VanityNPC* GetNPC(const std::string& name); private: - static void SetupNPCTalk(Entity* npc); + static void SetupNPCTalk(Entity* npc); - static void NPCTalk(Entity* npc); + static void NPCTalk(Entity* npc); - static std::vector<VanityNPC> m_NPCs; + static std::vector<VanityNPC> m_NPCs; - static std::vector<VanityParty> m_Parties; + static std::vector<VanityParty> m_Parties; - static std::vector<std::string> m_PartyPhrases; + static std::vector<std::string> m_PartyPhrases; }; diff --git a/dGame/dUtilities/dLocale.cpp b/dGame/dUtilities/dLocale.cpp deleted file mode 100644 index 5f918fec..00000000 --- a/dGame/dUtilities/dLocale.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "dLocale.h" - -#include <clocale> -#include <fstream> -#include <sstream> -#include <vector> -#include <algorithm> - -#include "tinyxml2.h" -#include "Game.h" -#include "dConfig.h" - -dLocale::dLocale() { - if (Game::config->GetValue("locale_enabled") != "1") { - return; - } - - std::ifstream file(m_LocalePath); - - if (!file.good()) { - return; - } - - std::stringstream data; - data << file.rdbuf(); - - if (data.str().empty()) { - return; - } - - auto* doc = new tinyxml2::XMLDocument(); - - if (doc == nullptr) { - return; - } - - if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { - return; - } - - std::hash<std::string> hash; - - auto* localization = doc->FirstChildElement("localization"); - auto* phrases = localization->FirstChildElement("phrases"); - - auto* phrase = phrases->FirstChildElement("phrase"); - - while (phrase != nullptr) { - // Add the phrase hash to the vector - m_Phrases.push_back(hash(phrase->Attribute("id"))); - phrase = phrase->NextSiblingElement("phrase"); - } - - file.close(); - - delete doc; -} - -dLocale::~dLocale() = default; - -std::string dLocale::GetTemplate(const std::string& phraseID) { - return "%[" + phraseID + "]"; -} - -bool dLocale::HasPhrase(const std::string& phraseID) { - if (Game::config->GetValue("locale_enabled") != "1") { - return true; - } - - // Compute the hash and see if it's in the vector - std::hash<std::string> hash; - std::size_t hashValue = hash(phraseID); - return std::find(m_Phrases.begin(), m_Phrases.end(), hashValue) != m_Phrases.end(); -} - -/*std::string dLocale::GetPhrase(const std::string& phraseID) { - if (m_Phrases.find(phraseID) == m_Phrases.end()) { - return ""; - } - return m_Phrases[phraseID]; -}*/ \ No newline at end of file diff --git a/dGame/dUtilities/dLocale.h b/dGame/dUtilities/dLocale.h deleted file mode 100644 index 398f903b..00000000 --- a/dGame/dUtilities/dLocale.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include <map> -#include <string> -#include <vector> -#include <cstdint> - -class dLocale { -public: - dLocale(); - ~dLocale(); - static std::string GetTemplate(const std::string& phraseID); - bool HasPhrase(const std::string& phraseID); - //std::string GetPhrase(const std::string& phraseID); - -private: - std::string m_LocalePath = "./locale/locale.xml"; - std::string m_Locale = "en_US"; // TODO: add to config - std::vector<std::size_t> m_Phrases; -}; \ No newline at end of file diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt new file mode 100644 index 00000000..2161681f --- /dev/null +++ b/dMasterServer/CMakeLists.txt @@ -0,0 +1,14 @@ +set(DMASTERSERVER_SOURCES + "InstanceManager.cpp" + "ObjectIDManager.cpp" +) + +add_library(dMasterServer ${DMASTERSERVER_SOURCES}) +add_executable(MasterServer "MasterServer.cpp") + +target_link_libraries(dMasterServer ${COMMON_LIBRARIES}) +target_link_libraries(MasterServer ${COMMON_LIBRARIES} dMasterServer) + +if(WIN32) + add_dependencies(MasterServer WorldServer AuthServer ChatServer) +endif() diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 41d34cfc..50f55b72 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -7,9 +7,11 @@ #include "CDClientDatabase.h" #include "CDClientManager.h" #include "CDZoneTableTable.h" -#include "dMessageIdentifiers.h" #include "MasterPackets.h" #include "PacketUtils.h" +#include "BinaryPathFinder.h" +#include "eConnectionType.h" +#include "eMasterMessageType.h" InstanceManager::InstanceManager(dLogger* logger, const std::string& externalIP) { mLogger = logger; @@ -25,65 +27,73 @@ InstanceManager::~InstanceManager() { } } -Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID) { - mLogger->Log("InstanceManager", "Searching for an instance for mapID %i/%i\n", mapID, cloneID); +Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID) { + mLogger->Log("InstanceManager", "Searching for an instance for mapID %i/%i", mapID, cloneID); Instance* instance = FindInstance(mapID, isFriendTransfer, cloneID); if (instance) return instance; - //TODO: Update this so that the IP is read from a configuration file instead + // If we are shutting down, return a nullptr so a new instance is not created. + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } + //TODO: Update this so that the IP is read from a configuration file instead - int softCap = 8; - int maxPlayers = 12; + int softCap = 8; + int maxPlayers = 12; - if (mapID == 0) { - softCap = 999; - maxPlayers = softCap; - } else { + if (mapID == 0) { + softCap = 999; + maxPlayers = softCap; + } else { softCap = GetSoftCap(mapID); maxPlayers = GetHardCap(mapID); } - uint32_t port = GetFreePort(); - instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers); + uint32_t port = GetFreePort(); + instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers); - //Start the actual process: + //Start the actual process: #ifdef _WIN32 - std::string cmd = "start ./WorldServer.exe -zone "; + std::string cmd = "start " + (BinaryPathFinder::GetBinaryDir() / "WorldServer.exe").string() + " -zone "; #else std::string cmd; - if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) { - cmd = "sudo ./WorldServer -zone "; + if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) { + cmd = "sudo " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; } else { - cmd = "./WorldServer -zone "; + cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; } #endif - cmd.append(std::to_string(mapID)); - cmd.append(" -port "); - cmd.append(std::to_string(port)); - cmd.append(" -instance "); - cmd.append(std::to_string(m_LastInstanceID)); - cmd.append(" -maxclients "); - cmd.append(std::to_string(maxPlayers)); + cmd.append(std::to_string(mapID)); + cmd.append(" -port "); + cmd.append(std::to_string(port)); + cmd.append(" -instance "); + cmd.append(std::to_string(m_LastInstanceID)); + cmd.append(" -maxclients "); + cmd.append(std::to_string(maxPlayers)); - cmd.append(" -clone "); - cmd.append(std::to_string(cloneID)); + cmd.append(" -clone "); + cmd.append(std::to_string(cloneID)); #ifndef _WIN32 - cmd.append("&"); //Sends our next process to the background on Linux + cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); - m_Instances.push_back(instance); + m_Instances.push_back(instance); - if (instance) { - mLogger->Log("InstanceManager", "Created new instance: %i/%i/%i with min/max %i/%i\n", mapID, m_LastInstanceID, cloneID, softCap, maxPlayers); - return instance; - } - else mLogger->Log("InstanceManager", "Failed to create a new instance!\n"); + if (instance) { + mLogger->Log("InstanceManager", "Created new instance: %i/%i/%i with min/max %i/%i", mapID, m_LastInstanceID, cloneID, softCap, maxPlayers); + return instance; + } else mLogger->Log("InstanceManager", "Failed to create a new instance!"); - return nullptr; + return nullptr; } bool InstanceManager::IsPortInUse(uint32_t port) { @@ -92,27 +102,27 @@ bool InstanceManager::IsPortInUse(uint32_t port) { return true; } } - + return false; } uint32_t InstanceManager::GetFreePort() { - uint32_t port = m_LastPort; - std::vector<uint32_t> usedPorts; - for (Instance* i : m_Instances) { - usedPorts.push_back(i->GetPort()); - } - - std::sort(usedPorts.begin(), usedPorts.end()); + uint32_t port = m_LastPort; + std::vector<uint32_t> usedPorts; + for (Instance* i : m_Instances) { + usedPorts.push_back(i->GetPort()); + } - int portIdx = 0; - while (portIdx < usedPorts.size() && port == usedPorts[portIdx]) { - //increment by 3 since each instance uses 3 ports (instance, world-server, world-chat) - port += 3; - portIdx++; - } + std::sort(usedPorts.begin(), usedPorts.end()); - return port; + int portIdx = 0; + while (portIdx < usedPorts.size() && port == usedPorts[portIdx]) { + //increment by 3 since each instance uses 3 ports (instance, world-server, world-chat) + port += 3; + portIdx++; + } + + return port; } void InstanceManager::AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID) { @@ -135,26 +145,23 @@ void InstanceManager::RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWO } } -std::vector<Instance*> InstanceManager::GetInstances() const -{ +std::vector<Instance*> InstanceManager::GetInstances() const { return m_Instances; } void InstanceManager::AddInstance(Instance* instance) { if (instance == nullptr) return; - + m_Instances.push_back(instance); } void InstanceManager::RemoveInstance(Instance* instance) { - for (uint32_t i = 0; i < m_Instances.size(); ++i) - { - if (m_Instances[i] == instance) - { + for (uint32_t i = 0; i < m_Instances.size(); ++i) { + if (m_Instances[i] == instance) { instance->SetShutdownComplete(true); - - RedirectPendingRequests(instance); - + + if (!Game::shouldShutdown) RedirectPendingRequests(instance); + delete m_Instances[i]; m_Instances.erase(m_Instances.begin() + i); @@ -164,17 +171,15 @@ void InstanceManager::RemoveInstance(Instance* instance) { } } -void InstanceManager::ReadyInstance(Instance* instance) -{ +void InstanceManager::ReadyInstance(Instance* instance) { instance->SetIsReady(true); auto& pending = instance->GetPendingRequests(); - for (const auto& request : pending) - { + for (const auto& request : pending) { const auto& zoneId = instance->GetZoneID(); - Game::logger->Log("InstanceManager", "Responding to pending request %llu -> %i (%i)\n", request, zoneId.GetMapID(), zoneId.GetCloneID()); + Game::logger->Log("InstanceManager", "Responding to pending request %llu -> %i (%i)", request, zoneId.GetMapID(), zoneId.GetCloneID()); MasterPackets::SendZoneTransferResponse( Game::server, @@ -188,36 +193,33 @@ void InstanceManager::ReadyInstance(Instance* instance) instance->GetPort() ); } - + pending.clear(); } -void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstanceRequest& request) -{ +void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstanceRequest& request) { instance->GetPendingAffirmations().push_back(request); CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_AFFIRM_TRANSFER_REQUEST); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_REQUEST); bitStream.Write(request.id); - + Game::server->Send(&bitStream, instance->GetSysAddr(), false); - - Game::logger->Log("MasterServer", "Sent affirmation request %llu to %i/%i\n", request.id, + + Game::logger->Log("MasterServer", "Sent affirmation request %llu to %i/%i", request.id, static_cast<int>(instance->GetZoneID().GetMapID()), static_cast<int>(instance->GetZoneID().GetCloneID()) ); } -void InstanceManager::AffirmTransfer(Instance* instance, const uint64_t transferID) -{ +void InstanceManager::AffirmTransfer(Instance* instance, const uint64_t transferID) { auto& pending = instance->GetPendingAffirmations(); - for (auto i = 0u; i < pending.size(); ++i) - { + for (auto i = 0u; i < pending.size(); ++i) { const auto& request = pending[i]; - + if (request.id != transferID) continue; const auto& zoneId = instance->GetZoneID(); @@ -233,22 +235,20 @@ void InstanceManager::AffirmTransfer(Instance* instance, const uint64_t transfer instance->GetIP(), instance->GetPort() ); - + pending.erase(pending.begin() + i); break; } } -void InstanceManager::RedirectPendingRequests(Instance* instance) -{ +void InstanceManager::RedirectPendingRequests(Instance* instance) { const auto& zoneId = instance->GetZoneID(); - - for (const auto& request : instance->GetPendingAffirmations()) - { + + for (const auto& request : instance->GetPendingAffirmations()) { auto* in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID()); - if (!in->GetIsReady()) // Instance not ready, make a pending request + if (in && !in->GetIsReady()) // Instance not ready, make a pending request { in->GetPendingRequests().push_back(request); @@ -270,17 +270,17 @@ Instance* InstanceManager::GetInstanceBySysAddr(SystemAddress& sysAddr) { } bool InstanceManager::IsInstanceFull(Instance* instance, bool isFriendTransfer) { - if (!isFriendTransfer && instance->GetSoftCap() > instance->GetCurrentClientCount()) + if (!isFriendTransfer && instance->GetSoftCap() > instance->GetCurrentClientCount()) return false; - else if (isFriendTransfer && instance->GetHardCap() > instance->GetCurrentClientCount()) + else if (isFriendTransfer && instance->GetHardCap() > instance->GetCurrentClientCount()) return false; - + return true; } -Instance * InstanceManager::FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId) { +Instance* InstanceManager::FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId) { for (Instance* i : m_Instances) { - if (i && i->GetMapID() == mapID && i->GetCloneID() == cloneId && !IsInstanceFull(i, isFriendTransfer) && !i->GetIsPrivate() && !i->GetShutdownComplete()) { + if (i && i->GetMapID() == mapID && i->GetCloneID() == cloneId && !IsInstanceFull(i, isFriendTransfer) && !i->GetIsPrivate() && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) { return i; } } @@ -288,9 +288,9 @@ Instance * InstanceManager::FindInstance(LWOMAPID mapID, bool isFriendTransfer, return nullptr; } -Instance * InstanceManager::FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID) { +Instance* InstanceManager::FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID) { for (Instance* i : m_Instances) { - if (i && i->GetMapID() == mapID && i->GetInstanceID() == instanceID && !i->GetIsPrivate()) { + if (i && i->GetMapID() == mapID && i->GetInstanceID() == instanceID && !i->GetIsPrivate() && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) { return i; } } @@ -298,67 +298,70 @@ Instance * InstanceManager::FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceI return nullptr; } -Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password) -{ +Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password) { auto* instance = FindPrivateInstance(password); - if (instance != nullptr) - { + if (instance != nullptr) { return instance; } + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new private instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } + int maxPlayers = 999; - + uint32_t port = GetFreePort(); instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password); - //Start the actual process: - std::string cmd = "start ./WorldServer.exe -zone "; + //Start the actual process: + std::string cmd = "start " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; #ifndef _WIN32 - cmd = "./WorldServer -zone "; + cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; #endif - cmd.append(std::to_string(mapID)); - cmd.append(" -port "); - cmd.append(std::to_string(port)); - cmd.append(" -instance "); - cmd.append(std::to_string(m_LastInstanceID)); - cmd.append(" -maxclients "); - cmd.append(std::to_string(maxPlayers)); + cmd.append(std::to_string(mapID)); + cmd.append(" -port "); + cmd.append(std::to_string(port)); + cmd.append(" -instance "); + cmd.append(std::to_string(m_LastInstanceID)); + cmd.append(" -maxclients "); + cmd.append(std::to_string(maxPlayers)); - cmd.append(" -clone "); - cmd.append(std::to_string(cloneID)); + cmd.append(" -clone "); + cmd.append(std::to_string(cloneID)); #ifndef WIN32 - cmd.append("&"); //Sends our next process to the background on Linux + cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); if (instance) return instance; - else mLogger->Log("InstanceManager", "Failed to create a new instance!\n"); + else mLogger->Log("InstanceManager", "Failed to create a new instance!"); return instance; } -Instance* InstanceManager::FindPrivateInstance(const std::string& password) -{ - for (auto* instance : m_Instances) - { +Instance* InstanceManager::FindPrivateInstance(const std::string& password) { + for (auto* instance : m_Instances) { if (!instance) continue; - if (!instance->GetIsPrivate()) - { + if (!instance->GetIsPrivate()) { continue; } - mLogger->Log("InstanceManager", "Password: %s == %s => %d\n", password.c_str(), instance->GetPassword().c_str(), password == instance->GetPassword()); + mLogger->Log("InstanceManager", "Password: %s == %s => %d", password.c_str(), instance->GetPassword().c_str(), password == instance->GetPassword()); - if (instance->GetPassword() == password) - { + if (instance->GetPassword() == password) { return instance; } } @@ -367,7 +370,7 @@ Instance* InstanceManager::FindPrivateInstance(const std::string& password) } int InstanceManager::GetSoftCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); if (zoneTable) { const CDZoneTable* zone = zoneTable->Query(mapID); @@ -375,12 +378,12 @@ int InstanceManager::GetSoftCap(LWOMAPID mapID) { return zone->population_soft_cap; } } - + return 8; } int InstanceManager::GetHardCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); if (zoneTable) { const CDZoneTable* zone = zoneTable->Query(mapID); @@ -392,23 +395,20 @@ int InstanceManager::GetHardCap(LWOMAPID mapID) { return 12; } -void Instance::SetShutdownComplete(const bool value) -{ +void Instance::SetShutdownComplete(const bool value) { m_Shutdown = value; } -bool Instance::GetShutdownComplete() const -{ +bool Instance::GetShutdownComplete() const { return m_Shutdown; } -void Instance::Shutdown() -{ +void Instance::Shutdown() { CBITSTREAM; - - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN); + + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); Game::server->Send(&bitStream, this->m_SysAddr, false); - - Game::logger->Log("Instance", "Triggered world shutdown\n"); + + Game::logger->Log("Instance", "Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID()); } diff --git a/dMasterServer/InstanceManager.h b/dMasterServer/InstanceManager.h index 5dc93849..5f48f93b 100644 --- a/dMasterServer/InstanceManager.h +++ b/dMasterServer/InstanceManager.h @@ -31,6 +31,7 @@ public: m_PendingAffirmations = {}; m_PendingRequests = {}; m_Ready = false; + m_IsShuttingDown = false; } const std::string& GetIP() const { return m_IP; } @@ -46,9 +47,11 @@ public: bool GetIsReady() const { return m_Ready; } void SetIsReady(bool value) { m_Ready = value; } + bool GetIsShuttingDown() const { return m_IsShuttingDown; } + void SetIsShuttingDown(bool value) { m_IsShuttingDown = value; } std::vector<PendingInstanceRequest>& GetPendingRequests() { return m_PendingRequests; } std::vector<PendingInstanceRequest>& GetPendingAffirmations() { return m_PendingAffirmations; } - + int GetHardCap() const { return m_MaxClientsHardCap; } int GetSoftCap() const { return m_MaxClientsSoftCap; } int GetCurrentClientCount() const { return m_CurrentClientCount; } @@ -57,10 +60,10 @@ public: uint32_t GetAffirmationTimeout() const { return m_AffirmationTimeout; } void AddPlayer(Player player) { /*m_Players.push_back(player);*/ m_CurrentClientCount++; } - void RemovePlayer(Player player) { + void RemovePlayer(Player player) { m_CurrentClientCount--; if (m_CurrentClientCount < 0) m_CurrentClientCount = 0; - /*for (size_t i = 0; i < m_Players.size(); ++i) + /*for (size_t i = 0; i < m_Players.size(); ++i) if (m_Players[i].addr == player.addr) m_Players.erase(m_Players.begin() + i);*/ } @@ -69,7 +72,7 @@ public: void SetShutdownComplete(bool value); bool GetShutdownComplete() const; - + void Shutdown(); private: @@ -82,11 +85,12 @@ private: std::vector<Player> m_Players; SystemAddress m_SysAddr; bool m_Ready; + bool m_IsShuttingDown; std::vector<PendingInstanceRequest> m_PendingRequests; std::vector<PendingInstanceRequest> m_PendingAffirmations; uint32_t m_AffirmationTimeout; - + bool m_IsPrivate; std::string m_Password; @@ -103,7 +107,7 @@ public: Instance* GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID); //Creates an instance if none found bool IsPortInUse(uint32_t port); uint32_t GetFreePort(); - + void AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID); void RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID); @@ -124,6 +128,7 @@ public: Instance* CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password); Instance* FindPrivateInstance(const std::string& password); + void SetIsShuttingDown(bool value) { this->m_IsShuttingDown = value; }; private: dLogger* mLogger; @@ -132,6 +137,11 @@ private: unsigned short m_LastPort; LWOINSTANCEID m_LastInstanceID; + /** + * Whether or not the master server is currently shutting down. + */ + bool m_IsShuttingDown = false; + //Private functions: bool IsInstanceFull(Instance* instance, bool isFriendTransfer); int GetSoftCap(LWOMAPID mapID); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index ac49b1a1..bc0937c2 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -19,11 +19,16 @@ #include "CDClientDatabase.h" #include "CDClientManager.h" #include "Database.h" +#include "MigrationRunner.h" #include "Diagnostics.h" #include "dCommonVars.h" #include "dConfig.h" #include "dLogger.h" #include "dServer.h" +#include "AssetManager.h" +#include "BinaryPathFinder.h" +#include "eConnectionType.h" +#include "eMasterMessageType.h" //RakNet includes: #include "RakNetDefines.h" @@ -36,27 +41,31 @@ #include "MasterPackets.h" #include "ObjectIDManager.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" +#include "FdbToSqlite.h" namespace Game { - dLogger* logger; - dServer* server; - InstanceManager* im; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + InstanceManager* im = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + bool shouldShutdown = false; } //namespace Game bool shutdownSequenceStarted = false; -void ShutdownSequence(); -int FinalizeShutdown(); +void ShutdownSequence(int32_t signal = -1); +int32_t FinalizeShutdown(int32_t signal = -1); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); void HandlePacket(Packet* packet); std::map<uint32_t, std::string> activeSessions; -bool shouldShutdown = false; +SystemAddress authServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { + constexpr uint32_t masterFramerate = mediumFramerate; + constexpr uint32_t masterFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Master"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -66,64 +75,131 @@ int main(int argc, char** argv) { #endif //Triggers the shutdown sequence at application exit - std::atexit(ShutdownSequence); - signal(SIGINT, [](int) { ShutdownSequence(); }); - signal(SIGTERM, [](int) { ShutdownSequence(); }); + std::atexit([]() { ShutdownSequence(); }); + signal(SIGINT, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGTERM, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); //Create all the objects we need to run our service: Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; - Game::logger->Log("MasterServer", "Starting Master server...\n"); - Game::logger->Log("MasterServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); - Game::logger->Log("MasterServer", "Compiled on: %s\n", __TIMESTAMP__); - - //Read our config: - dConfig config("masterconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - - //Check CDClient exists - const std::string cdclient_path = "./res/CDServer.sqlite"; - std::ifstream cdclient_fd(cdclient_path); - if (!cdclient_fd.good()) { - Game::logger->Log("WorldServer", "%s could not be opened\n", cdclient_path.c_str()); - return EXIT_FAILURE; - } - cdclient_fd.close(); - - //Connect to CDClient - try { - CDClientDatabase::Connect(cdclient_path); - } catch (CppSQLite3Exception& e) { - Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database\n"); - Game::logger->Log("WorldServer", "Error: %s\n", e.errorMessage()); - Game::logger->Log("WorldServer", "Error Code: %i\n", e.errorCode()); + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find authconfig.ini"); return EXIT_FAILURE; } - //Get CDClient initial information - try { - CDClientManager::Instance()->Initialize(); - } catch (CppSQLite3Exception& e) { - Game::logger->Log("WorldServer", "Failed to initialize CDServer SQLite Database\n"); - Game::logger->Log("WorldServer", "May be caused by corrupted file: %s\n", cdclient_path.c_str()); - Game::logger->Log("WorldServer", "Error: %s\n", e.errorMessage()); - Game::logger->Log("WorldServer", "Error Code: %i\n", e.errorCode()); + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini"); return EXIT_FAILURE; } + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini"); + return EXIT_FAILURE; + } + + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + + Game::logger->Log("MasterServer", "Starting Master server..."); + Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); + Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); + //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { - Game::logger->Log("MasterServer", "Got an error while connecting to the database: %s\n", ex.what()); + Game::logger->Log("MasterServer", "Got an error while connecting to the database: %s", ex.what()); + Game::logger->Log("MigrationRunner", "Migrations not run"); + return EXIT_FAILURE; + } + + try { + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + + Game::assetManager = new AssetManager(clientPath); + } catch (std::runtime_error& ex) { + Game::logger->Log("MasterServer", "Got an error while setting up assets: %s", ex.what()); + + return EXIT_FAILURE; + } + + MigrationRunner::RunMigrations(); + + const bool cdServerExists = std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + const bool oldCDServerExists = std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite"); + const bool fdbExists = std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb"); + + if (!cdServerExists) { + if (oldCDServerExists) { + // If the file doesn't exist in the new CDServer location, copy it there. We copy because we may not have write permissions from the previous directory. + Game::logger->Log("MasterServer", "CDServer.sqlite is not located at resServer, but is located at res path. Copying file..."); + std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + } else { + Game::logger->Log("MasterServer", + "%s could not be found in resServer or res. Looking for %s to convert to sqlite.", + (BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), + (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + + AssetMemoryBuffer cdClientBuffer = Game::assetManager->GetFileAsBuffer("cdclient.fdb"); + if (!cdClientBuffer.m_Success) { + Game::logger->Log("MasterServer", "Failed to load %s", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + throw std::runtime_error("Aborting initialization due to missing cdclient.fdb."); + } + + Game::logger->Log("MasterServer", "Found %s. Converting to SQLite", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + Game::logger->Flush(); + + if (FdbToSqlite::Convert((BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase(cdClientBuffer) == false) { + Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite."); + return EXIT_FAILURE; + } + cdClientBuffer.close(); + } + } + + //Connect to CDClient + try { + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); + Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); + Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); + return EXIT_FAILURE; + } + + // Run migrations should any need to be run. + MigrationRunner::RunSQLiteMigrations(); + + //Get CDClient initial information + try { + CDClientManager::Instance(); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("WorldServer", "Failed to initialize CDServer SQLite Database"); + Game::logger->Log("WorldServer", "May be caused by corrupted file: %s", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str()); + Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); + Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); return EXIT_FAILURE; } @@ -137,60 +213,96 @@ int main(int argc, char** argv) { std::cout << "Enter a username: "; std::cin >> username; + std::unique_ptr<sql::PreparedStatement> userLookupStatement(Database::CreatePreppedStmt("SELECT id FROM accounts WHERE name=? LIMIT 1;")); + userLookupStatement->setString(1, username.c_str()); + std::unique_ptr<sql::ResultSet> res(userLookupStatement->executeQuery()); + if (res->rowsCount() > 0) { + Game::logger->Log("MasterServer", "Account with name \"%s\" already exists", username.c_str()); + std::cout << "Do you want to change the password of that account? [y/n]?"; + std::string prompt = ""; + std::cin >> prompt; + if (prompt == "y" || prompt == "yes"){ + uint32_t accountId = 0; + res->next(); + accountId = res->getUInt(1); + if (accountId == 0) return EXIT_FAILURE; + + //Read the password from the console without echoing it. + #ifdef __linux__ + //This function is obsolete, but it only meant to be used by the + //sysadmin to create their first account. + password = getpass("Enter a password: "); + #else + std::cout << "Enter a password: "; + std::cin >> password; + #endif + + // Regenerate hash based on new password + char salt[BCRYPT_HASHSIZE]; + char hash[BCRYPT_HASHSIZE]; + int32_t bcryptState = ::bcrypt_gensalt(12, salt); + assert(bcryptState == 0); + bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); + assert(bcryptState == 0); + + std::unique_ptr<sql::PreparedStatement> userUpdateStatement(Database::CreatePreppedStmt("UPDATE accounts SET password = ? WHERE id = ?;")); + userUpdateStatement->setString(1, std::string(hash, BCRYPT_HASHSIZE).c_str()); + userUpdateStatement->setUInt(2, accountId); + userUpdateStatement->execute(); + + Game::logger->Log("MasterServer", "Account \"%s\" password updated successfully!", username.c_str()); + } else { + Game::logger->Log("MasterServer", "Account \"%s\" was not updated.", username.c_str()); + } + return EXIT_SUCCESS; + } + //Read the password from the console without echoing it. -#ifdef __linux__ - //This function is obsolete, but it only meant to be used by the - //sysadmin to create their first account. - password = getpass("Enter a password: "); -#else - std::cout << "Enter a password: "; - std::cin >> password; -#endif + #ifdef __linux__ + //This function is obsolete, but it only meant to be used by the + //sysadmin to create their first account. + password = getpass("Enter a password: "); + #else + std::cout << "Enter a password: "; + std::cin >> password; + #endif //Generate new hash for bcrypt - char salt[BCRYPT_HASHSIZE]; char hash[BCRYPT_HASHSIZE]; - int32_t bcryptState = ::bcrypt_gensalt(12, salt); - assert(bcryptState == 0); - bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); - assert(bcryptState == 0); //Create account + try { + std::unique_ptr<sql::PreparedStatement> statement(Database::CreatePreppedStmt("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);")); + statement->setString(1, username.c_str()); + statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); + statement->setInt(3, 9); + statement->execute(); + } catch(sql::SQLException& e) { + Game::logger->Log("MasterServer", "A SQL error occurred!:\n %s", e.what()); + return EXIT_FAILURE; + } - auto* statement = Database::CreatePreppedStmt("INSERT INTO accounts (name, password, ""gm_level) VALUES (?, ?, ?);"); - statement->setString(1, username); - statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); - statement->setInt(3, 9); - - statement->execute(); - - delete statement; - - std::cout << "Account created successfully!\n"; - - Database::Destroy("MasterServer"); - delete Game::logger; - + Game::logger->Log("MasterServer", "Account created successfully!"); return EXIT_SUCCESS; } - int maxClients = 999; - int ourPort = 1000; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::stoi(config.GetValue("port")); + uint32_t maxClients = 999; + uint32_t ourPort = 1000; + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::shouldShutdown); //Query for the database for a server labeled "master" auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); auto* result = masterLookupStatement->executeQuery(); - auto master_server_ip = config.GetValue("master_ip"); + auto master_server_ip = Game::config->GetValue("master_ip"); if (master_server_ip == "") { master_server_ip = Game::server->GetIP(); @@ -199,16 +311,15 @@ int main(int argc, char** argv) { //If we found a server, update it's IP and port to the current one. if (result->next()) { auto* updateStatement = Database::CreatePreppedStmt("UPDATE `servers` SET `ip` = ?, `port` = ? WHERE `id` = ?"); - updateStatement->setString(1, master_server_ip); + updateStatement->setString(1, master_server_ip.c_str()); updateStatement->setInt(2, Game::server->GetPort()); updateStatement->setInt(3, result->getInt("id")); updateStatement->execute(); delete updateStatement; - } - else { + } else { //If we didn't find a server, create one. auto* insertStatement = Database::CreatePreppedStmt("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171023)"); - insertStatement->setString(1, master_server_ip); + insertStatement->setString(1, master_server_ip.c_str()); insertStatement->setInt(2, Game::server->GetPort()); insertStatement->execute(); delete insertStatement; @@ -219,20 +330,24 @@ int main(int argc, char** argv) { Game::im = new InstanceManager(Game::logger, Game::server->GetIP()); //Depending on the config, start up servers: - if (config.GetValue("prestart_servers") != "" && config.GetValue("prestart_servers") == "1") { + if (Game::config->GetValue("prestart_servers") != "" && Game::config->GetValue("prestart_servers") == "1") { StartChatServer(); - Game::im->GetInstance(0, false, 0)->SetIsReady(true); - Game::im->GetInstance(1000, false, 0)->SetIsReady(true); + Game::im->GetInstance(0, false, 0); + Game::im->GetInstance(1000, false, 0); StartAuthServer(); } auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceLastSQLPing = 0; - int framesSinceKillUniverseCommand = 0; + constexpr uint32_t logFlushTime = 15 * masterFramerate; + constexpr uint32_t sqlPingTime = 10 * 60 * masterFramerate; + constexpr uint32_t shutdownUniverseTime = 10 * 60 * masterFramerate; + constexpr uint32_t instanceReadyTimeout = 30 * masterFramerate; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceKillUniverseCommand = 0; while (true) { //In world we'd update our other systems here. @@ -246,18 +361,17 @@ int main(int argc, char** argv) { } //Push our log every 15s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; - } - else + } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -269,17 +383,15 @@ int main(int argc, char** argv) { delete stmt; framesSinceLastSQLPing = 0; - } - else + } else framesSinceLastSQLPing++; //10m shutdown for universe kill command - if (shouldShutdown) { - if (framesSinceKillUniverseCommand >= 40000) { + if (Game::shouldShutdown) { + if (framesSinceKillUniverseCommand >= shutdownUniverseTime) { //Break main loop and exit break; - } - else + } else framesSinceKillUniverseCommand++; } @@ -294,16 +406,15 @@ int main(int argc, char** argv) { if (!instance->GetPendingAffirmations().empty()) { affirmTimeout++; - } - else { + } else { affirmTimeout = 0; } instance->SetAffirmationTimeout(affirmTimeout); - if (affirmTimeout == 1000) { + if (affirmTimeout == instanceReadyTimeout) { instance->Shutdown(); - instance->SetShutdownComplete(true); + instance->SetIsShuttingDown(true); Game::im->RedirectPendingRequests(instance); } @@ -320,17 +431,15 @@ int main(int argc, char** argv) { } } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(masterFrameDelta); std::this_thread::sleep_until(t); } - FinalizeShutdown(); - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; + return FinalizeShutdown(EXIT_SUCCESS); } dLogger* SetupLogger() { std::string logPath = - "./logs/MasterServer_" + std::to_string(time(nullptr)) + ".log"; + (BinaryPathFinder::GetBinaryDir() / ("logs/MasterServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -343,41 +452,55 @@ dLogger* SetupLogger() { void HandlePacket(Packet* packet) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION) { - Game::logger->Log("MasterServer", "A server has disconnected\n"); + Game::logger->Log("MasterServer", "A server has disconnected"); //Since this disconnection is intentional, we'll just delete it as //we'll start a new one anyway if needed: Instance* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress); if (instance) { + Game::logger->Log("MasterServer", "Actually disconnected from zone %i clone %i instance %i port %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance->GetPort()); Game::im->RemoveInstance(instance); //Delete the old } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } if (packet->data[0] == ID_CONNECTION_LOST) { - Game::logger->Log("MasterServer", "A server has lost the connection\n"); + Game::logger->Log("MasterServer", "A server has lost the connection"); Instance* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress); if (instance) { LWOZONEID zoneID = instance->GetZoneID(); //Get the zoneID so we can recreate a server Game::im->RemoveInstance(instance); //Delete the old - //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } - if (packet->data[1] == MASTER) { - switch (packet->data[3]) { - case MSG_MASTER_REQUEST_PERSISTENT_ID: { - Game::logger->Log("MasterServer", "A persistent ID req\n"); + if (packet->length < 4) return; + + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) { + switch (static_cast<eMasterMessageType>(packet->data[3])) { + case eMasterMessageType::REQUEST_PERSISTENT_ID: { + Game::logger->Log("MasterServer", "A persistent ID req"); RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint64_t requestID = 0; @@ -388,8 +511,8 @@ void HandlePacket(Packet* packet) { break; } - case MSG_MASTER_REQUEST_ZONE_TRANSFER: { - Game::logger->Log("MasterServer","Received zone transfer req\n"); + case eMasterMessageType::REQUEST_ZONE_TRANSFER: { + Game::logger->Log("MasterServer", "Received zone transfer req"); RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint64_t requestID = 0; @@ -401,27 +524,30 @@ void HandlePacket(Packet* packet) { inStream.Read(mythranShift); inStream.Read(zoneID); inStream.Read(zoneClone); - + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not creating a new zone."); + break; + } Instance* in = Game::im->GetInstance(zoneID, false, zoneClone); for (auto* instance : Game::im->GetInstances()) { - Game::logger->Log("MasterServer", "Instance: %i/%i/%i -> %i\n",instance->GetMapID(), instance->GetCloneID(),instance->GetInstanceID(), instance == in); + Game::logger->Log("MasterServer", "Instance: %i/%i/%i -> %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance == in); } - if (!in->GetIsReady()) //Instance not ready, make a pending request + if (in && !in->GetIsReady()) //Instance not ready, make a pending request { in->GetPendingRequests().push_back({ requestID, static_cast<bool>(mythranShift), packet->systemAddress }); - Game::logger->Log("MasterServer", "Server not ready, adding pending request %llu %i %i\n", requestID, zoneID, zoneClone); + Game::logger->Log("MasterServer", "Server not ready, adding pending request %llu %i %i", requestID, zoneID, zoneClone); break; } //Instance is ready, transfer - Game::logger->Log("MasterServer", "Responding to transfer request %llu for zone %i %i\n", requestID, zoneID, zoneClone); + Game::logger->Log("MasterServer", "Responding to transfer request %llu for zone %i %i", requestID, zoneID, zoneClone); Game::im->RequestAffirmation(in, { requestID, static_cast<bool>(mythranShift), packet->systemAddress }); break; } - case MSG_MASTER_SERVER_INFO: { + case eMasterMessageType::SERVER_INFO: { //MasterPackets::HandleServerInfo(packet); //This is here because otherwise we'd have to include IM in @@ -451,8 +577,7 @@ void HandlePacket(Packet* packet) { in->SetSysAddr(copy); Game::im->AddInstance(in); - } - else { + } else { auto instance = Game::im->FindInstance( theirZoneID, static_cast<uint16_t>(theirInstanceID)); if (instance) { @@ -468,12 +593,20 @@ void HandlePacket(Packet* packet) { chatServerMasterPeerSysAddr = copy; } - Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i\n", theirInstanceID, theirPort); + if (theirServerType == ServerType::Auth) { + SystemAddress copy; + copy.binaryAddress = packet->systemAddress.binaryAddress; + copy.port = packet->systemAddress.port; + + authServerMasterPeerSysAddr = copy; + } + + Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i", theirInstanceID, theirPort); break; } - case MSG_MASTER_SET_SESSION_KEY: { + case eMasterMessageType::SET_SESSION_KEY: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint32_t sessionKey = 0; @@ -487,9 +620,12 @@ void HandlePacket(Packet* packet) { activeSessions.erase(it.first); CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_NEW_SESSION_ALERT); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::NEW_SESSION_ALERT); bitStream.Write(sessionKey); - bitStream.Write(RakNet::RakString(username.c_str())); + bitStream.Write<uint32_t>(username.size()); + for (auto character : username) { + bitStream.Write(character); + } SEND_PACKET_BROADCAST; break; @@ -497,11 +633,11 @@ void HandlePacket(Packet* packet) { } activeSessions.insert(std::make_pair(sessionKey, username)); - Game::logger->Log("MasterServer", "Got sessionKey %i for user %s\n", sessionKey, username.c_str()); + Game::logger->Log("MasterServer", "Got sessionKey %i for user %s", sessionKey, username.c_str()); break; } - case MSG_MASTER_REQUEST_SESSION_KEY: { + case eMasterMessageType::REQUEST_SESSION_KEY: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); std::string username = PacketUtils::ReadString(8, packet, false); @@ -509,7 +645,7 @@ void HandlePacket(Packet* packet) { for (auto key : activeSessions) { if (key.second == username) { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SESSION_KEY_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SESSION_KEY_RESPONSE); bitStream.Write(key.first); PacketUtils::WriteString(bitStream, key.second, 64); Game::server->Send(&bitStream, packet->systemAddress, false); @@ -519,7 +655,7 @@ void HandlePacket(Packet* packet) { break; } - case MSG_MASTER_PLAYER_ADDED: { + case eMasterMessageType::PLAYER_ADDED: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -533,14 +669,13 @@ void HandlePacket(Packet* packet) { Game::im->FindInstance(theirZoneID, theirInstanceID); if (instance) { instance->AddPlayer(Player()); - } - else { - printf("Instance missing? What?\n"); + } else { + printf("Instance missing? What?"); } break; } - case MSG_MASTER_PLAYER_REMOVED: { + case eMasterMessageType::PLAYER_REMOVED: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -558,40 +693,53 @@ void HandlePacket(Packet* packet) { break; } - case MSG_MASTER_CREATE_PRIVATE_ZONE: { + case eMasterMessageType::CREATE_PRIVATE_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint32_t mapId; LWOCLONEID cloneId; - RakNet::RakString password; + std::string password; inStream.Read(mapId); inStream.Read(cloneId); - inStream.Read(password); - Game::im->CreatePrivateInstance(mapId, cloneId, - password.C_String()); + uint32_t len; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + password += character; + } + + Game::im->CreatePrivateInstance(mapId, cloneId, password.c_str()); break; } - case MSG_MASTER_REQUEST_PRIVATE_ZONE: { + case eMasterMessageType::REQUEST_PRIVATE_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint64_t requestID = 0; uint8_t mythranShift = false; - RakNet::RakString password; + std::string password; inStream.Read(requestID); inStream.Read(mythranShift); - inStream.Read(password); - auto* instance = Game::im->FindPrivateInstance(password.C_String()); + uint32_t len; + inStream.Read<uint32_t>(len); - Game::logger->Log( "MasterServer", "Join private zone: %llu %d %s %p\n", requestID, mythranShift, password.C_String(), instance); + for (uint32_t i = 0; i < len; i++) { + char character; inStream.Read<char>(character); + password += character; + } + + auto* instance = Game::im->FindPrivateInstance(password.c_str()); + + Game::logger->Log("MasterServer", "Join private zone: %llu %d %s %p", requestID, mythranShift, password.c_str(), instance); if (instance == nullptr) { return; @@ -599,12 +747,12 @@ void HandlePacket(Packet* packet) { const auto& zone = instance->GetZoneID(); - MasterPackets::SendZoneTransferResponse(Game::server, packet->systemAddress, requestID,(bool)mythranShift, zone.GetMapID(),instance->GetInstanceID(), zone.GetCloneID(),instance->GetIP(), instance->GetPort()); + MasterPackets::SendZoneTransferResponse(Game::server, packet->systemAddress, requestID, (bool)mythranShift, zone.GetMapID(), instance->GetInstanceID(), zone.GetCloneID(), instance->GetIP(), instance->GetPort()); break; } - case MSG_MASTER_WORLD_READY: { + case eMasterMessageType::WORLD_READY: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -614,33 +762,37 @@ void HandlePacket(Packet* packet) { inStream.Read(zoneID); inStream.Read(instanceID); - Game::logger->Log("MasterServer", "Got world ready %i %i\n",zoneID, instanceID); + Game::logger->Log("MasterServer", "Got world ready %i %i", zoneID, instanceID); auto* instance = Game::im->FindInstance(zoneID, instanceID); if (instance == nullptr) { - Game::logger->Log("MasterServer","Failed to find zone to ready\n"); + Game::logger->Log("MasterServer", "Failed to find zone to ready"); return; } - Game::logger->Log("MasterServer", "Ready zone %i\n", zoneID); + Game::logger->Log("MasterServer", "Ready zone %i", zoneID); Game::im->ReadyInstance(instance); break; } - case MSG_MASTER_PREP_ZONE: { + case eMasterMessageType::PREP_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - int zoneID; + int32_t zoneID; inStream.Read(zoneID); - - Game::logger->Log("MasterServer", "Prepping zone %i\n", zoneID); - Game::im->GetInstance(zoneID, false, 0); + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not prepping a new zone."); + break; + } else { + Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); + Game::im->GetInstance(zoneID, false, 0); + } break; } - case MSG_MASTER_AFFIRM_TRANSFER_RESPONSE: { + case eMasterMessageType::AFFIRM_TRANSFER_RESPONSE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -648,19 +800,19 @@ void HandlePacket(Packet* packet) { inStream.Read(requestID); - Game::logger->Log("MasterServer","Got affirmation of transfer %llu\n",requestID); + Game::logger->Log("MasterServer", "Got affirmation of transfer %llu", requestID); - auto* instance =Game::im->GetInstanceBySysAddr(packet->systemAddress); + auto* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress); if (instance == nullptr) return; Game::im->AffirmTransfer(instance, requestID); - Game::logger->Log("MasterServer", "Affirmation complete %llu\n",requestID); + Game::logger->Log("MasterServer", "Affirmation complete %llu", requestID); break; } - case MSG_MASTER_SHUTDOWN_RESPONSE: { + case eMasterMessageType::SHUTDOWN_RESPONSE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -670,96 +822,113 @@ void HandlePacket(Packet* packet) { return; } - Game::logger->Log("MasterServer", "Got shutdown response\n"); - instance->SetShutdownComplete(true); + Game::logger->Log("MasterServer", "Got shutdown response from zone %i clone %i instance %i port %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance->GetPort()); + instance->SetIsShuttingDown(true); break; } - case MSG_MASTER_SHUTDOWN_UNIVERSE: { - Game::logger->Log("MasterServer","Received shutdown universe command, shutting down in 10 minutes.\n"); - shouldShutdown = true; + case eMasterMessageType::SHUTDOWN_UNIVERSE: { + Game::logger->Log("MasterServer", "Received shutdown universe command, shutting down in 10 minutes."); + Game::shouldShutdown = true; break; } default: - Game::logger->Log("MasterServer","Unknown master packet ID from server: %i\n",packet->data[3]); + Game::logger->Log("MasterServer", "Unknown master packet ID from server: %i", packet->data[3]); } } } void StartChatServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Chat will not be restarted."); + return; + } #ifdef __APPLE__ - //macOS doesn't need sudo to run on ports < 1024 - system("./ChatServer&"); + //macOS doesn't need sudo to run on ports < 1024 + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); #elif _WIN32 - system("start ./ChatServer.exe"); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); #else - if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - system("sudo ./ChatServer&"); - } - else { - system("./ChatServer&"); - } + if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + } else { + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); +} #endif } void StartAuthServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Auth will not be restarted."); + return; + } #ifdef __APPLE__ - system("./AuthServer&"); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 - system("start ./AuthServer.exe"); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); #else - if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - system("sudo ./AuthServer&"); - } - else { - system("./AuthServer&"); - } + if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + } else { + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); +} #endif } -void ShutdownSequence() { +void ShutdownSequence(int32_t signal) { if (shutdownSequenceStarted) { return; } + if (!Game::im) { + FinalizeShutdown(EXIT_FAILURE); + } + + Game::im->SetIsShuttingDown(true); shutdownSequenceStarted = true; + Game::shouldShutdown = true; - if (Game::im) { - for (auto* instance : Game::im->GetInstances()) { - if (instance == nullptr) { - continue; - } - - instance->Shutdown(); - } + { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); + Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::logger->Log("MasterServer", "Triggered master shutdown"); } auto* objIdManager = ObjectIDManager::TryInstance(); - if (objIdManager != nullptr) { + if (objIdManager) { objIdManager->SaveToDatabase(); - Game::logger->Log("MasterServer", "Saved ObjectIDTracker to DB\n"); + Game::logger->Log("MasterServer", "Saved ObjectIDTracker to DB"); } + // A server might not be finished spinning up yet, remove all of those here. + for (auto* instance : Game::im->GetInstances()) { + if (!instance->GetIsReady()) { + Game::im->RemoveInstance(instance); + } + } + + for (auto* instance : Game::im->GetInstances()) { + instance->SetIsShuttingDown(true); + } + + Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); + auto t = std::chrono::high_resolution_clock::now(); - auto ticks = 0; - - if (!Game::im) { - exit(EXIT_SUCCESS); - } - - Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...\n"); - + uint32_t framesSinceShutdownStart = 0; + constexpr uint32_t maxShutdownTime = 60 * mediumFramerate; + bool allInstancesShutdown = false; + Packet* packet = nullptr; while (true) { - - auto packet = Game::server->Receive(); + packet = Game::server->Receive(); if (packet) { HandlePacket(packet); Game::server->DeallocatePacket(packet); packet = nullptr; } - - auto done = true; + + allInstancesShutdown = true; for (auto* instance : Game::im->GetInstances()) { if (instance == nullptr) { @@ -767,36 +936,37 @@ void ShutdownSequence() { } if (!instance->GetShutdownComplete()) { - done = false; + allInstancesShutdown = false; } } - if (done) { - Game::logger->Log("MasterServer", "Finished shutting down MasterServer!\n"); + if (allInstancesShutdown && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { + Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); break; } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(mediumFrameDelta); std::this_thread::sleep_until(t); - ticks++; + framesSinceShutdownStart++; - if (ticks == 600 * 6) { - Game::logger->Log("MasterServer", "Finished shutting down by timeout!\n"); + if (framesSinceShutdownStart == maxShutdownTime) { + Game::logger->Log("MasterServer", "Finished shutting down by timeout!"); break; } } - FinalizeShutdown(); + FinalizeShutdown(signal); } -int FinalizeShutdown() { +int32_t FinalizeShutdown(int32_t signal) { //Delete our objects here: Database::Destroy("MasterServer"); - delete Game::im; - delete Game::server; - delete Game::logger; + if (Game::config) delete Game::config; + if (Game::im) delete Game::im; + if (Game::server) delete Game::server; + if (Game::logger) delete Game::logger; - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; -} \ No newline at end of file + if (signal != EXIT_SUCCESS) exit(signal); + return signal; +} diff --git a/dMasterServer/ObjectIDManager.cpp b/dMasterServer/ObjectIDManager.cpp index 28a8ea17..83dde8dd 100644 --- a/dMasterServer/ObjectIDManager.cpp +++ b/dMasterServer/ObjectIDManager.cpp @@ -5,67 +5,67 @@ #include "dLogger.h" // Static Variables -ObjectIDManager *ObjectIDManager::m_Address = nullptr; +ObjectIDManager* ObjectIDManager::m_Address = nullptr; //! Initializes the manager -void ObjectIDManager::Initialize(dLogger *logger) { - this->mLogger = logger; - this->currentPersistentID = 1; +void ObjectIDManager::Initialize(dLogger* logger) { + this->mLogger = logger; + this->currentPersistentID = 1; - try { - sql::PreparedStatement *stmt = Database::CreatePreppedStmt( - "SELECT last_object_id FROM object_id_tracker"); + try { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt( + "SELECT last_object_id FROM object_id_tracker"); - sql::ResultSet *result = stmt->executeQuery(); - auto next = result->next(); + sql::ResultSet* result = stmt->executeQuery(); + auto next = result->next(); - if (!next) { - sql::PreparedStatement *insertStmt = Database::CreatePreppedStmt( - "INSERT INTO object_id_tracker VALUES (1)"); + if (!next) { + sql::PreparedStatement* insertStmt = Database::CreatePreppedStmt( + "INSERT INTO object_id_tracker VALUES (1)"); - insertStmt->execute(); + insertStmt->execute(); - delete insertStmt; + delete insertStmt; - return; - } + return; + } - while (next) { - this->currentPersistentID = - result->getInt(1) > 0 ? result->getInt(1) : 1; - next = result->next(); - } + while (next) { + this->currentPersistentID = + result->getInt(1) > 0 ? result->getInt(1) : 1; + next = result->next(); + } - delete result; - delete stmt; - } catch (sql::SQLException &e) { - mLogger->Log("ObjectIDManager", "Unable to fetch max persistent object " - "ID in use. Defaulting to 1.\n"); - mLogger->Log("ObjectIDManager", "SQL error: %s\n", e.what()); - this->currentPersistentID = 1; - } + delete result; + delete stmt; + } catch (sql::SQLException& e) { + mLogger->Log("ObjectIDManager", "Unable to fetch max persistent object " + "ID in use. Defaulting to 1."); + mLogger->Log("ObjectIDManager", "SQL error: %s", e.what()); + this->currentPersistentID = 1; + } } //! Generates a new persistent ID uint32_t ObjectIDManager::GeneratePersistentID(void) { - uint32_t toReturn = ++this->currentPersistentID; + uint32_t toReturn = ++this->currentPersistentID; - // So we peroidically save our ObjID to the database: - if (toReturn % 25 == 0) { // TEMP: DISABLED FOR DEBUG / DEVELOPMENT! - sql::PreparedStatement *stmt = Database::CreatePreppedStmt( - "UPDATE object_id_tracker SET last_object_id=?"); - stmt->setUInt(1, toReturn); - stmt->execute(); - delete stmt; - } + // So we peroidically save our ObjID to the database: + // if (toReturn % 25 == 0) { // TEMP: DISABLED FOR DEBUG / DEVELOPMENT! + sql::PreparedStatement* stmt = Database::CreatePreppedStmt( + "UPDATE object_id_tracker SET last_object_id=?"); + stmt->setUInt(1, toReturn); + stmt->execute(); + delete stmt; + // } - return toReturn; + return toReturn; } void ObjectIDManager::SaveToDatabase() { - sql::PreparedStatement *stmt = Database::CreatePreppedStmt( - "UPDATE object_id_tracker SET last_object_id=?"); - stmt->setUInt(1, currentPersistentID); - stmt->execute(); - delete stmt; + sql::PreparedStatement* stmt = Database::CreatePreppedStmt( + "UPDATE object_id_tracker SET last_object_id=?"); + stmt->setUInt(1, currentPersistentID); + stmt->execute(); + delete stmt; } diff --git a/dMasterServer/ObjectIDManager.h b/dMasterServer/ObjectIDManager.h index fd63434b..b18619bc 100644 --- a/dMasterServer/ObjectIDManager.h +++ b/dMasterServer/ObjectIDManager.h @@ -10,38 +10,38 @@ class dLogger; \brief A manager that handles requests for object IDs */ -//! The Object ID Manager + //! The Object ID Manager class ObjectIDManager { private: dLogger* mLogger; - static ObjectIDManager * m_Address; //!< The singleton instance - - uint32_t currentPersistentID; //!< The highest current persistent ID in use - + static ObjectIDManager* m_Address; //!< The singleton instance + + uint32_t currentPersistentID; //!< The highest current persistent ID in use + public: - - //! Return the singleton if it is initialized - static ObjectIDManager* TryInstance() { - return m_Address; - } - //! The singleton method - static ObjectIDManager * Instance() { - if (m_Address == nullptr) { - m_Address = new ObjectIDManager; - } - - return m_Address; - } - - //! Initializes the manager - void Initialize(dLogger* logger); - - //! Generates a new persistent ID - /*! - \return The new persistent ID - */ - uint32_t GeneratePersistentID(void); + //! Return the singleton if it is initialized + static ObjectIDManager* TryInstance() { + return m_Address; + } - void SaveToDatabase(); + //! The singleton method + static ObjectIDManager* Instance() { + if (m_Address == nullptr) { + m_Address = new ObjectIDManager; + } + + return m_Address; + } + + //! Initializes the manager + void Initialize(dLogger* logger); + + //! Generates a new persistent ID + /*! + \return The new persistent ID + */ + uint32_t GeneratePersistentID(void); + + void SaveToDatabase(); }; diff --git a/dNavigation/CMakeLists.txt b/dNavigation/CMakeLists.txt new file mode 100644 index 00000000..4c03d24b --- /dev/null +++ b/dNavigation/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DNAVIGATION_SOURCES "dNavMesh.cpp") + +add_subdirectory(dTerrain) + +foreach(file ${DNAVIGATIONS_DTERRAIN_SOURCES}) + set(DNAVIGATION_SOURCES ${DNAVIGATION_SOURCES} "dTerrain/${file}") +endforeach() + +add_library(dNavigation STATIC ${DNAVIGATION_SOURCES}) +target_link_libraries(dNavigation Detour Recast) diff --git a/dNavigation/DetourExtensions.h b/dNavigation/DetourExtensions.h new file mode 100644 index 00000000..55d3e29c --- /dev/null +++ b/dNavigation/DetourExtensions.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Recast.h" +#include "DetourCommon.h" +#include "DetourNavMesh.h" +#include "DetourNavMeshBuilder.h" +#include "DetourNavMeshQuery.h" + +static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; // char[4] of 'MSET' +static const int NAVMESHSET_VERSION = 1; + +struct NavMeshSetHeader { + int magic; + int version; + int numTiles; + dtNavMeshParams params; +}; + +struct NavMeshTileHeader { + dtTileRef tileRef; + int dataSize; +}; + +static const int MAX_POLYS = 256; +static const int MAX_SMOOTH = 2048; diff --git a/dNavigation/dNavMesh.cpp b/dNavigation/dNavMesh.cpp new file mode 100644 index 00000000..fdba4a2d --- /dev/null +++ b/dNavigation/dNavMesh.cpp @@ -0,0 +1,233 @@ +#include "dNavMesh.h" + +#include "RawFile.h" + +#include "Game.h" +#include "dLogger.h" +#include "dPlatforms.h" +#include "NiPoint3.h" +#include "BinaryIO.h" +#include "BinaryPathFinder.h" + +#include "dZoneManager.h" + +dNavMesh::dNavMesh(uint32_t zoneId) { + m_ZoneId = zoneId; + + this->LoadNavmesh(); + + if (m_NavMesh) { + m_NavQuery = dtAllocNavMeshQuery(); + m_NavQuery->init(m_NavMesh, 2048); + + Game::logger->Log("dNavMesh", "Navmesh loaded successfully!"); + } else { + Game::logger->Log("dNavMesh", "Navmesh loading failed (This may be intended)."); + } +} + +dNavMesh::~dNavMesh() { + // Clean up Recast information + + if(m_Solid) rcFreeHeightField(m_Solid); + if (m_CHF) rcFreeCompactHeightfield(m_CHF); + if (m_CSet) rcFreeContourSet(m_CSet); + if (m_PMesh) rcFreePolyMesh(m_PMesh); + if (m_PMDMesh) rcFreePolyMeshDetail(m_PMDMesh); + if (m_NavMesh) dtFreeNavMesh(m_NavMesh); + if (m_NavQuery) dtFreeNavMeshQuery(m_NavQuery); + + if (m_Ctx) delete m_Ctx; + if (m_Triareas) delete[] m_Triareas; +} + + +void dNavMesh::LoadNavmesh() { + + std::string path = (BinaryPathFinder::GetBinaryDir() / "navmeshes/" / (std::to_string(m_ZoneId) + ".bin")).string(); + + if (!BinaryIO::DoesFileExist(path)) { + return; + } + + FILE* fp; + +#ifdef _WIN32 + fopen_s(&fp, path.c_str(), "rb"); +#elif __APPLE__ + // macOS has 64bit file IO by default + fp = fopen(path.c_str(), "rb"); +#else + fp = fopen64(path.c_str(), "rb"); +#endif + + if (!fp) { + return; + } + + // Read header. + NavMeshSetHeader header; + size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp); + if (readLen != 1) { + fclose(fp); + return; + } + + if (header.magic != NAVMESHSET_MAGIC) { + fclose(fp); + return; + } + + if (header.version != NAVMESHSET_VERSION) { + fclose(fp); + return; + } + + dtNavMesh* mesh = dtAllocNavMesh(); + if (!mesh) { + fclose(fp); + return; + } + + dtStatus status = mesh->init(&header.params); + if (dtStatusFailed(status)) { + fclose(fp); + return; + } + + // Read tiles. + for (int i = 0; i < header.numTiles; ++i) { + NavMeshTileHeader tileHeader; + readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp); + if (readLen != 1) return; + + if (!tileHeader.tileRef || !tileHeader.dataSize) + break; + + unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); + if (!data) break; + memset(data, 0, tileHeader.dataSize); + readLen = fread(data, tileHeader.dataSize, 1, fp); + if (readLen != 1) return; + + mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0); + } + + fclose(fp); + + m_NavMesh = mesh; +} + +float dNavMesh::GetHeightAtPoint(const NiPoint3& location) { + if (m_NavMesh == nullptr) { + return location.y; + } + + float toReturn = 0.0f; + float pos[3]; + pos[0] = location.x; + pos[1] = location.y; + pos[2] = location.z; + + dtPolyRef nearestRef = 0; + float polyPickExt[3] = { 32.0f, 32.0f, 32.0f }; + dtQueryFilter filter{}; + + m_NavQuery->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, 0); + m_NavQuery->getPolyHeight(nearestRef, pos, &toReturn); + + if (toReturn == 0.0f) { + toReturn = location.y; + } + + return toReturn; +} + +std::vector<NiPoint3> dNavMesh::GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed) { + std::vector<NiPoint3> path; + + // Allows for non-navmesh maps (like new custom maps) to have "basic" enemies. + if (m_NavMesh == nullptr) { + // How many points to generate between start/end? + // Note: not actually 100% accurate due to rounding, but worst case it causes them to go a tiny bit faster + // than their speed value would normally allow at the end. + int numPoints = startPos.Distance(startPos, endPos) / speed; + + path.push_back(startPos); //insert the start pos + + // Linearly interpolate between these two points: + for (int i = 0; i < numPoints; i++) { + NiPoint3 newPoint{ startPos }; + + newPoint.x += speed; + newPoint.y = newPoint.y + (((endPos.y - startPos.y) / (endPos.x - startPos.x)) * (newPoint.x - startPos.x)); + + path.push_back(newPoint); + } + + path.push_back(endPos); //finally insert our end pos + + return path; + } + + float sPos[3]; + float ePos[3]; + sPos[0] = startPos.x; + sPos[1] = startPos.y; + sPos[2] = startPos.z; + + ePos[0] = endPos.x; + ePos[1] = endPos.y; + ePos[2] = endPos.z; + + dtStatus pathFindStatus; + dtPolyRef startRef; + dtPolyRef endRef; + float polyPickExt[3] = { 32.0f, 32.0f, 32.0f }; + dtQueryFilter filter{}; + + //Find our start poly + m_NavQuery->findNearestPoly(sPos, polyPickExt, &filter, &startRef, 0); + + //Find our end poly + m_NavQuery->findNearestPoly(ePos, polyPickExt, &filter, &endRef, 0); + + pathFindStatus = DT_FAILURE; + int m_nstraightPath = 0; + int m_npolys = 0; + dtPolyRef m_polys[MAX_POLYS]; + float m_straightPath[MAX_POLYS * 3]; + unsigned char m_straightPathFlags[MAX_POLYS]; + dtPolyRef m_straightPathPolys[MAX_POLYS]; + int m_straightPathOptions = 0; + + if (startRef && endRef) { + m_NavQuery->findPath(startRef, endRef, sPos, ePos, &filter, m_polys, &m_npolys, MAX_POLYS); + + if (m_npolys) { + // In case of partial path, make sure the end point is clamped to the last polygon. + float epos[3]; + dtVcopy(epos, ePos); + + if (m_polys[m_npolys - 1] != endRef) { + m_NavQuery->closestPointOnPoly(m_polys[m_npolys - 1], ePos, epos, 0); + } + + m_NavQuery->findStraightPath(sPos, epos, m_polys, m_npolys, + m_straightPath, m_straightPathFlags, + m_straightPathPolys, &m_nstraightPath, MAX_POLYS, m_straightPathOptions); + + // At this point we have our path. Copy it to the path store + int nIndex = 0; + for (int nVert = 0; nVert < m_nstraightPath; nVert++) { + NiPoint3 newPoint{ m_straightPath[nIndex++], m_straightPath[nIndex++], m_straightPath[nIndex++] }; + path.push_back(newPoint); + } + } + } else { + m_npolys = 0; + m_nstraightPath = 0; + } + + return path; +} diff --git a/dNavigation/dNavMesh.h b/dNavigation/dNavMesh.h new file mode 100644 index 00000000..dc3db854 --- /dev/null +++ b/dNavigation/dNavMesh.h @@ -0,0 +1,41 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <map> +#include <string> +#include <cstring> + +#include "DetourExtensions.h" + +class NiPoint3; + +class dNavMesh { +public: + dNavMesh(uint32_t zoneId); + ~dNavMesh(); + + float GetHeightAtPoint(const NiPoint3& location); + std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f); + + class dtNavMesh* GetdtNavMesh() { return m_NavMesh; } + +private: + void LoadNavmesh(); + + uint32_t m_ZoneId; + + uint8_t* m_Triareas = nullptr; + rcHeightfield* m_Solid = nullptr; + rcCompactHeightfield* m_CHF = nullptr; + rcContourSet* m_CSet = nullptr; + rcPolyMesh* m_PMesh = nullptr; + rcConfig m_Config; + rcPolyMeshDetail* m_PMDMesh = nullptr; + + class InputGeom* m_Geometry = nullptr; + class dtNavMesh* m_NavMesh = nullptr; + class dtNavMeshQuery* m_NavQuery = nullptr; + uint8_t m_NavMeshDrawFlags; + rcContext* m_Ctx = nullptr; +}; diff --git a/dNavigation/dTerrain/CMakeLists.txt b/dNavigation/dTerrain/CMakeLists.txt new file mode 100644 index 00000000..91d0741b --- /dev/null +++ b/dNavigation/dTerrain/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DNAVIGATIONS_DTERRAIN_SOURCES "RawFile.cpp" + "RawChunk.cpp" + "RawHeightMap.cpp" PARENT_SCOPE) diff --git a/dNavigation/dTerrain/RawChunk.cpp b/dNavigation/dTerrain/RawChunk.cpp new file mode 100644 index 00000000..e4f753cd --- /dev/null +++ b/dNavigation/dTerrain/RawChunk.cpp @@ -0,0 +1,92 @@ +#include "RawChunk.h" + +#include "BinaryIO.h" + +#include "RawMesh.h" +#include "RawHeightMap.h" + +RawChunk::RawChunk(std::ifstream& stream) { + // Read the chunk index and info + + BinaryIO::BinaryRead(stream, m_ChunkIndex); + BinaryIO::BinaryRead(stream, m_Width); + BinaryIO::BinaryRead(stream, m_Height); + BinaryIO::BinaryRead(stream, m_X); + BinaryIO::BinaryRead(stream, m_Z); + + m_HeightMap = new RawHeightMap(stream, m_Height, m_Width); + + // We can just skip the rest of the data so we can read the next chunks, we don't need anymore data + + uint32_t colorMapSize; + BinaryIO::BinaryRead(stream, colorMapSize); + stream.seekg((uint32_t)stream.tellg() + (colorMapSize * colorMapSize * 4)); + + uint32_t lightmapSize; + BinaryIO::BinaryRead(stream, lightmapSize); + stream.seekg((uint32_t)stream.tellg() + (lightmapSize)); + + uint32_t colorMapSize2; + BinaryIO::BinaryRead(stream, colorMapSize2); + stream.seekg((uint32_t)stream.tellg() + (colorMapSize2 * colorMapSize2 * 4)); + + uint8_t unknown; + BinaryIO::BinaryRead(stream, unknown); + + uint32_t blendmapSize; + BinaryIO::BinaryRead(stream, blendmapSize); + stream.seekg((uint32_t)stream.tellg() + (blendmapSize)); + + uint32_t pointSize; + BinaryIO::BinaryRead(stream, pointSize); + stream.seekg((uint32_t)stream.tellg() + (pointSize * 9 * 4)); + + stream.seekg((uint32_t)stream.tellg() + (colorMapSize * colorMapSize)); + + uint32_t endCounter; + BinaryIO::BinaryRead(stream, endCounter); + stream.seekg((uint32_t)stream.tellg() + (endCounter * 2)); + + if (endCounter != 0) { + stream.seekg((uint32_t)stream.tellg() + (32)); + + for (int i = 0; i < 0x10; i++) { + uint16_t finalCountdown; + BinaryIO::BinaryRead(stream, finalCountdown); + stream.seekg((uint32_t)stream.tellg() + (finalCountdown * 2)); + } + } + + // Generate our mesh/geo data for this chunk + + this->GenerateMesh(); +} + +RawChunk::~RawChunk() { + if (m_Mesh) delete m_Mesh; + if (m_HeightMap) delete m_HeightMap; +} + +void RawChunk::GenerateMesh() { + RawMesh* meshData = new RawMesh(); + + for (int i = 0; i < m_Width; ++i) { + for (int j = 0; j < m_Height; ++j) { + float y = *std::next(m_HeightMap->m_FloatMap.begin(), m_Width * i + j); + + meshData->m_Vertices.push_back(NiPoint3(i, y, j)); + + if (i == 0 || j == 0) continue; + + meshData->m_Triangles.push_back(m_Width * i + j); + meshData->m_Triangles.push_back(m_Width * i + j - 1); + meshData->m_Triangles.push_back(m_Width * (i - 1) + j - 1); + + meshData->m_Triangles.push_back(m_Width * (i - 1) + j - 1); + meshData->m_Triangles.push_back(m_Width * (i - 1) + j); + meshData->m_Triangles.push_back(m_Width * i + j); + } + } + + m_Mesh = meshData; +} diff --git a/dNavigation/dTerrain/RawChunk.h b/dNavigation/dTerrain/RawChunk.h new file mode 100644 index 00000000..1e26f11d --- /dev/null +++ b/dNavigation/dTerrain/RawChunk.h @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <fstream> + +struct RawMesh; +class RawHeightMap; + +class RawChunk { +public: + RawChunk(std::ifstream& stream); + ~RawChunk(); + + void GenerateMesh(); + + uint32_t m_ChunkIndex; + uint32_t m_Width; + uint32_t m_Height; + float m_X; + float m_Z; + + RawHeightMap* m_HeightMap; + RawMesh* m_Mesh; +}; diff --git a/dNavigation/dTerrain/RawFile.cpp b/dNavigation/dTerrain/RawFile.cpp new file mode 100644 index 00000000..d4496b2f --- /dev/null +++ b/dNavigation/dTerrain/RawFile.cpp @@ -0,0 +1,82 @@ +#include "RawFile.h" + +#include "BinaryIO.h" +#include "RawChunk.h" +#include "RawMesh.h" +#include "RawHeightMap.h" + +RawFile::RawFile(std::string fileName) { + if (!BinaryIO::DoesFileExist(fileName)) return; + + std::ifstream file(fileName, std::ios::binary); + + // Read header + + BinaryIO::BinaryRead(file, m_Version); + BinaryIO::BinaryRead(file, m_Padding); + BinaryIO::BinaryRead(file, m_ChunkCount); + BinaryIO::BinaryRead(file, m_Width); + BinaryIO::BinaryRead(file, m_Height); + + + if (m_Version < 0x20) { + return; // Version too crusty to handle + } + + // Read in chunks + + m_Chunks = {}; + + for (uint32_t i = 0; i < m_ChunkCount; i++) { + RawChunk* chunk = new RawChunk(file); + m_Chunks.push_back(chunk); + } + + this->GenerateFinalMeshFromChunks(); +} + +RawFile::~RawFile() { + delete m_FinalMesh; + for (const auto* item : m_Chunks) { + delete item; + } +} + +void RawFile::GenerateFinalMeshFromChunks() { + uint32_t lenOfLastChunk = 0; // index of last vert set in the last chunk + + for (const auto& chunk : m_Chunks) { + for (const auto& vert : chunk->m_Mesh->m_Vertices) { + auto tempVert = vert; + + tempVert.SetX(tempVert.GetX() + (chunk->m_X / 4)); + tempVert.SetZ(tempVert.GetZ() + (chunk->m_Z / 4)); + + tempVert* chunk->m_HeightMap->m_ScaleFactor; + + m_FinalMesh->m_Vertices.push_back(tempVert); + } + + for (const auto& tri : chunk->m_Mesh->m_Triangles) { + m_FinalMesh->m_Triangles.push_back(tri + lenOfLastChunk); + } + + lenOfLastChunk += chunk->m_Mesh->m_Vertices.size(); + } +} + +void RawFile::WriteFinalMeshToOBJ(std::string path) { + std::ofstream file(path); + std::string vertData; + + for (const auto& v : m_FinalMesh->m_Vertices) { + vertData += "v " + std::to_string(v.x) + " " + std::to_string(v.y) + " " + std::to_string(v.z) + "\n"; + } + + for (int i = 0; i < m_FinalMesh->m_Triangles.size(); i += 3) { + vertData += "f " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i) + 1) + " " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i + 1) + 1) + " " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i + 2) + 1) + "\n"; + } + + file.write(vertData.c_str(), vertData.size()); + file.close(); +} diff --git a/dNavigation/dTerrain/RawFile.h b/dNavigation/dTerrain/RawFile.h new file mode 100644 index 00000000..84afae94 --- /dev/null +++ b/dNavigation/dTerrain/RawFile.h @@ -0,0 +1,27 @@ +#pragma once + +#include <string> +#include <vector> + +class RawChunk; +struct RawMesh; + +class RawFile { +public: + RawFile(std::string filePath); + ~RawFile(); + +private: + + void GenerateFinalMeshFromChunks(); + void WriteFinalMeshToOBJ(std::string path); + + uint8_t m_Version; + uint16_t m_Padding; + uint32_t m_ChunkCount; + uint32_t m_Width; + uint32_t m_Height; + + std::vector<RawChunk*> m_Chunks; + RawMesh* m_FinalMesh; +}; diff --git a/dNavigation/dTerrain/RawHeightMap.cpp b/dNavigation/dTerrain/RawHeightMap.cpp new file mode 100644 index 00000000..e1310669 --- /dev/null +++ b/dNavigation/dTerrain/RawHeightMap.cpp @@ -0,0 +1,27 @@ +#include "RawHeightMap.h" + +#include "BinaryIO.h" + +RawHeightMap::RawHeightMap() {} + +RawHeightMap::RawHeightMap(std::ifstream& stream, float height, float width) { + // Read in height map data header and scale + + BinaryIO::BinaryRead(stream, m_Unknown1); + BinaryIO::BinaryRead(stream, m_Unknown2); + BinaryIO::BinaryRead(stream, m_Unknown3); + BinaryIO::BinaryRead(stream, m_Unknown4); + BinaryIO::BinaryRead(stream, m_ScaleFactor); + + // read all vertices in + + for (uint64_t i = 0; i < width * height; i++) { + float value; + BinaryIO::BinaryRead(stream, value); + m_FloatMap.push_back(value); + } +} + +RawHeightMap::~RawHeightMap() { + +} diff --git a/dNavigation/dTerrain/RawHeightMap.h b/dNavigation/dTerrain/RawHeightMap.h new file mode 100644 index 00000000..9a4bda3b --- /dev/null +++ b/dNavigation/dTerrain/RawHeightMap.h @@ -0,0 +1,21 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <fstream> + +class RawHeightMap { +public: + RawHeightMap(); + RawHeightMap(std::ifstream& stream, float height, float width); + ~RawHeightMap(); + + uint32_t m_Unknown1; + uint32_t m_Unknown2; + uint32_t m_Unknown3; + uint32_t m_Unknown4; + + float m_ScaleFactor; + + std::vector<float> m_FloatMap = {}; +}; diff --git a/dNavigation/dTerrain/RawMesh.h b/dNavigation/dTerrain/RawMesh.h new file mode 100644 index 00000000..ed8eb4f3 --- /dev/null +++ b/dNavigation/dTerrain/RawMesh.h @@ -0,0 +1,10 @@ +#pragma once + +#include <vector> + +#include "NiPoint3.h" + +struct RawMesh { + std::vector<NiPoint3> m_Vertices; + std::vector<uint32_t> m_Triangles; +}; diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index c2aca466..4bbb0576 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -1,6 +1,5 @@ #include "AuthPackets.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "dNetCommon.h" #include "dServer.h" @@ -21,29 +20,34 @@ #include "Game.h" #include "dConfig.h" +#include "eServerDisconnectIdentifiers.h" +#include "eLoginResponse.h" +#include "eConnectionType.h" +#include "eServerMessageType.h" +#include "eMasterMessageType.h" void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint32_t clientVersion = 0; inStream.Read(clientVersion); - - server->GetLogger()->Log("AuthPackets", "Received client version: %i\n", clientVersion); - SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort()); + + server->GetLogger()->Log("AuthPackets", "Received client version: %i", clientVersion); + SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort(), server->GetServerType()); } -void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort) { +void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServerType serverType) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, SERVER, MSG_SERVER_VERSION_CONFIRM); - bitStream.Write<unsigned int>(NET_VERSION); + PacketUtils::WriteHeader(bitStream, eConnectionType::SERVER, eServerMessageType::VERSION_CONFIRM); + bitStream.Write<unsigned int>(NET_VERSION); bitStream.Write(uint32_t(0x93)); - - if (nextServerPort == 1001) bitStream.Write(uint32_t(1)); //Conn: auth + + if (serverType == ServerType::Auth) bitStream.Write(uint32_t(1)); //Conn: auth else bitStream.Write(uint32_t(4)); //Conn: world - + bitStream.Write(uint32_t(0)); //Server process ID bitStream.Write(nextServerPort); - + server->Send(&bitStream, sysAddr, false); } @@ -55,15 +59,15 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { // Fetch account details sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT password, banned, locked, play_key_id, gm_level FROM accounts WHERE name=? LIMIT 1;"); stmt->setString(1, szUsername); - + sql::ResultSet* res = stmt->executeQuery(); - + if (res->rowsCount() == 0) { - server->GetLogger()->Log("AuthPackets", "No user found!\n"); - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_WRONG_PASS_OR_USER, "", "", 2001, username); + server->GetLogger()->Log("AuthPackets", "No user found!"); + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::INVALID_USER, "", "", 2001, username); return; } - + std::string sqlPass = ""; bool sqlBanned = false; bool sqlLocked = false; @@ -77,22 +81,22 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { sqlPlayKey = res->getInt(4); sqlGmLevel = res->getInt(5); } - + delete stmt; delete res; //If we aren't running in live mode, then only GMs are allowed to enter: const auto& closedToNonDevs = Game::config->GetValue("closed_to_non_devs"); if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && sqlGmLevel == 0) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH, "The server is currently only open to developers.", "", 2001, username); + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "The server is currently only open to developers.", "", 2001, username); return; } if (Game::config->GetValue("dont_use_keys") != "1") { //Check to see if we have a play key: if (sqlPlayKey == 0 && sqlGmLevel == 0) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); - server->GetLogger()->Log("AuthPackets", "User %s tried to log in, but they don't have a play key.\n", username.c_str()); + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); + server->GetLogger()->Log("AuthPackets", "User %s tried to log in, but they don't have a play key.", username.c_str()); return; } @@ -101,9 +105,9 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { keyCheckStmt->setInt(1, sqlPlayKey); auto keyRes = keyCheckStmt->executeQuery(); bool isKeyActive = false; - + if (keyRes->rowsCount() == 0 && sqlGmLevel == 0) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); return; } @@ -112,18 +116,18 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { } if (!isKeyActive && sqlGmLevel == 0) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH, "Your play key has been disabled.", "", 2001, username); - server->GetLogger()->Log("AuthPackets", "User %s tried to log in, but their play key was disabled\n", username.c_str()); + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your play key has been disabled.", "", 2001, username); + server->GetLogger()->Log("AuthPackets", "User %s tried to log in, but their play key was disabled", username.c_str()); return; } } - - if (sqlBanned) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_BANNED, "", "", 2001, username); return; + + if (sqlBanned) { + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::BANNED, "", "", 2001, username); return; } if (sqlLocked) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_ACCOUNT_LOCKED, "", "", 2001, username); return; + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::ACCOUNT_LOCKED, "", "", 2001, username); return; } /* @@ -131,23 +135,19 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { * First attempt bcrypt. * If that fails, fallback to old method and setup bcrypt for new login. */ - + bool loginSuccess = true; int32_t bcryptState = ::bcrypt_checkpw(password.c_str(), sqlPass.c_str()); - if (bcryptState != 0) - { + if (bcryptState != 0) { // Fallback on old method std::string oldPassword = sha512(password + username); - if (sqlPass != oldPassword) - { + if (sqlPass != oldPassword) { loginSuccess = false; - } - else - { + } else { // Generate new hash for bcrypt char salt[BCRYPT_HASHSIZE]; @@ -162,109 +162,106 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { assert(bcryptState == 0); sql::PreparedStatement* accountUpdate = Database::CreatePreppedStmt("UPDATE accounts SET password = ? WHERE name = ? LIMIT 1;"); - + accountUpdate->setString(1, std::string(hash, BCRYPT_HASHSIZE).c_str()); accountUpdate->setString(2, szUsername); accountUpdate->executeUpdate(); } - } - else - { + } else { // Login success with bcrypt } if (!loginSuccess) { - AuthPackets::SendLoginResponse(server, packet->systemAddress, LOGIN_RESPONSE_WRONG_PASS_OR_USER, "", "", 2001, username); - server->GetLogger()->Log("AuthPackets", "Wrong password used\n"); - } - else { + AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::WRONG_PASS, "", "", 2001, username); + server->GetLogger()->Log("AuthPackets", "Wrong password used"); + } else { SystemAddress system = packet->systemAddress; //Copy the sysAddr before the Packet gets destroyed from main if (!server->GetIsConnectedToMaster()) { - AuthPackets::SendLoginResponse(server, system, LOGIN_RESPONSE_GENERAL_FAILED, "", "", 0, username); + AuthPackets::SendLoginResponse(server, system, eLoginResponse::GENERAL_FAILED, "", "", 0, username); return; } - + ZoneInstanceManager::Instance()->RequestZoneTransfer(server, 0, 0, false, [system, server, username](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string zoneIP, uint16_t zonePort) { - AuthPackets::SendLoginResponse(server, system, LOGIN_RESPONSE_SUCCESS, "", zoneIP, zonePort, username); - }); + AuthPackets::SendLoginResponse(server, system, eLoginResponse::SUCCESS, "", zoneIP, zonePort, username); + }); } } void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username) { - RakNet::BitStream packet; - PacketUtils::WriteHeader(packet, CLIENT, MSG_CLIENT_LOGIN_RESPONSE); - - packet.Write(static_cast<uint8_t>(responseCode)); - - PacketUtils::WritePacketString("Talk_Like_A_Pirate", 33, &packet); - - // 7 unknown strings - perhaps other IP addresses? - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - - packet.Write(static_cast<uint16_t>(1)); // Version Major - packet.Write(static_cast<uint16_t>(10)); // Version Current - packet.Write(static_cast<uint16_t>(64)); // Version Minor - - // Writes the user key + RakNet::BitStream packet; + PacketUtils::WriteHeader(packet, eConnectionType::CLIENT, eClientMessageType::LOGIN_RESPONSE); + + packet.Write(static_cast<uint8_t>(responseCode)); + + PacketUtils::WritePacketString("Talk_Like_A_Pirate", 33, &packet); + + // 7 unknown strings - perhaps other IP addresses? + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + + packet.Write(static_cast<uint16_t>(1)); // Version Major + packet.Write(static_cast<uint16_t>(10)); // Version Current + packet.Write(static_cast<uint16_t>(64)); // Version Minor + + // Writes the user key uint32_t sessionKey = rand(); // not mt but whatever std::string userHash = std::to_string(sessionKey); - userHash = md5(userHash); - PacketUtils::WritePacketWString(userHash, 33, &packet); - - // Write the Character and Chat IPs - PacketUtils::WritePacketString(wServerIP, 33, &packet); - PacketUtils::WritePacketString("", 33, &packet); - - // Write the Character and Chat Ports - packet.Write(static_cast<uint16_t>(wServerPort)); - packet.Write(static_cast<uint16_t>(0)); - - // Write another IP - PacketUtils::WritePacketString("", 33, &packet); - - // Write a GUID or something... - PacketUtils::WritePacketString("00000000-0000-0000-0000-000000000000", 37, &packet); - - packet.Write(static_cast<uint32_t>(0)); // ??? - - // Write the localization - PacketUtils::WritePacketString("US", 3, &packet); - - packet.Write(static_cast<uint8_t>(false)); // User first logged in? - packet.Write(static_cast<uint8_t>(false)); // User is F2P? - packet.Write(static_cast<uint64_t>(0)); // ??? - - // Write custom error message - packet.Write(static_cast<uint16_t>(errorMsg.length())); - PacketUtils::WritePacketWString(errorMsg, static_cast<uint32_t>(errorMsg.length()), &packet); - - // Here write auth logs - packet.Write(static_cast<uint32_t>(20)); - for (uint32_t i = 0; i < 20; ++i) { - packet.Write(static_cast<uint32_t>(8)); - packet.Write(static_cast<uint32_t>(44)); - packet.Write(static_cast<uint32_t>(14000)); - packet.Write(static_cast<uint32_t>(0)); - } - - server->Send(&packet, sysAddr, false); + userHash = md5(userHash); + PacketUtils::WritePacketWString(userHash, 33, &packet); + + // Write the Character and Chat IPs + PacketUtils::WritePacketString(wServerIP, 33, &packet); + PacketUtils::WritePacketString("", 33, &packet); + + // Write the Character and Chat Ports + packet.Write(static_cast<uint16_t>(wServerPort)); + packet.Write(static_cast<uint16_t>(0)); + + // Write another IP + PacketUtils::WritePacketString("", 33, &packet); + + // Write a GUID or something... + PacketUtils::WritePacketString("00000000-0000-0000-0000-000000000000", 37, &packet); + + packet.Write(static_cast<uint32_t>(0)); // ??? + + // Write the localization + PacketUtils::WritePacketString("US", 3, &packet); + + packet.Write(static_cast<uint8_t>(false)); // User first logged in? + packet.Write(static_cast<uint8_t>(false)); // User is F2P? + packet.Write(static_cast<uint64_t>(0)); // ??? + + // Write custom error message + packet.Write(static_cast<uint16_t>(errorMsg.length())); + PacketUtils::WritePacketWString(errorMsg, static_cast<uint32_t>(errorMsg.length()), &packet); + + // Here write auth logs + packet.Write(static_cast<uint32_t>(20)); + for (uint32_t i = 0; i < 20; ++i) { + packet.Write(static_cast<uint32_t>(8)); + packet.Write(static_cast<uint32_t>(44)); + packet.Write(static_cast<uint32_t>(14000)); + packet.Write(static_cast<uint32_t>(0)); + } + + server->Send(&packet, sysAddr, false); //Inform the master server that we've created a session for this user: { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SET_SESSION_KEY); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SET_SESSION_KEY); bitStream.Write(sessionKey); PacketUtils::WriteString(bitStream, username, 66); server->SendToMaster(&bitStream); - server->GetLogger()->Log("AuthPackets", "Set sessionKey: %i for user %s\n", sessionKey, username.c_str()); + server->GetLogger()->Log("AuthPackets", "Set sessionKey: %i for user %s", sessionKey, username.c_str()); } } diff --git a/dNet/AuthPackets.h b/dNet/AuthPackets.h index 2830480f..0f004ca4 100644 --- a/dNet/AuthPackets.h +++ b/dNet/AuthPackets.h @@ -5,14 +5,16 @@ #include "dCommonVars.h" #include "dNetCommon.h" +enum class ServerType : uint32_t; +enum class eLoginResponse : uint8_t; class dServer; namespace AuthPackets { void HandleHandshake(dServer* server, Packet* packet); - void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort); - + void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServerType serverType); + void HandleLoginRequest(dServer* server, Packet* packet); void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username); } -#endif // AUTHPACKETS_H \ No newline at end of file +#endif // AUTHPACKETS_H diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt new file mode 100644 index 00000000..938c0449 --- /dev/null +++ b/dNet/CMakeLists.txt @@ -0,0 +1,11 @@ +set(DNET_SOURCES "AuthPackets.cpp" + "ChatPackets.cpp" + "ClientPackets.cpp" + "dServer.cpp" + "MasterPackets.cpp" + "PacketUtils.cpp" + "WorldPackets.cpp" + "ZoneInstanceManager.cpp") + +add_library(dNet STATIC ${DNET_SOURCES}) +target_link_libraries(dNet dCommon dDatabase) diff --git a/dNet/ChatPackets.cpp b/dNet/ChatPackets.cpp index db90bcfe..41661523 100644 --- a/dNet/ChatPackets.cpp +++ b/dNet/ChatPackets.cpp @@ -8,67 +8,68 @@ #include "BitStream.h" #include "Game.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "dServer.h" +#include "eConnectionType.h" +#include "eChatMessageType.h" void ChatPackets::SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, CHAT, MSG_CHAT_GENERAL_CHAT_MESSAGE); - - bitStream.Write(static_cast<uint64_t>(0)); - bitStream.Write(chatChannel); - - bitStream.Write(static_cast<uint32_t>(message.size())); - PacketUtils::WriteWString(bitStream, senderName, 33); + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE); - bitStream.Write(playerObjectID); - bitStream.Write(static_cast<uint16_t>(0)); - bitStream.Write(static_cast<char>(0)); + bitStream.Write(static_cast<uint64_t>(0)); + bitStream.Write(chatChannel); - for (uint32_t i = 0; i < message.size(); ++i) { - bitStream.Write(static_cast<uint16_t>(message[i])); - } - bitStream.Write(static_cast<uint16_t>(0)); - - SEND_PACKET_BROADCAST + bitStream.Write(static_cast<uint32_t>(message.size())); + PacketUtils::WriteWString(bitStream, senderName, 33); + + bitStream.Write(playerObjectID); + bitStream.Write(static_cast<uint16_t>(0)); + bitStream.Write(static_cast<char>(0)); + + for (uint32_t i = 0; i < message.size(); ++i) { + bitStream.Write(static_cast<uint16_t>(message[i])); + } + bitStream.Write(static_cast<uint16_t>(0)); + + SEND_PACKET_BROADCAST; } void ChatPackets::SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, const bool broadcast) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, CHAT, MSG_CHAT_GENERAL_CHAT_MESSAGE); - - bitStream.Write(static_cast<uint64_t>(0)); - bitStream.Write(static_cast<char>(4)); + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE); - bitStream.Write(static_cast<uint32_t>(message.size())); - PacketUtils::WriteWString(bitStream, "", 33); + bitStream.Write(static_cast<uint64_t>(0)); + bitStream.Write(static_cast<char>(4)); - bitStream.Write(static_cast<uint64_t>(0)); - bitStream.Write(static_cast<uint16_t>(0)); - bitStream.Write(static_cast<char>(0)); + bitStream.Write(static_cast<uint32_t>(message.size())); + PacketUtils::WriteWString(bitStream, "", 33); - for (uint32_t i = 0; i < message.size(); ++i) { - bitStream.Write(static_cast<uint16_t>(message[i])); - } + bitStream.Write(static_cast<uint64_t>(0)); + bitStream.Write(static_cast<uint16_t>(0)); + bitStream.Write(static_cast<char>(0)); + + for (uint32_t i = 0; i < message.size(); ++i) { + bitStream.Write(static_cast<uint16_t>(message[i])); + } + + bitStream.Write(static_cast<uint16_t>(0)); - bitStream.Write(static_cast<uint16_t>(0)); - //This is so Wincent's announcement works: if (sysAddr != UNASSIGNED_SYSTEM_ADDRESS) { SEND_PACKET; return; } - + SEND_PACKET_BROADCAST; } void ChatPackets::SendMessageFail(const SystemAddress& sysAddr) { - //0x00 - "Chat is currently disabled." - //0x01 - "Upgrade to a full LEGO Universe Membership to chat with other players." + //0x00 - "Chat is currently disabled." + //0x01 - "Upgrade to a full LEGO Universe Membership to chat with other players." - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_SEND_CANNED_TEXT); - bitStream.Write<uint8_t>(0); //response type, options above ^ - //docs say there's a wstring here-- no idea what it's for, or if it's even needed so leaving it as is for now. - SEND_PACKET; + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SEND_CANNED_TEXT); + bitStream.Write<uint8_t>(0); //response type, options above ^ + //docs say there's a wstring here-- no idea what it's for, or if it's even needed so leaving it as is for now. + SEND_PACKET; } diff --git a/dNet/ChatPackets.h b/dNet/ChatPackets.h index aa58977c..8f6de175 100644 --- a/dNet/ChatPackets.h +++ b/dNet/ChatPackets.h @@ -12,9 +12,9 @@ struct SystemAddress; #include "dCommonVars.h" namespace ChatPackets { - void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message); - void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false); - void SendMessageFail(const SystemAddress& sysAddr); + void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message); + void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false); + void SendMessageFail(const SystemAddress& sysAddr); }; #endif // CHATPACKETS_H diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index ef5b68ef..1c22bdcd 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -30,11 +30,14 @@ #include "VehiclePhysicsComponent.h" #include "dConfig.h" #include "CharacterComponent.h" +#include "Database.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) { - Game::logger->Log("ClientPackets", "Unable to get user to parse chat message\n"); + Game::logger->Log("ClientPackets", "Unable to get user to parse chat message"); return; } @@ -43,9 +46,7 @@ void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* pack return; } - CINSTREAM; - uint64_t header; - inStream.Read(header); + CINSTREAM_SKIP_HEADER; char chatChannel; uint16_t unknown; @@ -63,30 +64,28 @@ void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* pack } std::string playerName = user->GetLastUsedChar()->GetName(); - bool isMythran = user->GetLastUsedChar()->GetGMLevel() > 0; + bool isMythran = user->GetLastUsedChar()->GetGMLevel() > eGameMasterLevel::CIVILIAN; if (!user->GetLastChatMessageApproved() && !isMythran) return; std::string sMessage = GeneralUtils::UTF16ToWTF8(message); - Game::logger->Log("Chat", "%s: %s\n", playerName.c_str(), sMessage.c_str()); + Game::logger->Log("Chat", "%s: %s", playerName.c_str(), sMessage.c_str()); ChatPackets::SendChatMessage(sysAddr, chatChannel, playerName, user->GetLoggedInChar(), isMythran, message); } void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Packet* packet) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) { - Game::logger->Log("ClientPackets", "Unable to get user to parse position update\n"); + Game::logger->Log("ClientPackets", "Unable to get user to parse position update"); return; } - CINSTREAM; - uint64_t header; - inStream.Read(header); + CINSTREAM_SKIP_HEADER; Entity* entity = EntityManager::Instance()->GetEntity(user->GetLastUsedChar()->GetObjectID()); if (!entity) return; - ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!comp) return; /* @@ -137,14 +136,19 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac inStream.Read(angVelocity.z); } - bool hasVehicle = false; + bool updateChar = true; if (possessorComponent != nullptr) { auto* possassableEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); if (possassableEntity != nullptr) { - auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>(); + auto* possessableComponent = possassableEntity->GetComponent<PossessableComponent>(); + if (possessableComponent) { + // While possessing something, only update char if we are attached to the thing we are possessing + if (possessableComponent->GetPossessionType() != ePossessionType::ATTACHED_VISIBLE) updateChar = false; + } + auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>(); if (vehiclePhysicsComponent != nullptr) { // This is flipped for whatever reason rotation = NiQuaternion(rotation.z, rotation.y, rotation.x, rotation.w); @@ -157,23 +161,34 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac vehiclePhysicsComponent->SetDirtyVelocity(velocityFlag); vehiclePhysicsComponent->SetAngularVelocity(angVelocity); vehiclePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag); - - EntityManager::Instance()->SerializeEntity(possassableEntity); - - hasVehicle = true; + } else { + // Need to get the mount's controllable physics + auto* controllablePhysicsComponent = possassableEntity->GetComponent<ControllablePhysicsComponent>(); + if (!controllablePhysicsComponent) return; + controllablePhysicsComponent->SetPosition(position); + controllablePhysicsComponent->SetRotation(rotation); + controllablePhysicsComponent->SetIsOnGround(onGround); + controllablePhysicsComponent->SetIsOnRail(onRail); + controllablePhysicsComponent->SetVelocity(velocity); + controllablePhysicsComponent->SetDirtyVelocity(velocityFlag); + controllablePhysicsComponent->SetAngularVelocity(angVelocity); + controllablePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag); } + EntityManager::Instance()->SerializeEntity(possassableEntity); } } - if (hasVehicle) { + if (!updateChar) { velocity = NiPoint3::ZERO; angVelocity = NiPoint3::ZERO; } + + // Handle statistics auto* characterComponent = entity->GetComponent<CharacterComponent>(); if (characterComponent != nullptr) { - characterComponent->TrackPositionUpdate(position); + characterComponent->TrackPositionUpdate(position); } comp->SetPosition(position); @@ -189,9 +204,7 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac player->SetGhostReferencePoint(position); EntityManager::Instance()->QueueGhostUpdate(player->GetObjectID()); - if (!hasVehicle) { - EntityManager::Instance()->SerializeEntity(entity); - } + if (updateChar) EntityManager::Instance()->SerializeEntity(entity); //TODO: add moving platform stuffs /*bool movingPlatformFlag; @@ -237,22 +250,21 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Packet* packet) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) { - Game::logger->Log("ClientPackets", "Unable to get user to parse chat moderation request\n"); + Game::logger->Log("ClientPackets", "Unable to get user to parse chat moderation request"); return; } auto* entity = Player::GetPlayer(sysAddr); if (entity == nullptr) { - Game::logger->Log("ClientPackets", "Unable to get player to parse chat moderation request\n"); + Game::logger->Log("ClientPackets", "Unable to get player to parse chat moderation request"); return; } // Check if the player has restricted chat access auto* character = entity->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedChatAccess)) - { + if (character->HasPermission(ePermissionMap::RestrictedChatAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -284,6 +296,12 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa receiver.push_back(static_cast<uint8_t>(character)); } + if (!receiver.empty()) { + if (std::string(receiver.c_str(), 4) == "[GM]") { // Shift the string forward if we are speaking to a GM as the client appends "[GM]" if they are + receiver = std::string(receiver.c_str() + 4, receiver.size() - 4); + } + } + stream.Read(messageLength); for (uint32_t i = 0; i < messageLength; ++i) { uint16_t character; @@ -291,16 +309,60 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa message.push_back(static_cast<uint8_t>(character)); } - std::unordered_map<char, char> unacceptedItems; - bool bAllClean = Game::chatFilter->IsSentenceOkay(message, user->GetLastUsedChar()->GetGMLevel()); - if (!bAllClean) { - unacceptedItems.insert(std::make_pair((char)0, (char)message.length())); + bool isBestFriend = false; + + if (chatLevel == 1) { + // Private chat + LWOOBJID idOfReceiver = LWOOBJID_EMPTY; + + { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE name = ?"); + stmt->setString(1, receiver); + + sql::ResultSet* res = stmt->executeQuery(); + + if (res->next()) { + idOfReceiver = res->getInt("id"); + } + + delete stmt; + delete res; + } + + if (user->GetIsBestFriendMap().find(receiver) == user->GetIsBestFriendMap().end() && idOfReceiver != LWOOBJID_EMPTY) { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); + stmt->setInt(1, entity->GetObjectID()); + stmt->setInt(2, idOfReceiver); + stmt->setInt(3, idOfReceiver); + stmt->setInt(4, entity->GetObjectID()); + + sql::ResultSet* res = stmt->executeQuery(); + + if (res->next()) { + isBestFriend = res->getInt("best_friend") == 3; + } + + if (isBestFriend) { + auto tmpBestFriendMap = user->GetIsBestFriendMap(); + tmpBestFriendMap[receiver] = true; + user->SetIsBestFriendMap(tmpBestFriendMap); + } + + delete res; + delete stmt; + } else if (user->GetIsBestFriendMap().find(receiver) != user->GetIsBestFriendMap().end()) { + isBestFriend = true; + } } + std::vector<std::pair<uint8_t, uint8_t>> segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel(), !(isBestFriend && chatLevel == 1)); + + bool bAllClean = segments.empty(); + if (user->GetIsMuted()) { bAllClean = false; } user->SetLastChatMessageApproved(bAllClean); - WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, unacceptedItems); + WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments); } diff --git a/dNet/ClientPackets.h b/dNet/ClientPackets.h index 236955fc..a36384e2 100644 --- a/dNet/ClientPackets.h +++ b/dNet/ClientPackets.h @@ -9,9 +9,9 @@ #include "RakNetTypes.h" namespace ClientPackets { - void HandleChatMessage(const SystemAddress& sysAddr, Packet* packet); - void HandleClientPositionUpdate(const SystemAddress& sysAddr, Packet* packet); - void HandleChatModerationRequest(const SystemAddress& sysAddr, Packet* packet); + void HandleChatMessage(const SystemAddress& sysAddr, Packet* packet); + void HandleClientPositionUpdate(const SystemAddress& sysAddr, Packet* packet); + void HandleChatModerationRequest(const SystemAddress& sysAddr, Packet* packet); }; #endif // CLIENTPACKETS_H diff --git a/dNet/MasterPackets.cpp b/dNet/MasterPackets.cpp index 96ad1b81..4233a37d 100644 --- a/dNet/MasterPackets.cpp +++ b/dNet/MasterPackets.cpp @@ -1,119 +1,123 @@ #include "MasterPackets.h" #include "BitStream.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "dCommonVars.h" #include "dServer.h" +#include "eConnectionType.h" +#include "eMasterMessageType.h" #include <string> void MasterPackets::SendPersistentIDRequest(dServer* server, uint64_t requestID) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_PERSISTENT_ID); - bitStream.Write(requestID); + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PERSISTENT_ID); + bitStream.Write(requestID); server->SendToMaster(&bitStream); } void MasterPackets::SendPersistentIDResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, uint32_t objID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_PERSISTENT_ID_RESPONSE); - + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE); + bitStream.Write(requestID); bitStream.Write(objID); - + server->Send(&bitStream, sysAddr, false); } void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t cloneID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_ZONE_TRANSFER); - - bitStream.Write(requestID); - bitStream.Write(static_cast<uint8_t>(mythranShift)); - bitStream.Write(zoneID); - bitStream.Write(cloneID); - + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER); + + bitStream.Write(requestID); + bitStream.Write(static_cast<uint8_t>(mythranShift)); + bitStream.Write(zoneID); + bitStream.Write(cloneID); + server->SendToMaster(&bitStream); } void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint32_t cloneID, const std::string& password) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_CREATE_PRIVATE_ZONE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::CREATE_PRIVATE_ZONE); bitStream.Write(zoneID); bitStream.Write(cloneID); - RakNet::RakString passwd(password.c_str()); - bitStream.Write(passwd); + bitStream.Write<uint32_t>(password.size()); + for (auto character : password) { + bitStream.Write<char>(character); + } server->SendToMaster(&bitStream); } void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, bool mythranShift, const std::string& password) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_PRIVATE_ZONE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PRIVATE_ZONE); bitStream.Write(requestID); bitStream.Write(static_cast<uint8_t>(mythranShift)); - RakNet::RakString passwd(password.c_str()); - bitStream.Write(passwd); + bitStream.Write<uint32_t>(password.size()); + for (auto character : password) { + bitStream.Write<char>(character); + } server->SendToMaster(&bitStream); } -void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCEID instanceId) -{ +void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCEID instanceId) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_WORLD_READY); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::WORLD_READY); bitStream.Write(zoneId); bitStream.Write(instanceId); - + server->SendToMaster(&bitStream); } void MasterPackets::SendZoneTransferResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, const std::string& serverIP, uint32_t serverPort) { - RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_ZONE_TRANSFER_RESPONSE); - - bitStream.Write(requestID); - bitStream.Write(static_cast<uint8_t>(mythranShift)); - bitStream.Write(zoneID); - bitStream.Write(zoneInstance); - bitStream.Write(zoneClone); - bitStream.Write(static_cast<uint16_t>(serverPort)); - PacketUtils::WriteString(bitStream, serverIP, static_cast<uint32_t>(serverIP.size() + 1)); - - server->Send(&bitStream, sysAddr, false); + RakNet::BitStream bitStream; + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE); + + bitStream.Write(requestID); + bitStream.Write(static_cast<uint8_t>(mythranShift)); + bitStream.Write(zoneID); + bitStream.Write(zoneInstance); + bitStream.Write(zoneClone); + bitStream.Write(static_cast<uint16_t>(serverPort)); + PacketUtils::WriteString(bitStream, serverIP, static_cast<uint32_t>(serverIP.size() + 1)); + + server->Send(&bitStream, sysAddr, false); } void MasterPackets::HandleServerInfo(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - + uint32_t theirPort = 0; uint32_t theirZoneID = 0; uint32_t theirInstanceID = 0; std::string theirIP = ""; - + inStream.Read(theirPort); inStream.Read(theirZoneID); inStream.Read(theirInstanceID); theirIP = PacketUtils::ReadString(inStream.GetReadOffset(), packet, false); //20 is the current offset - + //TODO: Actually mark this server as an available server in the manager } void MasterPackets::SendServerInfo(dServer* server, Packet* packet) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SERVER_INFO); - + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SERVER_INFO); + bitStream.Write(server->GetPort()); bitStream.Write(server->GetZoneID()); bitStream.Write(server->GetInstanceID()); bitStream.Write(server->GetServerType()); PacketUtils::WriteString(bitStream, server->GetIP(), server->GetIP().size()); - + server->SendToMaster(&bitStream); } diff --git a/dNet/MasterPackets.h b/dNet/MasterPackets.h index 19979092..93fd158e 100644 --- a/dNet/MasterPackets.h +++ b/dNet/MasterPackets.h @@ -8,21 +8,21 @@ class dServer; namespace MasterPackets { - void SendPersistentIDRequest(dServer* server, uint64_t requestID); //Called from the World server + void SendPersistentIDRequest(dServer* server, uint64_t requestID); //Called from the World server void SendPersistentIDResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, uint32_t objID); - + void SendZoneTransferRequest(dServer* server, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t cloneID); void SendZoneTransferResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, const std::string& serverIP, uint32_t serverPort); - + void HandleServerInfo(Packet* packet); void SendServerInfo(dServer* server, Packet* packet); - + void SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint32_t cloneID, const std::string& password); - + void SendZoneRequestPrivate(dServer* server, uint64_t requestID, bool mythranShift, const std::string& password); void SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCEID instanceId); - + void HandleSetSessionKey(Packet* packet); } diff --git a/dNet/PacketUtils.cpp b/dNet/PacketUtils.cpp index a5d9f0ea..77b314d6 100644 --- a/dNet/PacketUtils.cpp +++ b/dNet/PacketUtils.cpp @@ -1,83 +1,77 @@ #include "PacketUtils.h" -#include <MessageIdentifiers.h> #include <vector> #include <fstream> #include "dLogger.h" #include "Game.h" -void PacketUtils::WriteHeader(RakNet::BitStream& bitStream, uint16_t connectionType, uint32_t internalPacketID) { - bitStream.Write(MessageID(ID_USER_PACKET_ENUM)); - bitStream.Write(connectionType); - bitStream.Write(internalPacketID); - bitStream.Write(uint8_t(0)); +uint16_t PacketUtils::ReadPacketU16(uint32_t startLoc, Packet* packet) { + if (startLoc + 2 > packet->length) return 0; + + std::vector<unsigned char> t; + for (uint32_t i = startLoc; i < startLoc + 2; i++) t.push_back(packet->data[i]); + return *(uint16_t*)t.data(); } -uint16_t PacketUtils::ReadPacketU16(uint32_t startLoc, Packet * packet) { - if (startLoc + 2 > packet->length) return 0; - - std::vector<unsigned char> t; - for (uint32_t i = startLoc; i < startLoc + 2; i++) t.push_back(packet->data[i]); - return *(uint16_t*)t.data(); +uint32_t PacketUtils::ReadPacketU32(uint32_t startLoc, Packet* packet) { + if (startLoc + 4 > packet->length) return 0; + + std::vector<unsigned char> t; + for (uint32_t i = startLoc; i < startLoc + 4; i++) { + t.push_back(packet->data[i]); + } + return *(uint32_t*)t.data(); } -uint32_t PacketUtils::ReadPacketU32(uint32_t startLoc, Packet * packet) { - if (startLoc + 4 > packet->length) return 0; - - std::vector<unsigned char> t; - for (uint32_t i = startLoc; i < startLoc + 4; i++) { - t.push_back(packet->data[i]); - } - return *(uint32_t*)t.data(); +uint64_t PacketUtils::ReadPacketU64(uint32_t startLoc, Packet* packet) { + if (startLoc + 8 > packet->length) return 0; + + std::vector<unsigned char> t; + for (uint32_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); + return *(uint64_t*)t.data(); } -uint64_t PacketUtils::ReadPacketU64(uint32_t startLoc, Packet * packet) { - if (startLoc + 8 > packet->length) return 0; - - std::vector<unsigned char> t; - for (uint32_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); - return *(uint64_t*)t.data(); +int64_t PacketUtils::ReadPacketS64(uint32_t startLoc, Packet* packet) { + if (startLoc + 8 > packet->length) return 0; + + std::vector<unsigned char> t; + for (size_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); + return *(int64_t*)t.data(); } -int64_t PacketUtils::ReadPacketS64(uint32_t startLoc, Packet * packet) { - if (startLoc + 8 > packet->length) return 0; - - std::vector<unsigned char> t; - for (size_t i = startLoc; i < startLoc + 8; i++) t.push_back(packet->data[i]); - return *(int64_t*)t.data(); -} - -std::string PacketUtils::ReadString(uint32_t startLoc, Packet* packet, bool wide) { +std::string PacketUtils::ReadString(uint32_t startLoc, Packet* packet, bool wide, uint32_t maxLen) { std::string readString = ""; - - if (packet->length > startLoc) { - uint32_t i = 0; - while (packet->data[startLoc + i] != '\0' && packet->length > (uint32_t)(startLoc + i)) { - readString.push_back(packet->data[startLoc + i]); - - if (wide) { - i += 2; // Wide-char string - } else { - i++; // Regular string - } - } - } - - return readString; + + if (wide) maxLen *= 2; + + if (packet->length > startLoc) { + uint32_t i = 0; + while (packet->data[startLoc + i] != '\0' && packet->length > (uint32_t)(startLoc + i) && maxLen > i) { + readString.push_back(packet->data[startLoc + i]); + + if (wide) { + i += 2; // Wide-char string + } else { + i++; // Regular string + } + } + } + + return readString; } -void PacketUtils::WritePacketString(const std::string& string, uint32_t maxSize, RakNet::BitStream * bitStream) { - uint32_t size = static_cast<uint32_t>(string.size()); - uint32_t remSize = static_cast<uint32_t>(maxSize - size); - - if (size > maxSize) size = maxSize; - - for (uint32_t i = 0; i < size; ++i) { - bitStream->Write(static_cast<char>(string[i])); - } - - for (uint32_t j = 0; j < remSize; ++j) { - bitStream->Write(static_cast<char>(0)); - } +void PacketUtils::WritePacketString(const std::string& string, uint32_t maxSize, RakNet::BitStream* bitStream) { + uint32_t size = static_cast<uint32_t>(string.size()); + uint32_t remSize = static_cast<uint32_t>(maxSize - size); + + if (size > maxSize) size = maxSize; + + for (uint32_t i = 0; i < size; ++i) { + bitStream->Write(static_cast<char>(string[i])); + } + + for (uint32_t j = 0; j < remSize; ++j) { + bitStream->Write(static_cast<char>(0)); + } } void PacketUtils::WriteString(RakNet::BitStream& bitStream, const std::string& s, uint32_t maxSize) { @@ -96,60 +90,60 @@ void PacketUtils::WriteString(RakNet::BitStream& bitStream, const std::string& s } void PacketUtils::WriteWString(RakNet::BitStream& bitStream, const std::string& string, uint32_t maxSize) { - uint32_t size = static_cast<uint32_t>(string.length()); - uint32_t remSize = static_cast<uint32_t>(maxSize - size); - - if (size > maxSize) size = maxSize; - - for (uint32_t i = 0; i < size; ++i) { - bitStream.Write(static_cast<uint16_t>(string[i])); - } - - for (uint32_t j = 0; j < remSize; ++j) { - bitStream.Write(static_cast<uint16_t>(0)); - } + uint32_t size = static_cast<uint32_t>(string.length()); + uint32_t remSize = static_cast<uint32_t>(maxSize - size); + + if (size > maxSize) size = maxSize; + + for (uint32_t i = 0; i < size; ++i) { + bitStream.Write(static_cast<uint16_t>(string[i])); + } + + for (uint32_t j = 0; j < remSize; ++j) { + bitStream.Write(static_cast<uint16_t>(0)); + } } void PacketUtils::WriteWString(RakNet::BitStream& bitStream, const std::u16string& string, uint32_t maxSize) { - uint32_t size = static_cast<uint32_t>(string.length()); - uint32_t remSize = static_cast<uint32_t>(maxSize - size); - - if (size > maxSize) size = maxSize; - - for (uint32_t i = 0; i < size; ++i) { - bitStream.Write(static_cast<uint16_t>(string[i])); - } - - for (uint32_t j = 0; j < remSize; ++j) { - bitStream.Write(static_cast<uint16_t>(0)); - } + uint32_t size = static_cast<uint32_t>(string.length()); + uint32_t remSize = static_cast<uint32_t>(maxSize - size); + + if (size > maxSize) size = maxSize; + + for (uint32_t i = 0; i < size; ++i) { + bitStream.Write(static_cast<uint16_t>(string[i])); + } + + for (uint32_t j = 0; j < remSize; ++j) { + bitStream.Write(static_cast<uint16_t>(0)); + } } -void PacketUtils::WritePacketWString(const std::string& string, uint32_t maxSize, RakNet::BitStream * bitStream) { - uint32_t size = static_cast<uint32_t>(string.length()); - uint32_t remSize = static_cast<uint32_t>(maxSize - size); - - if (size > maxSize) size = maxSize; - - for (uint32_t i = 0; i < size; ++i) { - bitStream->Write(static_cast<uint16_t>(string[i])); - } - - for (uint32_t j = 0; j < remSize; ++j) { - bitStream->Write(static_cast<uint16_t>(0)); - } +void PacketUtils::WritePacketWString(const std::string& string, uint32_t maxSize, RakNet::BitStream* bitStream) { + uint32_t size = static_cast<uint32_t>(string.length()); + uint32_t remSize = static_cast<uint32_t>(maxSize - size); + + if (size > maxSize) size = maxSize; + + for (uint32_t i = 0; i < size; ++i) { + bitStream->Write(static_cast<uint16_t>(string[i])); + } + + for (uint32_t j = 0; j < remSize; ++j) { + bitStream->Write(static_cast<uint16_t>(0)); + } } //! Saves a packet to the filesystem -void PacketUtils::SavePacket(const std::string& filename, const char * data, size_t length) { +void PacketUtils::SavePacket(const std::string& filename, const char* data, size_t length) { //If we don't log to the console, don't save the bin files either. This takes up a lot of time. if (!Game::logger->GetIsLoggingToConsole()) return; - std::string path = "packets/" + filename; - - std::ofstream file(path, std::ios::binary); - if (!file.is_open()) return; - - file.write(data, length); - file.close(); + std::string path = "packets/" + filename; + + std::ofstream file(path, std::ios::binary); + if (!file.is_open()) return; + + file.write(data, length); + file.close(); } diff --git a/dNet/PacketUtils.h b/dNet/PacketUtils.h index 3426c3ab..d07759a0 100644 --- a/dNet/PacketUtils.h +++ b/dNet/PacketUtils.h @@ -1,25 +1,34 @@ #ifndef PACKETUTILS_H #define PACKETUTILS_H +#include <MessageIdentifiers.h> #include <BitStream.h> #include <string> +enum class eConnectionType : uint16_t; + namespace PacketUtils { - void WriteHeader(RakNet::BitStream& bitStream, uint16_t connectionType, uint32_t internalPacketID); - - uint16_t ReadPacketU16(uint32_t startLoc, Packet * packet); - uint32_t ReadPacketU32(uint32_t startLoc, Packet * packet); - uint64_t ReadPacketU64(uint32_t startLoc, Packet * packet); - int64_t ReadPacketS64(uint32_t startLoc, Packet * packet); - std::string ReadString(uint32_t startLoc, Packet * packet, bool wide); - - void WritePacketString(const std::string& string, uint32_t maxSize, RakNet::BitStream * bitStream); + template<typename T> + void WriteHeader(RakNet::BitStream& bitStream, eConnectionType connectionType, T internalPacketID) { + bitStream.Write<uint8_t>(MessageID(ID_USER_PACKET_ENUM)); + bitStream.Write<eConnectionType>(connectionType); + bitStream.Write<uint32_t>(static_cast<uint32_t>(internalPacketID)); + bitStream.Write<uint8_t>(0); + } + + uint16_t ReadPacketU16(uint32_t startLoc, Packet* packet); + uint32_t ReadPacketU32(uint32_t startLoc, Packet* packet); + uint64_t ReadPacketU64(uint32_t startLoc, Packet* packet); + int64_t ReadPacketS64(uint32_t startLoc, Packet* packet); + std::string ReadString(uint32_t startLoc, Packet* packet, bool wide, uint32_t maxLen = 33); + + void WritePacketString(const std::string& string, uint32_t maxSize, RakNet::BitStream* bitStream); void WriteString(RakNet::BitStream& bitStream, const std::string& s, uint32_t maxSize); void WriteWString(RakNet::BitStream& bitStream, const std::string& string, uint32_t maxSize); void WriteWString(RakNet::BitStream& bitStream, const std::u16string& string, uint32_t maxSize); - void WritePacketWString(const std::string& string, uint32_t maxSize, RakNet::BitStream * bitStream); - - void SavePacket(const std::string& filename, const char * data, size_t length); + void WritePacketWString(const std::string& string, uint32_t maxSize, RakNet::BitStream* bitStream); + + void SavePacket(const std::string& filename, const char* data, size_t length); }; #endif // PACKETUTILS_H diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index ae8f71a4..5fce14d3 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -1,7 +1,6 @@ #include "dCommonVars.h" #include "WorldPackets.h" #include "BitStream.h" -#include "dMessageIdentifiers.h" #include "PacketUtils.h" #include "GeneralUtils.h" #include "User.h" @@ -14,209 +13,221 @@ #include "dZoneManager.h" #include "CharacterComponent.h" #include "ZCompression.h" +#include "eConnectionType.h" void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum) { - RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_LOAD_STATIC_ZONE); - + RakNet::BitStream bitStream; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE); + auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); bitStream.Write(static_cast<uint16_t>(zone.GetMapID())); bitStream.Write(static_cast<uint16_t>(zone.GetInstanceID())); //bitStream.Write(static_cast<uint32_t>(zone.GetCloneID())); bitStream.Write(0); - bitStream.Write(checksum); - bitStream.Write(static_cast<uint16_t>(0)); // ?? + bitStream.Write(checksum); + bitStream.Write(static_cast<uint16_t>(0)); // ?? - bitStream.Write(x); - bitStream.Write(y); - bitStream.Write(z); + bitStream.Write(x); + bitStream.Write(y); + bitStream.Write(z); - bitStream.Write(static_cast<uint32_t>(0)); // Change this to eventually use 4 on activity worlds - - SEND_PACKET + bitStream.Write(static_cast<uint32_t>(0)); // Change this to eventually use 4 on activity worlds + + SEND_PACKET; } -void WorldPackets::SendCharacterList ( const SystemAddress& sysAddr, User* user ) { +void WorldPackets::SendCharacterList(const SystemAddress& sysAddr, User* user) { if (!user) return; RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_LIST_RESPONSE); - + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_LIST_RESPONSE); + std::vector<Character*> characters = user->GetCharacters(); bitStream.Write(static_cast<uint8_t>(characters.size())); - bitStream.Write(static_cast<uint8_t>(0)); //character index in front, just picking 0 - + bitStream.Write(static_cast<uint8_t>(0)); //character index in front, just picking 0 + for (uint32_t i = 0; i < characters.size(); ++i) { bitStream.Write(characters[i]->GetObjectID()); - bitStream.Write(static_cast<uint32_t>(0)); - + bitStream.Write(static_cast<uint32_t>(0)); + PacketUtils::WriteWString(bitStream, characters[i]->GetName(), 33); - PacketUtils::WriteWString(bitStream, characters[i]->GetUnapprovedName(), 33); - + PacketUtils::WriteWString(bitStream, characters[i]->GetUnapprovedName(), 33); + bitStream.Write(static_cast<uint8_t>(characters[i]->GetNameRejected())); - bitStream.Write(static_cast<uint8_t>(false)); - + bitStream.Write(static_cast<uint8_t>(false)); + PacketUtils::WriteString(bitStream, "", 10); - + bitStream.Write(characters[i]->GetShirtColor()); - bitStream.Write(characters[i]->GetShirtStyle()); - bitStream.Write(characters[i]->GetPantsColor()); - bitStream.Write(characters[i]->GetHairStyle()); - bitStream.Write(characters[i]->GetHairColor()); - bitStream.Write(characters[i]->GetLeftHand()); - bitStream.Write(characters[i]->GetRightHand()); - bitStream.Write(characters[i]->GetEyebrows()); - bitStream.Write(characters[i]->GetEyes()); - bitStream.Write(characters[i]->GetMouth()); - bitStream.Write(static_cast<uint32_t>(0)); + bitStream.Write(characters[i]->GetShirtStyle()); + bitStream.Write(characters[i]->GetPantsColor()); + bitStream.Write(characters[i]->GetHairStyle()); + bitStream.Write(characters[i]->GetHairColor()); + bitStream.Write(characters[i]->GetLeftHand()); + bitStream.Write(characters[i]->GetRightHand()); + bitStream.Write(characters[i]->GetEyebrows()); + bitStream.Write(characters[i]->GetEyes()); + bitStream.Write(characters[i]->GetMouth()); + bitStream.Write(static_cast<uint32_t>(0)); - bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneID())); - bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneInstance())); - bitStream.Write(characters[i]->GetZoneClone()); + bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneID())); + bitStream.Write(static_cast<uint16_t>(characters[i]->GetZoneInstance())); + bitStream.Write(characters[i]->GetZoneClone()); - bitStream.Write(characters[i]->GetLastLogin()); + bitStream.Write(characters[i]->GetLastLogin()); - const auto& equippedItems = characters[i]->GetEquippedItems(); - bitStream.Write(static_cast<uint16_t>(equippedItems.size())); - - for (uint32_t j = 0; j < equippedItems.size(); ++j) { - bitStream.Write(equippedItems[j]); - } + const auto& equippedItems = characters[i]->GetEquippedItems(); + bitStream.Write(static_cast<uint16_t>(equippedItems.size())); + + for (uint32_t j = 0; j < equippedItems.size(); ++j) { + bitStream.Write(equippedItems[j]); + } } - - SEND_PACKET + + SEND_PACKET; } -void WorldPackets::SendCharacterCreationResponse ( const SystemAddress& sysAddr, eCreationResponse response ) { +void WorldPackets::SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_CREATE_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_CREATE_RESPONSE); bitStream.Write(response); - SEND_PACKET + SEND_PACKET; } -void WorldPackets::SendCharacterRenameResponse ( const SystemAddress& sysAddr, eRenameResponse response ) { +void WorldPackets::SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_RENAME_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_RENAME_RESPONSE); bitStream.Write(response); - SEND_PACKET + SEND_PACKET; } void WorldPackets::SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response) { - RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_DELETE_CHARACTER_RESPONSE); - bitStream.Write(static_cast<uint8_t>(response)); - SEND_PACKET + RakNet::BitStream bitStream; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DELETE_CHARACTER_RESPONSE); + bitStream.Write(static_cast<uint8_t>(response)); + SEND_PACKET; } -void WorldPackets::SendTransferToWorld ( const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift ) { +void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TRANSFER_TO_WORLD); - + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TRANSFER_TO_WORLD); + PacketUtils::WriteString(bitStream, serverIP, 33); bitStream.Write(static_cast<uint16_t>(serverPort)); bitStream.Write(static_cast<uint8_t>(mythranShift)); - - SEND_PACKET + + SEND_PACKET; } -void WorldPackets::SendServerState ( const SystemAddress& sysAddr ) { +void WorldPackets::SendServerState(const SystemAddress& sysAddr) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_SERVER_STATES); + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SERVER_STATES); bitStream.Write(static_cast<uint8_t>(1)); //If the server is receiving this request, it probably is ready anyway. - SEND_PACKET + SEND_PACKET; } -void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm) { - RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CREATE_CHARACTER); - - RakNet::BitStream data; - data.Write<uint32_t>(7); //LDF key count +void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) { + RakNet::BitStream bitStream; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CREATE_CHARACTER); - auto character = entity->GetComponent<CharacterComponent>(); - if (!character) { - Game::logger->Log("WorldPackets", "Entity is not a character?? what??"); - return; - } + RakNet::BitStream data; + data.Write<uint32_t>(7); //LDF key count - LDFData<LWOOBJID>* objid = new LDFData<LWOOBJID>(u"objid", entity->GetObjectID()); - LDFData<LOT>* lot = new LDFData<LOT>(u"template", 1); - LDFData<std::string> * xmlConfigData = new LDFData<std::string>(u"xmlData", xmlData); - LDFData<std::u16string>* name = new LDFData<std::u16string>(u"name", username); - LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", gm); - LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", gm); - LDFData<int64_t>* reputation = new LDFData<int64_t>(u"reputation", character->GetReputation()); - - objid->WriteToPacket(&data); - lot->WriteToPacket(&data); - name->WriteToPacket(&data); - gmlevel->WriteToPacket(&data); - chatmode->WriteToPacket(&data); - xmlConfigData->WriteToPacket(&data); - reputation->WriteToPacket(&data); - - delete objid; - delete lot; - delete xmlConfigData; - delete gmlevel; - delete chatmode; - delete name; - delete reputation; - -#ifdef _WIN32 - bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed() + 1); - bitStream.Write<uint8_t>(0); - bitStream.Write((char*)data.GetData(), data.GetNumberOfBytesUsed()); -#else - //Compress the data before sending: - const int reservedSize = 5 * 1024 * 1024; - uint8_t compressedData[reservedSize]; - size_t size = ZCompression::Compress(data.GetData(), data.GetNumberOfBytesUsed(), compressedData, reservedSize); - - bitStream.Write<uint32_t>(size + 9); //size of data + header bytes (8) - bitStream.Write<uint8_t>(1); //compressed boolean, true - bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed()); - bitStream.Write<uint32_t>(size); - - for (size_t i = 0; i < size; i++) - bitStream.Write(compressedData[i]); -#endif - - PacketUtils::SavePacket("chardata.bin", (const char *)bitStream.GetData(), static_cast<uint32_t>(bitStream.GetNumberOfBytesUsed())); - SEND_PACKET - Game::logger->Log("WorldPackets", "Sent CreateCharacter for ID: %llu\n", entity->GetObjectID()); -} - -void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::unordered_map<char, char> unacceptedItems) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHAT_MODERATION_STRING); - - bitStream.Write(static_cast<char>(requestAccepted)); - bitStream.Write(static_cast<uint16_t>(0)); - bitStream.Write(static_cast<uint8_t>(requestID)); - bitStream.Write(static_cast<char>(0)); - - for (uint32_t i = 0; i < 33; ++i) { - bitStream.Write(static_cast<uint16_t>(receiver[i])); + auto character = entity->GetComponent<CharacterComponent>(); + if (!character) { + Game::logger->Log("WorldPackets", "Entity is not a character?? what??"); + return; } - for (std::unordered_map<char, char>::iterator it = unacceptedItems.begin(); it != unacceptedItems.end(); ++it) { - bitStream.Write(it->first); - bitStream.Write(it->second); + LDFData<LWOOBJID>* objid = new LDFData<LWOOBJID>(u"objid", entity->GetObjectID()); + LDFData<LOT>* lot = new LDFData<LOT>(u"template", 1); + LDFData<std::string>* xmlConfigData = new LDFData<std::string>(u"xmlData", xmlData); + LDFData<std::u16string>* name = new LDFData<std::u16string>(u"name", username); + LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gm)); + LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm)); + LDFData<int64_t>* reputation = new LDFData<int64_t>(u"reputation", character->GetReputation()); + + objid->WriteToPacket(&data); + lot->WriteToPacket(&data); + name->WriteToPacket(&data); + gmlevel->WriteToPacket(&data); + chatmode->WriteToPacket(&data); + xmlConfigData->WriteToPacket(&data); + reputation->WriteToPacket(&data); + + delete objid; + delete lot; + delete xmlConfigData; + delete gmlevel; + delete chatmode; + delete name; + delete reputation; + + //Compress the data before sending: + const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed()); + uint8_t* compressedData = new uint8_t[reservedSize]; + + // TODO There should be better handling here for not enough memory... + if (!compressedData) return; + + size_t size = ZCompression::Compress(data.GetData(), data.GetNumberOfBytesUsed(), compressedData, reservedSize); + + assert(size <= reservedSize); + + bitStream.Write<uint32_t>(size + 9); //size of data + header bytes (8) + bitStream.Write<uint8_t>(1); //compressed boolean, true + bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed()); + bitStream.Write<uint32_t>(size); + + /** + * In practice, this warning serves no purpose for us. We allocate the max memory needed on the heap + * and then compress the data. In the off chance that the compression actually increases the size, + * an assertion is done to prevent bad data from being saved or sent. + */ +#pragma warning(disable:6385) // C6385 Reading invalid data from 'compressedData'. + for (size_t i = 0; i < size; i++) + bitStream.Write(compressedData[i]); +#pragma warning(default:6385) + + // PacketUtils::SavePacket("chardata.bin", (const char*)bitStream.GetData(), static_cast<uint32_t>(bitStream.GetNumberOfBytesUsed())); + SEND_PACKET; + delete[] compressedData; + Game::logger->Log("WorldPackets", "Sent CreateCharacter for ID: %llu", entity->GetObjectID()); +} + +void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHAT_MODERATION_STRING); + + bitStream.Write<uint8_t>(unacceptedItems.empty()); // Is sentence ok? + bitStream.Write<uint16_t>(0x16); // Source ID, unknown + + bitStream.Write(static_cast<uint8_t>(requestID)); // request ID + bitStream.Write(static_cast<char>(0)); // chat mode + + PacketUtils::WritePacketWString(receiver, 42, &bitStream); // receiver name + + for (auto it : unacceptedItems) { + bitStream.Write<uint8_t>(it.first); // start index + bitStream.Write<uint8_t>(it.second); // length } - SEND_PACKET + for (int i = unacceptedItems.size(); 64 > i; i++) { + bitStream.Write<uint16_t>(0); + } + + SEND_PACKET; } -void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAKE_GM_RESPONSE); - - bitStream.Write<uint8_t>(success); - bitStream.Write<uint16_t>(highestLevel); - bitStream.Write<uint16_t>(prevLevel); - bitStream.Write<uint16_t>(newLevel); - - SEND_PACKET +void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAKE_GM_RESPONSE); + + bitStream.Write<uint8_t>(success); + bitStream.Write(static_cast<uint16_t>(highestLevel)); + bitStream.Write(static_cast<uint16_t>(prevLevel)); + bitStream.Write(static_cast<uint16_t>(newLevel)); + + SEND_PACKET; } diff --git a/dNet/WorldPackets.h b/dNet/WorldPackets.h index 3508d6f0..ea8186c7 100644 --- a/dNet/WorldPackets.h +++ b/dNet/WorldPackets.h @@ -8,18 +8,21 @@ class User; struct SystemAddress; +enum class eGameMasterLevel : uint8_t; +enum class eCharacterCreationResponse : uint8_t; +enum class eRenameResponse : uint8_t; namespace WorldPackets { - void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum); - void SendCharacterList(const SystemAddress& sysAddr, User * user); - void SendCharacterCreationResponse(const SystemAddress& sysAddr, eCreationResponse response); + void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum); + void SendCharacterList(const SystemAddress& sysAddr, User* user); + void SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response); void SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response); - void SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response); + void SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response); void SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift); void SendServerState(const SystemAddress& sysAddr); - void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm); - void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::unordered_map<char, char> unacceptedItems); - void SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel); + void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm); + void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems); + void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel); } #endif // WORLDPACKETS_H diff --git a/dNet/ZoneInstanceManager.cpp b/dNet/ZoneInstanceManager.cpp index 9e7653a6..b57bb634 100644 --- a/dNet/ZoneInstanceManager.cpp +++ b/dNet/ZoneInstanceManager.cpp @@ -10,60 +10,58 @@ #include <future> // Static Variables -ZoneInstanceManager * ZoneInstanceManager::m_Address = nullptr; +ZoneInstanceManager* ZoneInstanceManager::m_Address = nullptr; //! Requests a zone transfer void ZoneInstanceManager::RequestZoneTransfer(dServer* server, uint32_t zoneID, uint32_t zoneClone, bool mythranShift, std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback) { - - ZoneTransferRequest * request = new ZoneTransferRequest(); - request->requestID = ++currentRequestID; - request->callback = callback; - - this->requests.push_back(request); - - MasterPackets::SendZoneTransferRequest(server, request->requestID, mythranShift, zoneID, zoneClone); + + ZoneTransferRequest* request = new ZoneTransferRequest(); + request->requestID = ++currentRequestID; + request->callback = callback; + + this->requests.push_back(request); + + MasterPackets::SendZoneTransferRequest(server, request->requestID, mythranShift, zoneID, zoneClone); } //! Handles a zone transfer response -void ZoneInstanceManager::HandleRequestZoneTransferResponse(uint64_t requestID, Packet * packet) { - - bool mythranShift = static_cast<bool>(packet->data[16]); - uint32_t zoneID = PacketUtils::ReadPacketU32(17, packet); - uint32_t zoneInstance = PacketUtils::ReadPacketU32(21, packet); - uint32_t zoneClone = PacketUtils::ReadPacketU32(25, packet); - uint16_t serverPort = PacketUtils::ReadPacketU16(29, packet); - std::string serverIP = PacketUtils::ReadString(31, packet, false); - - for (uint32_t i = 0; i < this->requests.size(); ++i) { - if (this->requests[i]->requestID == requestID) { - - // Call the request callback - this->requests[i]->callback(mythranShift, zoneID, zoneInstance, zoneClone, serverIP, serverPort); - - delete this->requests[i]; - this->requests.erase(this->requests.begin() + i); - return; - } - } - +void ZoneInstanceManager::HandleRequestZoneTransferResponse(uint64_t requestID, Packet* packet) { + + bool mythranShift = static_cast<bool>(packet->data[16]); + uint32_t zoneID = PacketUtils::ReadPacketU32(17, packet); + uint32_t zoneInstance = PacketUtils::ReadPacketU32(21, packet); + uint32_t zoneClone = PacketUtils::ReadPacketU32(25, packet); + uint16_t serverPort = PacketUtils::ReadPacketU16(29, packet); + std::string serverIP = PacketUtils::ReadString(31, packet, false); + + for (uint32_t i = 0; i < this->requests.size(); ++i) { + if (this->requests[i]->requestID == requestID) { + + // Call the request callback + this->requests[i]->callback(mythranShift, zoneID, zoneInstance, zoneClone, serverIP, serverPort); + + delete this->requests[i]; + this->requests.erase(this->requests.begin() + i); + return; + } + } + } -void ZoneInstanceManager::CreatePrivateZone(dServer* server, uint32_t zoneID, uint32_t zoneClone, const std::string& password) -{ - MasterPackets::SendZoneCreatePrivate(server, zoneID, zoneClone, password); +void ZoneInstanceManager::CreatePrivateZone(dServer* server, uint32_t zoneID, uint32_t zoneClone, const std::string& password) { + MasterPackets::SendZoneCreatePrivate(server, zoneID, zoneClone, password); } void ZoneInstanceManager::RequestPrivateZone( - dServer* server, - bool mythranShift, + dServer* server, + bool mythranShift, const std::string& password, - std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback) -{ - ZoneTransferRequest* request = new ZoneTransferRequest(); - request->requestID = ++currentRequestID; - request->callback = callback; + std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback) { + ZoneTransferRequest* request = new ZoneTransferRequest(); + request->requestID = ++currentRequestID; + request->callback = callback; - this->requests.push_back(request); + this->requests.push_back(request); - MasterPackets::SendZoneRequestPrivate(server, request->requestID, mythranShift, password); + MasterPackets::SendZoneRequestPrivate(server, request->requestID, mythranShift, password); } diff --git a/dNet/ZoneInstanceManager.h b/dNet/ZoneInstanceManager.h index d81fe3c3..a8e32c4e 100644 --- a/dNet/ZoneInstanceManager.h +++ b/dNet/ZoneInstanceManager.h @@ -16,50 +16,50 @@ class dServer; \brief A class for handling zone transfers and zone-related functions */ -//! The zone request + //! The zone request struct ZoneTransferRequest { - uint64_t requestID; - std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback; + uint64_t requestID; + std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback; }; //! The zone manager class ZoneInstanceManager { private: - static ZoneInstanceManager * m_Address; //!< The singleton instance - - std::vector<ZoneTransferRequest*> requests; //!< The zone transfer requests - uint64_t currentRequestID; //!< The current request ID - -public: - - //! The singleton method - static ZoneInstanceManager * Instance() { - if (m_Address == 0) { - m_Address = new ZoneInstanceManager; - m_Address->currentRequestID = 0; - } - - return m_Address; - } - - //! Requests a zone transfer - /*! - \param zoneID The zone ID - \param zoneClone The zone clone - \param mythranShift Whether or not this is a mythran shift - \param callback The callback function - */ - void RequestZoneTransfer(dServer* server, uint32_t zoneID, uint32_t zoneClone, bool mythranShift, std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback); - - //! Handles a zone transfer response - /*! - \param requestID The request ID - \param packet The packet - */ - void HandleRequestZoneTransferResponse(uint64_t requestID, Packet * packet); + static ZoneInstanceManager* m_Address; //!< The singleton instance - void CreatePrivateZone(dServer* server, uint32_t zoneID, uint32_t zoneClone, const std::string& password); - - void RequestPrivateZone(dServer* server, bool mythranShift, const std::string& password, std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback); + std::vector<ZoneTransferRequest*> requests; //!< The zone transfer requests + uint64_t currentRequestID; //!< The current request ID + +public: + + //! The singleton method + static ZoneInstanceManager* Instance() { + if (m_Address == 0) { + m_Address = new ZoneInstanceManager; + m_Address->currentRequestID = 0; + } + + return m_Address; + } + + //! Requests a zone transfer + /*! + \param zoneID The zone ID + \param zoneClone The zone clone + \param mythranShift Whether or not this is a mythran shift + \param callback The callback function + */ + void RequestZoneTransfer(dServer* server, uint32_t zoneID, uint32_t zoneClone, bool mythranShift, std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback); + + //! Handles a zone transfer response + /*! + \param requestID The request ID + \param packet The packet + */ + void HandleRequestZoneTransferResponse(uint64_t requestID, Packet* packet); + + void CreatePrivateZone(dServer* server, uint32_t zoneID, uint32_t zoneClone, const std::string& password); + + void RequestPrivateZone(dServer* server, bool mythranShift, const std::string& password, std::function<void(bool, uint32_t, uint32_t, uint32_t, std::string, uint16_t)> callback); }; diff --git a/dNet/dMessageIdentifiers.h b/dNet/dMessageIdentifiers.h deleted file mode 100644 index 5b2ff639..00000000 --- a/dNet/dMessageIdentifiers.h +++ /dev/null @@ -1,542 +0,0 @@ -#pragma once -#include "MessageIdentifiers.h" - -enum CONNECTION_TYPE { - SERVER = 0, //!< Means it is used throughout all servers - AUTH, //!< Means it is sent from the client authentication - CHAT, //!< Means it is sent from and to the chat server - CHAT_INTERNAL, //!< Unused - We can potentially use this in the future for various things - WORLD, //!< Means it is sent from the client world - CLIENT, //!< Means it is sent to the client from the world server - MASTER //!< Means it is sent to and from the master server -}; - -//! The Internal Server Packet Identifiers -enum SERVER { - MSG_SERVER_VERSION_CONFIRM = 0, /*!< Sent during a handshake to confirm the server/client version */ - MSG_SERVER_DISCONNECT_NOTIFY, /*!< Sent when a user disconnected */ - MSG_SERVER_GENERAL_NOTIFY /*!< A general notification */ -}; - -//! The Internal Authentication Packet Identifiers -enum AUTH { - MSG_AUTH_LOGIN_REQUEST = 0, /*!< Sent from the client when a user logs in */ - MSG_AUTH_LOGOUT_REQUEST, /*!< Sent from the client when a user logs out */ - MSG_AUTH_CREATE_NEW_ACCOUNT_REQUEST, /*!< Sent from the client when a user creates a new account */ - MSG_AUTH_LEGOINTERFACE_AUTH_RESPONSE, /*!< Unknown */ - MSG_AUTH_SESSIONKEY_RECEIVED_CONFIRM, /*!< Sent when the server recieved the session key (?) */ - MSG_AUTH_RUNTIME_CONFIG /*!< Unknown */ -}; - -//! The Internal Chat Packet Identifiers -enum CHAT { - MSG_CHAT_LOGIN_SESSION_NOTIFY = 0, /*!< When a user logs in */ - MSG_CHAT_GENERAL_CHAT_MESSAGE, /*!< Used for global chat messages */ - MSG_CHAT_PRIVATE_CHAT_MESSAGE, /*!< Used for private chat messages */ - MSG_CHAT_USER_CHANNEL_CHAT_MESSAGE, /*!< Unknown */ - MSG_CHAT_WORLD_DISCONNECT_REQUEST, /*!< Unknown */ - MSG_CHAT_WORLD_PROXIMITY_RESPONSE, /*!< Unknown */ - MSG_CHAT_WORLD_PARCEL_RESPONSE, /*!< Unknown */ - MSG_CHAT_ADD_FRIEND_REQUEST, /*!< When the client requests to add a friend */ - MSG_CHAT_ADD_FRIEND_RESPONSE, /*!< Sent from the server when the client adds a friend */ - MSG_CHAT_REMOVE_FRIEND, /*!< When the client removes a friend */ - MSG_CHAT_GET_FRIENDS_LIST, /*!< Sent when the client requests a user's friends list */ - MSG_CHAT_ADD_IGNORE, /*!< Sent when the client adds a friend to the "ignore" list */ - MSG_CHAT_REMOVE_IGNORE, /*!< Sent when the client removes a friend from the "ignore" list */ - MSG_CHAT_GET_IGNORE_LIST, /*!< Sent when the client requests a user's ignored list */ - MSG_CHAT_TEAM_MISSED_INVITE_CHECK, /*!< Unknown (Something with an unresponded-to friend request probably) */ - MSG_CHAT_TEAM_INVITE, /*!< When the client invites a user to a team */ - MSG_CHAT_TEAM_INVITE_RESPONSE, /*!< Sent from the server when the client invites someone to the team */ - MSG_CHAT_TEAM_KICK, /*!< Sent when the client kicks a member from a team */ - MSG_CHAT_TEAM_LEAVE, /*!< Sent when the client leaves a team */ - MSG_CHAT_TEAM_SET_LOOT, /*!< Unknown (Something to do with team loot) */ - MSG_CHAT_TEAM_SET_LEADER, /*!< Unknown (Probably sets the team leader or something) */ - MSG_CHAT_TEAM_GET_STATUS, /*!< Check to see if we are in a team or not, sent on world join */ - MSG_CHAT_GUILD_CREATE, /*!< Guild Creation */ - MSG_CHAT_GUILD_INVITE, /*!< Guild Invitation */ - MSG_CHAT_GUILD_INVITE_RESPONSE, /*!< Guild Invite Response */ - MSG_CHAT_GUILD_LEAVE, /*!< Guild Leave */ - MSG_CHAT_GUILD_KICK, /*!< Guild Kick */ - MSG_CHAT_GUILD_GET_STATUS, /*!< Guild Get Status */ - MSG_CHAT_GUILD_GET_ALL, /*!< Guild Get All */ - MSG_CHAT_SHOW_ALL, - MSG_CHAT_BLUEPRINT_MODERATED, - MSG_CHAT_BLUEPRINT_MODEL_READY, - MSG_CHAT_PROPERTY_READY_FOR_APPROVAL, - MSG_CHAT_PROPERTY_MODERATION_CHANGED, - MSG_CHAT_PROPERTY_BUILDMODE_CHANGED, - MSG_CHAT_PROPERTY_BUILDMODE_CHANGED_REPORT, - MSG_CHAT_MAIL, - MSG_CHAT_WORLD_INSTANCE_LOCATION_REQUEST, - MSG_CHAT_REPUTATION_UPDATE, - MSG_CHAT_SEND_CANNED_TEXT, - MSG_CHAT_GMLEVEL_UPDATE, - MSG_CHAT_CHARACTER_NAME_CHANGE_REQUEST, - MSG_CHAT_CSR_REQUEST, - MSG_CHAT_CSR_REPLY, - MSG_CHAT_GM_KICK, - MSG_CHAT_GM_ANNOUNCE, - MSG_CHAT_GM_MUTE, - MSG_CHAT_ACTIVITY_UPDATE, - MSG_CHAT_WORLD_ROUTE_PACKET, - MSG_CHAT_GET_ZONE_POPULATIONS, - MSG_CHAT_REQUEST_MINIMUM_CHAT_MODE, - MSG_CHAT_REQUEST_MINIMUM_CHAT_MODE_PRIVATE, - MSG_CHAT_MATCH_REQUEST, - MSG_CHAT_UGCMANIFEST_REPORT_MISSING_FILE, - MSG_CHAT_UGCMANIFEST_REPORT_DONE_FILE, - MSG_CHAT_UGCMANIFEST_REPORT_DONE_BLUEPRINT, - MSG_CHAT_UGCC_REQUEST, - MSG_CHAT_WHO, - MSG_CHAT_WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE, - MSG_CHAT_ACHIEVEMENT_NOTIFY, - MSG_CHAT_GM_CLOSE_PRIVATE_CHAT_WINDOW, - MSG_CHAT_UNEXPECTED_DISCONNECT, - MSG_CHAT_PLAYER_READY, - MSG_CHAT_GET_DONATION_TOTAL, - MSG_CHAT_UPDATE_DONATION, - MSG_CHAT_PRG_CSR_COMMAND, - MSG_CHAT_HEARTBEAT_REQUEST_FROM_WORLD, - MSG_CHAT_UPDATE_FREE_TRIAL_STATUS -}; - -//! Used for packets related to chatting -enum CHAT_INTERNAL { - MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION = 0, - MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION, - MSG_CHAT_INTERNAL_ADD_FRIEND, - MSG_CHAT_INTERNAL_ADD_BEST_FRIEND, - MSG_CHAT_INTERNAL_ADD_TO_TEAM, - MSG_CHAT_INTERNAL_ADD_BLOCK, - MSG_CHAT_INTERNAL_REMOVE_FRIEND, - MSG_CHAT_INTERNAL_REMOVE_BLOCK, - MSG_CHAT_INTERNAL_REMOVE_FROM_TEAM, - MSG_CHAT_INTERNAL_DELETE_TEAM, - MSG_CHAT_INTERNAL_REPORT, - MSG_CHAT_INTERNAL_PRIVATE_CHAT, - MSG_CHAT_INTERNAL_PRIVATE_CHAT_RESPONSE, - MSG_CHAT_INTERNAL_ANNOUNCEMENT, - MSG_CHAT_INTERNAL_MAIL_COUNT_UPDATE, - MSG_CHAT_INTERNAL_MAIL_SEND_NOTIFY, - MSG_CHAT_INTERNAL_REQUEST_USER_LIST, - MSG_CHAT_INTERNAL_FRIEND_LIST, - MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER, - MSG_CHAT_INTERNAL_TEAM_UPDATE, - MSG_CHAT_INTERNAL_MUTE_UPDATE, - MSG_CHAT_INTERNAL_CREATE_TEAM, -}; - -//! Used for packets send to the world -enum WORLD { - MSG_WORLD_CLIENT_VALIDATION = 1, // Session info - MSG_WORLD_CLIENT_CHARACTER_LIST_REQUEST, - MSG_WORLD_CLIENT_CHARACTER_CREATE_REQUEST, - MSG_WORLD_CLIENT_LOGIN_REQUEST, // Character selected - MSG_WORLD_CLIENT_GAME_MSG, - MSG_WORLD_CLIENT_CHARACTER_DELETE_REQUEST, - MSG_WORLD_CLIENT_CHARACTER_RENAME_REQUEST, - MSG_WORLD_CLIENT_HAPPY_FLOWER_MODE_NOTIFY, - MSG_WORLD_CLIENT_SLASH_RELOAD_MAP, // Reload map cmp - MSG_WORLD_CLIENT_SLASH_PUSH_MAP_REQUEST, // Push map req cmd - MSG_WORLD_CLIENT_SLASH_PUSH_MAP, // Push map cmd - MSG_WORLD_CLIENT_SLASH_PULL_MAP, // Pull map cmd - MSG_WORLD_CLIENT_LOCK_MAP_REQUEST, - MSG_WORLD_CLIENT_GENERAL_CHAT_MESSAGE, // General chat message - MSG_WORLD_CLIENT_HTTP_MONITOR_INFO_REQUEST, - MSG_WORLD_CLIENT_SLASH_DEBUG_SCRIPTS, // Debug scripts cmd - MSG_WORLD_CLIENT_MODELS_CLEAR, - MSG_WORLD_CLIENT_EXHIBIT_INSERT_MODEL, - MSG_WORLD_CLIENT_LEVEL_LOAD_COMPLETE, // Character data request - MSG_WORLD_CLIENT_TMP_GUILD_CREATE, - MSG_WORLD_CLIENT_ROUTE_PACKET, // Social? - MSG_WORLD_CLIENT_POSITION_UPDATE, - MSG_WORLD_CLIENT_MAIL, - MSG_WORLD_CLIENT_WORD_CHECK, // Whitelist word check - MSG_WORLD_CLIENT_STRING_CHECK, // Whitelist string check - MSG_WORLD_CLIENT_GET_PLAYERS_IN_ZONE, - MSG_WORLD_CLIENT_REQUEST_UGC_MANIFEST_INFO, - MSG_WORLD_CLIENT_BLUEPRINT_GET_ALL_DATA_REQUEST, - MSG_WORLD_CLIENT_CANCEL_MAP_QUEUE, - MSG_WORLD_CLIENT_HANDLE_FUNNESS, - MSG_WORLD_CLIENT_FAKE_PRG_CSR_MESSAGE, - MSG_WORLD_CLIENT_REQUEST_FREE_TRIAL_REFRESH, - MSG_WORLD_CLIENT_GM_SET_FREE_TRIAL_STATUS -}; - -//! An enum for packets sent to the client -enum CLIENT { - MSG_CLIENT_LOGIN_RESPONSE = 0, - MSG_CLIENT_LOGOUT_RESPONSE, - MSG_CLIENT_LOAD_STATIC_ZONE, - MSG_CLIENT_CREATE_OBJECT, - MSG_CLIENT_CREATE_CHARACTER, - MSG_CLIENT_CREATE_CHARACTER_EXTENDED, - MSG_CLIENT_CHARACTER_LIST_RESPONSE, - MSG_CLIENT_CHARACTER_CREATE_RESPONSE, - MSG_CLIENT_CHARACTER_RENAME_RESPONSE, - MSG_CLIENT_CHAT_CONNECT_RESPONSE, - MSG_CLIENT_AUTH_ACCOUNT_CREATE_RESPONSE, - MSG_CLIENT_DELETE_CHARACTER_RESPONSE, - MSG_CLIENT_GAME_MSG, - MSG_CLIENT_CONNECT_CHAT, - MSG_CLIENT_TRANSFER_TO_WORLD, - MSG_CLIENT_IMPENDING_RELOAD_NOTIFY, - MSG_CLIENT_MAKE_GM_RESPONSE, - MSG_CLIENT_HTTP_MONITOR_INFO_RESPONSE, - MSG_CLIENT_SLASH_PUSH_MAP_RESPONSE, - MSG_CLIENT_SLASH_PULL_MAP_RESPONSE, - MSG_CLIENT_SLASH_LOCK_MAP_RESPONSE, - MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE, - MSG_CLIENT_BLUEPRINT_LUP_SAVE_RESPONSE, - MSG_CLIENT_BLUEPRINT_LOAD_RESPONSE_ITEMID, - MSG_CLIENT_BLUEPRINT_GET_ALL_DATA_RESPONSE, - MSG_CLIENT_MODEL_INSTANTIATE_RESPONSE, - MSG_CLIENT_DEBUG_OUTPUT, - MSG_CLIENT_ADD_FRIEND_REQUEST, - MSG_CLIENT_ADD_FRIEND_RESPONSE, - MSG_CLIENT_REMOVE_FRIEND_RESPONSE, - MSG_CLIENT_GET_FRIENDS_LIST_RESPONSE, - MSG_CLIENT_UPDATE_FRIEND_NOTIFY, - MSG_CLIENT_ADD_IGNORE_RESPONSE, - MSG_CLIENT_REMOVE_IGNORE_RESPONSE, - MSG_CLIENT_GET_IGNORE_LIST_RESPONSE, - MSG_CLIENT_TEAM_INVITE, - MSG_CLIENT_TEAM_INVITE_INITIAL_RESPONSE, - MSG_CLIENT_GUILD_CREATE_RESPONSE, - MSG_CLIENT_GUILD_GET_STATUS_RESPONSE, - MSG_CLIENT_GUILD_INVITE, - MSG_CLIENT_GUILD_INVITE_INITIAL_RESPONSE, - MSG_CLIENT_GUILD_INVITE_FINAL_RESPONSE, - MSG_CLIENT_GUILD_INVITE_CONFIRM, - MSG_CLIENT_GUILD_ADD_PLAYER, - MSG_CLIENT_GUILD_REMOVE_PLAYER, - MSG_CLIENT_GUILD_LOGIN_LOGOUT, - MSG_CLIENT_GUILD_RANK_CHANGE, - MSG_CLIENT_GUILD_DATA, - MSG_CLIENT_GUILD_STATUS, - MSG_CLIENT_MAIL, - MSG_CLIENT_DB_PROXY_RESULT, - MSG_CLIENT_SHOW_ALL_RESPONSE, - MSG_CLIENT_WHO_RESPONSE, - MSG_CLIENT_SEND_CANNED_TEXT, - MSG_CLIENT_UPDATE_CHARACTER_NAME, - MSG_CLIENT_SET_NETWORK_SIMULATOR, - MSG_CLIENT_INVALID_CHAT_MESSAGE, - MSG_CLIENT_MINIMUM_CHAT_MODE_RESPONSE, - MSG_CLIENT_MINIMUM_CHAT_MODE_RESPONSE_PRIVATE, - MSG_CLIENT_CHAT_MODERATION_STRING, - MSG_CLIENT_UGC_MANIFEST_RESPONSE, - MSG_CLIENT_IN_LOGIN_QUEUE, - MSG_CLIENT_SERVER_STATES, - MSG_CLIENT_GM_CLOSE_TARGET_CHAT_WINDOW, - MSG_CLIENT_GENERAL_TEXT_FOR_LOCALIZATION, - MSG_CLIENT_UPDATE_FREE_TRIAL_STATUS, - MSG_CLIENT_UGC_DOWNLOAD_FAILED = 120 -}; - -//! Used for packets sent to the master server -enum MASTER { - MSG_MASTER_REQUEST_PERSISTENT_ID = 1, - MSG_MASTER_REQUEST_PERSISTENT_ID_RESPONSE, - MSG_MASTER_REQUEST_ZONE_TRANSFER, - MSG_MASTER_REQUEST_ZONE_TRANSFER_RESPONSE, - MSG_MASTER_SERVER_INFO, - MSG_MASTER_REQUEST_SESSION_KEY, - MSG_MASTER_SET_SESSION_KEY, - MSG_MASTER_SESSION_KEY_RESPONSE, - MSG_MASTER_PLAYER_ADDED, - MSG_MASTER_PLAYER_REMOVED, - - MSG_MASTER_CREATE_PRIVATE_ZONE, - MSG_MASTER_REQUEST_PRIVATE_ZONE, - - MSG_MASTER_WORLD_READY, - MSG_MASTER_PREP_ZONE, - - MSG_MASTER_SHUTDOWN, - MSG_MASTER_SHUTDOWN_RESPONSE, - MSG_MASTER_SHUTDOWN_IMMEDIATE, - - MSG_MASTER_SHUTDOWN_UNIVERSE, - - MSG_MASTER_AFFIRM_TRANSFER_REQUEST, - MSG_MASTER_AFFIRM_TRANSFER_RESPONSE, - - MSG_MASTER_NEW_SESSION_ALERT -}; - -//! The Game messages -enum GAME_MSG : unsigned short { - GAME_MSG_TELEPORT = 19, - GAME_MSG_SET_PLAYER_CONTROL_SCHEME = 26, - GAME_MSG_DROP_CLIENT_LOOT = 30, - GAME_MSG_DIE = 37, - GAME_MSG_REQUEST_DIE = 38, - GAME_MSG_PLAY_EMOTE = 41, - GAME_MSG_PLAY_ANIMATION = 43, - GAME_MSG_SET_NAME = 72, - GAME_MSG_ECHO_START_SKILL = 118, - GAME_MSG_START_SKILL = 119, - GAME_MSG_VERIFY_ACK = 121, - GAME_MSG_ADD_SKILL = 127, - GAME_MSG_REMOVE_SKILL = 128, - GAME_MSG_SET_CURRENCY = 133, - GAME_MSG_PICKUP_CURRENCY = 137, - GAME_MSG_PICKUP_ITEM = 139, - GAME_MSG_TEAM_PICKUP_ITEM = 140, - GAME_MSG_PLAY_FX_EFFECT = 154, - GAME_MSG_STOP_FX_EFFECT = 155, - GAME_MSG_REQUEST_RESURRECT = 159, - GAME_MSG_RESURRECT = 160, - GAME_MSG_PUSH_EQUIPPED_ITEMS_STATE = 191, - GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192, - GAME_MSG_SET_GM_LEVEL = 193, - GAME_MSG_SET_STUNNED = 198, - GAME_MSG_KNOCKBACK = 202, - GAME_MSG_REBUILD_CANCEL = 209, - GAME_MSG_ENABLE_REBUILD = 213, - GAME_MSG_MOVE_ITEM_IN_INVENTORY = 224, - GAME_MSG_ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227, - GAME_MSG_REMOVE_ITEM_FROM_INVENTORY = 230, - GAME_MSG_EQUIP_ITEM = 231, - GAME_MSG_UN_EQUIP_ITEM = 233, - GAME_MSG_OFFER_MISSION = 248, - GAME_MSG_RESPOND_TO_MISSION = 249, - GAME_MSG_NOTIFY_MISSION = 254, - GAME_MSG_NOTIFY_MISSION_TASK = 255, - GAME_MSG_REBUILD_NOTIFY_STATE = 336, - GAME_MSG_TERMINATE_INTERACTION = 357, - GAME_MSG_SERVER_TERMINATE_INTERACTION = 358, - GAME_MSG_REQUEST_USE = 364, - GAME_MSG_VENDOR_OPEN_WINDOW = 369, - GAME_MSG_BUY_FROM_VENDOR = 373, - GAME_MSG_SELL_TO_VENDOR = 374, - GAME_MSG_TEAM_SET_OFF_WORLD_FLAG = 383, - GAME_MSG_SET_INVENTORY_SIZE = 389, - GAME_MSG_ACKNOWLEDGE_POSSESSION = 391, - GAME_MSG_SET_SHOOTING_GALLERY_PARAMS = 400, - GAME_MSG_REQUEST_ACTIVITY_START_STOP = 402, - GAME_MSG_REQUEST_ACTIVITY_ENTER = 403, - GAME_MSG_REQUEST_ACTIVITY_EXIT = 404, - GAME_MSG_ACTIVITY_ENTER = 405, - GAME_MSG_ACTIVITY_EXIT = 406, - GAME_MSG_ACTIVITY_START = 407, - GAME_MSG_ACTIVITY_STOP = 408, - GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409, - GAME_MSG_SHOOTING_GALLERY_FIRE = 411, - GAME_MSG_REQUEST_VENDOR_STATUS_UPDATE = 416, - GAME_MSG_VENDOR_STATUS_UPDATE = 417, - GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425, - GAME_MSG_CONSUME_CLIENT_ITEM = 427, - GAME_MSG_CLIENT_ITEM_CONSUMED = 428, - GAME_MSG_UPDATE_SHOOTING_GALLERY_ROTATION = 448, - GAME_MSG_SET_FLAG = 471, - GAME_MSG_NOTIFY_CLIENT_FLAG_CHANGE = 472, - GAME_MSG_VENDOR_TRANSACTION_RESULT = 476, - GAME_MSG_HAS_BEEN_COLLECTED = 486, - GAME_MSG_DISPLAY_CHAT_BUBBLE = 495, - GAME_MSG_SPAWN_PET = 498, - GAME_MSG_DESPAWN_PET = 499, - GAME_MSG_PLAYER_LOADED = 505, - GAME_MSG_PLAYER_READY = 509, - GAME_MSG_REQUEST_LINKED_MISSION = 515, - GAME_MSG_INVALID_ZONE_TRANSFER_LIST = 519, - GAME_MSG_MISSION_DIALOGUE_OK = 520, - GAME_MSG_DISPLAY_MESSAGE_BOX = 529, - GAME_MSG_MESSAGE_BOX_RESPOND = 530, - GAME_MSG_CHOICE_BOX_RESPOND = 531, - GAME_MSG_SET_SHOOTING_GALLERY_RETICULE_EFFECT = 548, - GAME_MSG_PLACE_MODEL_RESPONSE = 0x223, - GAME_MSG_SET_JET_PACK_MODE = 561, - GAME_MSG_REGISTER_PET_ID = 565, - GAME_MSG_REGISTER_PET_DBID = 566, - GAME_MSG_SHOW_ACTIVITY_COUNTDOWN = 568, - GAME_MSG_START_ACTIVITY_TIME = 576, - GAME_MSG_ACTIVITY_PAUSE = 602, - GAME_MSG_USE_NON_EQUIPMENT_ITEM = 603, - GAME_MSG_USE_ITEM_RESULT = 607, - GAME_MSG_COMMAND_PET = 640, - GAME_MSG_PET_RESPONSE = 641, - GAME_MSG_REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 648, - GAME_MSG_SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 649, - GAME_MSG_NOTIFY_OBJECT = 656, - GAME_MSG_CLIENT_NOTIFY_PET = 659, - GAME_MSG_NOTIFY_PET = 660, - GAME_MSG_NOTIFY_PET_TAMING_MINIGAME = 661, - GAME_MSG_START_SERVER_PET_MINIGAME_TIMER = 662, - GAME_MSG_CLIENT_EXIT_TAMING_MINIGAME = 663, - GAME_MSG_PET_NAME_CHANGED = 686, - GAME_MSG_PET_TAMING_MINIGAME_RESULT = 667, - GAME_MSG_PET_TAMING_TRY_BUILD_RESULT = 668, - GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS = 673, - GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, - GAME_MSG_ADD_PET_TO_PLAYER = 681, - GAME_MSG_REQUEST_SET_PET_NAME = 683, - GAME_MSG_SET_PET_NAME = 684, - GAME_MSG_NOTIFY_PET_TAMING_PUZZLE_SELECTED = 675, - GAME_MSG_SHOW_PET_ACTION_BUTTON = 692, - GAME_MSG_SET_EMOTE_LOCK_STATE = 693, - GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE = 703, - GAME_MSG_PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, - GAME_MSG_DOWNLOAD_PROPERTY_DATA = 716, - GAME_MSG_QUERY_PROPERTY_DATA = 717, - GAME_MSG_PROPERTY_EDITOR_BEGIN = 724, - GAME_MSG_PROPERTY_EDITOR_END = 725, - GAME_MSG_START_PATHING = 735, - GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT = 737, - GAME_MSG_UPDATE_REPUTATION = 746, - GAME_MSG_PROPERTY_RENTAL_RESPONSE = 750, - GAME_MSG_REQUEST_PLATFORM_RESYNC = 760, - GAME_MSG_PLATFORM_RESYNC = 761, - GAME_MSG_PLAY_CINEMATIC = 762, - GAME_MSG_END_CINEMATIC = 763, - GAME_MSG_CINEMATIC_UPDATE = 764, - GAME_MSG_TOGGLE_GHOST_REFERENCE_OVERRIDE = 767, - GAME_MSG_SET_GHOST_REFERENCE_POSITION = 768, - GAME_MSG_FIRE_EVENT_SERVER_SIDE = 770, - GAME_MSG_SET_NETWORK_SCRIPT_VAR = 781, - GAME_MSG_UPDATE_MODEL_FROM_CLIENT = 793, - GAME_MSG_DELETE_MODEL_FROM_CLIENT = 794, - GAME_MSG_PLAY_ND_AUDIO_EMITTER = 821, - GAME_MSG_PLAY2_DAMBIENT_SOUND = 831, - GAME_MSG_ENTER_PROPERTY1 = 840, - GAME_MSG_ENTER_PROPERTY2 = 841, - GAME_MSG_PROPERTY_ENTRANCE_SYNC = 842, - GAME_MSG_PROPERTY_SELECT_QUERY = 845, - GAME_MSG_PARSE_CHAT_MESSAGE = 850, - GAME_MSG_BROADCAST_TEXT_TO_CHATBOX = 858, - GAME_MSG_OPEN_PROPERTY_MANAGEMENT = 860, - GAME_MSG_OPEN_PROPERTY_VENDOR = 861, - GAME_MSG_UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK = 863, - GAME_MSG_CLIENT_TRADE_REQUEST = 868, - GAME_MSG_SERVER_TRADE_REQUEST = 869, - GAME_MSG_SERVER_TRADE_INVITE = 870, - GAME_MSG_CLIENT_TRADE_REPLY = 871, - GAME_MSG_SERVER_TRADE_REPLY = 872, - GAME_MSG_SERVER_TRADE_INITIAL_REPLY = 873, - GAME_MSG_SERVER_TRADE_FINAL_REPLY = 874, - GAME_MSG_CLIENT_TRADE_UPDATE = 875, - GAME_MSG_SERVER_SIDE_TRADE_UPDATE = 876, - GAME_MSG_SERVER_TRADE_UPDATE = 877, - GAME_MSG_CLIENT_TRADE_CANCEL = 878, - GAME_MSG_CLIENT_SIDE_TRADE_CANCEL = 879, - GAME_MSG_CLIENT_TRADE_ACCEPT = 880, - GAME_MSG_SERVER_SIDE_TRADE_ACCEPT = 881, - GAME_MSG_SERVER_SIDE_TRADE_CANCEL = 882, - GAME_MSG_SERVER_TRADE_CANCEL = 883, - GAME_MSG_SERVER_TRADE_ACCEPT = 884, - GAME_MSG_READY_FOR_UPDATES = 888, - GAME_MSG_ORIENT_TO_OBJECT = 905, - GAME_MSG_ORIENT_TO_POSITION = 906, - GAME_MSG_ORIENT_TO_ANGLE = 907, - GAME_MSG_BOUNCER_ACTIVE_STATUS = 942, - GAME_MSG_BBB_LOAD_ITEM_REQUEST = 1000, - GAME_MSG_BBB_SAVE_REQUEST = 1001, - GAME_MSG_BBB_SAVE_RESPONSE = 1006, - GAME_MSG_NOTIFY_CLIENT_OBJECT = 1042, - GAME_MSG_DISPLAY_ZONE_SUMMARY = 1043, - GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST = 1053, - GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC = 1046, - GAME_MSG_START_BUILDING_WITH_ITEM = 1057, - GAME_MSG_START_ARRANGING_WITH_ITEM = 1061, - GAME_MSG_FINISH_ARRANGING_WITH_ITEM = 1062, - GAME_MSG_DONE_ARRANGING_WITH_ITEM = 1063, - GAME_MSG_SET_BUILD_MODE = 1068, - GAME_MSG_BUILD_MODE_SET = 1069, - GAME_MSG_SET_BUILD_MODE_CONFIRMED = 1073, - GAME_MSG_NOTIFY_CLIENT_FAILED_PRECONDITION = 1081, - GAME_MSG_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1093, - GAME_MSG_MODULAR_BUILD_BEGIN = 1094, - GAME_MSG_MODULAR_BUILD_END = 1095, - GAME_MSG_MODULAR_BUILD_MOVE_AND_EQUIP = 1096, - GAME_MSG_MODULAR_BUILD_FINISH = 1097, - GAME_MSG_REPORT_BUG = 1198, - GAME_MSG_MISSION_DIALOGUE_CANCELLED = 1129, - GAME_MSG_ECHO_SYNC_SKILL = 1144, - GAME_MSG_SYNC_SKILL = 1145, - GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT = 1148, - GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT = 1151, - GAME_MSG_MODULAR_BUILD_CONVERT_MODEL = 1155, - GAME_MSG_SET_PLAYER_ALLOWED_RESPAWN = 1165, - GAME_MSG_UI_MESSAGE_SERVER_TO_SINGLE_CLIENT = 1184, - GAME_MSG_UI_MESSAGE_SERVER_TO_ALL_CLIENTS = 1185, - GAME_MSG_PET_TAMING_TRY_BUILD = 1197, - GAME_MSG_REQUEST_SMASH_PLAYER = 1202, - GAME_MSG_FIRE_EVENT_CLIENT_SIDE = 1213, - GAME_MSG_TOGGLE_GM_INVIS = 1218, - GAME_MSG_CHANGE_OBJECT_WORLD_STATE = 1223, - GAME_MSG_VEHICLE_LOCK_INPUT = 1230, - GAME_MSG_VEHICLE_UNLOCK_INPUT = 1231, - GAME_MSG_RACING_RESET_PLAYER_TO_LAST_RESET = 1252, - GAME_MSG_RACING_SERVER_SET_PLAYER_LAP_AND_PLANE = 1253, - GAME_MSG_RACING_SET_PLAYER_RESET_INFO = 1254, - GAME_MSG_RACING_PLAYER_INFO_RESET_FINISHED = 1255, - GAME_MSG_LOCK_NODE_ROTATION = 1260, - GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE = 1273, - GAME_MSG_NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, - GAME_MSG_PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, - GAME_MSG_HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE = 1300, - GAME_MSG_HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE = 1301, - GAME_MSG_PROPERTY_CONTENTS_FROM_CLIENT = 1305, - GAME_MSG_GET_MODELS_ON_PROPERTY = 1306, - GAME_MSG_MATCH_REQUEST = 1308, - GAME_MSG_MATCH_RESPONSE = 1309, - GAME_MSG_MATCH_UPDATE = 1310, - GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, - GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132, - GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, - GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, - GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342, - GAME_MSG_VEHICLE_NOTIFY_SERVER_REMOVE_PASSIVE_BOOST_ACTION = 1343, - GAME_MSG_VEHICLE_ADD_SLOWDOWN_ACTION = 1344, - GAME_MSG_VEHICLE_REMOVE_SLOWDOWN_ACTION = 1345, - GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_SLOWDOWN_ACTION = 1346, - GAME_MSG_VEHICLE_NOTIFY_SERVER_REMOVE_SLOWDOWN_ACTION = 1347, - GAME_MSG_BUYBACK_FROM_VENDOR = 1350, - GAME_MSG_SET_PROPERTY_ACCESS = 1366, - GAME_MSG_ZONE_PROPERTY_MODEL_PLACED = 1369, - GAME_MSG_ZONE_PROPERTY_MODEL_ROTATED = 1370, - GAME_MSG_ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED = 1371, - GAME_MSG_ZONE_PROPERTY_MODEL_EQUIPPED = 1372, - GAME_MSG_ZONE_PROPERTY_MODEL_PICKED_UP = 1373, - GAME_MSG_ZONE_PROPERTY_MODEL_REMOVED = 1374, - GAME_MSG_NOTIFY_RACING_CLIENT = 1390, - GAME_MSG_RACING_PLAYER_HACK_CAR = 1391, - GAME_MSG_RACING_PLAYER_LOADED = 1392, - GAME_MSG_RACING_CLIENT_READY = 1393, - GAME_MSG_UPDATE_CHAT_MODE = 1395, - GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396, - GAME_MSG_SET_CONSUMABLE_ITEM = 1409, - GAME_MSG_SET_PET_NAME_MODERATED = 1448, - GAME_MSG_MODIFY_LEGO_SCORE = 1459, - GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468, - GAME_MSG_SET_RAIL_MOVEMENT = 1471, - GAME_MSG_START_RAIL_MOVEMENT = 1472, - GAME_MSG_CANCEL_RAIL_MOVEMENT = 1474, - GAME_MSG_CLIENT_RAIL_MOVEMENT_READY = 1476, - GAME_MSG_PLAYER_RAIL_ARRIVED_NOTIFICATION = 1477, - GAME_MSG_UPDATE_PLAYER_STATISTIC = 1481, - GAME_MSG_MODULAR_ASSEMBLY_NIF_COMPLETED = 1498, - GAME_MSG_NOTIFY_NOT_ENOUGH_INV_SPACE = 1516, - GAME_MSG_TEAM_SET_LEADER = 0x0615, - GAME_MSG_TEAM_INVITE_CONFIRM = 0x0616, - GAME_MSG_TEAM_GET_STATUS_RESPONSE = 0x0617, - GAME_MSG_TEAM_ADD_PLAYER = 0x061a, - GAME_MSG_TEAM_REMOVE_PLAYER = 0x061b, - GAME_MSG_START_CELEBRATION_EFFECT = 1618, - GAME_MSG_ADD_BUFF = 1647, - GAME_MSG_SERVER_DONE_LOADING_ALL_OBJECTS = 1642, - GAME_MSG_PLACE_PROPERTY_MODEL = 1170, - GAME_MSG_VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER = 1606, - GAME_MSG_ADD_RUN_SPEED_MODIFIER = 1505, - GAME_MSG_REMOVE_RUN_SPEED_MODIFIER = 1506, - GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST = 1547, - GAME_MSG_PROPERTY_ENTRANCE_BEGIN = 1553, - GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, - GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, - GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676, - GAME_MSG_NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734, - GAME_MSG_NOTIFY_LEVEL_REWARDS = 1735, - GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE = 1767, - END -}; \ No newline at end of file diff --git a/dNet/dNetCommon.h b/dNet/dNetCommon.h index 10103f3b..73a90bc0 100644 --- a/dNet/dNetCommon.h +++ b/dNet/dNetCommon.h @@ -3,4 +3,4 @@ #include "RakPeer.h" #define NET_PASSWORD_EXTERNAL "3.25 ND1" -#define NET_PASSWORD_INTERNAL "3.25 DARKFLAME1" \ No newline at end of file +#define NET_PASSWORD_INTERNAL "3.25 DARKFLAME1" diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 27b6df7c..610f06a5 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -2,40 +2,43 @@ #include "dServer.h" #include "dNetCommon.h" #include "dLogger.h" +#include "dConfig.h" #include "RakNetworkFactory.h" #include "MessageIdentifiers.h" +#include "eConnectionType.h" +#include "eServerMessageType.h" +#include "eMasterMessageType.h" #include "PacketUtils.h" -#include "dMessageIdentifiers.h" #include "MasterPackets.h" #include "ZoneInstanceManager.h" //! Replica Constructor class class ReplicaConstructor : public ReceiveConstructionInterface { -public: - ReplicaReturnResult ReceiveConstruction(RakNet::BitStream *inBitStream, RakNetTime timestamp, NetworkID networkID, NetworkIDObject *existingObject, SystemAddress senderId, ReplicaManager *caller) { - return REPLICA_PROCESSING_DONE; - } +public: + ReplicaReturnResult ReceiveConstruction(RakNet::BitStream* inBitStream, RakNetTime timestamp, NetworkID networkID, NetworkIDObject* existingObject, SystemAddress senderId, ReplicaManager* caller) { + return REPLICA_PROCESSING_DONE; + } } ConstructionCB; //! Replica Download Sender class class ReplicaSender : public SendDownloadCompleteInterface { public: - ReplicaReturnResult SendDownloadComplete(RakNet::BitStream *outBitStream, RakNetTime currentTime, SystemAddress senderId, ReplicaManager *caller) { - return REPLICA_PROCESSING_DONE; - } + ReplicaReturnResult SendDownloadComplete(RakNet::BitStream* outBitStream, RakNetTime currentTime, SystemAddress senderId, ReplicaManager* caller) { + return REPLICA_PROCESSING_DONE; + } } SendDownloadCompleteCB; //! Replica Download Receiver class class ReplicaReceiever : public ReceiveDownloadCompleteInterface { public: - ReplicaReturnResult ReceiveDownloadComplete(RakNet::BitStream *inBitStream, SystemAddress senderId, ReplicaManager *caller) { - return REPLICA_PROCESSING_DONE; - } + ReplicaReturnResult ReceiveDownloadComplete(RakNet::BitStream* inBitStream, SystemAddress senderId, ReplicaManager* caller) { + return REPLICA_PROCESSING_DONE; + } } ReceiveDownloadCompleteCB; -dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, unsigned int zoneID) { +dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool* shouldShutdown, unsigned int zoneID) { mIP = ip; mPort = port; mZoneID = zoneID; @@ -50,7 +53,8 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect mNetIDManager = nullptr; mReplicaManager = nullptr; mServerType = serverType; - + mConfig = config; + mShouldShutdown = shouldShutdown; //Attempt to start our server here: mIsOkay = Startup(); @@ -60,11 +64,10 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect if (mIsOkay) { if (zoneID == 0) - mLogger->Log("dServer", "Server is listening on %s:%i with encryption: %i\n", ip.c_str(), port, int(useEncryption)); + mLogger->Log("dServer", "Server is listening on %s:%i with encryption: %i", ip.c_str(), port, int(useEncryption)); else - mLogger->Log("dServer", "Server is listening on %s:%i with encryption: %i, running zone %i / %i\n", ip.c_str(), port, int(useEncryption), zoneID, instanceID); - } - else { mLogger->Log("dServer", "FAILED TO START SERVER ON IP/PORT: %s:%i\n", ip.c_str(), port); return; } + mLogger->Log("dServer", "Server is listening on %s:%i with encryption: %i, running zone %i / %i", ip.c_str(), port, int(useEncryption), zoneID, instanceID); + } else { mLogger->Log("dServer", "FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; } mLogger->SetLogToConsole(prevLogSetting); @@ -104,31 +107,34 @@ Packet* dServer::ReceiveFromMaster() { if (packet->length < 1) { mMasterPeer->DeallocatePacket(packet); return nullptr; } if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { - mLogger->Log("dServer", "Lost our connection to master, shutting DOWN!\n"); + mLogger->Log("dServer", "Lost our connection to master, shutting DOWN!"); mMasterConnectionActive = false; //ConnectToMaster(); //We'll just shut down now } - + if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) { - mLogger->Log("dServer", "Established connection to master, zone (%i), instance (%i)\n",this->GetZoneID(), this->GetInstanceID()); + mLogger->Log("dServer", "Established connection to master, zone (%i), instance (%i)", this->GetZoneID(), this->GetInstanceID()); mMasterConnectionActive = true; mMasterSystemAddress = packet->systemAddress; MasterPackets::SendServerInfo(this, packet); } if (packet->data[0] == ID_USER_PACKET_ENUM) { - if (packet->data[1] == MASTER) { - switch (packet->data[3]) { - case MSG_MASTER_REQUEST_ZONE_TRANSFER_RESPONSE: { - uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); - ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); - break; - } + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) { + switch (static_cast<eMasterMessageType>(packet->data[3])) { + case eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE: { + uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); + ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); + break; + } + case eMasterMessageType::SHUTDOWN: + *mShouldShutdown = true; + break; - //When we handle these packets in World instead dServer, we just return the packet's pointer. - default: + //When we handle these packets in World instead dServer, we just return the packet's pointer. + default: - return packet; + return packet; } } } @@ -143,15 +149,15 @@ Packet* dServer::Receive() { return mPeer->Receive(); } -void dServer::DeallocatePacket(Packet * packet) { +void dServer::DeallocatePacket(Packet* packet) { mPeer->DeallocatePacket(packet); } -void dServer::DeallocateMasterPacket(Packet * packet) { +void dServer::DeallocateMasterPacket(Packet* packet) { mMasterPeer->DeallocatePacket(packet); } -void dServer::Send(RakNet::BitStream * bitStream, const SystemAddress & sysAddr, bool broadcast) { +void dServer::Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast) { mPeer->Send(bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, broadcast); } @@ -160,9 +166,9 @@ void dServer::SendToMaster(RakNet::BitStream* bitStream) { mMasterPeer->Send(bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); } -void dServer::Disconnect(const SystemAddress& sysAddr, uint32_t disconNotifyID) { +void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { RakNet::BitStream bitStream; - PacketUtils::WriteHeader(bitStream, SERVER, MSG_SERVER_DISCONNECT_NOTIFY); + PacketUtils::WriteHeader(bitStream, eConnectionType::SERVER, eServerMessageType::DISCONNECT_NOTIFY); bitStream.Write(disconNotifyID); mPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, false); @@ -182,9 +188,9 @@ bool dServer::Startup() { if (mIsInternal) { mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15); - } - else { - //mPeer->SetPerConnectionOutgoingBandwidthLimit(800000); //100Kb/s + } else { + UpdateBandwidthLimit(); + UpdateMaximumMtuSize(); mPeer->SetIncomingPassword("3.25 ND1", 8); } @@ -194,8 +200,21 @@ bool dServer::Startup() { return true; } +void dServer::UpdateMaximumMtuSize() { + auto maxMtuSize = mConfig->GetValue("maximum_mtu_size"); + mPeer->SetMTUSize(maxMtuSize.empty() ? 1228 : std::stoi(maxMtuSize)); +} + +void dServer::UpdateBandwidthLimit() { + auto newBandwidth = mConfig->GetValue("maximum_outgoing_bandwidth"); + mPeer->SetPerConnectionOutgoingBandwidthLimit(!newBandwidth.empty() ? std::stoi(newBandwidth) : 0); +} + void dServer::Shutdown() { - mPeer->Shutdown(1000); + if (mPeer) { + mPeer->Shutdown(1000); + RakNetworkFactory::DestroyRakPeerInterface(mPeer); + } if (mNetIDManager) { delete mNetIDManager; @@ -207,10 +226,9 @@ void dServer::Shutdown() { mReplicaManager = nullptr; } - //RakNetworkFactory::DestroyRakPeerInterface(mPeer); //Not needed, we already called Shutdown ourselves. - if (mServerType != ServerType::Master) { + if (mServerType != ServerType::Master && mMasterPeer) { mMasterPeer->Shutdown(1000); - //RakNetworkFactory::DestroyRakPeerInterface(mMasterPeer); + RakNetworkFactory::DestroyRakPeerInterface(mMasterPeer); } } @@ -228,12 +246,10 @@ void dServer::UpdateReplica() { mReplicaManager->Update(mPeer); } -int dServer::GetPing(const SystemAddress& sysAddr) const -{ +int dServer::GetPing(const SystemAddress& sysAddr) const { return mPeer->GetAveragePing(sysAddr); } -int dServer::GetLatestPing(const SystemAddress& sysAddr) const -{ +int dServer::GetLatestPing(const SystemAddress& sysAddr) const { return mPeer->GetLastPing(sysAddr); } diff --git a/dNet/dServer.h b/dNet/dServer.h index 3ac6700a..797647b6 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -5,6 +5,8 @@ #include "NetworkIDManager.h" class dLogger; +class dConfig; +enum class eServerDisconnectIdentifiers : uint32_t; enum class ServerType : uint32_t { Master, @@ -15,17 +17,32 @@ enum class ServerType : uint32_t { class dServer { public: - dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, unsigned int zoneID = 0); + // Default constructor should only used for testing! + dServer() {}; + dServer( + const std::string& ip, + int port, + int instanceID, + int maxConnections, + bool isInternal, + bool useEncryption, + dLogger* logger, + const std::string masterIP, + int masterPort, + ServerType serverType, + dConfig* config, + bool* shouldShutdown, + unsigned int zoneID = 0); ~dServer(); Packet* ReceiveFromMaster(); Packet* Receive(); void DeallocatePacket(Packet* packet); void DeallocateMasterPacket(Packet* packet); - void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast); + virtual void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast); void SendToMaster(RakNet::BitStream* bitStream); - void Disconnect(const SystemAddress& sysAddr, uint32_t disconNotifyID); + void Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID); bool IsConnected(const SystemAddress& sysAddr); const std::string& GetIP() const { return mIP; } @@ -40,6 +57,8 @@ public: const int GetInstanceID() const { return mInstanceID; } ReplicaManager* GetReplicaManager() { return mReplicaManager; } void UpdateReplica(); + void UpdateBandwidthLimit(); + void UpdateMaximumMtuSize(); int GetPing(const SystemAddress& sysAddr) const; int GetLatestPing(const SystemAddress& sysAddr) const; @@ -55,13 +74,19 @@ private: bool ConnectToMaster(); private: - dLogger* mLogger; - RakPeerInterface* mPeer; - ReplicaManager* mReplicaManager; - NetworkIDManager* mNetIDManager; + dLogger* mLogger = nullptr; + dConfig* mConfig = nullptr; + RakPeerInterface* mPeer = nullptr; + ReplicaManager* mReplicaManager = nullptr; + NetworkIDManager* mNetIDManager = nullptr; + + /** + * Whether or not to shut down the server. Pointer to Game::shouldShutdown. + */ + bool* mShouldShutdown = nullptr; SocketDescriptor mSocketDescriptor; std::string mIP; - int mPort; + int mPort; int mMaxConnections; unsigned int mZoneID; int mInstanceID; @@ -71,9 +96,9 @@ private: bool mMasterConnectionActive; ServerType mServerType; - RakPeerInterface* mMasterPeer; + RakPeerInterface* mMasterPeer = nullptr; SocketDescriptor mMasterSocketDescriptor; SystemAddress mMasterSystemAddress; std::string mMasterIP; int mMasterPort; -}; \ No newline at end of file +}; diff --git a/dPhysics/CMakeLists.txt b/dPhysics/CMakeLists.txt new file mode 100644 index 00000000..5fe6adaa --- /dev/null +++ b/dPhysics/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DPHYSICS_SOURCES "dpCollisionChecks.cpp" + "dpEntity.cpp" + "dpGrid.cpp" + "dpShapeBase.cpp" + "dpShapeBox.cpp" + "dpShapeSphere.cpp" + "dpWorld.cpp") + +add_library(dPhysics STATIC ${DPHYSICS_SOURCES}) +target_link_libraries(dPhysics Recast Detour) diff --git a/dPhysics/dpCollisionChecks.cpp b/dPhysics/dpCollisionChecks.cpp index 5e18f894..c2efee90 100644 --- a/dPhysics/dpCollisionChecks.cpp +++ b/dPhysics/dpCollisionChecks.cpp @@ -54,7 +54,7 @@ bool dpCollisionChecks::CheckBoxes(dpEntity* a, dpEntity* b) { /*//Check if we're overlapping on X/Z: if ((boxA->GetMaxWidth() >= boxB->GetMinWidth()) && //If our max width is greater than starting X of b (boxA->GetMinWidth() <= boxB->GetMaxWidth()) && //If our start x is less than b's max width - (boxA->GetMaxDepth() >= boxB->GetMinDepth()) && + (boxA->GetMaxDepth() >= boxB->GetMinDepth()) && (boxA->GetMinDepth() <= boxB->GetMaxDepth())) { //Check if we're in the right height @@ -93,8 +93,7 @@ bool dpCollisionChecks::CheckSphereBox(dpEntity* a, dpEntity* b) { sphere = static_cast<dpShapeSphere*>(b->GetShape()); boxPos = a->GetPosition(); spherePos = b->GetPosition(); - } - else { + } else { box = static_cast<dpShapeBox*>(b->GetShape()); sphere = static_cast<dpShapeSphere*>(a->GetShape()); boxPos = b->GetPosition(); @@ -110,8 +109,8 @@ bool dpCollisionChecks::CheckSphereBox(dpEntity* a, dpEntity* b) { float dX = x - spherePos.x; float dY = y - spherePos.y; float dZ = z - spherePos.z; - float distanceSquared = (dX * dX) + (dY * dY) + (dZ * dZ); + float distanceSquared = (dX * dX) + (dY * dY) + (dZ * dZ); const float radius = sphere->GetRadius(); - return distanceSquared < radius * radius; + return distanceSquared < radius* radius; } diff --git a/dPhysics/dpCollisionChecks.h b/dPhysics/dpCollisionChecks.h index ed51bbe4..069832f9 100644 --- a/dPhysics/dpCollisionChecks.h +++ b/dPhysics/dpCollisionChecks.h @@ -9,4 +9,4 @@ namespace dpCollisionChecks { bool CheckBoxes(dpEntity* a, dpEntity* b); bool CheckSphereBox(dpEntity* a, dpEntity* b); -}; \ No newline at end of file +}; diff --git a/dPhysics/dpCollisionGroups.h b/dPhysics/dpCollisionGroups.h deleted file mode 100644 index 5853070f..00000000 --- a/dPhysics/dpCollisionGroups.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include <cstdint> - -/* - * Collision Groups - */ - -enum eCollisionGroup : uint8_t -{ - COLLISION_GROUP_ALL = 0 << 0, - COLLISION_GROUP_NEUTRAL = 1 << 0, - COLLISION_GROUP_FRIENDLY = 1 << 1, - COLLISION_GROUP_ENEMY = 1 << 2, - COLLISION_GROUP_DYNAMIC = 1 << 3, -}; diff --git a/dPhysics/dpEntity.cpp b/dPhysics/dpEntity.cpp index 78920807..c7ed56f8 100644 --- a/dPhysics/dpEntity.cpp +++ b/dPhysics/dpEntity.cpp @@ -34,7 +34,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, NiPoint3 boxDimensions, bool isStat m_CollisionGroup = COLLISION_GROUP_ALL; m_CollisionShape = new dpShapeBox(this, boxDimensions.x, boxDimensions.y, boxDimensions.z); - if (boxDimensions.x > 100.0f) m_IsGargantuan = true; } dpEntity::dpEntity(const LWOOBJID& objectID, float width, float height, float depth, bool isStatic) { @@ -45,7 +44,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, float width, float height, float de m_CollisionGroup = COLLISION_GROUP_ALL; m_CollisionShape = new dpShapeBox(this, width, height, depth); - if (width > 100.0f) m_IsGargantuan = true; } dpEntity::dpEntity(const LWOOBJID& objectID, float radius, bool isStatic) { @@ -56,7 +54,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, float radius, bool isStatic) { m_CollisionGroup = COLLISION_GROUP_ALL; m_CollisionShape = new dpShapeSphere(this, radius); - if (radius > 200.0f) m_IsGargantuan = true; } dpEntity::~dpEntity() { @@ -89,8 +86,7 @@ void dpEntity::CheckCollision(dpEntity* other) { //if (m_CollisionShape->GetShapeType() == dpShapeType::Sphere && other->GetShape()->GetShapeType() == dpShapeType::Sphere) //std::cout << "started sphere col at: " << other->GetPosition().x << ", " << other->GetPosition().y << ", " << other->GetPosition().z << std::endl; - } - else if (!isColliding && wasFound) { + } else if (!isColliding && wasFound) { m_CurrentlyCollidingObjects.erase(other->GetObjectID()); m_RemovedObjects.push_back(other); @@ -147,5 +143,12 @@ void dpEntity::SetAngularVelocity(const NiPoint3& newAngularVelocity) { void dpEntity::SetGrid(dpGrid* grid) { m_Grid = grid; + + if (m_CollisionShape->GetShapeType() == dpShapeType::Sphere && static_cast<dpShapeSphere*>(m_CollisionShape)->GetRadius() * 2.0f > static_cast<float>(m_Grid->CELL_SIZE)) { + m_IsGargantuan = true; + } else if (m_CollisionShape->GetShapeType() == dpShapeType::Box && static_cast<dpShapeBox*>(m_CollisionShape)->GetWidth() > static_cast<float>(m_Grid->CELL_SIZE)) { + m_IsGargantuan = true; + } + m_Grid->Add(this); } diff --git a/dPhysics/dpEntity.h b/dPhysics/dpEntity.h index cc363f8b..ea7a49b2 100644 --- a/dPhysics/dpEntity.h +++ b/dPhysics/dpEntity.h @@ -83,4 +83,4 @@ private: std::vector<dpEntity*> m_NewObjects; std::vector<dpEntity*> m_RemovedObjects; std::map<LWOOBJID, dpEntity*> m_CurrentlyCollidingObjects; -}; \ No newline at end of file +}; diff --git a/dPhysics/dpGrid.cpp b/dPhysics/dpGrid.cpp index 6e44ade9..1631c91a 100644 --- a/dPhysics/dpGrid.cpp +++ b/dPhysics/dpGrid.cpp @@ -6,6 +6,7 @@ dpGrid::dpGrid(int numCells, int cellSize) { NUM_CELLS = numCells; CELL_SIZE = cellSize; + m_DeleteGrid = true; //dumb method but i can't be bothered @@ -23,6 +24,7 @@ dpGrid::dpGrid(int numCells, int cellSize) { } dpGrid::~dpGrid() { + if (!this->m_DeleteGrid) return; for (auto& x : m_Cells) { //x for (auto& y : x) { //y for (auto en : y) { @@ -61,13 +63,13 @@ void dpGrid::Move(dpEntity* entity, float x, float z) { if (cellX < 0) cellX = 0; if (cellZ < 0) cellZ = 0; - if (cellX > NUM_CELLS) cellX = NUM_CELLS; - if (cellZ > NUM_CELLS) cellZ = NUM_CELLS; + if (cellX >= NUM_CELLS) cellX = NUM_CELLS - 1; + if (cellZ >= NUM_CELLS) cellZ = NUM_CELLS - 1; if (oldCellX < 0) oldCellX = 0; if (oldCellZ < 0) oldCellZ = 0; - if (oldCellX > NUM_CELLS) oldCellX = NUM_CELLS; - if (oldCellZ > NUM_CELLS) oldCellZ = NUM_CELLS; + if (oldCellX >= NUM_CELLS) oldCellX = NUM_CELLS - 1; + if (oldCellZ >= NUM_CELLS) oldCellZ = NUM_CELLS - 1; if (oldCellX == cellX && oldCellZ == cellZ) return; diff --git a/dPhysics/dpGrid.h b/dPhysics/dpGrid.h index 532ee02f..229e7449 100644 --- a/dPhysics/dpGrid.h +++ b/dPhysics/dpGrid.h @@ -9,26 +9,36 @@ class dpEntity; class dpGrid { public: - //LU has a chunk size of 64x64, with each chunk unit being 3.2 ingame units. - int NUM_CELLS = 12; //Most worlds consist of 10 or 11 chunks, so I'm picking 12 to be safe. - int CELL_SIZE = 205; //64 * 3.2 = 204.8 rounded up + //LU has a chunk size of 64x64, with each chunk unit being 3.2 ingame units. + int NUM_CELLS = 12; //Most worlds consist of 10 or 11 chunks, so I'm picking 12 to be safe. + int CELL_SIZE = 205; //64 * 3.2 = 204.8 rounded up public: - dpGrid(int numCells, int cellSize); - ~dpGrid(); + dpGrid(int numCells, int cellSize); + ~dpGrid(); - void Add(dpEntity* entity); - void Move(dpEntity* entity, float x, float z); - void Delete(dpEntity* entity); + void Add(dpEntity* entity); + void Move(dpEntity* entity, float x, float z); + void Delete(dpEntity* entity); - void Update(float deltaTime); + void Update(float deltaTime); + + /** + * Sets the delete grid parameter to value. When false, the grid will not clean up memory. + * + * @param value Whether or not to delete entities on deletion of the grid. + */ + void SetDeleteGrid(bool value) { this->m_DeleteGrid = value; }; + + std::vector<std::vector<std::forward_list<dpEntity*>>> GetCells() { return this->m_Cells; }; private: - void HandleEntity(dpEntity* entity, dpEntity* other); - void HandleCell(int x, int z, float deltaTime); + void HandleEntity(dpEntity* entity, dpEntity* other); + void HandleCell(int x, int z, float deltaTime); private: - //cells on X, cells on Y for that X, then another vector that contains the entities within that cell. - std::vector<std::vector<std::forward_list<dpEntity*>>> m_Cells; - std::map<LWOOBJID, dpEntity*> m_GargantuanObjects; + //cells on X, cells on Y for that X, then another vector that contains the entities within that cell. + std::vector<std::vector<std::forward_list<dpEntity*>>> m_Cells; + std::map<LWOOBJID, dpEntity*> m_GargantuanObjects; + bool m_DeleteGrid = true; }; diff --git a/dPhysics/dpShapeBase.cpp b/dPhysics/dpShapeBase.cpp index c6562e71..54575159 100644 --- a/dPhysics/dpShapeBase.cpp +++ b/dPhysics/dpShapeBase.cpp @@ -3,8 +3,7 @@ #include <iostream> dpShapeBase::dpShapeBase(dpEntity* parentEntity) : - m_ParentEntity(parentEntity) -{ + m_ParentEntity(parentEntity) { } dpShapeBase::~dpShapeBase() { @@ -14,4 +13,4 @@ bool dpShapeBase::IsColliding(dpShapeBase* other) { std::cout << "Base shapes do not have any *shape* to them, and thus cannot be overlapping." << std::endl; std::cout << "You should be using a shape class inherited from this base class." << std::endl; return false; -} \ No newline at end of file +} diff --git a/dPhysics/dpShapeBase.h b/dPhysics/dpShapeBase.h index 3bf52f50..60d908c9 100644 --- a/dPhysics/dpShapeBase.h +++ b/dPhysics/dpShapeBase.h @@ -17,4 +17,4 @@ public: protected: dpEntity* m_ParentEntity; dpShapeType m_ShapeType = dpShapeType::Invalid; -}; \ No newline at end of file +}; diff --git a/dPhysics/dpShapeBox.cpp b/dPhysics/dpShapeBox.cpp index 766ffb35..b40be6af 100644 --- a/dPhysics/dpShapeBox.cpp +++ b/dPhysics/dpShapeBox.cpp @@ -11,11 +11,10 @@ dpShapeBox::dpShapeBox(dpEntity* parentEntity, float width, float height, float depth) : dpShapeBase(parentEntity), - m_Width(width/2), - m_Height(height/2), - m_Depth(depth/2), - m_Scale(1.0f) -{ + m_Width(width / 2), + m_Height(height / 2), + m_Depth(depth / 2), + m_Scale(1.0f) { m_ShapeType = dpShapeType::Box; InitVertices(); diff --git a/dPhysics/dpShapeBox.h b/dPhysics/dpShapeBox.h index ec80012b..4af0396e 100644 --- a/dPhysics/dpShapeBox.h +++ b/dPhysics/dpShapeBox.h @@ -69,4 +69,4 @@ private: bool isTransformed = false; void InsertVertices(); -}; \ No newline at end of file +}; diff --git a/dPhysics/dpShapeSphere.cpp b/dPhysics/dpShapeSphere.cpp index bc1ceef5..168a3b21 100644 --- a/dPhysics/dpShapeSphere.cpp +++ b/dPhysics/dpShapeSphere.cpp @@ -4,8 +4,7 @@ dpShapeSphere::dpShapeSphere(dpEntity* parentEntity, float radius) : dpShapeBase(parentEntity), - m_Radius(radius) -{ + m_Radius(radius) { m_ShapeType = dpShapeType::Sphere; } diff --git a/dPhysics/dpShapeSphere.h b/dPhysics/dpShapeSphere.h index 3b23673a..a5d8142b 100644 --- a/dPhysics/dpShapeSphere.h +++ b/dPhysics/dpShapeSphere.h @@ -14,4 +14,4 @@ public: private: float m_Radius; -}; \ No newline at end of file +}; diff --git a/dPhysics/dpWorld.cpp b/dPhysics/dpWorld.cpp index bb918b23..70fbfa3a 100644 --- a/dPhysics/dpWorld.cpp +++ b/dPhysics/dpWorld.cpp @@ -9,11 +9,11 @@ #include "dLogger.h" #include "dConfig.h" -void dpWorld::Initialize(unsigned int zoneID) { +void dpWorld::Initialize(unsigned int zoneID, bool generateNewNavMesh) { phys_sp_tilecount = std::atoi(Game::config->GetValue("phys_sp_tilecount").c_str()); phys_sp_tilesize = std::atoi(Game::config->GetValue("phys_sp_tilesize").c_str()); - //If spatial partitioning is enabled, then we need to create the m_Grid. + //If spatial partitioning is enabled, then we need to create the m_Grid. //if m_Grid exists, then the old method will be used. //SP will NOT be used unless it is added to ShouldUseSP(); if (std::atoi(Game::config->GetValue("phys_spatial_partitioning").c_str()) == 1 @@ -21,27 +21,51 @@ void dpWorld::Initialize(unsigned int zoneID) { m_Grid = new dpGrid(phys_sp_tilecount, phys_sp_tilesize); } - Game::logger->Log("dpWorld", "Physics world initialized!\n"); + if (generateNewNavMesh) m_NavMesh = new dNavMesh(zoneID); - if (ShouldLoadNavmesh(zoneID)) { - if (LoadNavmeshByZoneID(zoneID)) Game::logger->Log("dpWorld", "Loaded navmesh!\n"); - else Game::logger->Log("dpWorld", "Error(s) occurred during navmesh load.\n"); + Game::logger->Log("dpWorld", "Physics world initialized!"); + m_ZoneID = zoneID; +} + +void dpWorld::Reload() { + if (m_Grid) { + m_Grid->SetDeleteGrid(false); + auto oldGridCells = m_Grid->GetCells(); + delete m_Grid; + m_Grid = nullptr; + + Initialize(m_ZoneID, false); + for (auto column : oldGridCells) { + for (auto row : column) { + for (auto entity : row) { + AddEntity(entity); + } + } + } + Game::logger->Log("dpWorld", "Successfully reloaded physics world!"); + } else { + Game::logger->Log("dpWorld", "No physics world to reload!"); } } dpWorld::~dpWorld() { if (m_Grid) { + // Triple check this is true + m_Grid->SetDeleteGrid(true); delete m_Grid; m_Grid = nullptr; } - RecastCleanup(); + if (m_NavMesh) { + delete m_NavMesh; + m_NavMesh = nullptr; + } } void dpWorld::StepWorld(float deltaTime) { - if (m_Grid) { - m_Grid->Update(deltaTime); - return; + if (m_Grid) { + m_Grid->Update(deltaTime); + return; } //Pre update: @@ -53,7 +77,7 @@ void dpWorld::StepWorld(float deltaTime) { //Do actual update: for (auto entity : m_DynamicEntites) { if (!entity || entity->GetSleeping()) continue; - + entity->Update(deltaTime); for (auto other : m_StaticEntities) { @@ -77,8 +101,7 @@ void dpWorld::RemoveEntity(dpEntity* entity) { if (m_Grid) { m_Grid->Delete(entity); - } - else { + } else { if (entity->GetIsStatic()) { for (size_t i = 0; i < m_StaticEntities.size(); ++i) { if (m_StaticEntities[i] == entity) { @@ -87,8 +110,7 @@ void dpWorld::RemoveEntity(dpEntity* entity) { break; } } - } - else { + } else { for (size_t i = 0; i < m_DynamicEntites.size(); ++i) { if (m_DynamicEntites[i] == entity) { delete m_DynamicEntites[i]; @@ -100,258 +122,20 @@ void dpWorld::RemoveEntity(dpEntity* entity) { } } -void dpWorld::RecastCleanup() { - if (m_triareas) delete[] m_triareas; - m_triareas = 0; - - rcFreeHeightField(m_solid); - m_solid = 0; - rcFreeCompactHeightfield(m_chf); - m_chf = 0; - rcFreeContourSet(m_cset); - m_cset = 0; - rcFreePolyMesh(m_pmesh); - m_pmesh = 0; - rcFreePolyMeshDetail(m_dmesh); - m_dmesh = 0; - dtFreeNavMesh(m_navMesh); - m_navMesh = 0; - - dtFreeNavMeshQuery(m_navQuery); - m_navQuery = 0; - - if (m_ctx) delete m_ctx; -} - -bool dpWorld::LoadNavmeshByZoneID(unsigned int zoneID) { - std::string path = "./res/maps/navmeshes/" + std::to_string(zoneID) + ".bin"; - m_navMesh = LoadNavmesh(path.c_str()); - - if (m_navMesh) { m_navQuery = dtAllocNavMeshQuery(); m_navQuery->init(m_navMesh, 2048); } - else return false; - - return true; -} - -dtNavMesh* dpWorld::LoadNavmesh(const char* path) { - FILE* fp; - - #ifdef _WIN32 - fopen_s(&fp, path, "rb"); - #elif __APPLE__ - // macOS has 64bit file IO by default - fp = fopen(path, "rb"); - #else - fp = fopen64(path, "rb"); - #endif - - if (!fp) { - return 0; - } - - // Read header. - NavMeshSetHeader header; - size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp); - if (readLen != 1) { - fclose(fp); - return 0; - } - - if (header.magic != NAVMESHSET_MAGIC) { - fclose(fp); - return 0; - } - - if (header.version != NAVMESHSET_VERSION) { - fclose(fp); - return 0; - } - - dtNavMesh* mesh = dtAllocNavMesh(); - if (!mesh) { - fclose(fp); - return 0; - } - - dtStatus status = mesh->init(&header.params); - if (dtStatusFailed(status)) { - fclose(fp); - return 0; - } - - // Read tiles. - for (int i = 0; i < header.numTiles; ++i) { - NavMeshTileHeader tileHeader; - readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp); - if (readLen != 1) - return 0; - - if (!tileHeader.tileRef || !tileHeader.dataSize) - break; - - unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); - if (!data) break; - memset(data, 0, tileHeader.dataSize); - readLen = fread(data, tileHeader.dataSize, 1, fp); - if (readLen != 1) - return 0; - - mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0); - } - - fclose(fp); - - return mesh; -} - -bool dpWorld::ShouldLoadNavmesh(unsigned int zoneID) { - return true; //We use default paths now. Might re-tool this function later. - - //TODO: Add to this list as the navmesh folder grows. - switch (zoneID) { - case 1100: - case 1150: - case 1151: - case 1200: - case 1201: - case 1300: - case 1400: - case 1603: - return true; - } - - return false; -} - bool dpWorld::ShouldUseSP(unsigned int zoneID) { - //TODO: Add to this list as needed. Only large maps should be added as tiling likely makes little difference on small maps. + // TODO: Add to this list as needed. + // Only large maps should be added as tiling likely makes little difference on small maps. + switch (zoneID) { - case 1100: //Avant Gardens - case 1200: //Nimbus Station - case 1300: //Gnarled Forest - case 1400: //Forbidden Valley - case 1800: //Crux Prime - case 1900: //Nexus Tower - case 2000: //Ninjago + case 1100: // Avant Gardens + case 1200: // Nimbus Station + case 1300: // Gnarled Forest + case 1400: // Forbidden Valley + case 1800: // Crux Prime + case 1900: // Nexus Tower + case 2000: // Ninjago return true; } return false; } - -float dpWorld::GetHeightAtPoint(const NiPoint3& location) { - if (m_navMesh == nullptr) { - return location.y; - } - - float toReturn = 0.0f; - float pos[3]; - pos[0] = location.x; - pos[1] = location.y; - pos[2] = location.z; - - dtPolyRef nearestRef = 0; - float polyPickExt[3] = { 32.0f, 32.0f, 32.0f }; - dtQueryFilter filter{}; - - m_navQuery->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, 0); - m_navQuery->getPolyHeight(nearestRef, pos, &toReturn); - - if (toReturn == 0.0f) { - toReturn = location.y; - } - - return toReturn; -} - -std::vector<NiPoint3> dpWorld::GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed) { - std::vector<NiPoint3> path; - - //allows for non-navmesh maps (like new custom maps) to have "basic" enemies. - if (m_navMesh == nullptr) { - //how many points to generate between start/end? - //note: not actually 100% accurate due to rounding, but worst case it causes them to go a tiny bit faster - //than their speed value would normally allow at the end. - int numPoints = startPos.Distance(startPos, endPos) / speed; - - path.push_back(startPos); //insert the start pos - - //Linearly interpolate between these two points: - for (int i = 0; i < numPoints; i++) { - NiPoint3 newPoint{ startPos }; - - newPoint.x += speed; - newPoint.y = newPoint.y + (((endPos.y - startPos.y) / (endPos.x - startPos.x)) * (newPoint.x - startPos.x)); - - path.push_back(newPoint); - } - - path.push_back(endPos); //finally insert our end pos - - return path; - } - - float sPos[3]; - float ePos[3]; - sPos[0] = startPos.x; - sPos[1] = startPos.y; - sPos[2] = startPos.z; - - ePos[0] = endPos.x; - ePos[1] = endPos.y; - ePos[2] = endPos.z; - - dtStatus pathFindStatus; - dtPolyRef startRef; - dtPolyRef endRef; - float polyPickExt[3] = { 32.0f, 32.0f, 32.0f }; - dtQueryFilter filter{}; - - //Find our start poly - m_navQuery->findNearestPoly(sPos, polyPickExt, &filter, &startRef, 0); - - //Find our end poly - m_navQuery->findNearestPoly(ePos, polyPickExt, &filter, &endRef, 0); - - pathFindStatus = DT_FAILURE; - int m_nstraightPath = 0; - int m_npolys = 0; - dtPolyRef m_polys[MAX_POLYS]; - float m_straightPath[MAX_POLYS * 3]; - unsigned char m_straightPathFlags[MAX_POLYS]; - dtPolyRef m_straightPathPolys[MAX_POLYS]; - int m_straightPathOptions = 0; - - if (startRef && endRef) { - m_navQuery->findPath(startRef, endRef, sPos, ePos, &filter, m_polys, &m_npolys, MAX_POLYS); - - if (m_npolys) { - // In case of partial path, make sure the end point is clamped to the last polygon. - float epos[3]; - dtVcopy(epos, ePos); - if (m_polys[m_npolys - 1] != endRef) - m_navQuery->closestPointOnPoly(m_polys[m_npolys - 1], ePos, epos, 0); - - m_navQuery->findStraightPath(sPos, epos, m_polys, m_npolys, - m_straightPath, m_straightPathFlags, - m_straightPathPolys, &m_nstraightPath, MAX_POLYS, m_straightPathOptions); - - // At this point we have our path. Copy it to the path store - int nIndex = 0; - for (int nVert = 0; nVert < m_nstraightPath; nVert++) { - /*m_PathStore[nPathSlot].PosX[nVert] = StraightPath[nIndex++]; - m_PathStore[nPathSlot].PosY[nVert] = StraightPath[nIndex++]; - m_PathStore[nPathSlot].PosZ[nVert] = StraightPath[nIndex++];*/ - - NiPoint3 newPoint{ m_straightPath[nIndex++], m_straightPath[nIndex++], m_straightPath[nIndex++] }; - path.push_back(newPoint); - } - } - } - else { - m_npolys = 0; - m_nstraightPath = 0; - } - - return path; -} diff --git a/dPhysics/dpWorld.h b/dPhysics/dpWorld.h index 5897a7cd..d48435d0 100644 --- a/dPhysics/dpWorld.h +++ b/dPhysics/dpWorld.h @@ -1,6 +1,6 @@ #pragma once + #include "Singleton.h" -#include <vector> //Navmesh includes: #include "Recast.h" @@ -11,23 +11,7 @@ #include <vector> #include <map> -static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET'; -static const int NAVMESHSET_VERSION = 1; - -struct NavMeshSetHeader { - int magic; - int version; - int numTiles; - dtNavMeshParams params; -}; - -struct NavMeshTileHeader { - dtTileRef tileRef; - int dataSize; -}; - -static const int MAX_POLYS = 256; -static const int MAX_SMOOTH = 2048; +#include "dNavMesh.h" class NiPoint3; class dpEntity; @@ -35,25 +19,21 @@ class dpGrid; class dpWorld : public Singleton<dpWorld> { public: - void Initialize(unsigned int zoneID); + void Initialize(unsigned int zoneID, bool generateNewNavMesh = true); + void Reload(); ~dpWorld(); - void RecastCleanup(); - bool LoadNavmeshByZoneID(unsigned int zoneID); - dtNavMesh* LoadNavmesh(const char* path); - bool ShouldLoadNavmesh(unsigned int zoneID); bool ShouldUseSP(unsigned int zoneID); - - float GetHeightAtPoint(const NiPoint3& location); - std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f); - bool IsLoaded() const { return m_navMesh != nullptr; } + bool IsLoaded() const { return m_NavMesh->GetdtNavMesh() != nullptr; } void StepWorld(float deltaTime); void AddEntity(dpEntity* entity); void RemoveEntity(dpEntity* entity); + dNavMesh* GetNavMesh() { return m_NavMesh; } + private: dpGrid* m_Grid; bool phys_spatial_partitioning = 1; @@ -63,18 +43,6 @@ private: std::vector<dpEntity*> m_StaticEntities; std::vector<dpEntity*> m_DynamicEntites; - //Navmesh stuffs: - unsigned char* m_triareas; - rcHeightfield* m_solid; - rcCompactHeightfield* m_chf; - rcContourSet* m_cset; - rcPolyMesh* m_pmesh; - rcConfig m_cfg; - rcPolyMeshDetail* m_dmesh; - - class InputGeom* m_geom; - class dtNavMesh* m_navMesh; - class dtNavMeshQuery* m_navQuery; - unsigned char m_navMeshDrawFlags; - rcContext* m_ctx; -}; \ No newline at end of file + dNavMesh* m_NavMesh = nullptr; + uint32_t m_ZoneID = 0; +}; diff --git a/dPhysics/main.cpp b/dPhysics/main.cpp index a4c303a3..7de1555a 100644 --- a/dPhysics/main.cpp +++ b/dPhysics/main.cpp @@ -32,4 +32,4 @@ int main() { } return 0; -}*/ \ No newline at end of file +}*/ diff --git a/dScripts/02_server/CMakeLists.txt b/dScripts/02_server/CMakeLists.txt new file mode 100644 index 00000000..1e38386f --- /dev/null +++ b/dScripts/02_server/CMakeLists.txt @@ -0,0 +1,45 @@ +set(DSCRIPTS_SOURCES_02_SERVER) + +add_subdirectory(DLU) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_DLU}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "DLU/${file}") +endforeach() + +add_subdirectory(Enemy) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Enemy/${file}") +endforeach() + +add_subdirectory(Equipment) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_EQUIPMENT}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Equipment/${file}") +endforeach() + +add_subdirectory(Map) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Map/${file}") +endforeach() + +add_subdirectory(Minigame) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MINIGAME}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Minigame/${file}") +endforeach() + +add_subdirectory(Objects) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_OBJECTS}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Objects/${file}") +endforeach() + +add_subdirectory(Pets) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_PETS}) + set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Pets/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} PARENT_SCOPE) diff --git a/dScripts/02_server/DLU/CMakeLists.txt b/dScripts/02_server/DLU/CMakeLists.txt new file mode 100644 index 00000000..64d4cbbd --- /dev/null +++ b/dScripts/02_server/DLU/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_DLU + "DLUVanityNPC.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/DLU/DLUVanityNPC.cpp b/dScripts/02_server/DLU/DLUVanityNPC.cpp new file mode 100644 index 00000000..e3db2353 --- /dev/null +++ b/dScripts/02_server/DLU/DLUVanityNPC.cpp @@ -0,0 +1,46 @@ +#include "DLUVanityNPC.h" +#include "GameMessages.h" +#include "dServer.h" +#include "VanityUtilities.h" + +void DLUVanityNPC::OnStartup(Entity* self) { + m_NPC = VanityUtilities::GetNPC("averysumner - Destroyer of Worlds"); + + if (m_NPC == nullptr) { + return; + } + + if (self->GetVar<bool>(u"teleport")) { + self->AddTimer("setupTeleport", 15.0f); + } +} + +void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "setupTeleport") { + GameMessages::SendPlayAnimation(self, u"interact"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); + + self->AddTimer("teleport", 2.0f); + self->AddTimer("stopFX", 2.0f); + } else if (timerName == "stopFX") { + GameMessages::SendStopFXEffect(self, true, "teleportBeam"); + GameMessages::SendStopFXEffect(self, true, "teleportRings"); + } else if (timerName == "teleport") { + std::vector<VanityNPCLocation>& locations = m_NPC->m_Locations[Game::server->GetZoneID()]; + + selectLocation: + VanityNPCLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)]; + + if (self->GetPosition() == newLocation.m_Position) { + goto selectLocation; // cry about it + } + + self->SetPosition(newLocation.m_Position); + self->SetRotation(newLocation.m_Rotation); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); + self->AddTimer("stopFX", 2.0f); + self->AddTimer("setupTeleport", 15.0f); + } +} diff --git a/dScripts/02_server/DLU/DLUVanityNPC.h b/dScripts/02_server/DLU/DLUVanityNPC.h new file mode 100644 index 00000000..aeb8e051 --- /dev/null +++ b/dScripts/02_server/DLU/DLUVanityNPC.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class VanityNPC; +class DLUVanityNPC : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + VanityNPC* m_NPC; +}; diff --git a/dScripts/BossSpiderQueenEnemyServer.cpp b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp similarity index 61% rename from dScripts/BossSpiderQueenEnemyServer.cpp rename to dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp index dd0b80c8..a3b9cc3f 100644 --- a/dScripts/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp @@ -1,4 +1,4 @@ -#include "BossSpiderQueenEnemyServer.h" +#include "BossSpiderQueenEnemyServer.h" #include "GeneralUtils.h" @@ -13,6 +13,7 @@ #include "GameMessages.h" #include "SkillComponent.h" +#include "eReplicaComponentType.h" #include <vector> @@ -22,14 +23,14 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { // Make immune to stuns //self:SetStunImmunity{ StateChangeType = "PUSH", bImmuneToStunAttack = true, bImmuneToStunMove = true, bImmuneToStunTurn = true, bImmuneToStunUseItem = true, bImmuneToStunEquip = true, bImmuneToStunInteract = true, bImmuneToStunJump = true } - + // Make immune to knockbacks and pulls //self:SetStatusImmunity{ StateChangeType = "PUSH", bImmuneToPullToPoint = true, bImmuneToKnockback = true, bImmuneToInterrupt = true } //Get our components: - destroyable = static_cast<DestroyableComponent*>(self->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - controllable = static_cast<ControllablePhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); - combat = static_cast<BaseCombatAIComponent*>(self->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + destroyable = static_cast<DestroyableComponent*>(self->GetComponent(eReplicaComponentType::DESTROYABLE)); + controllable = static_cast<ControllablePhysicsComponent*>(self->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + combat = static_cast<BaseCombatAIComponent*>(self->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); if (!destroyable || !controllable) return; @@ -47,8 +48,6 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { m_CurrentBossStage = 1; // Obtain faction and collision group to save for subsequent resets - //self : SetVar("SBFactionList", self:GetFaction().factionList) - //self : SetVar("SBCollisionGroup", self:GetCollisionGroup().colGroup) } void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { @@ -60,14 +59,12 @@ void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { missionComponent->CompleteMission(instanceMissionID); } - Game::logger->Log("BossSpiderQueenEnemyServer", "Starting timer...\n"); - // There is suppose to be a 0.1 second delay here but that may be admitted? auto* controller = EntityManager::Instance()->GetZoneControlEntity(); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 10, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); - self->SetPosition({10000, 0, 10000}); + self->SetPosition({ 10000, 0, 10000 }); EntityManager::Instance()->SerializeEntity(self); @@ -88,15 +85,15 @@ void BossSpiderQueenEnemyServer::WithdrawSpider(Entity* self, const bool withdra //First rotate for anim NiQuaternion rot = NiQuaternion::IDENTITY; - + controllable->SetStatic(false); controllable->SetRotation(rot); - + controllable->SetStatic(true); - + controllable->SetDirtyPosition(true); - + rot = controllable->GetRotation(); EntityManager::Instance()->SerializeEntity(self); @@ -119,22 +116,21 @@ void BossSpiderQueenEnemyServer::WithdrawSpider(Entity* self, const bool withdra self->AddTimer("WithdrawComplete", withdrawTime + 1.0f); waitForIdle = true; - } - else { + } else { controllable->SetStatic(false); - + //Cancel all remaining timers for say idle anims: self->CancelAllTimers(); - + auto* baseCombatAi = self->GetComponent<BaseCombatAIComponent>(); baseCombatAi->SetDisabled(false); // Move the Spider to its ground location - // preparing its stage attacks, and removing invulnerability + // preparing its stage attacks, and removing invulnerability //destroyable->SetIsImmune(false); - - // Run the advance animation and prepare a timer for resuming AI + + // Run the advance animation and prepare a timer for resuming AI float animTime = PlayAnimAndReturnTime(self, spiderAdvanceAnim); animTime += 1.f; @@ -142,19 +138,19 @@ void BossSpiderQueenEnemyServer::WithdrawSpider(Entity* self, const bool withdra destroyable->SetFaction(4); destroyable->SetIsImmune(false); - - //Advance stage + + //Advance stage m_CurrentBossStage++; - //Reset the current wave death counter + //Reset the current wave death counter m_DeathCounter = 0; - + EntityManager::Instance()->SerializeEntity(self); - // Prepare a timer for post leap attack + // Prepare a timer for post leap attack self->AddTimer("AdvanceAttack", attackPause); - // Prepare a timer for post leap + // Prepare a timer for post leap self->AddTimer("AdvanceComplete", animTime); } @@ -162,12 +158,9 @@ void BossSpiderQueenEnemyServer::WithdrawSpider(Entity* self, const bool withdra } void BossSpiderQueenEnemyServer::SpawnSpiderWave(Entity* self, int spiderCount) { - // The Spider Queen Boss is withdrawing and requesting the spawn + // The Spider Queen Boss is withdrawing and requesting the spawn // of a hatchling wave - /*auto SpiderEggNetworkID = self->GetI64(u"SpiderEggNetworkID"); - if (SpiderEggNetworkID == 0) return;*/ - // Clamp invalid Spiderling number requests to the maximum amount of eggs available if ((spiderCount > maxSpiderEggCnt) || (spiderCount < 0)) spiderCount = maxSpiderEggCnt; @@ -176,100 +169,67 @@ void BossSpiderQueenEnemyServer::SpawnSpiderWave(Entity* self, int spiderCount) hatchCounter = spiderCount; hatchList = {}; - Game::logger->Log("SpiderQueen", "Trying to spawn %i spiders\n", hatchCounter); - - - // Run the wave manager + // Run the wave manager SpiderWaveManager(self); - } void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) { auto SpiderEggNetworkID = self->GetI64(u"SpiderEggNetworkID"); - // Reset the spider egg spawner network to ensure a maximum number of eggs - //SpiderEggNetworkID:SpawnerReset() - - // Obtain a list of all the eggs on the egg spawner network - - //auto spiderEggList = SpiderEggNetworkID:SpawnerGetAllObjectIDsSpawned().objects; - - //if (table.maxn(spiderEggList) <= 0) { - // self->AddTimer("PollSpiderWaveManager", 1.0f); - // return; - //} - // - //// A check for (wave mangement across multiple spawn iterations - //if(hatchCounter < spiderWaveCnt) { - // // We have already prepped some objects for (hatching, - // // remove them from our list for (random egg pulls - // for (i, sVal in ipairs(spiderEggList) { - // if(hatchList[sVal:GetID()]) { - // // We have found a prepped egg, remove it from the spiderEggList - // spiderEggList[i] = nil - // } - // } - - //} - - - std::vector<LWOOBJID> spiderEggs{}; auto spooders = EntityManager::Instance()->GetEntitiesInGroup("EGG"); for (auto spodder : spooders) { spiderEggs.push_back(spodder->GetObjectID()); } - - // Select a number of random spider eggs from the list equal to the + + // Select a number of random spider eggs from the list equal to the // current number needed to complete the current wave - for (int i = 0; i < hatchCounter; i++) { - // Select a random spider egg - auto randomEggLoc = GeneralUtils::GenerateRandomNumber<int>(0, spiderEggs.size() - 1); - auto randomEgg = spiderEggs[randomEggLoc]; + if (!spiderEggs.empty()) { + for (int i = 0; i < hatchCounter; i++) { + // Select a random spider egg + auto randomEggLoc = GeneralUtils::GenerateRandomNumber<int>(0, spiderEggs.size() - 1); + auto randomEgg = spiderEggs[randomEggLoc]; - //Just a quick check to try and prevent dupes: - for (auto en : hatchList) { - if (en == randomEgg) { - randomEggLoc++; - randomEgg = spiderEggs[randomEggLoc]; - } - } - - if (randomEgg) { - auto* eggEntity = EntityManager::Instance()->GetEntity(randomEgg); - - if (eggEntity == nullptr) { - continue; + //Just a quick check to try and prevent dupes: + for (auto en : hatchList) { + if (en == randomEgg) { + randomEggLoc++; + randomEgg = spiderEggs[randomEggLoc]; + } } - // Prep the selected spider egg - //randomEgg:FireEvent{s}erID=self, args="prepEgg"} - eggEntity->OnFireEventServerSide(self, "prepEgg"); - Game::logger->Log("SpiderQueen", "Prepping egg %llu\n", eggEntity->GetObjectID()); - - // Add the prepped egg to our hatchList - hatchList.push_back(eggEntity->GetObjectID()); + if (randomEgg) { + auto* eggEntity = EntityManager::Instance()->GetEntity(randomEgg); - // Decrement the hatchCounter - hatchCounter = hatchCounter - 1; - } - - // Remove it from our spider egg list - //table.remove(spiderEggList, randomEggLoc); - spiderEggs[randomEggLoc] = LWOOBJID_EMPTY; - - if (spiderEggs.size() <= 0 || (hatchCounter <= 0)) { - break; + if (eggEntity == nullptr) { + continue; + } + + // Prep the selected spider egg + eggEntity->OnFireEventServerSide(self, "prepEgg"); + + // Add the prepped egg to our hatchList + hatchList.push_back(eggEntity->GetObjectID()); + + // Decrement the hatchCounter + hatchCounter = hatchCounter - 1; + } + + // Remove it from our spider egg list + spiderEggs[randomEggLoc] = LWOOBJID_EMPTY; + + if (spiderEggs.size() <= 0 || (hatchCounter <= 0)) { + break; + } } } - + if (hatchCounter > 0) { // We still have more eggs to hatch, poll the SpiderWaveManager again self->AddTimer("PollSpiderWaveManager", 1.0f); - } - else { + } else { // We have successfully readied a full wave // initiate hatching! for (auto egg : hatchList) { @@ -280,35 +240,30 @@ void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) { } eggEntity->OnFireEventServerSide(self, "hatchEgg"); - Game::logger->Log("SpiderQueen", "hatching egg %llu\n", eggEntity->GetObjectID()); auto time = PlayAnimAndReturnTime(self, spiderWithdrawIdle); combat->SetStunImmune(false); combat->Stun(time += 6.0f); combat->SetStunImmune(true); - - //self->AddTimer("disableWaitForIdle", defaultAnimPause); + self->AddTimer("checkForSpiders", 6.0f); } hatchList.clear(); - + } } -void BossSpiderQueenEnemyServer::ToggleForSpecial(Entity* self, const bool state) -{ +void BossSpiderQueenEnemyServer::ToggleForSpecial(Entity* self, const bool state) { self->SetBoolean(u"stoppedFlag", state); combat->SetDisabled(state); } -void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) -{ - if (self->GetBoolean(u"stoppedFlag")) - { +void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) { + if (self->GetBoolean(u"stoppedFlag")) { self->AddTimer("ROF", GeneralUtils::GenerateRandomNumber<float>(10, 20)); return; @@ -319,26 +274,20 @@ void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) impactList.clear(); auto index = 0u; - for (const auto& rofGroup : ROFTargetGroupIDTable) - { + for (const auto& rofGroup : ROFTargetGroupIDTable) { const auto spawners = dZoneManager::Instance()->GetSpawnersInGroup(rofGroup); - + std::vector<LWOOBJID> spawned; - for (auto* spawner : spawners) - { - for (const auto* node : spawner->m_Info.nodes) - { + for (auto* spawner : spawners) { + for (const auto* node : spawner->m_Info.nodes) { spawned.insert(spawned.end(), node->entities.begin(), node->entities.end()); } } - if (index == 0) - { + if (index == 0) { impactList.insert(impactList.end(), spawned.begin(), spawned.end()); - } - else - { + } else { const auto randomIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, spawned.size() - 1); impactList.push_back(spawned[randomIndex]); @@ -352,27 +301,23 @@ void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) self->AddTimer("StartROF", animTime); } -void BossSpiderQueenEnemyServer::RainOfFireManager(Entity* self) -{ - if (!impactList.empty()) - { +void BossSpiderQueenEnemyServer::RainOfFireManager(Entity* self) { + if (!impactList.empty()) { auto* entity = EntityManager::Instance()->GetEntity(impactList[0]); impactList.erase(impactList.begin()); - if (entity == nullptr) - { - Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find impact!\n"); + if (entity == nullptr) { + Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find impact!"); return; } auto* skillComponent = entity->GetComponent<SkillComponent>(); - if (skillComponent == nullptr) - { - Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find impact skill component!\n"); - + if (skillComponent == nullptr) { + Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find impact skill component!"); + return; } @@ -384,14 +329,12 @@ void BossSpiderQueenEnemyServer::RainOfFireManager(Entity* self) } ToggleForSpecial(self, false); - + self->AddTimer("ROF", GeneralUtils::GenerateRandomNumber<float>(20, 40)); } -void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) -{ - if (attackTargetTable.empty()) - { +void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) { + if (attackTargetTable.empty()) { const auto animationTime = PlayAnimAndReturnTime(self, spiderJeerAnim); self->AddTimer("RFSTauntComplete", animationTime); @@ -402,7 +345,7 @@ void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) } const auto target = attackTargetTable[0]; - + auto* skillComponent = self->GetComponent<SkillComponent>(); skillComponent->CalculateBehavior(1394, 32612, target, true); @@ -412,24 +355,17 @@ void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) self->AddTimer("PollRFSManager", 0.3f); } -void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) -{ - /* - const auto targets = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); - */ - +void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) { const auto targets = self->GetTargetsInPhantom(); - if (self->GetBoolean(u"stoppedFlag")) - { + if (self->GetBoolean(u"stoppedFlag")) { self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(5, 10)); return; } - if (targets.empty()) - { - Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find RFS targets\n"); + if (targets.empty()) { + Game::logger->Log("BossSpiderQueenEnemyServer", "Failed to find RFS targets"); self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(5, 10)); @@ -452,19 +388,15 @@ void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) PlayAnimAndReturnTime(self, spiderSingleShot); - Game::logger->Log("BossSpiderQueenEnemyServer", "Ran RFS\n"); - self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(10, 15)); } void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string timerName) { if (timerName == "PollSpiderWaveManager") { - //Call the manager again to attempt to finish prepping a Spiderling wave - //Run the wave manager + //Call the manager again to attempt to finish prepping a Spiderling wave + //Run the wave manager SpiderWaveManager(self); - } - else if (timerName == "disableWaitForIdle") { waitForIdle = false; } - else if (timerName == "checkForSpiders") { + } else if (timerName == "disableWaitForIdle") { waitForIdle = false; } else if (timerName == "checkForSpiders") { //Don't do anything if we ain't withdrawn: const auto withdrawn = self->GetBoolean(u"isWithdrawn"); if (!withdrawn) return; @@ -487,186 +419,159 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim //If there are still baby spiders, don't do anyhting either const auto spiders = EntityManager::Instance()->GetEntitiesInGroup("BabySpider"); - if (spiders.size() > 0) + if (spiders.size() > 0) self->AddTimer("checkForSpiders", time); else WithdrawSpider(self, false); - } - else if (timerName == "PollROFManager") { - //Call the manager again to attempt to initiate an impact on another random location - //Run the ROF Manager + } else if (timerName == "PollROFManager") { + //Call the manager again to attempt to initiate an impact on another random location + //Run the ROF Manager RainOfFireManager(self); - - } else if ( timerName == "PollRFSManager") { - //Call the manager again to attempt to initiate a rapid fire shot at the next sequential target - //Run the ROF Manager + + } else if (timerName == "PollRFSManager") { + //Call the manager again to attempt to initiate a rapid fire shot at the next sequential target + //Run the ROF Manager RapidFireShooterManager(self); - - } else if ( timerName == "StartROF") { - //Re-enable Spider Boss + + } else if (timerName == "StartROF") { + //Re-enable Spider Boss //ToggleForSpecial(self, false); - + RainOfFireManager(self); - - } else if ( timerName == "PollSpiderSkillManager") { - //Call the skill manager again to attempt to run the current Spider Boss - //stage's special attack again + + } else if (timerName == "PollSpiderSkillManager") { + //Call the skill manager again to attempt to run the current Spider Boss + //stage's special attack again //SpiderSkillManager(self, true); PlayAnimAndReturnTime(self, spiderJeerAnim); - - } else if ( timerName == "RFS") { - RunRapidFireShooter(self); - } else if ( timerName == "ROF") { - RunRainOfFire(self); - } else if ( timerName == "RFSTauntComplete") { - //Determine an appropriate random time to check our manager again - // local spiderCooldownDelay = math.random(s1DelayMin, s1DelayMax) - //Set a timer based on our random cooldown determination - //to pulse the SpiderSkillManager again + } else if (timerName == "RFS") { + RunRapidFireShooter(self); + } else if (timerName == "ROF") { + RunRainOfFire(self); + } else if (timerName == "RFSTauntComplete") { + //Determine an appropriate random time to check our manager again + // local spiderCooldownDelay = math.random(s1DelayMin, s1DelayMax) + + //Set a timer based on our random cooldown determination + //to pulse the SpiderSkillManager again //GAMEOBJ:GetTimer():AddTimerWithCancel(spiderCooldownDelay, "PollSpiderSkillManager", self) - //Re-enable Spider Boss - //ToggleForSpecial(self, false); - - } else if ( timerName == "WithdrawComplete") { - //Play the Spider Boss' mountain idle anim + //Re-enable Spider Boss + //ToggleForSpecial(self, false); + + } else if (timerName == "WithdrawComplete") { + //Play the Spider Boss' mountain idle anim PlayAnimAndReturnTime(self, spiderWithdrawIdle); - //The Spider Boss has retreated, hatch a wave! + //The Spider Boss has retreated, hatch a wave! int currentStage = m_CurrentBossStage; - //Prepare a Spiderling wave and initiate egg hatch events - //self->SetVar(u"SpiderWaveCount", ) + //Prepare a Spiderling wave and initiate egg hatch events + //self->SetVar(u"SpiderWaveCount", ) //TODO: Actually spawn the spiders here hatchCounter = 2; if (currentStage > 1) hatchCounter++; SpawnSpiderWave(self, spiderWaveCntTable[currentStage - 1]); - - } else if ( timerName == "AdvanceAttack") { + + } else if (timerName == "AdvanceAttack") { //TODO: Can we even do knockbacks yet? @Wincent01 // Yes ^ - //Fire the melee smash skill to throw players back - /*local landingTarget = self:GetVar("LandingTarget") or false - - if((landingTarget) and (landingTarget:Exists())) { - local advSmashFlag = landingTarget:CastSkill{skillID = bossLandingSkill} - landingTarget:PlayEmbeddedEffectOnAllClientsNearObject{radius = 100, fromObjectID = landingTarget, effectName = "camshake-bridge"} - }*/ - + //Fire the melee smash skill to throw players back + /*local landingTarget = self:GetVar("LandingTarget") or false + + if((landingTarget) and (landingTarget:Exists())) { + local advSmashFlag = landingTarget:CastSkill{skillID = bossLandingSkill} + landingTarget:PlayEmbeddedEffectOnAllClientsNearObject{radius = 100, fromObjectID = landingTarget, effectName = "camshake-bridge"} + }*/ + auto landingTarget = self->GetI64(u"LandingTarget"); auto landingEntity = EntityManager::Instance()->GetEntity(landingTarget); auto* skillComponent = self->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) - { + if (skillComponent != nullptr) { skillComponent->CalculateBehavior(bossLandingSkill, 37739, LWOOBJID_EMPTY); } - + if (landingEntity) { auto* landingSkill = landingEntity->GetComponent<SkillComponent>(); - if (landingSkill != nullptr) - { + if (landingSkill != nullptr) { landingSkill->CalculateBehavior(bossLandingSkill, 37739, LWOOBJID_EMPTY, true); } } GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake-bridge", self->GetObjectID(), 100.0f); - - } else if ( timerName == "AdvanceComplete") { - //Reset faction and collision - /*local SBFactionList = self:GetVar("SBFactionList") - local SBCollisionGroup = self:GetVar("SBCollisionGroup") - - for i, fVal in ipairs(SBFactionList) { - if(i == 1) { - //Our first faction - flush and add - self:SetFaction{faction = fVal} - else - //Add - self:ModifyFaction{factionID = fVal, bAddFaction = true} - } - }*/ - /* - auto SBCollisionGroup = self->GetI32(u"SBCollisionGroup"); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", SBCollisionGroup, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - */ - + } else if (timerName == "AdvanceComplete") { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 11, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); - //Wind up, telegraphing next round + //Wind up, telegraphing next round float animTime = PlayAnimAndReturnTime(self, spiderJeerAnim); self->AddTimer("AdvanceTauntComplete", animTime); - - } else if ( timerName == "AdvanceTauntComplete") { - - //Declare a default special Spider Boss skill cooldown + + } else if (timerName == "AdvanceTauntComplete") { + + //Declare a default special Spider Boss skill cooldown int spiderCooldownDelay = 10; - if(m_CurrentBossStage == 2) { + if (m_CurrentBossStage == 2) { spiderCooldownDelay = GeneralUtils::GenerateRandomNumber<int>(s1DelayMin, s1DelayMax); - } else if (m_CurrentBossStage == 3) { - spiderCooldownDelay = GeneralUtils::GenerateRandomNumber<int>(s2DelayMin, s2DelayMax); - } + } else if (m_CurrentBossStage == 3) { + spiderCooldownDelay = GeneralUtils::GenerateRandomNumber<int>(s2DelayMin, s2DelayMax); + } - //Set a timer based on our random cooldown determination - //to pulse the SpiderSkillManager + //Set a timer based on our random cooldown determination + //to pulse the SpiderSkillManager self->AddTimer("PollSpiderSkillManager", spiderCooldownDelay); - - //Remove current status immunity - /*self:SetStatusImmunity{ StateChangeType = "POP", bImmuneToSpeed = true, bImmuneToBasicAttack = true, bImmuneToDOT = true} - - self:SetStunned{StateChangeType = "POP", - bCantMove = true, - bCantJump = true, - bCantTurn = true, - bCantAttack = true, - bCantUseItem = true, - bCantEquip = true, - bCantInteract = true, - bIgnoreImmunity = true}*/ + + //Remove current status immunity + /*self:SetStatusImmunity{ StateChangeType = "POP", bImmuneToSpeed = true, bImmuneToBasicAttack = true, bImmuneToDOT = true} + + self:SetStunned{StateChangeType = "POP", + bCantMove = true, + bCantJump = true, + bCantTurn = true, + bCantAttack = true, + bCantUseItem = true, + bCantEquip = true, + bCantInteract = true, + bIgnoreImmunity = true}*/ destroyable->SetIsImmune(false); destroyable->SetFaction(4); EntityManager::Instance()->SerializeEntity(self); - - } else if ( timerName == "Clear") { + + } else if (timerName == "Clear") { EntityManager::Instance()->FireEventServerSide(self, "ClearProperty"); self->CancelAllTimers(); - } else if ( timerName == "UnlockSpecials") { - //We no longer need to lock specials + } else if (timerName == "UnlockSpecials") { + //We no longer need to lock specials self->SetBoolean(u"bSpecialLock", false); - - //Did we queue a spcial attack? - if(self->GetBoolean(u"bSpecialQueued")) { + + //Did we queue a spcial attack? + if (self->GetBoolean(u"bSpecialQueued")) { self->SetBoolean(u"bSpecialQueued", false); - //SpiderSkillManager(self, true); - } + } } } void BossSpiderQueenEnemyServer::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { - if (m_CurrentBossStage > 0 && !self->HasTimer("RFS")) - { + if (m_CurrentBossStage > 0 && !self->HasTimer("RFS")) { self->AddTimer("RFS", 5.0f); } - if (m_CurrentBossStage > 0 && !self->HasTimer("ROF")) - { + if (m_CurrentBossStage > 0 && !self->HasTimer("ROF")) { self->AddTimer("ROF", 10.0f); } - if (m_CurrentBossStage > ThresholdTable.size()) - { + if (m_CurrentBossStage > ThresholdTable.size()) { return; } @@ -691,8 +596,7 @@ void BossSpiderQueenEnemyServer::OnUpdate(Entity* self) { if (!isWithdrawn) return; - if (controllable->GetRotation() == NiQuaternion::IDENTITY) - { + if (controllable->GetRotation() == NiQuaternion::IDENTITY) { return; } @@ -701,17 +605,6 @@ void BossSpiderQueenEnemyServer::OnUpdate(Entity* self) { controllable->SetStatic(true); EntityManager::Instance()->SerializeEntity(self); - - //if (waitForIdle) return; - - ////Play the Spider Boss' mountain idle anim - //PlayAnimAndReturnTime(self, spiderWithdrawIdle); - - ////If there are still baby spiders, don't do anyhting either - //auto spooders = EntityManager::Instance()->GetEntitiesInGroup("BabySpider"); - //if (spooders.size() > 0) return; - //else - // WithdrawSpider(self, false); } //---------------------------------------------- @@ -723,17 +616,17 @@ float BossSpiderQueenEnemyServer::PlayAnimAndReturnTime(Entity* self, const std: //TODO: Get the actual animation time // Get the anim time - float animTimer = defaultAnimPause; //self:GetAnimationTime{animationID = animID}.time - + float animTimer = defaultAnimPause; //self:GetAnimationTime{animationID = animID}.time + // If we have an animation play it if (animTimer > 0) { GameMessages::SendPlayAnimation(self, animID); } - + // If the anim time is less than the the default time use default if (animTimer < defaultAnimPause) { animTimer = defaultAnimPause; } - + return animTimer; } diff --git a/dScripts/BossSpiderQueenEnemyServer.h b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.h similarity index 99% rename from dScripts/BossSpiderQueenEnemyServer.h rename to dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.h index f3219cf7..8f73d99f 100644 --- a/dScripts/BossSpiderQueenEnemyServer.h +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" /* @@ -19,25 +19,25 @@ class BaseCombatAIComponent; class BossSpiderQueenEnemyServer final : public CppScripts::Script { public: void OnStartup(Entity* self) override; - + void OnDie(Entity* self, Entity* killer) override; - + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; - + void OnUpdate(Entity* self) override; void WithdrawSpider(Entity* self, bool withdraw); void SpawnSpiderWave(Entity* self, int spiderCount); - + void SpiderWaveManager(Entity* self); void ToggleForSpecial(Entity* self, bool state); - + void RunRainOfFire(Entity* self); void RainOfFireManager(Entity* self); - + void RapidFireShooterManager(Entity* self); void RunRapidFireShooter(Entity* self); @@ -53,7 +53,7 @@ private: BaseCombatAIComponent* combat = nullptr; NiQuaternion originRotation; - + int m_CurrentBossStage = 0; int m_DeathCounter = 0; std::vector<int> ThresholdTable; diff --git a/dScripts/02_server/Enemy/AG/CMakeLists.txt b/dScripts/02_server/Enemy/AG/CMakeLists.txt new file mode 100644 index 00000000..865d4c3c --- /dev/null +++ b/dScripts/02_server/Enemy/AG/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AG + "BossSpiderQueenEnemyServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp new file mode 100644 index 00000000..28ba0044 --- /dev/null +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -0,0 +1,157 @@ +#include "AmDarklingDragon.h" +#include "BaseCombatAIComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "SkillComponent.h" +#include "BaseCombatAIComponent.h" +#include "EntityInfo.h" +#include "eAninmationFlags.h" + +void AmDarklingDragon::OnStartup(Entity* self) { + self->SetVar<int32_t>(u"weakspot", 0); + + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetStunImmune(true); + } +} + +void AmDarklingDragon::OnDie(Entity* self, Entity* killer) { + if (self->GetVar<bool>(u"bDied")) { + return; + } + + self->SetVar<bool>(u"bDied", true); + + auto golemId = self->GetVar<LWOOBJID>(u"Golem"); + + auto* golem = EntityManager::Instance()->GetEntity(golemId); + + if (golem != nullptr) { + golem->Smash(self->GetObjectID()); + } +} + +void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); + + if (true) { + auto weakpoint = self->GetVar<int32_t>(u"weakspot"); + + if (weakpoint == 1) { + self->Smash(attacker->GetObjectID()); + } + } + + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + + if (destroyableComponent != nullptr) { + if (destroyableComponent->GetArmor() > 0) return; + + auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); + + if (weakpoint == 0) { + self->AddTimer("ReviveTimer", 12); + + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetDisabled(true); + baseCombatAIComponent->SetStunned(true); + } + + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + skillComponent->Reset(); + } + + self->SetVar<int32_t>(u"weakpoint", 2); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); + + self->AddTimer("timeToStunLoop", 1); + + auto position = self->GetPosition(); + auto forward = self->GetRotation().GetForwardVector(); + auto backwards = forward * -1; + + forward.x *= 10; + forward.z *= 10; + + auto rotation = self->GetRotation(); + + auto objectPosition = NiPoint3(); + + objectPosition.y = position.y; + objectPosition.x = position.x - (backwards.x * 8); + objectPosition.z = position.z - (backwards.z * 8); + + auto golem = self->GetVar<int32_t>(u"DragonSmashingGolem"); + + EntityInfo info{}; + info.lot = golem != 0 ? golem : 8340; + info.pos = objectPosition; + info.rot = rotation; + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData<std::string>(u"rebuild_activators", + std::to_string(objectPosition.x + forward.x) + "\x1f" + + std::to_string(objectPosition.y) + "\x1f" + + std::to_string(objectPosition.z + forward.z) + ), + new LDFData<int32_t>(u"respawn", 100000), + new LDFData<float>(u"rebuild_reset_time", 15), + new LDFData<bool>(u"no_timed_spawn", true), + new LDFData<LWOOBJID>(u"Dragon", self->GetObjectID()) + }; + + auto* golemObject = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(golemObject); + } + } +} + +void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "ReviveHeldTimer") { + self->AddTimer("backToAttack", 2.5); + } else if (timerName == "ExposeWeakSpotTimer") { + self->SetVar<int32_t>(u"weakspot", 1); + } else if (timerName == "timeToStunLoop") { + GameMessages::SendPlayAnimation(self, u"stunloop", 1.8f); + } else if (timerName == "ReviveTimer") { + GameMessages::SendPlayAnimation(self, u"stunend", 2.0f); + self->AddTimer("backToAttack", 1); + } else if (timerName == "backToAttack") { + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetDisabled(false); + baseCombatAIComponent->SetStunned(false); + } + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + skillComponent->Reset(); + } + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + self->SetVar<int32_t>(u"weakspot", -1); + GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); + } +} + +void AmDarklingDragon::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args != "rebuildDone") return; + + self->AddTimer("ExposeWeakSpotTimer", 3.8f); + + self->CancelTimer("ReviveTimer"); + + self->AddTimer("ReviveHeldTimer", 10.5f); + + self->SetVar<LWOOBJID>(u"Golem", sender->GetObjectID()); + + GameMessages::SendPlayAnimation(self, u"quickbuildhold", 1.9f); +} diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.h b/dScripts/02_server/Enemy/AM/AmDarklingDragon.h new file mode 100644 index 00000000..5a85e329 --- /dev/null +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.h @@ -0,0 +1,48 @@ +#pragma once +#include "CppScripts.h" + +class AmDarklingDragon : public CppScripts::Script +{ +public: + /** + * @brief When called, this function will make self immune to stuns and initialize a weakspot boolean to false. + * + * @param self The Entity that called this function. + */ + void OnStartup(Entity* self) override; + /** + * @brief When called, this function will destroy the golem if it was alive, otherwise returns immediately. + * + * @param self The Entity that called this function. + * @param killer The Entity that killed self. + */ + void OnDie(Entity* self, Entity* killer) override; + /** + * @brief When self is hit or healed, this function will check if self is at zero armor. If self is at zero armor, a golem Entity Quick Build + * is spawned that, when built, will reveal a weakpoint on the dragon that if hit will smash the dragon instantly. If at more than zero armor, + * this function returns early. + * + * @param self The Entity that was hit. + * @param attacker The Entity that attacked self. + * @param damage The amount of damage attacker did to self. + */ + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + /** + * @brief Called when self has a timer that ended. + * + * @param self The Entity who owns a timer that finished. + * @param timerName The name of a timer attacked to self that has ended. + */ + void OnTimerDone(Entity* self, std::string timerName) override; + /** + * @brief When the Client has finished rebuilding the Golem for the dragon, this function exposes the weak spot for a set amount of time. + * + * @param self The Entity that called this script. + * @param sender The Entity that sent a fired event. + * @param args The argument that tells us what event has been fired off. + * @param param1 Unused in this script. + * @param param2 Unused in this script. + * @param param3 Unused in this script. + */ + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/02_server/Enemy/AM/AmDarklingMech.cpp b/dScripts/02_server/Enemy/AM/AmDarklingMech.cpp new file mode 100644 index 00000000..922296c2 --- /dev/null +++ b/dScripts/02_server/Enemy/AM/AmDarklingMech.cpp @@ -0,0 +1,6 @@ +#include "AmDarklingMech.h" + +void AmDarklingMech::OnStartup(Entity* self) { + BaseEnemyMech::OnStartup(self); + qbTurretLOT = 13171; +} diff --git a/dScripts/AmDarklingMech.h b/dScripts/02_server/Enemy/AM/AmDarklingMech.h similarity index 73% rename from dScripts/AmDarklingMech.h rename to dScripts/02_server/Enemy/AM/AmDarklingMech.h index cc179795..0f54ba7f 100644 --- a/dScripts/AmDarklingMech.h +++ b/dScripts/02_server/Enemy/AM/AmDarklingMech.h @@ -5,5 +5,5 @@ class AmDarklingMech : public BaseEnemyMech { public: - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/02_server/Enemy/AM/AmSkeletonEngineer.cpp b/dScripts/02_server/Enemy/AM/AmSkeletonEngineer.cpp new file mode 100644 index 00000000..a4972729 --- /dev/null +++ b/dScripts/02_server/Enemy/AM/AmSkeletonEngineer.cpp @@ -0,0 +1,24 @@ +#include "AmSkeletonEngineer.h" +#include "DestroyableComponent.h" +#include "SkillComponent.h" + +void AmSkeletonEngineer::OnHit(Entity* self, Entity* attacker) { + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (destroyableComponent == nullptr || skillComponent == nullptr) { + return; + } + + if (destroyableComponent->GetHealth() < 12 && !self->GetVar<bool>(u"injured")) { + self->SetVar(u"injured", true); + + skillComponent->CalculateBehavior(953, 19864, self->GetObjectID(), true); + + const auto attackerID = attacker->GetObjectID(); + + self->AddCallbackTimer(4.5f, [this, self, attackerID]() { + self->Smash(attackerID); + }); + } +} diff --git a/dScripts/AmSkeletonEngineer.h b/dScripts/02_server/Enemy/AM/AmSkeletonEngineer.h similarity index 68% rename from dScripts/AmSkeletonEngineer.h rename to dScripts/02_server/Enemy/AM/AmSkeletonEngineer.h index d4f6f36e..77a14d88 100644 --- a/dScripts/AmSkeletonEngineer.h +++ b/dScripts/02_server/Enemy/AM/AmSkeletonEngineer.h @@ -5,5 +5,5 @@ class AmSkeletonEngineer : public EnemyNjBuff { public: - void OnHit(Entity* self, Entity* attacker) override; + void OnHit(Entity* self, Entity* attacker) override; }; diff --git a/dScripts/02_server/Enemy/AM/CMakeLists.txt b/dScripts/02_server/Enemy/AM/CMakeLists.txt new file mode 100644 index 00000000..dd20edb0 --- /dev/null +++ b/dScripts/02_server/Enemy/AM/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AM + "AmDarklingMech.cpp" + "AmSkeletonEngineer.cpp" + "AmDarklingDragon.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/CMakeLists.txt b/dScripts/02_server/Enemy/CMakeLists.txt new file mode 100644 index 00000000..408ff733 --- /dev/null +++ b/dScripts/02_server/Enemy/CMakeLists.txt @@ -0,0 +1,45 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY) + +add_subdirectory(AG) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_AG}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "AG/${file}") +endforeach() + +add_subdirectory(AM) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_AM}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "AM/${file}") +endforeach() + +add_subdirectory(FV) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "FV/${file}") +endforeach() + +add_subdirectory(General) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "General/${file}") +endforeach() + +add_subdirectory(Survival) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_SURVIVAL}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "Survival/${file}") +endforeach() + +add_subdirectory(VE) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_VE}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "VE/${file}") +endforeach() + +add_subdirectory(Waves) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES}) + set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "Waves/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/FV/CMakeLists.txt b/dScripts/02_server/Enemy/FV/CMakeLists.txt new file mode 100644 index 00000000..5146d8d8 --- /dev/null +++ b/dScripts/02_server/Enemy/FV/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV + "FvMaelstromCavalry.cpp" + "FvMaelstromDragon.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromCavalry.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromCavalry.cpp new file mode 100644 index 00000000..9214667e --- /dev/null +++ b/dScripts/02_server/Enemy/FV/FvMaelstromCavalry.cpp @@ -0,0 +1,30 @@ +#include "FvMaelstromCavalry.h" +#include "EntityManager.h" + +void FvMaelstromCavalry::OnStartup(Entity* self) { + for (const auto& group : self->GetGroups()) { + const auto& objects = EntityManager::Instance()->GetEntitiesInGroup(group); + + for (auto* obj : objects) { + if (obj->GetLOT() != 8551) continue; + + obj->OnFireEventServerSide(self, "ISpawned"); + } + } +} + +void FvMaelstromCavalry::OnDie(Entity* self, Entity* killer) { + if (killer == nullptr) { + return; + } + + if (killer->GetLOT() != 8665) { + return; + } + + const auto& triggers = EntityManager::Instance()->GetEntitiesInGroup("HorsemenTrigger"); + + for (auto* trigger : triggers) { + trigger->OnFireEventServerSide(self, "HorsemenDeath"); + } +} diff --git a/dScripts/FvMaelstromCavalry.h b/dScripts/02_server/Enemy/FV/FvMaelstromCavalry.h similarity index 69% rename from dScripts/FvMaelstromCavalry.h rename to dScripts/02_server/Enemy/FV/FvMaelstromCavalry.h index 0fc3e840..40784ba9 100644 --- a/dScripts/FvMaelstromCavalry.h +++ b/dScripts/02_server/Enemy/FV/FvMaelstromCavalry.h @@ -1,7 +1,7 @@ #pragma once #include "CppScripts.h" -class FvMaelstromCavalry : public CppScripts::Script +class FvMaelstromCavalry : public CppScripts::Script { public: void OnStartup(Entity* self); diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp new file mode 100644 index 00000000..e78f537f --- /dev/null +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -0,0 +1,178 @@ +#include "FvMaelstromDragon.h" +#include "EntityManager.h" +#include "SkillComponent.h" +#include "BaseCombatAIComponent.h" +#include "DestroyableComponent.h" +#include "eAninmationFlags.h" +#include "EntityInfo.h" + +void FvMaelstromDragon::OnStartup(Entity* self) { + self->SetVar<int32_t>(u"weakspot", 0); + + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetStunImmune(true); + } +} + +void FvMaelstromDragon::OnDie(Entity* self, Entity* killer) { + if (self->GetVar<bool>(u"bDied")) { + return; + } + + self->SetVar<bool>(u"bDied", true); + + auto position = self->GetPosition(); + auto rotation = self->GetRotation(); + + auto chestObject = 11229; + + EntityInfo info{}; + info.lot = chestObject; + info.pos = position; + info.rot = rotation; + info.spawnerID = self->GetObjectID(); + + auto* chest = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(chest); + + auto golemId = self->GetVar<LWOOBJID>(u"Golem"); + + auto* golem = EntityManager::Instance()->GetEntity(golemId); + + if (golem != nullptr) { + golem->Smash(self->GetObjectID()); + } +} + +void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); + + if (true) { + auto weakpoint = self->GetVar<int32_t>(u"weakspot"); + + if (weakpoint == 1) { + self->Smash(attacker->GetObjectID()); + } + } + + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + + if (destroyableComponent != nullptr) { + if (destroyableComponent->GetArmor() > 0) return; + + auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); + + if (weakpoint == 0) { + Game::logger->Log("FvMaelstromDragon", "Activating weakpoint"); + + self->AddTimer("ReviveTimer", 12); + + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetDisabled(true); + baseCombatAIComponent->SetStunned(true); + } + + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + skillComponent->Reset(); + } + + self->SetVar<int32_t>(u"weakpoint", 2); + + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); + + self->AddTimer("timeToStunLoop", 1); + + auto position = self->GetPosition(); + auto forward = self->GetRotation().GetForwardVector(); + auto backwards = forward * -1; + + forward.x *= 10; + forward.z *= 10; + + auto rotation = self->GetRotation(); + + auto objectPosition = NiPoint3(); + + objectPosition.y = position.y; + objectPosition.x = position.x - (backwards.x * 8); + objectPosition.z = position.z - (backwards.z * 8); + + auto golem = self->GetVar<int32_t>(u"DragonSmashingGolem"); + + EntityInfo info{}; + info.lot = golem != 0 ? golem : 8340; + info.pos = objectPosition; + info.rot = rotation; + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData<std::string>(u"rebuild_activators", + std::to_string(objectPosition.x + forward.x) + "\x1f" + + std::to_string(objectPosition.y) + "\x1f" + + std::to_string(objectPosition.z + forward.z) + ), + new LDFData<int32_t>(u"respawn", 100000), + new LDFData<float>(u"rebuild_reset_time", 15), + new LDFData<bool>(u"no_timed_spawn", true), + new LDFData<LWOOBJID>(u"Dragon", self->GetObjectID()) + }; + + auto* golemObject = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(golemObject); + } + } +} + +void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "ReviveHeldTimer") { + self->AddTimer("backToAttack", 2.5); + } else if (timerName == "ExposeWeakSpotTimer") { + self->SetVar<int32_t>(u"weakspot", 1); + } else if (timerName == "timeToStunLoop") { + GameMessages::SendPlayAnimation(self, u"stunloop", 1.8f); + } else if (timerName == "ReviveTimer") { + GameMessages::SendPlayAnimation(self, u"stunend", 2.0f); + self->AddTimer("backToAttack", 1); + } else if (timerName == "backToAttack") { + auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetDisabled(false); + baseCombatAIComponent->SetStunned(false); + } + + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + skillComponent->Reset(); + } + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + self->SetVar<int32_t>(u"weakspot", -1); + + GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); + } +} + +void +FvMaelstromDragon::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args != "rebuildDone") return; + + self->AddTimer("ExposeWeakSpotTimer", 3.8f); + + self->CancelTimer("ReviveTimer"); + + self->AddTimer("ReviveHeldTimer", 10.5f); + + self->SetVar<LWOOBJID>(u"Golem", sender->GetObjectID()); + + GameMessages::SendPlayAnimation(self, u"quickbuildhold", 1.9f); +} diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.h b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.h new file mode 100644 index 00000000..d12e1bb4 --- /dev/null +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class FvMaelstromDragon : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp new file mode 100644 index 00000000..e9863b17 --- /dev/null +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -0,0 +1,141 @@ +#include "BaseEnemyApe.h" +#include "BaseCombatAIComponent.h" +#include "DestroyableComponent.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "SkillComponent.h" +#include "eAninmationFlags.h" +#include "eStateChangeType.h" + +void BaseEnemyApe::OnStartup(Entity* self) { + self->SetVar<uint32_t>(u"timesStunned", 2); + self->SetVar<bool>(u"knockedOut", false); +} + +void BaseEnemyApe::OnDie(Entity* self, Entity* killer) { + auto* anchor = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"QB")); + if (anchor != nullptr && !anchor->GetIsDead()) { + anchor->Smash(self->GetObjectID(), eKillType::SILENT); + } +} + +void BaseEnemyApe::OnSkillCast(Entity* self, uint32_t skillID) { + const auto groundPoundSkill = self->GetVar<uint32_t>(u"GroundPoundSkill") != 0 ? self->GetVar<uint32_t>(u"GroundPoundSkill") : 725; + const auto spawnQuickBuildTime = self->GetVar<float_t>(u"spawnQBTime") != 0.0f ? self->GetVar<float_t>(u"spawnQBTime") : 5.0f; + + if (skillID == groundPoundSkill && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) { + self->AddTimer("spawnQBTime", spawnQuickBuildTime); + } +} + +void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { + StunApe(self, true); + self->CancelTimer("spawnQBTime"); + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent) { + skillComponent->Reset(); + } + GameMessages::SendPlayAnimation(self, u"disable", 1.7f); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + const auto reviveTime = self->GetVar<float_t>(u"reviveTime") != 0.0f + ? self->GetVar<float_t>(u"reviveTime") : 12.0f; + self->AddTimer("reviveTime", reviveTime); + } +} + +void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "reviveTime") { + + // Revives the ape, giving it back some armor + const auto timesStunned = self->GetVar<uint32_t>(u"timesStunned"); + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); + } + EntityManager::Instance()->SerializeEntity(self); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1); + StunApe(self, false); + + } else if (timerName == "spawnQBTime" && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) { + // Spawn QB in front of ape. + const auto position = self->GetPosition(); + const auto rotation = self->GetRotation(); + + const auto backwardVector = rotation.GetForwardVector() * -1; + const auto objectPosition = NiPoint3( + position.GetX() - (backwardVector.GetX() * 8), + position.GetY(), + position.GetZ() - (backwardVector.GetZ() * 8) + ); + + EntityInfo entityInfo{}; + + entityInfo.pos = position; + entityInfo.rot = rotation; + entityInfo.pos.SetY(entityInfo.pos.GetY() + 13.0f); + + entityInfo.spawnerID = self->GetObjectID(); + entityInfo.lot = self->GetVar<LOT>(u"QuickbuildAnchorLOT") != 0 + ? self->GetVar<LOT>(u"QuickbuildAnchorLOT") : 7549; + entityInfo.settings = { + new LDFData<std::string>(u"rebuild_activators", + std::to_string(objectPosition.GetX()) + "\x1f" + + std::to_string(objectPosition.GetY()) + "\x1f" + + std::to_string(objectPosition.GetZ()) + ), + new LDFData<bool>(u"no_timed_spawn", true), + new LDFData<LWOOBJID>(u"ape", self->GetObjectID()) + }; + + auto* anchor = EntityManager::Instance()->CreateEntity(entityInfo); + EntityManager::Instance()->ConstructEntity(anchor); + self->SetVar<LWOOBJID>(u"QB", anchor->GetObjectID()); + + } else if (timerName == "anchorDamageTimer") { + + // Attacks the ape with some god skill + const auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"smasher")); + if (player == nullptr) { + return; + } + + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(1273, 29446, self->GetObjectID(), true, false, player->GetObjectID()); + } + + self->SetVar<LWOOBJID>(u"QB", LWOOBJID_EMPTY); + } +} + +void BaseEnemyApe::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "rebuildDone" && sender != nullptr) { + self->SetVar<LWOOBJID>(u"smasher", sender->GetObjectID()); + const auto anchorDamageDelayTime = self->GetVar<float_t>(u"AnchorDamageDelayTime") != 0.0f ? self->GetVar<float_t>(u"AnchorDamageDelayTime") : 0.5f; + self->AddTimer("anchorDamageTimer", anchorDamageDelayTime); + } +} + +void BaseEnemyApe::StunApe(Entity* self, bool stunState) { + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(stunState); + combatAIComponent->SetStunned(stunState); + + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + } + + GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), + true, true, true, true, true, + true, true, true, true); + + self->SetBoolean(u"knockedOut", stunState); + } +} diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.h b/dScripts/02_server/Enemy/General/BaseEnemyApe.h new file mode 100644 index 00000000..938312b6 --- /dev/null +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +class BaseEnemyApe : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; + void OnSkillCast(Entity* self, uint32_t skillID) override; + void OnHit(Entity* self, Entity* attacker) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +private: + static void StunApe(Entity* self, bool stunState); +}; diff --git a/dScripts/BaseEnemyMech.cpp b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp similarity index 72% rename from dScripts/BaseEnemyMech.cpp rename to dScripts/02_server/Enemy/General/BaseEnemyMech.cpp index 17c7a347..ce42585c 100644 --- a/dScripts/BaseEnemyMech.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp @@ -3,21 +3,23 @@ #include "ControllablePhysicsComponent.h" #include "EntityManager.h" #include "dpWorld.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void BaseEnemyMech::OnStartup(Entity* self) { - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetFaction(4); - } + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetFaction(4); + } } void BaseEnemyMech::OnDie(Entity* self, Entity* killer) { - ControllablePhysicsComponent* controlPhys = static_cast<ControllablePhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + ControllablePhysicsComponent* controlPhys = static_cast<ControllablePhysicsComponent*>(self->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!controlPhys) return; - NiPoint3 newLoc = {controlPhys->GetPosition().x, dpWorld::Instance().GetHeightAtPoint(controlPhys->GetPosition()), controlPhys->GetPosition().z }; + NiPoint3 newLoc = { controlPhys->GetPosition().x, dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(controlPhys->GetPosition()), controlPhys->GetPosition().z }; EntityInfo info = EntityInfo(); std::vector<LDFBaseData*> cfg; diff --git a/dScripts/BaseEnemyMech.h b/dScripts/02_server/Enemy/General/BaseEnemyMech.h similarity index 80% rename from dScripts/BaseEnemyMech.h rename to dScripts/02_server/Enemy/General/BaseEnemyMech.h index a8955061..133b855e 100644 --- a/dScripts/BaseEnemyMech.h +++ b/dScripts/02_server/Enemy/General/BaseEnemyMech.h @@ -4,7 +4,7 @@ class BaseEnemyMech : public CppScripts::Script { public: - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; void OnDie(Entity* self, Entity* killer) override; protected: LOT qbTurretLOT = 6254; diff --git a/dScripts/02_server/Enemy/General/CMakeLists.txt b/dScripts/02_server/Enemy/General/CMakeLists.txt new file mode 100644 index 00000000..5486d2b0 --- /dev/null +++ b/dScripts/02_server/Enemy/General/CMakeLists.txt @@ -0,0 +1,7 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL + "BaseEnemyMech.cpp" + "BaseEnemyApe.cpp" + "GfApeSmashingQB.cpp" + "TreasureChestDragonServer.cpp" + "EnemyNjBuff.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/General/EnemyNjBuff.cpp b/dScripts/02_server/Enemy/General/EnemyNjBuff.cpp new file mode 100644 index 00000000..07b2d899 --- /dev/null +++ b/dScripts/02_server/Enemy/General/EnemyNjBuff.cpp @@ -0,0 +1,12 @@ +#include "EnemyNjBuff.h" +#include "SkillComponent.h" + +void EnemyNjBuff::OnStartup(Entity* self) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior(1127, 24812, self->GetObjectID(), true); +} diff --git a/dScripts/EnemyNjBuff.h b/dScripts/02_server/Enemy/General/EnemyNjBuff.h similarity index 100% rename from dScripts/EnemyNjBuff.h rename to dScripts/02_server/Enemy/General/EnemyNjBuff.h diff --git a/dScripts/02_server/Enemy/General/GfApeSmashingQB.cpp b/dScripts/02_server/Enemy/General/GfApeSmashingQB.cpp new file mode 100644 index 00000000..5bba6450 --- /dev/null +++ b/dScripts/02_server/Enemy/General/GfApeSmashingQB.cpp @@ -0,0 +1,22 @@ +#include "GfApeSmashingQB.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void GfApeSmashingQB::OnStartup(Entity* self) { + self->SetNetworkVar<LWOOBJID>(u"lootTagOwner", self->GetVar<LWOOBJID>(u"lootTagOwner")); +} + +void GfApeSmashingQB::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "anchorBreakTime") { + self->Smash(); + } +} + +void GfApeSmashingQB::OnRebuildComplete(Entity* self, Entity* target) { + auto* ape = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"ape")); + if (ape != nullptr) { + ape->OnFireEventServerSide(target, "rebuildDone"); + GameMessages::SendPlayAnimation(self, u"smash", 1.7f); + self->AddTimer("anchorBreakTime", 1.0f); + } +} diff --git a/dScripts/02_server/Enemy/General/GfApeSmashingQB.h b/dScripts/02_server/Enemy/General/GfApeSmashingQB.h new file mode 100644 index 00000000..0306c260 --- /dev/null +++ b/dScripts/02_server/Enemy/General/GfApeSmashingQB.h @@ -0,0 +1,8 @@ +# pragma once +#include "CppScripts.h" + +class GfApeSmashingQB : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnRebuildComplete(Entity* self, Entity* target) override; +}; diff --git a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp new file mode 100644 index 00000000..19788677 --- /dev/null +++ b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp @@ -0,0 +1,43 @@ +#include "TreasureChestDragonServer.h" +#include "ScriptedActivityComponent.h" +#include "TeamManager.h" +#include "EntityManager.h" +#include "Loot.h" + +void TreasureChestDragonServer::OnStartup(Entity* self) { + +} + +void TreasureChestDragonServer::OnUse(Entity* self, Entity* user) { + if (self->GetVar<bool>(u"bUsed")) { + return; + } + + self->SetVar<bool>(u"bUsed", true); + + auto* scriptedActivityComponent = self->GetComponent<ScriptedActivityComponent>(); + + if (scriptedActivityComponent == nullptr) { + return; + } + + auto rating = 1; + + auto* team = TeamManager::Instance()->GetTeam(user->GetObjectID()); + + if (team != nullptr) { + rating = team->members.size(); + + for (const auto member : team->members) { + auto* memberObject = EntityManager::Instance()->GetEntity(member); + + if (memberObject == nullptr) continue; + + LootGenerator::Instance().DropActivityLoot(memberObject, self, scriptedActivityComponent->GetActivityID(), rating); + } + } else { + LootGenerator::Instance().DropActivityLoot(user, self, scriptedActivityComponent->GetActivityID(), rating); + } + + self->Smash(self->GetObjectID()); +} diff --git a/dScripts/TreasureChestDragonServer.h b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.h similarity index 100% rename from dScripts/TreasureChestDragonServer.h rename to dScripts/02_server/Enemy/General/TreasureChestDragonServer.h diff --git a/dScripts/02_server/Enemy/Survival/AgSurvivalMech.cpp b/dScripts/02_server/Enemy/Survival/AgSurvivalMech.cpp new file mode 100644 index 00000000..99f40b8b --- /dev/null +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalMech.cpp @@ -0,0 +1,15 @@ +#include "AgSurvivalMech.h" +#include "DestroyableComponent.h" + +void AgSurvivalMech::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + auto* destroyable = self->GetComponent<DestroyableComponent>(); + if (destroyable != nullptr) { + destroyable->SetFaction(4); + } +} + +uint32_t AgSurvivalMech::GetPoints() { + return 200; +} diff --git a/dScripts/AgSurvivalMech.h b/dScripts/02_server/Enemy/Survival/AgSurvivalMech.h similarity index 57% rename from dScripts/AgSurvivalMech.h rename to dScripts/02_server/Enemy/Survival/AgSurvivalMech.h index 8d6ba270..cc972b67 100644 --- a/dScripts/AgSurvivalMech.h +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalMech.h @@ -2,6 +2,6 @@ #include "BaseWavesGenericEnemy.h" class AgSurvivalMech : public BaseWavesGenericEnemy { - void OnStartup(Entity *self) override; - uint32_t GetPoints() override; + void OnStartup(Entity* self) override; + uint32_t GetPoints() override; }; diff --git a/dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.cpp b/dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.cpp new file mode 100644 index 00000000..8e2c173c --- /dev/null +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.cpp @@ -0,0 +1,15 @@ +#include "AgSurvivalSpiderling.h" +#include "BaseCombatAIComponent.h" + +void AgSurvivalSpiderling::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + auto* combatAI = self->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetStunImmune(true); + } +} + +uint32_t AgSurvivalSpiderling::GetPoints() { + return 300; +} diff --git a/dScripts/AgSurvivalSpiderling.h b/dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.h similarity index 58% rename from dScripts/AgSurvivalSpiderling.h rename to dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.h index 2f374563..4aa51024 100644 --- a/dScripts/AgSurvivalSpiderling.h +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalSpiderling.h @@ -2,6 +2,6 @@ #include "BaseWavesGenericEnemy.h" class AgSurvivalSpiderling : public BaseWavesGenericEnemy { - void OnStartup(Entity *self) override; - uint32_t GetPoints() override; + void OnStartup(Entity* self) override; + uint32_t GetPoints() override; }; diff --git a/dScripts/AgSurvivalStromling.cpp b/dScripts/02_server/Enemy/Survival/AgSurvivalStromling.cpp similarity index 83% rename from dScripts/AgSurvivalStromling.cpp rename to dScripts/02_server/Enemy/Survival/AgSurvivalStromling.cpp index bc6a6c74..2f4c6623 100644 --- a/dScripts/AgSurvivalStromling.cpp +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalStromling.cpp @@ -1,5 +1,5 @@ #include "AgSurvivalStromling.h" uint32_t AgSurvivalStromling::GetPoints() { - return 100; + return 100; } diff --git a/dScripts/AgSurvivalStromling.h b/dScripts/02_server/Enemy/Survival/AgSurvivalStromling.h similarity index 76% rename from dScripts/AgSurvivalStromling.h rename to dScripts/02_server/Enemy/Survival/AgSurvivalStromling.h index cfd46a63..e43a603d 100644 --- a/dScripts/AgSurvivalStromling.h +++ b/dScripts/02_server/Enemy/Survival/AgSurvivalStromling.h @@ -2,5 +2,5 @@ #include "BaseWavesGenericEnemy.h" class AgSurvivalStromling : public BaseWavesGenericEnemy { - uint32_t GetPoints() override; + uint32_t GetPoints() override; }; diff --git a/dScripts/02_server/Enemy/Survival/CMakeLists.txt b/dScripts/02_server/Enemy/Survival/CMakeLists.txt new file mode 100644 index 00000000..55236240 --- /dev/null +++ b/dScripts/02_server/Enemy/Survival/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_SURVIVAL + "AgSurvivalStromling.cpp" + "AgSurvivalMech.cpp" + "AgSurvivalSpiderling.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/VE/CMakeLists.txt b/dScripts/02_server/Enemy/VE/CMakeLists.txt new file mode 100644 index 00000000..a1cc39ad --- /dev/null +++ b/dScripts/02_server/Enemy/VE/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_VE + "VeMech.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/VE/VeMech.cpp b/dScripts/02_server/Enemy/VE/VeMech.cpp new file mode 100644 index 00000000..e1ec5674 --- /dev/null +++ b/dScripts/02_server/Enemy/VE/VeMech.cpp @@ -0,0 +1,6 @@ +#include "VeMech.h" + +void VeMech::OnStartup(Entity* self) { + BaseEnemyMech::OnStartup(self); + qbTurretLOT = 8432; +} diff --git a/dScripts/VeMech.h b/dScripts/02_server/Enemy/VE/VeMech.h similarity index 67% rename from dScripts/VeMech.h rename to dScripts/02_server/Enemy/VE/VeMech.h index 5fde6610..0f7c8836 100644 --- a/dScripts/VeMech.h +++ b/dScripts/02_server/Enemy/VE/VeMech.h @@ -3,5 +3,5 @@ class VeMech : public BaseEnemyMech { public: - void OnStartup(Entity *self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/02_server/Enemy/Waves/CMakeLists.txt b/dScripts/02_server/Enemy/Waves/CMakeLists.txt new file mode 100644 index 00000000..a25aca38 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES + "WaveBossHammerling.cpp" + "WaveBossApe.cpp" + "WaveBossSpiderling.cpp" + "WaveBossHorsemen.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Enemy/Waves/WaveBossApe.cpp b/dScripts/02_server/Enemy/Waves/WaveBossApe.cpp new file mode 100644 index 00000000..7c26cec1 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossApe.cpp @@ -0,0 +1,41 @@ +#include "WaveBossApe.h" +#include "BaseCombatAIComponent.h" +#include "Entity.h" + +void WaveBossApe::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + self->SetVar<LOT>(u"QuickbuildAnchorLOT", 12900); + self->SetVar<uint32_t>(u"GroundPoundSkill", 725); + self->SetVar<float_t>(u"reviveTime", 12); + self->SetVar<float_t>(u"AnchorDamageDelayTime", 0.5f); + self->SetVar<float_t>(u"spawnQBTime", 5.0f); + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(true); + combatAIComponent->SetStunImmune(true); + } + + self->AddToGroup("boss"); + + BaseEnemyApe::OnStartup(self); +} + +void WaveBossApe::OnDie(Entity* self, Entity* killer) { + BaseWavesGenericEnemy::OnDie(self, killer); + BaseEnemyApe::OnDie(self, killer); +} + +void WaveBossApe::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "startAI") { + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(false); + combatAIComponent->SetStunImmune(false); + } + } else { + BaseEnemyApe::OnFireEventServerSide(self, sender, args, param1, param2, param3); + } +} diff --git a/dScripts/02_server/Enemy/Waves/WaveBossApe.h b/dScripts/02_server/Enemy/Waves/WaveBossApe.h new file mode 100644 index 00000000..57f07402 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossApe.h @@ -0,0 +1,10 @@ +#include "BaseWavesGenericEnemy.h" +#include "BaseEnemyApe.h" + +class WaveBossApe : public BaseEnemyApe, public BaseWavesGenericEnemy { + uint32_t GetPoints() override { return 5000; } + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Enemy/Waves/WaveBossHammerling.cpp b/dScripts/02_server/Enemy/Waves/WaveBossHammerling.cpp new file mode 100644 index 00000000..4fa78087 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossHammerling.cpp @@ -0,0 +1,25 @@ +#include "WaveBossHammerling.h" +#include "BaseCombatAIComponent.h" +#include "Entity.h" + +void WaveBossHammerling::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(true); + combatAIComponent->SetStunImmune(true); + } + + self->AddToGroup("boss"); +} + +void WaveBossHammerling::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == "startAI") { + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(false); + } + } +} diff --git a/dScripts/02_server/Enemy/Waves/WaveBossHammerling.h b/dScripts/02_server/Enemy/Waves/WaveBossHammerling.h new file mode 100644 index 00000000..64da3647 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossHammerling.h @@ -0,0 +1,9 @@ +#pragma once +#include "BaseWavesGenericEnemy.h" + +class WaveBossHammerling : public BaseWavesGenericEnemy { + void OnStartup(Entity* self) override; + uint32_t GetPoints() override { return 1000; } + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.cpp b/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.cpp new file mode 100644 index 00000000..238544ab --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.cpp @@ -0,0 +1,26 @@ +#include "WaveBossHorsemen.h" +#include "BaseCombatAIComponent.h" +#include "Entity.h" + +void WaveBossHorsemen::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(true); + combatAIComponent->SetStunImmune(true); + } + + self->AddToGroup("boss"); +} + +void +WaveBossHorsemen::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "startAI") { + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(false); + } + } +} diff --git a/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.h b/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.h new file mode 100644 index 00000000..e490ffe4 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossHorsemen.h @@ -0,0 +1,9 @@ +#pragma once +#include "BaseWavesGenericEnemy.h" + +class WaveBossHorsemen : public BaseWavesGenericEnemy { + uint32_t GetPoints() override { return 5000; } + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.cpp b/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.cpp new file mode 100644 index 00000000..ec282ff4 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.cpp @@ -0,0 +1,26 @@ +#include "WaveBossSpiderling.h" +#include "BaseCombatAIComponent.h" +#include "Entity.h" + +void WaveBossSpiderling::OnStartup(Entity* self) { + BaseWavesGenericEnemy::OnStartup(self); + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(true); + combatAIComponent->SetStunImmune(true); + } + + self->AddToGroup("boss"); +} + +void WaveBossSpiderling::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == "startAI") { + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(false); + combatAIComponent->SetStunImmune(false); + } + } +} diff --git a/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.h b/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.h new file mode 100644 index 00000000..906b9d37 --- /dev/null +++ b/dScripts/02_server/Enemy/Waves/WaveBossSpiderling.h @@ -0,0 +1,9 @@ +#pragma once +#include "BaseWavesGenericEnemy.h" + +class WaveBossSpiderling : public BaseWavesGenericEnemy { + uint32_t GetPoints() override { return 5000; } + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Equipment/BootyDigServer.cpp b/dScripts/02_server/Equipment/BootyDigServer.cpp new file mode 100644 index 00000000..190c232b --- /dev/null +++ b/dScripts/02_server/Equipment/BootyDigServer.cpp @@ -0,0 +1,54 @@ +#include "BootyDigServer.h" +#include "EntityManager.h" +#include "RenderComponent.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "Loot.h" + +void BootyDigServer::OnStartup(Entity* self) { + auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); + if (zoneControlObject != nullptr) { + zoneControlObject->OnFireEventServerSide(self, "CheckForPropertyOwner"); + } +} + +void BootyDigServer::OnPlayerLoaded(Entity* self, Entity* player) { + auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); + if (zoneControlObject != nullptr) { + zoneControlObject->OnFireEventServerSide(self, "CheckForPropertyOwner"); + } +} + +void +BootyDigServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + + auto propertyOwner = self->GetNetworkVar<std::string>(u"PropertyOwnerID"); + auto* player = self->GetParentEntity(); + if (player == nullptr) + return; + + if (args == "ChestReady" && (propertyOwner == std::to_string(LWOOBJID_EMPTY) || player->GetVar<bool>(u"bootyDug"))) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } else if (args == "ChestOpened") { + // Make sure players only dig up one booty per instance + player->SetVar<bool>(u"bootyDug", true); + + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + auto* mission = missionComponent->GetMission(1881); + if (mission != nullptr && (mission->GetMissionState() == eMissionState::ACTIVE || mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) { + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) + renderComponent->PlayEffect(7730, u"cast", "bootyshine"); + + LootGenerator::Instance().DropLoot(player, self, 231, 75, 75); + } + } + } else if (args == "ChestDead") { + self->Smash(player->GetObjectID(), eKillType::SILENT); + } +} diff --git a/dScripts/02_server/Equipment/BootyDigServer.h b/dScripts/02_server/Equipment/BootyDigServer.h new file mode 100644 index 00000000..3f73a530 --- /dev/null +++ b/dScripts/02_server/Equipment/BootyDigServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class BootyDigServer : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/02_server/Equipment/CMakeLists.txt b/dScripts/02_server/Equipment/CMakeLists.txt new file mode 100644 index 00000000..d29e7ca7 --- /dev/null +++ b/dScripts/02_server/Equipment/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_02_SERVER_EQUIPMENT + "MaestromExtracticatorServer.cpp" + "BootyDigServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/MaestromExtracticatorServer.cpp b/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp similarity index 77% rename from dScripts/MaestromExtracticatorServer.cpp rename to dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp index a542389f..c01d2362 100644 --- a/dScripts/MaestromExtracticatorServer.cpp +++ b/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp @@ -3,6 +3,7 @@ #include "GeneralUtils.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void MaestromExtracticatorServer::OnStartup(Entity* self) { //self:SetNetworkVar("current_anim", failAnim) @@ -12,8 +13,8 @@ void MaestromExtracticatorServer::OnStartup(Entity* self) { self->AddTimer("RemoveSample", destroyAfterNoSampleTime); } -void MaestromExtracticatorServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { +void MaestromExtracticatorServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { if (sender == nullptr) return; @@ -24,9 +25,9 @@ void MaestromExtracticatorServer::OnFireEventServerSide(Entity *self, Entity *se auto missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, 14718); - CollectSample(self, sender->GetObjectID()); - sender->ScheduleKillAfterUpdate(); + missionComponent->Progress(eMissionTaskType::SMASH, 14718); + CollectSample(self, sender->GetObjectID()); + sender->ScheduleKillAfterUpdate(); } } diff --git a/dScripts/MaestromExtracticatorServer.h b/dScripts/02_server/Equipment/MaestromExtracticatorServer.h similarity index 82% rename from dScripts/MaestromExtracticatorServer.h rename to dScripts/02_server/Equipment/MaestromExtracticatorServer.h index e59628c9..c4adb51e 100644 --- a/dScripts/MaestromExtracticatorServer.h +++ b/dScripts/02_server/Equipment/MaestromExtracticatorServer.h @@ -4,8 +4,8 @@ class MaestromExtracticatorServer : public CppScripts::Script { public: void OnStartup(Entity* self); - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3); + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3); void CollectSample(Entity* self, LWOOBJID sampleObj); void PlayAnimAndReturnTime(Entity* self, std::string animID); void OnTimerDone(Entity* self, std::string timerName); @@ -15,4 +15,4 @@ private: const std::string collectAnim = "collect_maelstrom"; const float defaultTime = 4.0f; const float destroyAfterNoSampleTime = 8.0f; -}; \ No newline at end of file +}; diff --git a/dScripts/02_server/Map/AG/AgBugsprayer.cpp b/dScripts/02_server/Map/AG/AgBugsprayer.cpp new file mode 100644 index 00000000..d4ab7aa3 --- /dev/null +++ b/dScripts/02_server/Map/AG/AgBugsprayer.cpp @@ -0,0 +1,17 @@ +#include "AgBugsprayer.h" +#include "SkillComponent.h" + +void AgBugsprayer::OnRebuildComplete(Entity* self, Entity* target) { + self->AddTimer("castSkill", 1); + self->SetOwnerOverride(target->GetObjectID()); +} + +void AgBugsprayer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "castSkill") { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) return; + + skillComponent->CalculateBehavior(1435, 36581, LWOOBJID_EMPTY); + } +} diff --git a/dScripts/AgBugsprayer.h b/dScripts/02_server/Map/AG/AgBugsprayer.h similarity index 70% rename from dScripts/AgBugsprayer.h rename to dScripts/02_server/Map/AG/AgBugsprayer.h index 711fe708..055feb36 100644 --- a/dScripts/AgBugsprayer.h +++ b/dScripts/02_server/Map/AG/AgBugsprayer.h @@ -5,6 +5,6 @@ class AgBugsprayer : public CppScripts::Script { public: void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; + void OnTimerDone(Entity* self, std::string timerName) override; }; diff --git a/dScripts/AgCagedBricksServer.cpp b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp similarity index 81% rename from dScripts/AgCagedBricksServer.cpp rename to dScripts/02_server/Map/AG/AgCagedBricksServer.cpp index ec9f5306..13c9c04b 100644 --- a/dScripts/AgCagedBricksServer.cpp +++ b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp @@ -3,6 +3,8 @@ #include "GameMessages.h" #include "Character.h" #include "EntityManager.h" +#include "eReplicaComponentType.h" +#include "ePlayerFlag.h" void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { //Tell the client to spawn the baby spiderling: @@ -16,13 +18,12 @@ void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { if (!character) return; - character->SetPlayerFlag(74, true); + character->SetPlayerFlag(ePlayerFlag::CAGED_SPIDER, true); //Remove the maelstrom cube: - auto inv = static_cast<InventoryComponent*>(user->GetComponent(COMPONENT_TYPE_INVENTORY)); - - if (inv) - { + auto inv = static_cast<InventoryComponent*>(user->GetComponent(eReplicaComponentType::INVENTORY)); + + if (inv) { inv->RemoveItem(14553, 1); } } diff --git a/dScripts/AgCagedBricksServer.h b/dScripts/02_server/Map/AG/AgCagedBricksServer.h similarity index 97% rename from dScripts/AgCagedBricksServer.h rename to dScripts/02_server/Map/AG/AgCagedBricksServer.h index 4ec128ac..27ce9e70 100644 --- a/dScripts/AgCagedBricksServer.h +++ b/dScripts/02_server/Map/AG/AgCagedBricksServer.h @@ -3,4 +3,4 @@ class AgCagedBricksServer : public CppScripts::Script { void OnUse(Entity* self, Entity* user); -}; \ No newline at end of file +}; diff --git a/dScripts/AgLaserSensorServer.cpp b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp similarity index 67% rename from dScripts/AgLaserSensorServer.cpp rename to dScripts/02_server/Map/AG/AgLaserSensorServer.cpp index 342cc7e1..703625d2 100644 --- a/dScripts/AgLaserSensorServer.cpp +++ b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp @@ -5,15 +5,17 @@ #include "EntityManager.h" #include "AgMonumentLaserServer.h" #include "EntityManager.h" +#include "ePhysicsEffectType.h" +#include "eReplicaComponentType.h" void AgLaserSensorServer::OnStartup(Entity* self) { - PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); physComp->SetPhysicsEffectActive(true); - physComp->SetEffectType(2); // repulse (prolly should make definitions of these are in Entity.cpp) + physComp->SetEffectType(ePhysicsEffectType::REPULSE); physComp->SetDirectionalMultiplier(static_cast<float>(m_RepelForce)); physComp->SetDirection(NiPoint3::UNIT_Y); - + m_Skill = self->GetComponent<SkillComponent>(); } @@ -25,7 +27,7 @@ void AgLaserSensorServer::OnCollisionPhantom(Entity* self, Entity* target) { Entity* laser = nullptr; - for (auto script : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT)) { + for (auto script : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT)) { AgMonumentLaserServer* hasLaser = (AgMonumentLaserServer*)script; @@ -36,16 +38,13 @@ void AgLaserSensorServer::OnCollisionPhantom(Entity* self, Entity* target) { if (obj == 76690936093053 && Vector3::DistanceSquared(source, NiPoint3(149.007f, 417.083f, 218.346f)) <= 1.0f) { laser = script; break; - } - else if (obj == 75866302318824 && Vector3::DistanceSquared(source, NiPoint3(48.6403f, 403.803f, 196.711f)) <= 1.0f) { + } else if (obj == 75866302318824 && Vector3::DistanceSquared(source, NiPoint3(48.6403f, 403.803f, 196.711f)) <= 1.0f) { laser = script; break; - } - else if (obj == 75866302318822 && Vector3::DistanceSquared(source, NiPoint3(19.2155f, 420.083f, 249.226f)) <= 1.0f) { + } else if (obj == 75866302318822 && Vector3::DistanceSquared(source, NiPoint3(19.2155f, 420.083f, 249.226f)) <= 1.0f) { laser = script; break; - } - else if (obj == 75866302318823 && Vector3::DistanceSquared(source, NiPoint3(-6.61596f, 404.633f, 274.323f)) <= 1.0f) { + } else if (obj == 75866302318823 && Vector3::DistanceSquared(source, NiPoint3(-6.61596f, 404.633f, 274.323f)) <= 1.0f) { laser = script; break; } diff --git a/dScripts/AgLaserSensorServer.h b/dScripts/02_server/Map/AG/AgLaserSensorServer.h similarity index 100% rename from dScripts/AgLaserSensorServer.h rename to dScripts/02_server/Map/AG/AgLaserSensorServer.h diff --git a/dScripts/AgMonumentBirds.cpp b/dScripts/02_server/Map/AG/AgMonumentBirds.cpp similarity index 99% rename from dScripts/AgMonumentBirds.cpp rename to dScripts/02_server/Map/AG/AgMonumentBirds.cpp index 5870cfff..ad3417a4 100644 --- a/dScripts/AgMonumentBirds.cpp +++ b/dScripts/02_server/Map/AG/AgMonumentBirds.cpp @@ -28,6 +28,6 @@ void AgMonumentBirds::OnTimerDone(Entity* self, std::string timerName) { auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"PlayerID")); if (player == nullptr) return; - + self->ScheduleKillAfterUpdate(player); } diff --git a/dScripts/AgMonumentBirds.h b/dScripts/02_server/Map/AG/AgMonumentBirds.h similarity index 100% rename from dScripts/AgMonumentBirds.h rename to dScripts/02_server/Map/AG/AgMonumentBirds.h diff --git a/dScripts/AgMonumentLaserServer.cpp b/dScripts/02_server/Map/AG/AgMonumentLaserServer.cpp similarity index 99% rename from dScripts/AgMonumentLaserServer.cpp rename to dScripts/02_server/Map/AG/AgMonumentLaserServer.cpp index 646ca998..6efda89e 100644 --- a/dScripts/AgMonumentLaserServer.cpp +++ b/dScripts/02_server/Map/AG/AgMonumentLaserServer.cpp @@ -3,7 +3,7 @@ void AgMonumentLaserServer::OnStartup(Entity* self) { /* self->SetProximityRadius(m_Radius, "MonumentLaser"); - + std::cout << "Monument Laser " << self->GetObjectID() << " is at " << self->GetPosition().GetX() << ","<< self->GetPosition().GetY() << "," << self->GetPosition().GetZ() << std::endl; */ diff --git a/dScripts/AgMonumentLaserServer.h b/dScripts/02_server/Map/AG/AgMonumentLaserServer.h similarity index 100% rename from dScripts/AgMonumentLaserServer.h rename to dScripts/02_server/Map/AG/AgMonumentLaserServer.h diff --git a/dScripts/02_server/Map/AG/AgMonumentRaceCancel.cpp b/dScripts/02_server/Map/AG/AgMonumentRaceCancel.cpp new file mode 100644 index 00000000..2e744434 --- /dev/null +++ b/dScripts/02_server/Map/AG/AgMonumentRaceCancel.cpp @@ -0,0 +1,9 @@ +#include "AgMonumentRaceCancel.h" +#include "EntityManager.h" + +void AgMonumentRaceCancel::OnCollisionPhantom(Entity* self, Entity* target) { + auto managers = EntityManager::Instance()->GetEntitiesInGroup("race_manager"); + if (!managers.empty()) { + managers[0]->OnFireEventServerSide(target, "course_cancel"); + } +} diff --git a/dScripts/AgMonumentRaceCancel.h b/dScripts/02_server/Map/AG/AgMonumentRaceCancel.h similarity index 59% rename from dScripts/AgMonumentRaceCancel.h rename to dScripts/02_server/Map/AG/AgMonumentRaceCancel.h index fd324d25..8ddbc5b1 100644 --- a/dScripts/AgMonumentRaceCancel.h +++ b/dScripts/02_server/Map/AG/AgMonumentRaceCancel.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class AgMonumentRaceCancel : public CppScripts::Script { - void OnCollisionPhantom(Entity *self, Entity *target) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; }; diff --git a/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp b/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp new file mode 100644 index 00000000..0dd91bf2 --- /dev/null +++ b/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp @@ -0,0 +1,15 @@ +#include "AgMonumentRaceGoal.h" +#include "EntityManager.h" + + +void AgMonumentRaceGoal::OnStartup(Entity* self) { + self->SetProximityRadius(15, "RaceGoal"); +} + +void AgMonumentRaceGoal::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name == "RaceGoal" && entering && entering->IsPlayer() && status == "ENTER") { + auto managers = EntityManager::Instance()->GetEntitiesInGroup("race_manager"); + if (managers.empty() || !managers.at(0)) return; + managers.at(0)->OnFireEventServerSide(entering, "course_finish"); + } +} diff --git a/dScripts/AgMonumentRaceGoal.h b/dScripts/02_server/Map/AG/AgMonumentRaceGoal.h similarity index 100% rename from dScripts/AgMonumentRaceGoal.h rename to dScripts/02_server/Map/AG/AgMonumentRaceGoal.h diff --git a/dScripts/02_server/Map/AG/CMakeLists.txt b/dScripts/02_server/Map/AG/CMakeLists.txt new file mode 100644 index 00000000..df26dee4 --- /dev/null +++ b/dScripts/02_server/Map/AG/CMakeLists.txt @@ -0,0 +1,16 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_AG + "AgCagedBricksServer.cpp" + "NpcWispServer.cpp" + "NpcEpsilonServer.cpp" + "AgLaserSensorServer.cpp" + "AgMonumentLaserServer.cpp" + "AgMonumentBirds.cpp" + "RemoveRentalGear.cpp" + "NpcNjAssistantServer.cpp" + "AgBugsprayer.cpp" + "NpcAgCourseStarter.cpp" + "AgMonumentRaceGoal.cpp" + "AgMonumentRaceCancel.cpp" + "NpcCowboyServer.cpp" + "NpcPirateServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/NpcAgCourseStarter.cpp b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp similarity index 62% rename from dScripts/NpcAgCourseStarter.cpp rename to dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp index 188186fb..d2cc647e 100644 --- a/dScripts/NpcAgCourseStarter.cpp +++ b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp @@ -3,6 +3,8 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "LeaderboardManager.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include <ctime> @@ -19,8 +21,7 @@ void NpcAgCourseStarter::OnUse(Entity* self, Entity* user) { if (scriptedActivityComponent->GetActivityPlayerData(user->GetObjectID()) != nullptr) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"exit", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); - } - else { + } else { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"start", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); } } @@ -40,8 +41,7 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 scriptedActivityComponent->RemoveActivityPlayerData(sender->GetObjectID()); EntityManager::Instance()->SerializeEntity(self); - } - else if (identifier == u"player_dialog_start_course" && button == 1) { + } else if (identifier == u"player_dialog_start_course" && button == 1) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"start_timer", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); GameMessages::SendActivityStart(self->GetObjectID(), sender->GetSystemAddress()); @@ -55,14 +55,12 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 data->values[1] = *(float*)&startTime; EntityManager::Instance()->SerializeEntity(self); - } - else if (identifier == u"FootRaceCancel") { + } else if (identifier == u"FootRaceCancel") { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stop_timer", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); if (scriptedActivityComponent->GetActivityPlayerData(sender->GetObjectID()) != nullptr) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"exit", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); - } - else { + } else { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"start", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); } @@ -70,43 +68,43 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 } } -void NpcAgCourseStarter::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { +void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { auto* scriptedActivityComponent = self->GetComponent<ScriptedActivityComponent>(); if (scriptedActivityComponent == nullptr) return; auto* data = scriptedActivityComponent->GetActivityPlayerData(sender->GetObjectID()); - if (data == nullptr) - return; + if (data == nullptr) + return; if (args == "course_cancel") { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"cancel_timer", 0, 0, - LWOOBJID_EMPTY, "", sender->GetSystemAddress()); - scriptedActivityComponent->RemoveActivityPlayerData(sender->GetObjectID()); + LWOOBJID_EMPTY, "", sender->GetSystemAddress()); + scriptedActivityComponent->RemoveActivityPlayerData(sender->GetObjectID()); } else if (args == "course_finish") { - time_t endTime = std::time(0); - time_t finish = (endTime - *(time_t *) &data->values[1]); + time_t endTime = std::time(0); + time_t finish = (endTime - *(time_t*)&data->values[1]); - data->values[2] = *(float *) &finish; + data->values[2] = *(float*)&finish; - auto *missionComponent = sender->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->ForceProgressTaskType(1884, 1, 1, false); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, -finish, self->GetObjectID(), - "performact_time"); - } + auto* missionComponent = sender->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->ForceProgressTaskType(1884, 1, 1, false); + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, -finish, self->GetObjectID(), + "performact_time"); + } - EntityManager::Instance()->SerializeEntity(self); - LeaderboardManager::SaveScore(sender->GetObjectID(), scriptedActivityComponent->GetActivityID(), - 0, (uint32_t) finish); + EntityManager::Instance()->SerializeEntity(self); + LeaderboardManager::SaveScore(sender->GetObjectID(), scriptedActivityComponent->GetActivityID(), + 0, (uint32_t)finish); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", - scriptedActivityComponent->GetActivityID(), 0, sender->GetObjectID(), - "", sender->GetSystemAddress()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stop_timer", 1, finish, LWOOBJID_EMPTY, "", - sender->GetSystemAddress()); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", + scriptedActivityComponent->GetActivityID(), 0, sender->GetObjectID(), + "", sender->GetSystemAddress()); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stop_timer", 1, finish, LWOOBJID_EMPTY, "", + sender->GetSystemAddress()); - scriptedActivityComponent->RemoveActivityPlayerData(sender->GetObjectID()); + scriptedActivityComponent->RemoveActivityPlayerData(sender->GetObjectID()); } } diff --git a/dScripts/NpcAgCourseStarter.h b/dScripts/02_server/Map/AG/NpcAgCourseStarter.h similarity index 75% rename from dScripts/NpcAgCourseStarter.h rename to dScripts/02_server/Map/AG/NpcAgCourseStarter.h index bc885a40..eda1fa93 100644 --- a/dScripts/NpcAgCourseStarter.h +++ b/dScripts/02_server/Map/AG/NpcAgCourseStarter.h @@ -8,6 +8,6 @@ class NpcAgCourseStarter : public CppScripts::Script { void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; \ No newline at end of file + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/AG/NpcCowboyServer.cpp b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp new file mode 100644 index 00000000..6dd212a4 --- /dev/null +++ b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp @@ -0,0 +1,26 @@ +#include "NpcCowboyServer.h" +#include "eMissionState.h" +#include "InventoryComponent.h" + +void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID != 1880) { + return; + } + + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + + if (inventoryComponent == nullptr) { + return; + } + + if (missionState == eMissionState::COMPLETE_ACTIVE || + missionState == eMissionState::ACTIVE || + missionState == eMissionState::AVAILABLE || + missionState == eMissionState::COMPLETE_AVAILABLE) { + if (inventoryComponent->GetLotCount(14378) == 0) { + inventoryComponent->AddItem(14378, 1, eLootSourceType::NONE); + } + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + inventoryComponent->RemoveItem(14378, 1); + } +} diff --git a/dScripts/NpcCowboyServer.h b/dScripts/02_server/Map/AG/NpcCowboyServer.h similarity index 77% rename from dScripts/NpcCowboyServer.h rename to dScripts/02_server/Map/AG/NpcCowboyServer.h index e600d798..4493315c 100644 --- a/dScripts/NpcCowboyServer.h +++ b/dScripts/02_server/Map/AG/NpcCowboyServer.h @@ -3,5 +3,5 @@ class NpcCowboyServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/NpcEpsilonServer.cpp b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp similarity index 85% rename from dScripts/NpcEpsilonServer.cpp rename to dScripts/02_server/Map/AG/NpcEpsilonServer.cpp index f6b8f5c4..a928e9d9 100644 --- a/dScripts/NpcEpsilonServer.cpp +++ b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp @@ -1,7 +1,7 @@ #include "NpcEpsilonServer.h" #include "GameMessages.h" -void NpcEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { //If we are completing the Nexus Force join mission, play the celebration for it: if (missionID == 1851) { diff --git a/dScripts/NpcEpsilonServer.h b/dScripts/02_server/Map/AG/NpcEpsilonServer.h similarity index 81% rename from dScripts/NpcEpsilonServer.h rename to dScripts/02_server/Map/AG/NpcEpsilonServer.h index 798da33e..4de76bcd 100644 --- a/dScripts/NpcEpsilonServer.h +++ b/dScripts/02_server/Map/AG/NpcEpsilonServer.h @@ -2,6 +2,6 @@ #include "CppScripts.h" class NpcEpsilonServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); }; diff --git a/dScripts/NpcNjAssistantServer.cpp b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp similarity index 64% rename from dScripts/NpcNjAssistantServer.cpp rename to dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp index b9743756..8ee2e988 100644 --- a/dScripts/NpcNjAssistantServer.cpp +++ b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp @@ -3,26 +3,27 @@ #include "InventoryComponent.h" #include "MissionComponent.h" #include "Item.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" -void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != mailMission) return; - if (missionState == MissionState::MISSION_STATE_COMPLETE || missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionState == eMissionState::COMPLETE || missionState == eMissionState::READY_TO_COMPLETE) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"switch", 0, 0, LWOOBJID_EMPTY, "", target->GetSystemAddress()); - - auto* inv = static_cast<InventoryComponent*>(target->GetComponent(COMPONENT_TYPE_INVENTORY)); - + + auto* inv = static_cast<InventoryComponent*>(target->GetComponent(eReplicaComponentType::INVENTORY)); + // If we are ready to complete our missions, we take the kit from you: - if (inv && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (inv && missionState == eMissionState::READY_TO_COMPLETE) { auto* id = inv->FindItemByLot(14397); //the kit's lot if (id != nullptr) { inv->RemoveItem(id->GetLot(), id->GetCount()); } } - } - else if (missionState == MissionState::MISSION_STATE_AVAILABLE) { - auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); + } else if (missionState == eMissionState::AVAILABLE) { + auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); missionComponent->CompleteMission(mailAchievement, true); } } diff --git a/dScripts/NpcNjAssistantServer.h b/dScripts/02_server/Map/AG/NpcNjAssistantServer.h similarity index 89% rename from dScripts/NpcNjAssistantServer.h rename to dScripts/02_server/Map/AG/NpcNjAssistantServer.h index c8fac54c..1f932752 100644 --- a/dScripts/NpcNjAssistantServer.h +++ b/dScripts/02_server/Map/AG/NpcNjAssistantServer.h @@ -2,9 +2,9 @@ #include "CppScripts.h" class NpcNjAssistantServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); private: int mailMission = 1728; //mission to get the item out of your mailbox int mailAchievement = 1729; // fun fact: spelled "Achivement" in the actual script -}; \ No newline at end of file +}; diff --git a/dScripts/02_server/Map/AG/NpcPirateServer.cpp b/dScripts/02_server/Map/AG/NpcPirateServer.cpp new file mode 100644 index 00000000..cad0d64c --- /dev/null +++ b/dScripts/02_server/Map/AG/NpcPirateServer.cpp @@ -0,0 +1,18 @@ +#include "NpcPirateServer.h" +#include "eMissionState.h" +#include "InventoryComponent.h" + +void NpcPirateServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* inventory = target->GetComponent<InventoryComponent>(); + if (inventory != nullptr && missionID == 1881) { + auto* luckyShovel = inventory->FindItemByLot(14591); + + // Add or remove the lucky shovel based on whether the mission was completed or started + if ((missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE) + && luckyShovel == nullptr) { + inventory->AddItem(14591, 1, eLootSourceType::NONE); + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + inventory->RemoveItem(14591, 1); + } + } +} diff --git a/dScripts/02_server/Map/AG/NpcPirateServer.h b/dScripts/02_server/Map/AG/NpcPirateServer.h new file mode 100644 index 00000000..118aec89 --- /dev/null +++ b/dScripts/02_server/Map/AG/NpcPirateServer.h @@ -0,0 +1,6 @@ +#pragma once +#include "CppScripts.h" + +class NpcPirateServer : public CppScripts::Script { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +}; diff --git a/dScripts/02_server/Map/AG/NpcWispServer.cpp b/dScripts/02_server/Map/AG/NpcWispServer.cpp new file mode 100644 index 00000000..84196c8c --- /dev/null +++ b/dScripts/02_server/Map/AG/NpcWispServer.cpp @@ -0,0 +1,44 @@ +#include "NpcWispServer.h" +#include "InventoryComponent.h" +#include "EntityManager.h" +#include "Entity.h" +#include "GameMessages.h" +#include "eMissionState.h" + +void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID != 1849 && missionID != 1883) + return; + + auto* inventory = target->GetComponent<InventoryComponent>(); + if (inventory == nullptr) + return; + + LOT maelstromVacuumLot = 14592; + auto* maelstromVacuum = inventory->FindItemByLot(maelstromVacuumLot); + + // For the daily we add the maelstrom vacuum if the player doesn't have it yet + if (missionID == 1883 && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE) + && maelstromVacuum == nullptr) { + inventory->AddItem(maelstromVacuumLot, 1, eLootSourceType::NONE); + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + inventory->RemoveItem(maelstromVacuumLot, 1); + } + + // Next up hide or show the samples based on the mission state + auto visible = 1; + if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + visible = 0; + } + + auto groups = missionID == 1849 + ? std::vector<std::string> { "MaelstromSamples" } + : std::vector<std::string>{ "MaelstromSamples", "MaelstromSamples2ndary1", "MaelstromSamples2ndary2" }; + + for (const auto& group : groups) { + auto samples = EntityManager::Instance()->GetEntitiesInGroup(group); + for (auto* sample : samples) { + GameMessages::SendNotifyClientObject(sample->GetObjectID(), u"SetVisibility", visible, 0, + target->GetObjectID(), "", target->GetSystemAddress()); + } + } +} diff --git a/dScripts/NpcWispServer.h b/dScripts/02_server/Map/AG/NpcWispServer.h similarity index 79% rename from dScripts/NpcWispServer.h rename to dScripts/02_server/Map/AG/NpcWispServer.h index 133a9d8f..6eaa09e9 100644 --- a/dScripts/NpcWispServer.h +++ b/dScripts/02_server/Map/AG/NpcWispServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NpcWispServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); -}; \ No newline at end of file + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); +}; diff --git a/dScripts/RemoveRentalGear.cpp b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp similarity index 74% rename from dScripts/RemoveRentalGear.cpp rename to dScripts/02_server/Map/AG/RemoveRentalGear.cpp index 06d964b9..f9bdf1ce 100644 --- a/dScripts/RemoveRentalGear.cpp +++ b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp @@ -1,7 +1,10 @@ #include "RemoveRentalGear.h" #include "InventoryComponent.h" #include "Item.h" +#include "eMissionState.h" #include "Character.h" +#include "eReplicaComponentType.h" +#include "ePlayerFlag.h" /* -------------------------------------------------------------- @@ -16,11 +19,11 @@ -------------------------------------------------------------- */ -void RemoveRentalGear::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void RemoveRentalGear::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != defaultMission && missionID != 313) return; - if (missionState == MissionState::MISSION_STATE_COMPLETE || missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { - auto inv = static_cast<InventoryComponent*>(target->GetComponent(COMPONENT_TYPE_INVENTORY)); + if (missionState == eMissionState::COMPLETE || missionState == eMissionState::READY_TO_COMPLETE) { + auto inv = static_cast<InventoryComponent*>(target->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; //remove the inventory items @@ -34,6 +37,6 @@ void RemoveRentalGear::OnMissionDialogueOK(Entity* self, Entity* target, int mis //reset the equipment flag auto character = target->GetCharacter(); - if (character) character->SetPlayerFlag(equipFlag, false); + if (character) character->SetPlayerFlag(ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR, false); } } diff --git a/dScripts/RemoveRentalGear.h b/dScripts/02_server/Map/AG/RemoveRentalGear.h similarity index 73% rename from dScripts/RemoveRentalGear.h rename to dScripts/02_server/Map/AG/RemoveRentalGear.h index 49ca0860..cf9002d7 100644 --- a/dScripts/RemoveRentalGear.h +++ b/dScripts/02_server/Map/AG/RemoveRentalGear.h @@ -2,11 +2,10 @@ #include "CppScripts.h" class RemoveRentalGear : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); private: int defaultMission = 768; //mission to remove gearSets on completion std::vector<int> gearSets = { 14359,14321,14353,14315 }; //inventory items to remove - int equipFlag = 126; //Set upon wearing trial faction armor for the first time in a session }; diff --git a/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt b/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt new file mode 100644 index 00000000..f4204c13 --- /dev/null +++ b/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_AG_SPIDER_QUEEN + "ZoneAgSpiderQueen.cpp" + "SpiderBossTreasureChestServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/SpiderBossTreasureChestServer.cpp b/dScripts/02_server/Map/AG_Spider_Queen/SpiderBossTreasureChestServer.cpp similarity index 100% rename from dScripts/SpiderBossTreasureChestServer.cpp rename to dScripts/02_server/Map/AG_Spider_Queen/SpiderBossTreasureChestServer.cpp diff --git a/dScripts/SpiderBossTreasureChestServer.h b/dScripts/02_server/Map/AG_Spider_Queen/SpiderBossTreasureChestServer.h similarity index 100% rename from dScripts/SpiderBossTreasureChestServer.h rename to dScripts/02_server/Map/AG_Spider_Queen/SpiderBossTreasureChestServer.h diff --git a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp new file mode 100644 index 00000000..2711b179 --- /dev/null +++ b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp @@ -0,0 +1,84 @@ +#include "ZoneAgSpiderQueen.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "ZoneAgProperty.h" +#include "DestroyableComponent.h" +#include "EntityInfo.h" + +void ZoneAgSpiderQueen::SetGameVariables(Entity* self) { + ZoneAgProperty::SetGameVariables(self); + + // Disable property flags + self->SetVar<int32_t>(defeatedProperyFlag, 0); + self->SetVar<int32_t>(placedModelFlag, 0); + self->SetVar<uint32_t>(guardFirstMissionFlag, 0); + self->SetVar<uint32_t>(guardMissionFlag, 0); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 0); +} + +void ZoneAgSpiderQueen::OnStartup(Entity* self) { + LoadInstance(self); + + SpawnSpots(self); + StartMaelstrom(self, nullptr); +} + +void ZoneAgSpiderQueen::BasePlayerLoaded(Entity* self, Entity* player) { + ActivityManager::UpdatePlayer(self, player->GetObjectID()); + ActivityManager::TakeActivityCost(self, player->GetObjectID()); + + // Make sure the player has full stats when they join + auto* playerDestroyableComponent = player->GetComponent<DestroyableComponent>(); + if (playerDestroyableComponent != nullptr) { + playerDestroyableComponent->SetImagination(playerDestroyableComponent->GetMaxImagination()); + playerDestroyableComponent->SetArmor(playerDestroyableComponent->GetMaxArmor()); + playerDestroyableComponent->SetHealth(playerDestroyableComponent->GetMaxHealth()); + } + + self->SetNetworkVar(u"unclaimed", true); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, + "", player->GetSystemAddress()); +} + +void +ZoneAgSpiderQueen::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "ClearProperty") { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, + LWOOBJID_EMPTY, destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); + self->AddTimer("tornadoOff", 0.5f); + } else { + ZoneAgProperty::BaseOnFireEventServerSide(self, sender, args); + } +} + +void ZoneAgSpiderQueen::OnPlayerExit(Entity* self, Entity* player) { + UpdatePlayer(self, player->GetObjectID(), true); +} + +void ZoneAgSpiderQueen::OnTimerDone(Entity* self, std::string timerName) { + + // Disable some stuff from the regular property + if (timerName == "BoundsVisOn" || timerName == "GuardFlyAway" || timerName == "ShowVendor") + return; + + if (timerName == "killSpider") { + auto spawnTargets = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(LandTargetGroup)); + for (auto* spawnTarget : spawnTargets) { + EntityInfo info{}; + + info.spawnerID = spawnTarget->GetObjectID(); + info.pos = spawnTarget->GetPosition(); + info.rot = spawnTarget->GetRotation(); + info.lot = chestObject; + info.settings = { + new LDFData<LWOOBJID>(u"parent_tag", self->GetObjectID()) + }; + + auto* chest = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(chest); + } + } + + ZoneAgProperty::BaseTimerDone(self, timerName); +} diff --git a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.h b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.h new file mode 100644 index 00000000..d7ab1d71 --- /dev/null +++ b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.h @@ -0,0 +1,17 @@ +#pragma once +#include "ActivityManager.h" +#include "ZoneAgProperty.h" + +class ZoneAgSpiderQueen : ZoneAgProperty, ActivityManager { +public: + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnPlayerExit(Entity* self, Entity* player) override; + void BasePlayerLoaded(Entity* self, Entity* player) override; + void SetGameVariables(Entity* self) override; +protected: + std::string destroyedCinematic = "DesMaelstromInstance"; + const LOT chestObject = 16318; +}; diff --git a/dScripts/02_server/Map/AM/AmBlueX.cpp b/dScripts/02_server/Map/AM/AmBlueX.cpp new file mode 100644 index 00000000..312cdc47 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmBlueX.cpp @@ -0,0 +1,56 @@ +#include "AmBlueX.h" +#include "SkillComponent.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "Character.h" + +void AmBlueX::OnUse(Entity* self, Entity* user) { + auto* skillComponent = user->GetComponent<SkillComponent>(); + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(m_SwordSkill, m_SwordBehavior, self->GetObjectID()); + } +} + +void AmBlueX::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message == "FireDukesStrike") { + self->SetNetworkVar<bool>(m_XUsedVariable, true); + self->SetNetworkVar<bool>(m_StartEffectVariable, true); + + auto* character = caster->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(self->GetVar<uint32_t>(m_FlagVariable), true); + } + + EntityInfo info{}; + info.lot = m_FXObject; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.spawnerID = self->GetObjectID(); + + auto* fxObject = EntityManager::Instance()->CreateEntity(info, nullptr, self); + EntityManager::Instance()->ConstructEntity(fxObject); + + auto fxObjectID = fxObject->GetObjectID(); + auto playerID = caster->GetObjectID(); + + // Add a callback for the bomb to explode + self->AddCallbackTimer(m_BombTime, [this, self, fxObjectID, playerID]() { + auto* fxObject = EntityManager::Instance()->GetEntity(fxObjectID); + auto* player = EntityManager::Instance()->GetEntity(playerID); + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) + return; + + // Cast the skill that destroys the object + if (player != nullptr) { + skillComponent->CalculateBehavior(m_AOESkill, m_AOEBehavior, LWOOBJID_EMPTY, false, false, playerID); + } else { + skillComponent->CalculateBehavior(m_AOESkill, m_AOEBehavior, LWOOBJID_EMPTY); + } + + fxObject->Smash(); + self->Smash(); + }); + } +} diff --git a/dScripts/02_server/Map/AM/AmBlueX.h b/dScripts/02_server/Map/AM/AmBlueX.h new file mode 100644 index 00000000..79428514 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmBlueX.h @@ -0,0 +1,20 @@ +#pragma once +#include "CppScripts.h" + +class AmBlueX : public CppScripts::Script { + void OnUse(Entity* self, Entity* user) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; +private: + const float_t m_BombTime = 3.3f; + const uint32_t m_MissionID = 1448; + const uint32_t m_SwordSkill = 1259; + const uint32_t m_SwordBehavior = 29305; + const uint32_t m_AOESkill = 1258; + const uint32_t m_AOEBehavior = 29301; + const LOT m_FXObject = 13808; + + // Variables + const std::u16string m_XUsedVariable = u"XUsed"; + const std::u16string m_FlagVariable = u"flag"; + const std::u16string m_StartEffectVariable = u"startEffect"; +}; diff --git a/dScripts/02_server/Map/AM/AmBridge.cpp b/dScripts/02_server/Map/AM/AmBridge.cpp new file mode 100644 index 00000000..719ca058 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmBridge.cpp @@ -0,0 +1,28 @@ +#include "AmBridge.h" +#include "EntityManager.h" + +void AmBridge::OnStartup(Entity* self) { + +} + +void AmBridge::OnRebuildComplete(Entity* self, Entity* target) { + const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console" + GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"bridge"))); + + if (consoles.empty()) { + return; + } + + auto* console = consoles[0]; + + console->NotifyObject(self, "BridgeBuilt"); + + self->AddTimer("SmashBridge", 50); +} + +void AmBridge::OnTimerDone(Entity* self, std::string timerName) { + if (timerName != "SmashBridge") { + return; + } + + self->Smash(self->GetObjectID(), eKillType::VIOLENT); +} diff --git a/dScripts/02_server/Map/AM/AmBridge.h b/dScripts/02_server/Map/AM/AmBridge.h new file mode 100644 index 00000000..0dc025f9 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmBridge.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class AmBridge : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/AM/AmConsoleTeleportServer.cpp b/dScripts/02_server/Map/AM/AmConsoleTeleportServer.cpp new file mode 100644 index 00000000..f3931e0d --- /dev/null +++ b/dScripts/02_server/Map/AM/AmConsoleTeleportServer.cpp @@ -0,0 +1,30 @@ +#include "AmConsoleTeleportServer.h" +#include "ChooseYourDestinationNsToNt.h" +#include "AMFFormat.h" + +void AmConsoleTeleportServer::OnStartup(Entity* self) { + self->SetVar(u"teleportAnim", m_TeleportAnim); + self->SetVar(u"teleportString", m_TeleportString); + self->SetVar(u"teleportEffectID", m_TeleportEffectID); + self->SetVar(u"teleportEffectTypes", m_TeleportEffectTypes); +} + +void AmConsoleTeleportServer::OnUse(Entity* self, Entity* user) { + BaseOnUse(self, user); +} + +void AmConsoleTeleportServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + BaseOnMessageBoxResponse(self, sender, button, identifier, userData); +} + +void AmConsoleTeleportServer::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { + +} + +void AmConsoleTeleportServer::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); +} + +void AmConsoleTeleportServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); +} diff --git a/dScripts/02_server/Map/AM/AmConsoleTeleportServer.h b/dScripts/02_server/Map/AM/AmConsoleTeleportServer.h new file mode 100644 index 00000000..6206f22c --- /dev/null +++ b/dScripts/02_server/Map/AM/AmConsoleTeleportServer.h @@ -0,0 +1,22 @@ +#pragma once +#include "CppScripts.h" +#include "BaseConsoleTeleportServer.h" + +class AmConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; + void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + +private: + int32_t m_ChoiceZoneID = 1900; + std::string m_SpawnPoint = "NS_LW"; + std::u16string m_TeleportAnim = u"nexus-teleport"; + std::u16string m_TeleportString = u"UI_TRAVEL_TO_NEXUS_TOWER"; + int32_t m_TeleportEffectID = 6478; + std::vector<std::u16string> m_TeleportEffectTypes = { u"teleportRings", u"teleportBeam" }; +}; diff --git a/dScripts/02_server/Map/AM/AmDrawBridge.cpp b/dScripts/02_server/Map/AM/AmDrawBridge.cpp new file mode 100644 index 00000000..3c4dcce6 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmDrawBridge.cpp @@ -0,0 +1,122 @@ +#include "AmDrawBridge.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "SimplePhysicsComponent.h" +#include "eTerminateType.h" + +void AmDrawBridge::OnStartup(Entity* self) { + self->SetNetworkVar(u"InUse", false); + self->SetVar(u"BridgeDown", false); +} + +void AmDrawBridge::OnUse(Entity* self, Entity* user) { + auto* bridge = GetBridge(self); + + if (bridge == nullptr) { + return; + } + + if (!self->GetNetworkVar<bool>(u"InUse")) { + self->SetNetworkVar(u"startEffect", 5); + + self->AddTimer("ChangeBridge", 5); + + self->SetNetworkVar(u"InUse", true); + } + + auto* player = user; + + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} + +void AmDrawBridge::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "ChangeBridge") { + auto* bridge = GetBridge(self); + + if (bridge == nullptr) { + return; + } + + if (!self->GetVar<bool>(u"BridgeDown")) { + self->SetVar(u"BridgeDown", true); + + MoveBridgeDown(self, bridge, true); + } else { + self->SetVar(u"BridgeDown", false); + + MoveBridgeDown(self, bridge, false); + } + + self->SetNetworkVar(u"BridgeLeaving", true); + self->SetVar(u"BridgeDown", false); + } else if (timerName == "SmashEffectBridge") { + self->SetNetworkVar(u"SmashBridge", 5); + } else if (timerName == "rotateBridgeDown") { + auto* bridge = GetBridge(self); + + if (bridge == nullptr) { + return; + } + + self->SetNetworkVar(u"BridgeLeaving", false); + + auto* simplePhysicsComponent = bridge->GetComponent<SimplePhysicsComponent>(); + + if (simplePhysicsComponent == nullptr) { + return; + } + + simplePhysicsComponent->SetAngularVelocity(NiPoint3::ZERO); + + EntityManager::Instance()->SerializeEntity(bridge); + } +} + +void AmDrawBridge::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "BridgeBuilt") { + self->SetVar(u"BridgeID", sender->GetObjectID()); + + self->AddTimer("SmashEffectBridge", 45); + + self->SetNetworkVar(u"BridgeDead", true); + + sender->AddDieCallback([this, self, sender]() { + NotifyDie(self, sender); + }); + } +} + +void AmDrawBridge::MoveBridgeDown(Entity* self, Entity* bridge, bool down) { + auto* simplePhysicsComponent = bridge->GetComponent<SimplePhysicsComponent>(); + + if (simplePhysicsComponent == nullptr) { + return; + } + + auto forwardVect = simplePhysicsComponent->GetRotation().GetForwardVector(); + + auto degrees = down ? 90.0f : -90.0f; + + const auto travelTime = 2.0f; + + forwardVect = forwardVect * (float)((degrees / travelTime) * (3.14f / 180.0f)); + + simplePhysicsComponent->SetAngularVelocity(forwardVect); + + EntityManager::Instance()->SerializeEntity(bridge); + + self->AddTimer("rotateBridgeDown", travelTime); +} + +void AmDrawBridge::NotifyDie(Entity* self, Entity* other) { + self->SetNetworkVar(u"InUse", false); + self->SetVar(u"BridgeDown", false); + + self->CancelAllTimers(); +} + +Entity* AmDrawBridge::GetBridge(Entity* self) { + const auto bridgeID = self->GetVar<LWOOBJID>(u"BridgeID"); + + return EntityManager::Instance()->GetEntity(bridgeID); +} diff --git a/dScripts/02_server/Map/AM/AmDrawBridge.h b/dScripts/02_server/Map/AM/AmDrawBridge.h new file mode 100644 index 00000000..86237b7f --- /dev/null +++ b/dScripts/02_server/Map/AM/AmDrawBridge.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class AmDrawBridge : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; + + void MoveBridgeDown(Entity* self, Entity* bridge, bool down); + void NotifyDie(Entity* self, Entity* other); + + Entity* GetBridge(Entity* self); +}; diff --git a/dScripts/02_server/Map/AM/AmDropshipComputer.cpp b/dScripts/02_server/Map/AM/AmDropshipComputer.cpp new file mode 100644 index 00000000..f23fa93f --- /dev/null +++ b/dScripts/02_server/Map/AM/AmDropshipComputer.cpp @@ -0,0 +1,82 @@ +#include "AmDropshipComputer.h" +#include "MissionComponent.h" +#include "RebuildComponent.h" +#include "InventoryComponent.h" +#include "dZoneManager.h" +#include "eMissionState.h" + +void AmDropshipComputer::OnStartup(Entity* self) { + self->AddTimer("reset", 45.0f); +} + +void AmDropshipComputer::OnUse(Entity* self, Entity* user) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent == nullptr || rebuildComponent->GetState() != eRebuildState::COMPLETED) { + return; + } + + auto* missionComponent = user->GetComponent<MissionComponent>(); + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + + if (missionComponent == nullptr || inventoryComponent == nullptr) { + return; + } + + if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == eMissionState::COMPLETE) { + return; + } + + inventoryComponent->AddItem(m_NexusTalonDataCard, 1, eLootSourceType::NONE); +} + +void AmDropshipComputer::OnDie(Entity* self, Entity* killer) { + const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); + + int32_t pipeNum = 0; + if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) { + return; + } + + const auto pipeGroup = myGroup.substr(0, 10); + + const auto nextPipeNum = pipeNum + 1; + + const auto samePipeSpawners = dZoneManager::Instance()->GetSpawnersByName(myGroup); + + if (!samePipeSpawners.empty()) { + samePipeSpawners[0]->SoftReset(); + + samePipeSpawners[0]->Deactivate(); + } + + if (killer != nullptr && killer->IsPlayer()) { + const auto nextPipe = pipeGroup + std::to_string(nextPipeNum); + + const auto nextPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); + + if (!nextPipeSpawners.empty()) { + nextPipeSpawners[0]->Activate(); + } + } else { + const auto nextPipe = pipeGroup + "1"; + + const auto firstPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); + + if (!firstPipeSpawners.empty()) { + firstPipeSpawners[0]->Activate(); + } + } +} + +void AmDropshipComputer::OnTimerDone(Entity* self, std::string timerName) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent == nullptr) { + return; + } + + if (timerName == "reset" && rebuildComponent->GetState() == eRebuildState::OPEN) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } +} diff --git a/dScripts/02_server/Map/AM/AmDropshipComputer.h b/dScripts/02_server/Map/AM/AmDropshipComputer.h new file mode 100644 index 00000000..730f2222 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmDropshipComputer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class AmDropshipComputer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnDie(Entity* self, Entity* killer) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT m_NexusTalonDataCard = 12323; +}; diff --git a/dScripts/02_server/Map/AM/AmScrollReaderServer.cpp b/dScripts/02_server/Map/AM/AmScrollReaderServer.cpp new file mode 100644 index 00000000..cb8a7dba --- /dev/null +++ b/dScripts/02_server/Map/AM/AmScrollReaderServer.cpp @@ -0,0 +1,14 @@ +#include "AmScrollReaderServer.h" +#include "MissionComponent.h" + +void AmScrollReaderServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + if (identifier == u"story_end") { + auto* missionComponent = sender->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + return; + } + + missionComponent->ForceProgressTaskType(969, 1, 1, false); + } +} diff --git a/dScripts/02_server/Map/AM/AmScrollReaderServer.h b/dScripts/02_server/Map/AM/AmScrollReaderServer.h new file mode 100644 index 00000000..f00e29e0 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmScrollReaderServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class AmScrollReaderServer : public CppScripts::Script +{ +public: + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; +}; diff --git a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp new file mode 100644 index 00000000..5d1b7d08 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp @@ -0,0 +1,145 @@ +#include "AmShieldGenerator.h" +#include "EntityManager.h" +#include "DestroyableComponent.h" +#include "GameMessages.h" +#include "EntityInfo.h" +#include "MovementAIComponent.h" +#include "BaseCombatAIComponent.h" +#include "SkillComponent.h" + +void AmShieldGenerator::OnStartup(Entity* self) { + self->SetProximityRadius(20, "shield"); + self->SetProximityRadius(21, "buffer"); + + StartShield(self); +} + +void AmShieldGenerator::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + auto* destroyableComponent = entering->GetComponent<DestroyableComponent>(); + + if (status == "ENTER" && name == "shield") { + if (destroyableComponent->HasFaction(4)) { + EnemyEnteredShield(self, entering); + } + } + + if (name != "buffer" || !entering->IsPlayer()) { + return; + } + + auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + if (status == "ENTER") { + const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); + + if (iter == entitiesInProximity.end()) { + entitiesInProximity.push_back(entering->GetObjectID()); + } + } else if (status == "LEAVE") { + const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); + + if (iter != entitiesInProximity.end()) { + entitiesInProximity.erase(iter); + } + } + + self->SetVar<std::vector<LWOOBJID>>(u"Players", entitiesInProximity); +} + +void AmShieldGenerator::OnDie(Entity* self, Entity* killer) { + self->CancelAllTimers(); + + auto* child = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Child")); + + if (child != nullptr) { + child->Kill(); + } +} + +void AmShieldGenerator::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "BuffPlayers") { + BuffPlayers(self); + + self->AddTimer("BuffPlayers", 3.0f); + } else if (timerName == "PlayFX") { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); + + self->AddTimer("PlayFX", 1.5f); + } else if (timerName == "RefreshEnemies") { + auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); + + for (const auto enemyID : enemiesInProximity) { + auto* enemy = EntityManager::Instance()->GetEntity(enemyID); + + if (enemy != nullptr) { + EnemyEnteredShield(self, enemy); + } + } + + self->AddTimer("RefreshEnemies", 1.5f); + } +} + +void AmShieldGenerator::StartShield(Entity* self) { + self->AddTimer("PlayFX", 1.5f); + self->AddTimer("BuffPlayers", 3.0f); + self->AddTimer("RefreshEnemies", 1.5f); + + const auto myPos = self->GetPosition(); + const auto myRot = self->GetRotation(); + + EntityInfo info{}; + info.lot = 13111; + info.pos = myPos; + info.rot = myRot; + info.spawnerID = self->GetObjectID(); + + auto* child = EntityManager::Instance()->CreateEntity(info); + + self->SetVar(u"Child", child->GetObjectID()); + + BuffPlayers(self); +} + +void AmShieldGenerator::BuffPlayers(Entity* self) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + for (const auto playerID : entitiesInProximity) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + skillComponent->CalculateBehavior(1200, 27024, playerID, true); + } +} + +void AmShieldGenerator::EnemyEnteredShield(Entity* self, Entity* intruder) { + auto* baseCombatAIComponent = intruder->GetComponent<BaseCombatAIComponent>(); + auto* movementAIComponent = intruder->GetComponent<MovementAIComponent>(); + + if (baseCombatAIComponent == nullptr || movementAIComponent == nullptr) { + return; + } + + auto dir = intruder->GetRotation().GetForwardVector() * -1; + dir.y += 15; + dir.x *= 50; + dir.z *= 50; + + // TODO: Figure out how todo knockback, I'll stun them for now + + if (NiPoint3::DistanceSquared(self->GetPosition(), movementAIComponent->GetCurrentPosition()) < 20 * 20) { + baseCombatAIComponent->Stun(2.0f); + movementAIComponent->SetDestination(baseCombatAIComponent->GetStartPosition()); + } + + baseCombatAIComponent->ClearThreat(); +} diff --git a/dScripts/02_server/Map/AM/AmShieldGenerator.h b/dScripts/02_server/Map/AM/AmShieldGenerator.h new file mode 100644 index 00000000..9b46f021 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmShieldGenerator.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +class AmShieldGenerator : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnDie(Entity* self, Entity* killer) override; + void OnTimerDone(Entity* self, std::string timerName) override; + + void StartShield(Entity* self); + void BuffPlayers(Entity* self); + void EnemyEnteredShield(Entity* self, Entity* intruder); +}; diff --git a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp new file mode 100644 index 00000000..381c13bc --- /dev/null +++ b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp @@ -0,0 +1,203 @@ +#include "AmShieldGeneratorQuickbuild.h" +#include "EntityManager.h" +#include "DestroyableComponent.h" +#include "GameMessages.h" +#include "MovementAIComponent.h" +#include "BaseCombatAIComponent.h" +#include "SkillComponent.h" +#include "EntityInfo.h" +#include "RebuildComponent.h" +#include "MissionComponent.h" + +void AmShieldGeneratorQuickbuild::OnStartup(Entity* self) { + self->SetProximityRadius(20, "shield"); + self->SetProximityRadius(21, "buffer"); +} + +void AmShieldGeneratorQuickbuild::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + auto* destroyableComponent = entering->GetComponent<DestroyableComponent>(); + + if (name == "shield") { + if (!destroyableComponent->HasFaction(4) || entering->IsPlayer()) { + return; + } + + auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); + + if (status == "ENTER") { + EnemyEnteredShield(self, entering); + + const auto& iter = std::find(enemiesInProximity.begin(), enemiesInProximity.end(), entering->GetObjectID()); + + if (iter == enemiesInProximity.end()) { + enemiesInProximity.push_back(entering->GetObjectID()); + } + } else if (status == "LEAVE") { + const auto& iter = std::find(enemiesInProximity.begin(), enemiesInProximity.end(), entering->GetObjectID()); + + if (iter != enemiesInProximity.end()) { + enemiesInProximity.erase(iter); + } + } + + self->SetVar<std::vector<LWOOBJID>>(u"Enemies", enemiesInProximity); + } + + if (name != "buffer" || !entering->IsPlayer()) { + return; + } + + auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + if (status == "ENTER") { + const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); + + if (iter == entitiesInProximity.end()) { + entitiesInProximity.push_back(entering->GetObjectID()); + } + } else if (status == "LEAVE") { + const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); + + if (iter != entitiesInProximity.end()) { + entitiesInProximity.erase(iter); + } + } + + self->SetVar<std::vector<LWOOBJID>>(u"Players", entitiesInProximity); +} + +void AmShieldGeneratorQuickbuild::OnDie(Entity* self, Entity* killer) { + self->CancelAllTimers(); + + auto* child = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Child")); + + if (child != nullptr) { + child->Kill(); + } +} + +void AmShieldGeneratorQuickbuild::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "BuffPlayers") { + BuffPlayers(self); + + self->AddTimer("BuffPlayers", 3.0f); + } else if (timerName == "PlayFX") { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); + + self->AddTimer("PlayFX", 1.5f); + } else if (timerName == "RefreshEnemies") { + auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); + + for (const auto enemyID : enemiesInProximity) { + auto* enemy = EntityManager::Instance()->GetEntity(enemyID); + + if (enemy != nullptr) { + EnemyEnteredShield(self, enemy); + } + } + + self->AddTimer("RefreshEnemies", 1.5f); + } +} + +void AmShieldGeneratorQuickbuild::OnRebuildComplete(Entity* self, Entity* target) { + StartShield(self); + + auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); + + for (const auto enemyID : enemiesInProximity) { + auto* enemy = EntityManager::Instance()->GetEntity(enemyID); + + if (enemy != nullptr) { + enemy->Smash(); + } + } + + auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + for (const auto playerID : entitiesInProximity) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + continue; + } + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + return; + } + + missionComponent->ForceProgressTaskType(987, 1, 1, false); + } +} + +void AmShieldGeneratorQuickbuild::StartShield(Entity* self) { + self->AddTimer("PlayFX", 1.5f); + self->AddTimer("BuffPlayers", 3.0f); + self->AddTimer("RefreshEnemies", 1.5f); + + const auto myPos = self->GetPosition(); + const auto myRot = self->GetRotation(); + + EntityInfo info{}; + info.lot = 13111; + info.pos = myPos; + info.rot = myRot; + info.spawnerID = self->GetObjectID(); + + auto* child = EntityManager::Instance()->CreateEntity(info); + + self->SetVar(u"Child", child->GetObjectID()); + + BuffPlayers(self); +} + +void AmShieldGeneratorQuickbuild::BuffPlayers(Entity* self) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + for (const auto playerID : entitiesInProximity) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + skillComponent->CalculateBehavior(1200, 27024, playerID, true); + } +} + +void AmShieldGeneratorQuickbuild::EnemyEnteredShield(Entity* self, Entity* intruder) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent == nullptr || rebuildComponent->GetState() != eRebuildState::COMPLETED) { + return; + } + + auto* baseCombatAIComponent = intruder->GetComponent<BaseCombatAIComponent>(); + auto* movementAIComponent = intruder->GetComponent<MovementAIComponent>(); + + if (baseCombatAIComponent == nullptr || movementAIComponent == nullptr) { + return; + } + + auto dir = intruder->GetRotation().GetForwardVector() * -1; + dir.y += 15; + dir.x *= 50; + dir.z *= 50; + + // TODO: Figure out how todo knockback, I'll stun them for now + + if (NiPoint3::DistanceSquared(self->GetPosition(), movementAIComponent->GetCurrentPosition()) < 20 * 20) { + baseCombatAIComponent->Stun(2.0f); + movementAIComponent->SetDestination(baseCombatAIComponent->GetStartPosition()); + } + + baseCombatAIComponent->ClearThreat(); +} diff --git a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.h b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.h new file mode 100644 index 00000000..2aef6926 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class AmShieldGeneratorQuickbuild : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnDie(Entity* self, Entity* killer) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + + void StartShield(Entity* self); + void BuffPlayers(Entity* self); + void EnemyEnteredShield(Entity* self, Entity* intruder); +}; diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp new file mode 100644 index 00000000..d26218a2 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp @@ -0,0 +1,325 @@ +#include "AmSkullkinDrill.h" +#include "GameMessages.h" +#include "MovingPlatformComponent.h" +#include "DestroyableComponent.h" +#include "ProximityMonitorComponent.h" +#include "MissionComponent.h" +#include "EntityInfo.h" +#include "eStateChangeType.h" + +void AmSkullkinDrill::OnStartup(Entity* self) { + self->SetNetworkVar(u"bIsInUse", false); + self->SetVar(u"bActive", true); + + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); + + auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatformComponent == nullptr) { + return; + } + + movingPlatformComponent->SetSerialized(true); + + movingPlatformComponent->GotoWaypoint(0); + + auto* standObj = GetStandObj(self); + + if (standObj != nullptr) { + standObj->SetVar(u"bActive", true); + } + + self->SetProximityRadius(5, "spin_distance"); +} + +Entity* AmSkullkinDrill::GetStandObj(Entity* self) { + const auto& myGroup = self->GetGroups(); + + if (myGroup.empty()) { + return nullptr; + } + + std::string groupName = "Drill_Stand_"; + + groupName.push_back(myGroup[0][myGroup[0].size() - 1]); + + const auto standObjs = EntityManager::Instance()->GetEntitiesInGroup(groupName); + + if (standObjs.empty()) { + return nullptr; + } + + return standObjs[0]; +} + +void AmSkullkinDrill::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message != "NinjagoSpinEvent" || self->GetNetworkVar<bool>(u"bIsInUse")) { + return; + } + + auto* proximityMonitorComponent = self->GetComponent<ProximityMonitorComponent>(); + + if (proximityMonitorComponent == nullptr || !proximityMonitorComponent->IsInProximity("spin_distance", caster->GetObjectID())) { + return; + } + + self->SetVar(u"activaterID", caster->GetObjectID()); + + self->SetNetworkVar(u"bIsInUse", true); + + TriggerDrill(self); +} + +void AmSkullkinDrill::TriggerDrill(Entity* self) { + GameMessages::SendPlayAnimation(self, u"slowdown"); + + self->AddTimer("killDrill", 10.0f); + + auto* standObj = GetStandObj(self); + + if (standObj != nullptr) { + standObj->SetVar(u"bActive", false); + } + + auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatformComponent == nullptr) { + return; + } + + movingPlatformComponent->GotoWaypoint(1); +} + +void AmSkullkinDrill::OnWaypointReached(Entity* self, uint32_t waypointIndex) { + if (waypointIndex == 1) { + auto myPos = self->GetPosition(); + auto myRot = self->GetRotation(); + + myPos.y -= 21; + + EntityInfo info = {}; + info.lot = 12346; + info.pos = myPos; + info.rot = myRot; + info.scale = 3; // Needs the scale, otherwise attacks fail + info.spawnerID = self->GetObjectID(); + + auto* child = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(child); + + self->SetVar(u"ChildSmash", child->GetObjectID()); + + child->AddDieCallback([this, self]() { + const auto& userID = self->GetVar<LWOOBJID>(u"activaterID"); + + auto* player = EntityManager::Instance()->GetEntity(userID); + + if (player == nullptr) { + return; + } + + OnHitOrHealResult(self, player, 1); + }); + } + + OnArrived(self, waypointIndex); +} + +void AmSkullkinDrill::OnUse(Entity* self, Entity* user) { + if (self->GetNetworkVar<bool>(u"bIsInUse")) { + return; + } + + self->SetNetworkVar(u"bIsInUse", true); + + GameMessages::SendPlayFXEffect(user->GetObjectID(), 5499, u"on-anim", "tornado"); + GameMessages::SendPlayFXEffect(user->GetObjectID(), 5502, u"on-anim", "staff"); + + const auto userID = user->GetObjectID(); + + self->SetVar(u"userID", userID); + self->SetVar(u"activaterID", userID); + + PlayAnim(self, user, "spinjitzu-staff-windup"); + PlayCinematic(self); + + FreezePlayer(self, user, true); +} + +void AmSkullkinDrill::FreezePlayer(Entity* self, Entity* player, bool bFreeze) { + auto StateChangeType = eStateChangeType::POP; + + if (bFreeze) { + if (player->GetIsDead()) { + return; + } + + StateChangeType = eStateChangeType::PUSH; + } else { + if (player->GetIsDead()) { + // + } + } + + GameMessages::SendSetStunned(player->GetObjectID(), StateChangeType, player->GetSystemAddress(), self->GetObjectID(), + true, false, true, false, true, false, true + ); +} + +void AmSkullkinDrill::OnArrived(Entity* self, uint32_t waypointIndex) { + auto* standObj = GetStandObj(self); + + if (waypointIndex == 1) { + GameMessages::SendPlayAnimation(self, u"no-spin"); + GameMessages::SendStopFXEffect(self, true, "active"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"indicator", "indicator"); + + self->SetVar(u"bActive", false); + + const auto playerID = self->GetVar<LWOOBJID>(u"userID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player != nullptr) { + PlayAnim(self, player, "spinjitzu-staff-end"); + } + + if (standObj != nullptr) { + standObj->SetVar(u"bActive", false); + } + + return; + } else { + GameMessages::SendPlayAnimation(self, u"idle"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); + GameMessages::SendStopFXEffect(self, true, "indicator"); + } +} + +void AmSkullkinDrill::PlayCinematic(Entity* self) { + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"userID")); + + if (player == nullptr) { + return; + } + + const auto& cine = self->GetVar<std::u16string>(u"cinematic"); + + if (cine.empty()) { + return; + } + + GameMessages::SendPlayCinematic(player->GetObjectID(), cine, player->GetSystemAddress()); +} + +void AmSkullkinDrill::PlayAnim(Entity* self, Entity* player, const std::string& animName) { + const auto animTime = animName == "spinjitzu-staff-end" ? 0.5f : 1.0f; + + GameMessages::SendPlayAnimation(player, GeneralUtils::ASCIIToUTF16(animName)); + + self->AddTimer("AnimDone_" + animName, animTime); +} + +void AmSkullkinDrill::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + + if (destroyableComponent == nullptr || !attacker->IsPlayer()) { + return; + } + + if (self->GetVar<bool>(u"bActive")) { + return; + } + + const auto activaterID = self->GetVar<LWOOBJID>(u"activaterID"); + + auto* activator = EntityManager::Instance()->GetEntity(activaterID); + + // TODO: Missions + if (activator != nullptr) { + auto* missionComponent = activator->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + for (const auto missionID : m_MissionsToUpdate) { + missionComponent->ForceProgressValue(missionID, 1, self->GetLOT()); + } + } + } + + self->Smash(attacker->GetObjectID(), eKillType::SILENT); + + self->CancelAllTimers(); + + auto* standObj = GetStandObj(self); + + if (standObj != nullptr) { + GameMessages::SendPlayFXEffect(standObj->GetObjectID(), 4946, u"explode", "explode"); + } +} + +void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "killDrill") { + const auto childID = self->GetVar<LWOOBJID>(u"ChildSmash"); + + auto* child = EntityManager::Instance()->GetEntity(childID); + + if (child != nullptr) { + child->Smash(self->GetObjectID(), eKillType::SILENT); + } + + self->SetNetworkVar(u"bIsInUse", false); + self->SetVar(u"bActive", true); + self->SetVar(u"activaterID", LWOOBJID_EMPTY); + + auto* standObj = GetStandObj(self); + + if (standObj != nullptr) { + standObj->SetVar(u"bActive", true); + } + + auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatformComponent == nullptr) { + return; + } + + movingPlatformComponent->GotoWaypoint(0); + + return; + } + + const auto& data = GeneralUtils::SplitString(timerName, '_'); + + if (data.empty()) { + return; + } + + if (data[0] == "AnimDone") { + const auto& animName = data[1]; + + const auto playerID = self->GetVar<LWOOBJID>(u"userID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + if (animName == "spinjitzu-staff-windup") { + TriggerDrill(self); + + GameMessages::SendPlayAnimation(player, u"spinjitzu-staff-loop"); + } else if (animName == "spinjitzu-staff-end") { + FreezePlayer(self, player, false); + + self->SetVar(u"userID", LWOOBJID_EMPTY); + + GameMessages::SendStopFXEffect(player, true, "tornado"); + GameMessages::SendStopFXEffect(player, true, "staff"); + } + + } else if (data[0] == "TryUnFreezeAgain") { + + } +} diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.h b/dScripts/02_server/Map/AM/AmSkullkinDrill.h new file mode 100644 index 00000000..5e6c3179 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.h @@ -0,0 +1,33 @@ +#pragma once +#include "CppScripts.h" + +class AmSkullkinDrill : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + + Entity* GetStandObj(Entity* self); + + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; + + void TriggerDrill(Entity* self); + + void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; + + void OnUse(Entity* self, Entity* user) override; + + void FreezePlayer(Entity* self, Entity* player, bool bFreeze); + + void OnArrived(Entity* self, uint32_t waypointIndex); + + void PlayCinematic(Entity* self); + + void PlayAnim(Entity* self, Entity* player, const std::string& animName); + + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + std::vector<int32_t> m_MissionsToUpdate = { 972, 1305, 1308 }; +}; diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp new file mode 100644 index 00000000..628d616a --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp @@ -0,0 +1,35 @@ +#include "AmSkullkinDrillStand.h" +#include "GameMessages.h" +#include "dpEntity.h" + +void AmSkullkinDrillStand::OnStartup(Entity* self) { + self->SetVar(u"bActive", true); + + self->SetProximityRadius(new dpEntity(self->GetObjectID(), { 6, 14, 6 }), "knockback"); +} + +void AmSkullkinDrillStand::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + +} + +void AmSkullkinDrillStand::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (!self->GetVar<bool>(u"bActive")) { + return; + } + + if (!entering->IsPlayer() || status != "ENTER" || name != "knockback") { + return; + } + + auto myPos = self->GetPosition(); + + auto objPos = entering->GetPosition(); + + NiPoint3 newVec = { (objPos.x - myPos.x) * 4.5f, 15, (objPos.z - myPos.z) * 4.5f }; + + GameMessages::SendKnockback(entering->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, newVec); + + GameMessages::SendPlayFXEffect(entering->GetObjectID(), 1378, u"create", "pushBack"); + + GameMessages::SendPlayAnimation(entering, u"knockback-recovery"); +} diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrillStand.h b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.h new file mode 100644 index 00000000..673dee05 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.h @@ -0,0 +1,12 @@ +#pragma once +#include "CppScripts.h" + +class AmSkullkinDrillStand : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; + + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; +}; diff --git a/dScripts/02_server/Map/AM/AmSkullkinTower.cpp b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp new file mode 100644 index 00000000..01acdeaf --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp @@ -0,0 +1,244 @@ +#include "AmSkullkinTower.h" +#include "EntityManager.h" +#include "DestroyableComponent.h" +#include "MovingPlatformComponent.h" +#include "EntityInfo.h" +#include "GameMessages.h" +#include "MissionComponent.h" + +void AmSkullkinTower::OnStartup(Entity* self) { + self->SetProximityRadius(20, "Tower"); + + // onPhysicsComponentReady + + auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatformComponent != nullptr) { + movingPlatformComponent->StopPathing(); + } + + SpawnLegs(self, "Left"); + SpawnLegs(self, "Right"); + SpawnLegs(self, "Rear"); +} + +void AmSkullkinTower::SpawnLegs(Entity* self, const std::string& loc) { + auto pos = self->GetPosition(); + auto rot = self->GetRotation(); + pos.y += self->GetVarAs<float>(u"vert_offset"); + + auto newRot = rot; + auto offset = self->GetVarAs<float>(u"hort_offset"); + + auto legLOT = self->GetVar<LOT>(u"legLOT"); + + if (legLOT == 0) { + return; + } + + std::vector<LDFBaseData*> config = { new LDFData<std::string>(u"Leg", loc) }; + + EntityInfo info{}; + info.lot = legLOT; + info.spawnerID = self->GetObjectID(); + info.settings = config; + info.rot = newRot; + + if (loc == "Right") { + const auto dir = rot.GetForwardVector(); + pos.x += dir.x * offset; + pos.z += dir.z * offset; + info.pos = pos; + } else if (loc == "Rear") { + const auto dir = rot.GetRightVector(); + pos.x += dir.x * offset; + pos.z += dir.z * offset; + info.pos = pos; + } else if (loc == "Left") { + const auto dir = rot.GetForwardVector() * -1; + pos.x += dir.x * offset; + pos.z += dir.z * offset; + info.pos = pos; + } + + info.rot = NiQuaternion::LookAt(info.pos, self->GetPosition()); + + auto* entity = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(entity); + + OnChildLoaded(self, entity); +} + +void AmSkullkinTower::OnChildLoaded(Entity* self, Entity* child) { + auto legTable = self->GetVar<std::vector<LWOOBJID>>(u"legTable"); + + legTable.push_back(child->GetObjectID()); + + self->SetVar(u"legTable", legTable); + + const auto selfID = self->GetObjectID(); + + child->AddDieCallback([this, selfID, child]() { + auto* self = EntityManager::Instance()->GetEntity(selfID); + auto* destroyableComponent = child->GetComponent<DestroyableComponent>(); + + if (destroyableComponent == nullptr || self == nullptr) { + return; + } + + NotifyDie(self, child, destroyableComponent->GetKiller()); + }); +} + +void AmSkullkinTower::NotifyDie(Entity* self, Entity* other, Entity* killer) { + auto players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + const auto& iter = std::find(players.begin(), players.end(), killer->GetObjectID()); + + if (iter == players.end()) { + players.push_back(killer->GetObjectID()); + } + + self->SetVar(u"Players", players); + + OnChildRemoved(self, other); +} + +void AmSkullkinTower::OnChildRemoved(Entity* self, Entity* child) { + auto legTable = self->GetVar<std::vector<LWOOBJID>>(u"legTable"); + + const auto& iter = std::find(legTable.begin(), legTable.end(), child->GetObjectID()); + + if (iter != legTable.end()) { + legTable.erase(iter); + } + + self->SetVar(u"legTable", legTable); + + if (legTable.size() == 2) { + GameMessages::SendPlayAnimation(self, u"wobble-1"); + } else if (legTable.size() == 1) { + GameMessages::SendPlayAnimation(self, u"wobble-2"); + } else if (legTable.empty()) { + const auto animTime = 2.5f; + + GameMessages::SendPlayAnimation(self, u"fall"); + + self->AddTimer("spawnGuys", animTime - 0.2f); + + self->CancelTimer("RespawnLeg"); + self->CancelTimer("RespawnLeg"); + self->CancelTimer("RespawnLeg"); + + std::vector<int32_t> missionIDs; + + auto missionsString = self->GetVar<std::u16string>(u"missions"); + + if (!missionsString.empty()) { + // Split the missions string by '_' + const auto missions = GeneralUtils::SplitString( + GeneralUtils::UTF16ToWTF8(missionsString), + '_' + ); + + for (const auto& mission : missions) { + int32_t missionID = 0; + + if (!GeneralUtils::TryParse(mission, missionID)) { + continue; + } + + missionIDs.push_back(missionID); + } + } + + const auto& players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + for (const auto& playerID : players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + continue; + } + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + continue; + } + + for (const auto missionID : missionIDs) { + missionComponent->ForceProgressValue(missionID, 1, self->GetLOT()); + } + + //missionComponent->ForceProgressValue(1305, 1, self->GetLOT()); + } + } + + auto deadLegs = self->GetVar<std::vector<std::string>>(u"DeadLegs"); + + const auto& leg = child->GetVar<std::string>(u"Leg"); + + const auto& legIter = std::find(deadLegs.begin(), deadLegs.end(), leg); + + if (legIter == deadLegs.end()) { + deadLegs.push_back(leg); + } + + self->SetVar(u"DeadLegs", deadLegs); + + self->AddTimer("RespawnLeg", 20); +} + +void AmSkullkinTower::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status != "LEAVE") { + return; + } + + auto players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); + + const auto& iter = std::find(players.begin(), players.end(), entering->GetObjectID()); + + if (iter != players.end()) { + players.erase(iter); + } + + self->SetVar(u"Players", players); +} + +void AmSkullkinTower::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "RespawnLeg") { + auto deadLegs = self->GetVar<std::vector<std::string>>(u"DeadLegs"); + + if (deadLegs.empty()) { + return; + } + + SpawnLegs(self, deadLegs[0]); + + deadLegs.erase(deadLegs.begin()); + + self->SetVar<std::vector<std::string>>(u"DeadLegs", deadLegs); + } else if (timerName == "spawnGuys") { + EntityInfo info{}; + info.lot = self->GetVar<LOT>(u"enemyToSpawn"); + auto pos = self->GetPosition(); + pos.y += 7; + info.pos = pos; + info.rot = self->GetRotation(); + info.spawnerID = self->GetObjectID(); + + for (size_t i = 0; i < 2; i++) { + info.pos.x += i * 2; // Just to set the apart a bit + + auto* entity = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(entity); + } + + self->AddTimer("killTower", 0.7f); + } else if (timerName == "killTower") { + self->Smash(self->GetObjectID()); + } +} diff --git a/dScripts/02_server/Map/AM/AmSkullkinTower.h b/dScripts/02_server/Map/AM/AmSkullkinTower.h new file mode 100644 index 00000000..495641de --- /dev/null +++ b/dScripts/02_server/Map/AM/AmSkullkinTower.h @@ -0,0 +1,20 @@ +#pragma once +#include "CppScripts.h" + +class AmSkullkinTower : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + + void SpawnLegs(Entity* self, const std::string& loc); + + void OnChildLoaded(Entity* self, Entity* child); + + void NotifyDie(Entity* self, Entity* other, Entity* killer); + + void OnChildRemoved(Entity* self, Entity* child); + + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/AM/AmTeapotServer.cpp b/dScripts/02_server/Map/AM/AmTeapotServer.cpp new file mode 100644 index 00000000..93f05326 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmTeapotServer.cpp @@ -0,0 +1,23 @@ +#include "AmTeapotServer.h" +#include "InventoryComponent.h" +#include "GameMessages.h" +#include "Item.h" +#include "eTerminateType.h" + +void AmTeapotServer::OnUse(Entity* self, Entity* user) { + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + auto* blueFlowerItem = inventoryComponent->FindItemByLot(BLUE_FLOWER_LEAVES, eInventoryType::ITEMS); + if (!blueFlowerItem) { + blueFlowerItem = inventoryComponent->FindItemByLot(BLUE_FLOWER_LEAVES, eInventoryType::VAULT_ITEMS); + if (!blueFlowerItem) return; + } + + // The client allows you to use the teapot only if you have a stack of 10 leaves in some inventory somewhere. + if (blueFlowerItem->GetCount() >= 10) { + blueFlowerItem->SetCount(blueFlowerItem->GetCount() - 10); + inventoryComponent->AddItem(WU_S_IMAGINATION_TEA, 1); + } + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/02_server/Map/AM/AmTeapotServer.h b/dScripts/02_server/Map/AM/AmTeapotServer.h new file mode 100644 index 00000000..3ba2e331 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmTeapotServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class AmTeapotServer : public CppScripts::Script { +public: + void OnUse(Entity* self, Entity* user) override; +private: + LOT BLUE_FLOWER_LEAVES = 12317; + LOT WU_S_IMAGINATION_TEA = 12109; +}; diff --git a/dScripts/02_server/Map/AM/AmTemplateSkillVolume.cpp b/dScripts/02_server/Map/AM/AmTemplateSkillVolume.cpp new file mode 100644 index 00000000..3acc9063 --- /dev/null +++ b/dScripts/02_server/Map/AM/AmTemplateSkillVolume.cpp @@ -0,0 +1,23 @@ +#include "AmTemplateSkillVolume.h" +#include "MissionComponent.h" + +void AmTemplateSkillVolume::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message != "NinjagoSpinAttackEvent") { + return; + } + + auto* missionComponent = caster->GetComponent<MissionComponent>(); + + const auto missionIDsVariable = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"missions")); + const auto missionIDs = GeneralUtils::SplitString(missionIDsVariable, '_'); + + for (const auto& missionIDStr : missionIDs) { + int32_t missionID = 0; + + if (!GeneralUtils::TryParse(missionIDStr, missionID)) { + continue; + } + + missionComponent->ForceProgressTaskType(missionID, 1, 1, false); + } +} diff --git a/dScripts/AmTemplateSkillVolume.h b/dScripts/02_server/Map/AM/AmTemplateSkillVolume.h similarity index 52% rename from dScripts/AmTemplateSkillVolume.h rename to dScripts/02_server/Map/AM/AmTemplateSkillVolume.h index ab912f4d..f4002213 100644 --- a/dScripts/AmTemplateSkillVolume.h +++ b/dScripts/02_server/Map/AM/AmTemplateSkillVolume.h @@ -4,5 +4,5 @@ class AmTemplateSkillVolume : public CppScripts::Script { public: - void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; }; diff --git a/dScripts/02_server/Map/AM/CMakeLists.txt b/dScripts/02_server/Map/AM/CMakeLists.txt new file mode 100644 index 00000000..d3d13b73 --- /dev/null +++ b/dScripts/02_server/Map/AM/CMakeLists.txt @@ -0,0 +1,19 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_AM + "AmConsoleTeleportServer.cpp" + "RandomSpawnerFin.cpp" + "RandomSpawnerPit.cpp" + "RandomSpawnerStr.cpp" + "RandomSpawnerZip.cpp" + "AmBridge.cpp" + "AmDrawBridge.cpp" + "AmShieldGenerator.cpp" + "AmShieldGeneratorQuickbuild.cpp" + "AmDropshipComputer.cpp" + "AmScrollReaderServer.cpp" + "AmTemplateSkillVolume.cpp" + "AmSkullkinDrill.cpp" + "AmSkullkinDrillStand.cpp" + "AmSkullkinTower.cpp" + "AmBlueX.cpp" + "AmTeapotServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/RandomSpawnerFin.cpp b/dScripts/02_server/Map/AM/RandomSpawnerFin.cpp similarity index 78% rename from dScripts/RandomSpawnerFin.cpp rename to dScripts/02_server/Map/AM/RandomSpawnerFin.cpp index da0b655e..57793511 100644 --- a/dScripts/RandomSpawnerFin.cpp +++ b/dScripts/02_server/Map/AM/RandomSpawnerFin.cpp @@ -1,9 +1,8 @@ #include "RandomSpawnerFin.h" -void RandomSpawnerFin::OnStartup(Entity* self) -{ - zones = { - { //-- ** Load 1 -------------------------- ** +void RandomSpawnerFin::OnStartup(Entity* self) { + zones = { + { //-- ** Load 1 -------------------------- ** {{mobs.pirate, 3, "type1",}, {mobs.ronin, 3, "type2",}, {mobs.spider, 2, "type3",}}, @@ -63,25 +62,24 @@ void RandomSpawnerFin::OnStartup(Entity* self) {mobs.horse, 1, "type3",}}, 10 }, - }; - - sectionMultipliers = { - {"secA", 1}, - {"secB", 1}, - {"secC", 1.2f}, - {"secD", 1.3f}, - {"secE", 1.6f}, - {"secF", 1}, - {"secG", 1}, - {"secH", 1.2f}, - }; + }; - zoneName = "fin"; + sectionMultipliers = { + {"secA", 1}, + {"secB", 1}, + {"secC", 1.2f}, + {"secD", 1.3f}, + {"secE", 1.6f}, + {"secF", 1}, + {"secG", 1}, + {"secH", 1.2f}, + }; - BaseStartup(self); + zoneName = "fin"; + + BaseStartup(self); } -void RandomSpawnerFin::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); +void RandomSpawnerFin::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); } diff --git a/dScripts/02_server/Map/AM/RandomSpawnerFin.h b/dScripts/02_server/Map/AM/RandomSpawnerFin.h new file mode 100644 index 00000000..30416858 --- /dev/null +++ b/dScripts/02_server/Map/AM/RandomSpawnerFin.h @@ -0,0 +1,26 @@ +#pragma once +#include "CppScripts.h" +#include "BaseRandomServer.h" + +class RandomSpawnerFin : public CppScripts::Script, BaseRandomServer +{ + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + struct Mobs + { + static const LOT stromb = 11212; + static const LOT mech = 11213; + static const LOT spider = 11214; + static const LOT pirate = 11215; + static const LOT admiral = 11216; + static const LOT gorilla = 11217; + static const LOT ronin = 11218; + static const LOT horse = 11219; + static const LOT dragon = 112201; + }; + + Mobs mobs; +}; + diff --git a/dScripts/RandomSpawnerPit.cpp b/dScripts/02_server/Map/AM/RandomSpawnerPit.cpp similarity index 82% rename from dScripts/RandomSpawnerPit.cpp rename to dScripts/02_server/Map/AM/RandomSpawnerPit.cpp index 8dfa61b0..ceea9412 100644 --- a/dScripts/RandomSpawnerPit.cpp +++ b/dScripts/02_server/Map/AM/RandomSpawnerPit.cpp @@ -1,9 +1,8 @@ #include "RandomSpawnerPit.h" -void RandomSpawnerPit::OnStartup(Entity* self) -{ - zones = { - { //-- ** Load 1 -------------------------- ** +void RandomSpawnerPit::OnStartup(Entity* self) { + zones = { + { //-- ** Load 1 -------------------------- ** {{mobs.admiral, 4, "type1",}, {mobs.spider, 3, "type2",}}, 5 @@ -63,23 +62,22 @@ void RandomSpawnerPit::OnStartup(Entity* self) {mobs.pirate, 5, "type2",}}, 15 }, - }; + }; - sectionMultipliers = { - {"secA", 1}, - {"secB", 1.2f}, - {"secC", 1.2f}, - {"secD", 1}, - }; + sectionMultipliers = { + {"secA", 1}, + {"secB", 1.2f}, + {"secC", 1.2f}, + {"secD", 1}, + }; - zoneName = "pit"; + zoneName = "pit"; mobDeathResetNumber = 20; changeNum = 18; - BaseStartup(self); + BaseStartup(self); } -void RandomSpawnerPit::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); +void RandomSpawnerPit::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); } diff --git a/dScripts/02_server/Map/AM/RandomSpawnerPit.h b/dScripts/02_server/Map/AM/RandomSpawnerPit.h new file mode 100644 index 00000000..5ffceec5 --- /dev/null +++ b/dScripts/02_server/Map/AM/RandomSpawnerPit.h @@ -0,0 +1,26 @@ +#pragma once +#include "CppScripts.h" +#include "BaseRandomServer.h" + +class RandomSpawnerPit : public CppScripts::Script, BaseRandomServer +{ + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + struct Mobs + { + static const LOT stromb = 11212; + static const LOT mech = 11213; + static const LOT spider = 11214; + static const LOT pirate = 11215; + static const LOT admiral = 11216; + static const LOT gorilla = 11217; + static const LOT ronin = 11218; + static const LOT horse = 11219; + static const LOT dragon = 112200; + }; + + Mobs mobs; +}; + diff --git a/dScripts/RandomSpawnerStr.cpp b/dScripts/02_server/Map/AM/RandomSpawnerStr.cpp similarity index 83% rename from dScripts/RandomSpawnerStr.cpp rename to dScripts/02_server/Map/AM/RandomSpawnerStr.cpp index fa6ac117..0f7f5114 100644 --- a/dScripts/RandomSpawnerStr.cpp +++ b/dScripts/02_server/Map/AM/RandomSpawnerStr.cpp @@ -1,9 +1,8 @@ #include "RandomSpawnerStr.h" -void RandomSpawnerStr::OnStartup(Entity* self) -{ - zones = { - { //-- ** Load 1 -------------------------- ** +void RandomSpawnerStr::OnStartup(Entity* self) { + zones = { + { //-- ** Load 1 -------------------------- ** {{mobs.stromb, 4, "type1",}, {mobs.pirate, 3, "type2",}, {mobs.ronin, 3, "type3",}}, @@ -63,22 +62,21 @@ void RandomSpawnerStr::OnStartup(Entity* self) {mobs.pirate, 4, "type3",}}, 1 }, - }; + }; - sectionMultipliers = { - {"secA", 1}, - {"secB", 1}, - {"secC", 1.2f}, - }; + sectionMultipliers = { + {"secA", 1}, + {"secB", 1}, + {"secC", 1.2f}, + }; - zoneName = "str"; + zoneName = "str"; mobDeathResetNumber = 20; changeNum = 15; - BaseStartup(self); + BaseStartup(self); } -void RandomSpawnerStr::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); +void RandomSpawnerStr::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); } diff --git a/dScripts/02_server/Map/AM/RandomSpawnerStr.h b/dScripts/02_server/Map/AM/RandomSpawnerStr.h new file mode 100644 index 00000000..b6f0bbea --- /dev/null +++ b/dScripts/02_server/Map/AM/RandomSpawnerStr.h @@ -0,0 +1,26 @@ +#pragma once +#include "CppScripts.h" +#include "BaseRandomServer.h" + +class RandomSpawnerStr : public CppScripts::Script, BaseRandomServer +{ + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + struct Mobs + { + static const LOT stromb = 11212; + static const LOT mech = 11213; + static const LOT spider = 11214; + static const LOT pirate = 11215; + static const LOT admiral = 11216; + static const LOT gorilla = 11217; + static const LOT ronin = 11218; + static const LOT horse = 11219; + static const LOT dragon = 112200; + }; + + Mobs mobs; +}; + diff --git a/dScripts/RandomSpawnerZip.cpp b/dScripts/02_server/Map/AM/RandomSpawnerZip.cpp similarity index 86% rename from dScripts/RandomSpawnerZip.cpp rename to dScripts/02_server/Map/AM/RandomSpawnerZip.cpp index 083d4ae7..3f45a784 100644 --- a/dScripts/RandomSpawnerZip.cpp +++ b/dScripts/02_server/Map/AM/RandomSpawnerZip.cpp @@ -1,9 +1,8 @@ #include "RandomSpawnerZip.h" -void RandomSpawnerZip::OnStartup(Entity* self) -{ - zones = { - { //-- ** Load 1 -------------------------- ** +void RandomSpawnerZip::OnStartup(Entity* self) { + zones = { + { //-- ** Load 1 -------------------------- ** {{mobs.stromb, 3, "type1",}, {mobs.pirate, 2, "type2",}, {mobs.admiral, 2, "type3",}, @@ -73,21 +72,20 @@ void RandomSpawnerZip::OnStartup(Entity* self) {mobs.pirate, 0, "type4",}}, 1 }, - }; + }; - sectionMultipliers = { - {"secA", 1.2f}, - {"secB", 1.2f}, - }; + sectionMultipliers = { + {"secA", 1.2f}, + {"secB", 1.2f}, + }; - zoneName = "zip"; + zoneName = "zip"; mobDeathResetNumber = 20; changeNum = 9; - BaseStartup(self); + BaseStartup(self); } -void RandomSpawnerZip::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); +void RandomSpawnerZip::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); } diff --git a/dScripts/02_server/Map/AM/RandomSpawnerZip.h b/dScripts/02_server/Map/AM/RandomSpawnerZip.h new file mode 100644 index 00000000..f2aa6635 --- /dev/null +++ b/dScripts/02_server/Map/AM/RandomSpawnerZip.h @@ -0,0 +1,26 @@ +#pragma once +#include "CppScripts.h" +#include "BaseRandomServer.h" + +class RandomSpawnerZip : public CppScripts::Script, BaseRandomServer +{ + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + struct Mobs + { + static const LOT stromb = 11212; + static const LOT mech = 11213; + static const LOT spider = 11214; + static const LOT pirate = 11215; + static const LOT admiral = 11216; + static const LOT gorilla = 11217; + static const LOT ronin = 11218; + static const LOT horse = 11219; + static const LOT dragon = 112200; + }; + + Mobs mobs; +}; + diff --git a/dScripts/02_server/Map/CMakeLists.txt b/dScripts/02_server/Map/CMakeLists.txt new file mode 100644 index 00000000..feed8a97 --- /dev/null +++ b/dScripts/02_server/Map/CMakeLists.txt @@ -0,0 +1,81 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP) + +add_subdirectory(AG) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "AG/${file}") +endforeach() + +add_subdirectory(AG_Spider_Queen) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG_SPIDER_QUEEN}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "AG_Spider_Queen/${file}") +endforeach() + +add_subdirectory(AM) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_AM}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "AM/${file}") +endforeach() + +add_subdirectory(FV) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "FV/${file}") +endforeach() + +add_subdirectory(General) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "General/${file}") +endforeach() + +add_subdirectory(GF) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_GF}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "GF/${file}") +endforeach() + +add_subdirectory(njhub) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "njhub/${file}") +endforeach() + +add_subdirectory(NS) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "NS/${file}") +endforeach() + +add_subdirectory(NT) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NT}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "NT/${file}") +endforeach() + +add_subdirectory(PR) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PR}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "PR/${file}") +endforeach() + +add_subdirectory(Property) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "Property/${file}") +endforeach() + +add_subdirectory(SS) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_SS}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "SS/${file}") +endforeach() + +add_subdirectory(VE) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_VE}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} "VE/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP ${DSCRIPTS_SOURCES_02_SERVER_MAP} PARENT_SCOPE) diff --git a/dScripts/02_server/Map/FV/CMakeLists.txt b/dScripts/02_server/Map/FV/CMakeLists.txt new file mode 100644 index 00000000..505d97c4 --- /dev/null +++ b/dScripts/02_server/Map/FV/CMakeLists.txt @@ -0,0 +1,14 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV + "EnemyRoninSpawner.cpp" + "FvCandle.cpp" + "FvFong.cpp" + "FvHorsemenTrigger.cpp" + "ImgBrickConsoleQB.cpp") + +add_subdirectory(Racing) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV_RACING}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV} "Racing/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV} PARENT_SCOPE) diff --git a/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp new file mode 100644 index 00000000..cfc58fa0 --- /dev/null +++ b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp @@ -0,0 +1,69 @@ +#include "EnemyRoninSpawner.h" +#include "SkillComponent.h" +#include "RenderComponent.h" +#include "EntityInfo.h" +#include "EntityManager.h" + +void EnemyRoninSpawner::OnStartup(Entity* self) { + self->SetProximityRadius(15, "ronin"); +} + +void EnemyRoninSpawner::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "hatchTime") { + auto* renderComponent = self->GetComponent<RenderComponent>(); + + if (renderComponent != nullptr) { + renderComponent->PlayEffect(644, u"create", "BurstFX1"); + } + + EntityInfo info{}; + info.lot = 7815; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.spawnerID = self->GetObjectID(); + + auto* spawnedEntity = EntityManager::Instance()->CreateEntity(info); + + if (spawnedEntity == nullptr) { + return; + } + + EntityManager::Instance()->ConstructEntity(spawnedEntity); + + spawnedEntity->AddCallbackTimer(60, [spawnedEntity]() { + spawnedEntity->Smash(spawnedEntity->GetObjectID()); + }); + + self->Smash(self->GetObjectID()); + } +} + +void EnemyRoninSpawner::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (entering->IsPlayer() && name == "ronin" && status == "ENTER" && !self->GetVar<bool>(u"hatching")) { + StartHatching(self); + + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(305, 3568, LWOOBJID_EMPTY); + } + } +} + +void EnemyRoninSpawner::OnHit(Entity* self, Entity* attacker) { + if (!self->GetVar<bool>(u"hatching")) { + StartHatching(self); + } +} + +void EnemyRoninSpawner::StartHatching(Entity* self) { + self->SetVar(u"hatching", true); + + auto* renderComponent = self->GetComponent<RenderComponent>(); + + if (renderComponent != nullptr) { + renderComponent->PlayEffect(2260, u"rebuild_medium", "WakeUpFX1"); + } + + self->AddTimer("hatchTime", 2); +} diff --git a/dScripts/EnemyRoninSpawner.h b/dScripts/02_server/Map/FV/EnemyRoninSpawner.h similarity index 51% rename from dScripts/EnemyRoninSpawner.h rename to dScripts/02_server/Map/FV/EnemyRoninSpawner.h index 0b14d0cf..02990f36 100644 --- a/dScripts/EnemyRoninSpawner.h +++ b/dScripts/02_server/Map/FV/EnemyRoninSpawner.h @@ -5,8 +5,8 @@ class EnemyRoninSpawner final : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnTimerDone(Entity* self, std::string timerName) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnHit(Entity* self, Entity* attacker) override; - void StartHatching(Entity* self); + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnHit(Entity* self, Entity* attacker) override; + void StartHatching(Entity* self); }; diff --git a/dScripts/FvCandle.cpp b/dScripts/02_server/Map/FV/FvCandle.cpp similarity index 82% rename from dScripts/FvCandle.cpp rename to dScripts/02_server/Map/FV/FvCandle.cpp index 63f90f0b..0c4344d0 100644 --- a/dScripts/FvCandle.cpp +++ b/dScripts/02_server/Map/FV/FvCandle.cpp @@ -1,11 +1,12 @@ #include "FvCandle.h" #include "MissionComponent.h" #include "RenderComponent.h" +#include "eReplicaComponentType.h" -std::vector<int32_t> FvCandle::m_Missions = {850, 1431, 1529, 1566, 1603}; +std::vector<int32_t> FvCandle::m_Missions = { 850, 1431, 1529, 1566, 1603 }; void FvCandle::OnStartup(Entity* self) { - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; @@ -22,16 +23,14 @@ void FvCandle::BlowOutCandle(Entity* self, Entity* blower) { if (self->GetBoolean(u"AmHit")) return; - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; - + auto* missionComponent = blower->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) - { - for (const auto mission : m_Missions) - { + if (missionComponent != nullptr) { + for (const auto mission : m_Missions) { missionComponent->ForceProgressTaskType(mission, 1, 1); } } @@ -48,10 +47,10 @@ void FvCandle::BlowOutCandle(Entity* self, Entity* blower) { void FvCandle::OnTimerDone(Entity* self, std::string timerName) { self->SetBoolean(u"AmHit", false); - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; render->StopEffect("candle_smoke", false); render->PlayEffect(2108, u"create", "candle_light", LWOOBJID_EMPTY, 1.0f, 1.0f, true); -} \ No newline at end of file +} diff --git a/dScripts/FvCandle.h b/dScripts/02_server/Map/FV/FvCandle.h similarity index 85% rename from dScripts/FvCandle.h rename to dScripts/02_server/Map/FV/FvCandle.h index 362d2a05..e0cd4e04 100644 --- a/dScripts/FvCandle.h +++ b/dScripts/02_server/Map/FV/FvCandle.h @@ -1,7 +1,7 @@ #pragma once #include "CppScripts.h" -class FvCandle : public CppScripts::Script +class FvCandle : public CppScripts::Script { public: void OnStartup(Entity* self); @@ -11,4 +11,4 @@ private: void BlowOutCandle(Entity* self, Entity* blower); static std::vector<int32_t> m_Missions; -}; \ No newline at end of file +}; diff --git a/dScripts/FvFong.cpp b/dScripts/02_server/Map/FV/FvFong.cpp similarity index 50% rename from dScripts/FvFong.cpp rename to dScripts/02_server/Map/FV/FvFong.cpp index 9a3de0b2..13c637e7 100644 --- a/dScripts/FvFong.cpp +++ b/dScripts/02_server/Map/FV/FvFong.cpp @@ -1,11 +1,9 @@ #include "FvFong.h" #include "Darkitect.h" -#include "MissionState.h" +#include "eMissionState.h" -void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - if (missionID == 734 && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) - { +void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 734 && missionState == eMissionState::READY_TO_COMPLETE) { Darkitect Baron; Baron.Reveal(self, target); } diff --git a/dScripts/02_server/Map/FV/FvFong.h b/dScripts/02_server/Map/FV/FvFong.h new file mode 100644 index 00000000..c0b6d48b --- /dev/null +++ b/dScripts/02_server/Map/FV/FvFong.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class FvFong : public CppScripts::Script +{ +public: + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +}; diff --git a/dScripts/02_server/Map/FV/FvHorsemenTrigger.cpp b/dScripts/02_server/Map/FV/FvHorsemenTrigger.cpp new file mode 100644 index 00000000..e87d9629 --- /dev/null +++ b/dScripts/02_server/Map/FV/FvHorsemenTrigger.cpp @@ -0,0 +1,53 @@ +#include "FvHorsemenTrigger.h" +#include "EntityManager.h" +#include "MissionComponent.h" + +void FvHorsemenTrigger::OnStartup(Entity* self) { + self->SetProximityRadius(40, "horsemenTrigger"); + + self->SetVar<std::vector<LWOOBJID>>(u"players", {}); +} + +void FvHorsemenTrigger::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name != "horsemenTrigger" || !entering->IsPlayer()) { + return; + } + + auto players = self->GetVar<std::vector<LWOOBJID>>(u"players"); + + const auto& iter = std::find(players.begin(), players.end(), entering->GetObjectID()); + + if (status == "ENTER" && iter == players.end()) { + players.push_back(entering->GetObjectID()); + } else if (status == "LEAVE" && iter != players.end()) { + players.erase(iter); + } + + self->SetVar<std::vector<LWOOBJID>>(u"players", players); +} + +void +FvHorsemenTrigger::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + auto players = self->GetVar<std::vector<LWOOBJID>>(u"players"); + + if (args == "HorsemenDeath") { + for (const auto& playerId : self->GetVar<std::vector<LWOOBJID>>(u"players")) { + auto* player = EntityManager::Instance()->GetEntity(playerId); + + if (player == nullptr) { + continue; + } + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + continue; + } + + for (const auto missionId : m_Missions) { + missionComponent->ForceProgressTaskType(missionId, 1, 1); + } + } + } +} diff --git a/dScripts/02_server/Map/FV/FvHorsemenTrigger.h b/dScripts/02_server/Map/FV/FvHorsemenTrigger.h new file mode 100644 index 00000000..233e2f5b --- /dev/null +++ b/dScripts/02_server/Map/FV/FvHorsemenTrigger.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" +#include "RenderComponent.h" + +class FvHorsemenTrigger : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; + +private: + std::vector<int32_t> m_Missions = { 854, 738, 1432, 1530, 1567, 1604 }; +}; diff --git a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp new file mode 100644 index 00000000..7d86cc73 --- /dev/null +++ b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp @@ -0,0 +1,242 @@ +#include "ImgBrickConsoleQB.h" +#include "RebuildComponent.h" +#include "dZoneManager.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "MissionComponent.h" +#include "eMissionState.h" +#include "InventoryComponent.h" +#include "eTerminateType.h" + +int32_t ImgBrickConsoleQB::ResetBricks = 30; +int32_t ImgBrickConsoleQB::ResetConsole = 60; +int32_t ImgBrickConsoleQB::ResetInteract = 45; + +void ImgBrickConsoleQB::OnStartup(Entity* self) { + self->SetNetworkVar(u"used", false); + + self->AddTimer("reset", ResetBricks); +} + +void ImgBrickConsoleQB::OnUse(Entity* self, Entity* user) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent->GetState() == eRebuildState::COMPLETED) { + if (!self->GetNetworkVar<bool>(u"used")) { + const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); + + auto bothBuilt = false; + + for (auto* console : consoles) { + auto* consoleRebuildComponent = console->GetComponent<RebuildComponent>(); + + if (consoleRebuildComponent->GetState() != eRebuildState::COMPLETED) { + continue; + } + + console->CancelAllTimers(); + + if (console->GetNetworkVar<bool>(u"used")) { + bothBuilt = true; + } + } + + if (bothBuilt) { + SmashCanister(self); + } else { + SpawnBrick(self); + } + + self->AddTimer("Die", ResetInteract); + + auto onFX = 0; + + const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); + + if (location == "Left") { + onFX = 2776; + } else { + onFX = 2779; + } + + const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); + + if (!facility.empty()) { + GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); + GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), onFX, u"create", location + "PipeOn"); + } + } + + auto* player = user; + + auto* missionComponent = player->GetComponent<MissionComponent>(); + auto* inventoryComponent = player->GetComponent<InventoryComponent>(); + + if (missionComponent != nullptr && inventoryComponent != nullptr) { + if (missionComponent->GetMissionState(1302) == eMissionState::ACTIVE) { + inventoryComponent->RemoveItem(13074, 1); + + missionComponent->ForceProgressTaskType(1302, 1, 1); + } + + if (missionComponent->GetMissionState(1926) == eMissionState::ACTIVE) { + inventoryComponent->RemoveItem(14472, 1); + + missionComponent->ForceProgressTaskType(1926, 1, 1); + } + } + + self->SetNetworkVar(u"used", true); + + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + } +} + +void ImgBrickConsoleQB::SpawnBrick(Entity* self) { + const auto netDevil = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug"); + if (!netDevil.empty()) { + netDevil[0]->Reset(); + netDevil[0]->Deactivate(); + } + + const auto brick = dZoneManager::Instance()->GetSpawnersByName("Imagination"); + if (!brick.empty()) { + brick[0]->Activate(); + } +} + +void ImgBrickConsoleQB::SmashCanister(Entity* self) { + const auto brick = EntityManager::Instance()->GetEntitiesInGroup("Imagination"); + if (!brick.empty()) { + GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 122, u"create", "bluebrick"); + GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 1034, u"cast", "imaginationexplosion"); + } + + const auto canisters = EntityManager::Instance()->GetEntitiesInGroup("Canister"); + for (auto* canister : canisters) { + canister->Smash(canister->GetObjectID(), eKillType::VIOLENT); + } + + const auto canister = dZoneManager::Instance()->GetSpawnersByName("BrickCanister"); + if (!canister.empty()) { + canister[0]->Reset(); + canister[0]->Deactivate(); + } +} + +void ImgBrickConsoleQB::OnRebuildComplete(Entity* self, Entity* target) { + auto energyFX = 0; + + const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); + + if (location == "Left") { + energyFX = 2775; + } else { + energyFX = 2778; + } + + const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); + + if (!facility.empty()) { + GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOff"); + GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), energyFX, u"create", location + "PipeEnergy"); + } + + const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); + + for (auto* console : consoles) { + auto* consoleRebuildComponent = console->GetComponent<RebuildComponent>(); + + if (consoleRebuildComponent->GetState() != eRebuildState::COMPLETED) { + continue; + } + + console->CancelAllTimers(); + } + + self->AddTimer("Die", ResetConsole); +} + +void ImgBrickConsoleQB::OnDie(Entity* self, Entity* killer) { + if (self->GetVar<bool>(u"Died")) { + return; + } + + self->CancelAllTimers(); + + self->SetVar(u"Died", true); + + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent->GetState() == eRebuildState::COMPLETED) { + auto offFX = 0; + + const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); + + if (location == "Left") { + offFX = 2774; + } else { + offFX = 2777; + } + + const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); + + if (!facility.empty()) { + GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); + GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOn"); + GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), offFX, u"create", location + "PipeOff"); + GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), 2750, u"create", location + "imagination_canister"); + } + } + + const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); + + const auto pipeGroup = myGroup.substr(0, 10); + + const auto firstPipe = pipeGroup + "1"; + + const auto samePipeSpawner = dZoneManager::Instance()->GetSpawnersByName(myGroup); + if (!samePipeSpawner.empty()) { + samePipeSpawner[0]->Reset(); + samePipeSpawner[0]->Deactivate(); + } + + const auto firstPipeSpawner = dZoneManager::Instance()->GetSpawnersByName(firstPipe); + if (!firstPipeSpawner.empty()) { + firstPipeSpawner[0]->Activate(); + } + + const auto netdevil = dZoneManager::Instance()->GetSpawnersByName("Imagination"); + if (!netdevil.empty()) { + netdevil[0]->Reset(); + netdevil[0]->Deactivate(); + } + + const auto brick = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug"); + if (!brick.empty()) { + brick[0]->Activate(); + } + + const auto canister = dZoneManager::Instance()->GetSpawnersByName("BrickCanister"); + if (!canister.empty()) { + canister[0]->Activate(); + } + + self->SetNetworkVar(u"used", false); +} + +void ImgBrickConsoleQB::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "reset") { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent->GetState() == eRebuildState::OPEN) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } + } else if (timerName == "Die") { + const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); + + for (auto* console : consoles) { + console->Smash(console->GetObjectID(), eKillType::VIOLENT); + } + } +} diff --git a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.h b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.h new file mode 100644 index 00000000..062a5888 --- /dev/null +++ b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.h @@ -0,0 +1,19 @@ +#pragma once +#include "CppScripts.h" + +class ImgBrickConsoleQB : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void SpawnBrick(Entity* self); + void SmashCanister(Entity* self); + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnDie(Entity* self, Entity* killer) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +public: + static int32_t ResetBricks; + static int32_t ResetConsole; + static int32_t ResetInteract; +}; diff --git a/dScripts/02_server/Map/FV/Racing/CMakeLists.txt b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt new file mode 100644 index 00000000..89536b67 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV_RACING + "RaceMaelstromGeiser.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp new file mode 100644 index 00000000..155be92b --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp @@ -0,0 +1,85 @@ +#include "RaceMaelstromGeiser.h" +#include "GameMessages.h" +#include "PossessableComponent.h" +#include "PossessorComponent.h" +#include "EntityManager.h" +#include "RacingControlComponent.h" +#include "dZoneManager.h" + +void RaceMaelstromGeiser::OnStartup(Entity* self) { + self->SetVar(u"AmFiring", false); + + self->AddTimer("downTime", self->GetVar<int32_t>(u"startTime")); + + self->SetProximityRadius(15, "deathZone"); +} + +void RaceMaelstromGeiser::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (!entering->IsPlayer() || name != "deathZone" || status != "ENTER") { + return; + } + + if (!self->GetVar<bool>(u"AmFiring")) { + return; + } + + auto* possessableComponent = entering->GetComponent<PossessableComponent>(); + + Entity* vehicle; + Entity* player; + + if (possessableComponent != nullptr) { + player = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + + if (player == nullptr) { + return; + } + + vehicle = entering; + } else if (entering->IsPlayer()) { + auto* possessorComponent = entering->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) { + return; + } + + vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) { + return; + } + + player = entering; + } else { + return; + } + + + GameMessages::SendDie(vehicle, self->GetObjectID(), LWOOBJID_EMPTY, true, eKillType::VIOLENT, u"", 0, 0, 0, true, false, 0); + + auto* zoneController = dZoneManager::Instance()->GetZoneControlObject(); + + auto* racingControlComponent = zoneController->GetComponent<RacingControlComponent>(); + + if (racingControlComponent != nullptr) { + racingControlComponent->OnRequestDie(player); + } +} + +void RaceMaelstromGeiser::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "downTime") { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 4048, u"rebuild_medium", "geiser", LWOOBJID_EMPTY, 1, 1, true); + + self->AddTimer("buildUpTime", 1); + } else if (timerName == "buildUpTime") { + self->SetVar(u"AmFiring", true); + + self->AddTimer("killTime", 1.5f); + } else if (timerName == "killTime") { + GameMessages::SendStopFXEffect(self, true, "geiser"); + + self->SetVar(u"AmFiring", false); + + self->AddTimer("downTime", 3.0); + } +} diff --git a/dScripts/RaceMaelstromGeiser.h b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.h similarity index 65% rename from dScripts/RaceMaelstromGeiser.h rename to dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.h index 79cc384c..3ca0953b 100644 --- a/dScripts/RaceMaelstromGeiser.h +++ b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.h @@ -4,7 +4,7 @@ class RaceMaelstromGeiser : public CppScripts::Script { public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; }; diff --git a/dScripts/02_server/Map/GF/CMakeLists.txt b/dScripts/02_server/Map/GF/CMakeLists.txt new file mode 100644 index 00000000..90cc38a5 --- /dev/null +++ b/dScripts/02_server/Map/GF/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_GF + "GfTikiTorch.cpp" + "GfCaptainsCannon.cpp" + "MastTeleport.cpp" + "SpawnLionServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp new file mode 100644 index 00000000..13e2e4e5 --- /dev/null +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp @@ -0,0 +1,85 @@ +#include "GfCaptainsCannon.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "eTerminateType.h" +#include "eStateChangeType.h" + +void GfCaptainsCannon::OnUse(Entity* self, Entity* user) { + if (self->GetVar<bool>(u"bIsInUse")) { + return; + } + + self->SetVar<LWOOBJID>(u"userID", user->GetObjectID()); + + self->SetVar<bool>(u"bIsInUse", true); + self->SetNetworkVar<bool>(u"bIsInUse", true); + + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), + LWOOBJID_EMPTY, true, true, true, true, true, true, true, true + ); + + auto position = self->GetPosition(); + auto forward = self->GetRotation().GetForwardVector(); + + position.x += forward.x * -3; + position.z += forward.z * -3; + + auto rotation = self->GetRotation(); + + GameMessages::SendTeleport(user->GetObjectID(), position, rotation, user->GetSystemAddress()); + + GameMessages::SendPlayAnimation(user, u"cannon-strike-no-equip"); + + GameMessages::SendPlayFXEffect(user->GetObjectID(), 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); + + self->AddTimer("FireCannon", 1.667f); +} + +void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { + const auto playerId = self->GetVar<LWOOBJID>(u"userID"); + + auto* player = EntityManager::Instance()->GetEntity(playerId); + + if (player == nullptr) { + self->SetVar<bool>(u"bIsInUse", false); + self->SetNetworkVar<bool>(u"bIsInUse", false); + + return; + } + + if (timerName == "FireCannon") { + float cinematicTime = 6.3f; + + GameMessages::SendPlayCinematic(playerId, u"Cannon_Cam", player->GetSystemAddress()); + + self->AddTimer("cinematicTimer", cinematicTime); + + const auto sharkObjects = EntityManager::Instance()->GetEntitiesInGroup("SharkCannon"); + + for (auto* shark : sharkObjects) { + if (shark->GetLOT() != m_SharkItemID) continue; + + GameMessages::SendPlayAnimation(shark, u"cannon"); + } + + GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}"); + } else if (timerName == "cinematicTimer") { + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), + LWOOBJID_EMPTY, true, true, true, true, true, true, true, true + ); + + self->SetVar<bool>(u"bIsInUse", false); + self->SetNetworkVar<bool>(u"bIsInUse", false); + + GameMessages::SendStopFXEffect(player, true, "hook"); + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->ForceProgress(601, 910, 1); + } + + GameMessages::SendTerminateInteraction(playerId, eTerminateType::FROM_INTERACTION, self->GetObjectID()); + } +} diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.h b/dScripts/02_server/Map/GF/GfCaptainsCannon.h new file mode 100644 index 00000000..23429b5d --- /dev/null +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class GfCaptainsCannon : public CppScripts::Script +{ +public: + void OnUse(Entity* self, Entity* user) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + int32_t m_SharkItemID = 7343; +}; diff --git a/dScripts/GfTikiTorch.cpp b/dScripts/02_server/Map/GF/GfTikiTorch.cpp similarity index 54% rename from dScripts/GfTikiTorch.cpp rename to dScripts/02_server/Map/GF/GfTikiTorch.cpp index dd1c14a7..8528192f 100644 --- a/dScripts/GfTikiTorch.cpp +++ b/dScripts/02_server/Map/GF/GfTikiTorch.cpp @@ -3,6 +3,9 @@ #include "EntityManager.h" #include "MissionComponent.h" #include "RenderComponent.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" +#include "eTerminateType.h" void GfTikiTorch::OnStartup(Entity* self) { LightTorch(self); @@ -27,12 +30,11 @@ void GfTikiTorch::OnUse(Entity* self, Entity* killer) { void GfTikiTorch::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "Relight") { LightTorch(self); - } - else if (timerName == "InteractionCooldown") { + } else if (timerName == "InteractionCooldown") { Entity* player = EntityManager::Instance()->GetEntity(self->GetI64(u"userID")); - + if (player != nullptr && player->GetCharacter()) { - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); } self->SetBoolean(u"isInUse", false); @@ -42,35 +44,35 @@ void GfTikiTorch::OnTimerDone(Entity* self, std::string timerName) { } void GfTikiTorch::LightTorch(Entity* self) { - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) return; - + self->SetBoolean(u"isInUse", false); renderComponent->PlayEffect(611, u"fire", "tikitorch"); self->SetBoolean(u"isBurning", true); } -void GfTikiTorch::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - if (self->GetBoolean(u"isBurning") && message == "waterspray") { - GameMessages::SendPlayAnimation(self, u"water"); +void GfTikiTorch::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (self->GetBoolean(u"isBurning") && message == "waterspray") { + GameMessages::SendPlayAnimation(self, u"water"); - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("tikitorch"); - renderComponent->PlayEffect(611, u"water", "water"); - renderComponent->PlayEffect(611, u"steam", "steam"); - } + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("tikitorch"); + renderComponent->PlayEffect(611, u"water", "water"); + renderComponent->PlayEffect(611, u"steam", "steam"); + } - auto* casterMissionComponent = caster->GetComponent<MissionComponent>(); - if (casterMissionComponent != nullptr) { - for (const auto missionID : m_missions) { - casterMissionComponent->ForceProgressTaskType(missionID, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); - } - } + auto* casterMissionComponent = caster->GetComponent<MissionComponent>(); + if (casterMissionComponent != nullptr) { + for (const auto missionID : m_missions) { + casterMissionComponent->ForceProgressTaskType(missionID, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); + } + } - self->AddTimer("Relight", 7.0f); - self->SetBoolean(u"isBurning", false); - } + self->AddTimer("Relight", 7.0f); + self->SetBoolean(u"isBurning", false); + } } diff --git a/dScripts/GfTikiTorch.h b/dScripts/02_server/Map/GF/GfTikiTorch.h similarity index 59% rename from dScripts/GfTikiTorch.h rename to dScripts/02_server/Map/GF/GfTikiTorch.h index e9046ddc..5d3de0a8 100644 --- a/dScripts/GfTikiTorch.h +++ b/dScripts/02_server/Map/GF/GfTikiTorch.h @@ -1,17 +1,17 @@ #pragma once #include "CppScripts.h" -class GfTikiTorch : public CppScripts::Script +class GfTikiTorch : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnUse(Entity* self, Entity* killer) override; void OnTimerDone(Entity* self, std::string timerName) override; - void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; private: void LightTorch(Entity* self); LOT m_imaginationlot = 935; int32_t m_numspawn = 3; - std::vector<int> m_missions = {472, 1429, 1527, 1564, 1601}; -}; \ No newline at end of file + std::vector<int> m_missions = { 472, 1429, 1527, 1564, 1601 }; +}; diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp new file mode 100644 index 00000000..97b126b4 --- /dev/null +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -0,0 +1,96 @@ +#include "MastTeleport.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "Preconditions.h" +#include "eEndBehavior.h" +#include "DestroyableComponent.h" +#include "eStateChangeType.h" + +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#include <math.h> +#endif + +void MastTeleport::OnStartup(Entity* self) { + self->SetNetworkVar<std::string>(u"hookPreconditions", "154;44", UNASSIGNED_SYSTEM_ADDRESS); +} + +void MastTeleport::OnRebuildComplete(Entity* self, Entity* target) { + if (Preconditions::Check(target, 154) && Preconditions::Check(target, 44)) { + self->SetVar<LWOOBJID>(u"userID", target->GetObjectID()); + + GameMessages::SendSetStunned(target->GetObjectID(), eStateChangeType::PUSH, target->GetSystemAddress(), + LWOOBJID_EMPTY, true, true, true, true, true, true, true + ); + auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, false, false, true, true); + + self->AddTimer("Start", 3); + } +} + +void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { + const auto playerId = self->GetVar<LWOOBJID>(u"userID"); + + auto* player = EntityManager::Instance()->GetEntity(playerId); + + if (player == nullptr) return; + + if (timerName == "Start") { + auto position = self->GetPosition(); + auto rotation = self->GetRotation(); + + GameMessages::SendTeleport(playerId, position, rotation, player->GetSystemAddress(), true); + + // Hacky fix for odd rotations + if (self->GetVar<std::u16string>(u"MastName") != u"Jail") { + GameMessages::SendOrientToAngle(playerId, true, (M_PI / 180) * 140.0f, player->GetSystemAddress()); + } else { + GameMessages::SendOrientToAngle(playerId, true, (M_PI / 180) * 100.0f, player->GetSystemAddress()); + } + + const auto cinematic = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Cinematic")); + const auto leanIn = self->GetVar<float>(u"LeanIn"); + + if (!cinematic.empty()) { + GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(), + true, true, false, false, eEndBehavior::RETURN, false, leanIn + ); + } + + GameMessages::SendPlayFXEffect(playerId, 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); + + GameMessages::SendPlayAnimation(player, u"crow-swing-no-equip", 4.0f); + + GameMessages::SendPlayAnimation(self, u"swing"); + + self->AddTimer("PlayerAnimDone", 6.25f); + } else if (timerName == "PlayerAnimDone") { + GameMessages::SendStopFXEffect(player, true, "hook"); + + auto forward = self->GetRotation().GetForwardVector(); + + const auto degrees = -25.0f; + + const auto rads = degrees * (static_cast<float>(M_PI) / 180.0f); + + const Vector3 newPlayerRot = { 0, rads, 0 }; + + auto position = self->GetPosition(); + + position.x += (forward.x * 20.5f); + position.y += 12; + position.z += (forward.z * 20.5f); + + GameMessages::SendOrientToAngle(playerId, true, rads, player->GetSystemAddress()); + + GameMessages::SendTeleport(playerId, position, NiQuaternion::IDENTITY, player->GetSystemAddress()); + + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), + LWOOBJID_EMPTY, true, true, true, true, true, true, true + ); + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, false, false, true, true); + EntityManager::Instance()->SerializeEntity(player); + } +} diff --git a/dScripts/MastTeleport.h b/dScripts/02_server/Map/GF/MastTeleport.h similarity index 74% rename from dScripts/MastTeleport.h rename to dScripts/02_server/Map/GF/MastTeleport.h index 1b5dc481..ea35d754 100644 --- a/dScripts/MastTeleport.h +++ b/dScripts/02_server/Map/GF/MastTeleport.h @@ -4,6 +4,6 @@ class MastTeleport : public CppScripts::Script { public: void OnStartup(Entity* self) override; - void OnRebuildComplete(Entity* self, Entity* target) override; + void OnRebuildComplete(Entity* self, Entity* target) override; void OnTimerDone(Entity* self, std::string timerName) override; -}; \ No newline at end of file +}; diff --git a/dScripts/02_server/Map/GF/SpawnLionServer.cpp b/dScripts/02_server/Map/GF/SpawnLionServer.cpp new file mode 100644 index 00000000..622985b1 --- /dev/null +++ b/dScripts/02_server/Map/GF/SpawnLionServer.cpp @@ -0,0 +1,10 @@ +#include "SpawnLionServer.h" +#include "Entity.h" + +void SpawnLionServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 3520); + self->SetVar<std::string>(u"petType", "lion"); + self->SetVar<uint32_t>(u"maxPets", 5); + self->SetVar<std::u16string>(u"spawnAnim", u"spawn-lion"); + self->SetVar<std::u16string>(u"spawnCinematic", u"Lion_spawn"); +} diff --git a/dScripts/SpawnLionServer.h b/dScripts/02_server/Map/GF/SpawnLionServer.h similarity index 68% rename from dScripts/SpawnLionServer.h rename to dScripts/02_server/Map/GF/SpawnLionServer.h index b4cd208c..2c8e7f0f 100644 --- a/dScripts/SpawnLionServer.h +++ b/dScripts/02_server/Map/GF/SpawnLionServer.h @@ -2,5 +2,5 @@ #include "SpawnPetBaseServer.h" class SpawnLionServer : public SpawnPetBaseServer { - void SetVariables(Entity *self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/General/BankInteractServer.cpp b/dScripts/02_server/Map/General/BankInteractServer.cpp new file mode 100644 index 00000000..b96187cf --- /dev/null +++ b/dScripts/02_server/Map/General/BankInteractServer.cpp @@ -0,0 +1,25 @@ +#include "BankInteractServer.h" +#include "GameMessages.h" +#include "Entity.h" +#include "AMFFormat.h" + +void BankInteractServer::OnUse(Entity* self, Entity* user) { + AMFArrayValue args; + AMFStringValue* bank = new AMFStringValue(); + bank->SetStringValue("bank"); + args.InsertValue("state", bank); + + GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); +} + +void BankInteractServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == "ToggleBank") { + AMFArrayValue args; + args.InsertValue("visible", new AMFFalseValue()); + + GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &args); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); + } +} diff --git a/dScripts/02_server/Map/General/BankInteractServer.h b/dScripts/02_server/Map/General/BankInteractServer.h new file mode 100644 index 00000000..3fe4d25c --- /dev/null +++ b/dScripts/02_server/Map/General/BankInteractServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class BankInteractServer : public CppScripts::Script +{ +public: + void OnUse(Entity* self, Entity* user) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp new file mode 100644 index 00000000..44698956 --- /dev/null +++ b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp @@ -0,0 +1,30 @@ +#include "BaseInteractDropLootServer.h" +#include "Loot.h" +#include "GameMessages.h" + +void BaseInteractDropLootServer::OnUse(Entity* self, Entity* user) { + BaseUse(self, user); +} + +void BaseInteractDropLootServer::BaseUse(Entity* self, Entity* user) { + auto cooldownTime = self->GetVar<float>(u"cooldownTime"); + if (cooldownTime == 0) cooldownTime = 5; + + uint32_t lootMatrix = self->GetVar<int32_t>(u"UseLootMatrix"); + if (lootMatrix == 0) lootMatrix = self->GetVar<int32_t>(u"smashable_loot_matrix"); + if (lootMatrix == 0) lootMatrix = 715; + + auto useSound = self->GetVar<std::string>(u"sound1"); + + if (!useSound.empty()) { + GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound); + } + + self->SetNetworkVar(u"bInUse", true); + + LootGenerator::Instance().DropLoot(user, self, lootMatrix, 0, 0); + + self->AddCallbackTimer(cooldownTime, [this, self]() { + self->SetNetworkVar(u"bInUse", false); + }); +} diff --git a/dScripts/BaseInteractDropLootServer.h b/dScripts/02_server/Map/General/BaseInteractDropLootServer.h similarity index 51% rename from dScripts/BaseInteractDropLootServer.h rename to dScripts/02_server/Map/General/BaseInteractDropLootServer.h index d2e9b600..f2a084f5 100644 --- a/dScripts/BaseInteractDropLootServer.h +++ b/dScripts/02_server/Map/General/BaseInteractDropLootServer.h @@ -4,7 +4,7 @@ class BaseInteractDropLootServer : public CppScripts::Script { public: - virtual void OnUse(Entity* self, Entity* user) override; - void BaseUse(Entity* self, Entity* user); + virtual void OnUse(Entity* self, Entity* user) override; + void BaseUse(Entity* self, Entity* user); }; diff --git a/dScripts/Binoculars.cpp b/dScripts/02_server/Map/General/Binoculars.cpp similarity index 99% rename from dScripts/Binoculars.cpp rename to dScripts/02_server/Map/General/Binoculars.cpp index 348b3842..854ccf71 100644 --- a/dScripts/Binoculars.cpp +++ b/dScripts/02_server/Map/General/Binoculars.cpp @@ -12,4 +12,4 @@ void Binoculars::OnUse(Entity* self, Entity* user) { user->GetCharacter()->SetPlayerFlag(flag, true); GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); } -} \ No newline at end of file +} diff --git a/dScripts/Binoculars.h b/dScripts/02_server/Map/General/Binoculars.h similarity index 97% rename from dScripts/Binoculars.h rename to dScripts/02_server/Map/General/Binoculars.h index 141b3fb9..2f446119 100644 --- a/dScripts/Binoculars.h +++ b/dScripts/02_server/Map/General/Binoculars.h @@ -4,4 +4,4 @@ class Binoculars : public CppScripts::Script { public: void OnUse(Entity* self, Entity* user); -}; \ No newline at end of file +}; diff --git a/dScripts/02_server/Map/General/CMakeLists.txt b/dScripts/02_server/Map/General/CMakeLists.txt new file mode 100644 index 00000000..1fe3d785 --- /dev/null +++ b/dScripts/02_server/Map/General/CMakeLists.txt @@ -0,0 +1,28 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL + "BankInteractServer.cpp" + "BaseInteractDropLootServer.cpp" + "Binoculars.cpp" + "ExplodingAsset.cpp" + "ForceVolumeServer.cpp" + "GrowingFlower.cpp" + "ImaginationBackpackHealServer.cpp" + "InvalidScript.cpp" + "MailBoxServer.cpp" + "NjRailSwitch.cpp" + "PetDigServer.cpp" + "PropertyDevice.cpp" + "PropertyPlatform.cpp" + "QbEnemyStunner.cpp" + "QbSpawner.cpp" + "StoryBoxInteractServer.cpp" + "TokenConsoleServer.cpp" + "TouchMissionUpdateServer.cpp" + "WishingWellServer.cpp") + +add_subdirectory(Ninjago) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL_NINJAGO}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL} "Ninjago/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL} PARENT_SCOPE) diff --git a/dScripts/ExplodingAsset.cpp b/dScripts/02_server/Map/General/ExplodingAsset.cpp similarity index 78% rename from dScripts/ExplodingAsset.cpp rename to dScripts/02_server/Map/General/ExplodingAsset.cpp index b4bd6913..16340ee6 100644 --- a/dScripts/ExplodingAsset.cpp +++ b/dScripts/02_server/Map/General/ExplodingAsset.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "MissionComponent.h" #include "SkillComponent.h" +#include "eMissionTaskType.h" //TODO: this has to be updated so that you only get killed if you're in a certain radius. //And so that all entities in a certain radius are killed, not just the attacker. @@ -26,7 +27,7 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) { if (destroyable == nullptr) { continue; } - + destroyable->Smash(attacker->GetObjectID()); } } @@ -49,26 +50,25 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) { // Progress all scripted missions related to this asset auto* missionComponent = attacker->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - if (missionID != 0) { - missionComponent->ForceProgressValue(missionID, - static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), - self->GetLOT(), false); - } + if (missionID != 0) { + missionComponent->ForceProgressValue(missionID, + static_cast<uint32_t>(eMissionTaskType::SCRIPT), + self->GetLOT(), false); + } - if (!achievementIDs.empty()) { - for (const auto& achievementID : GeneralUtils::SplitString(achievementIDs, u'_')) { - missionComponent->ForceProgressValue(std::stoi(GeneralUtils::UTF16ToWTF8(achievementID)), - static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), - self->GetLOT()); - } - } + if (!achievementIDs.empty()) { + for (const auto& achievementID : GeneralUtils::SplitString(achievementIDs, u'_')) { + missionComponent->ForceProgressValue(std::stoi(GeneralUtils::UTF16ToWTF8(achievementID)), + static_cast<uint32_t>(eMissionTaskType::SCRIPT), + self->GetLOT()); + } + } } self->ScheduleKillAfterUpdate(); } -void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ +void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { /* if msg.objId:BelongsToFaction{factionID = 1}.bIsInFaction then if (msg.status == "ENTER") then @@ -94,21 +94,17 @@ void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::stri if (!std::count(factions.begin(), factions.end(), 1)) return; - if (status == "ENTER") - { + if (status == "ENTER") { GameMessages::SendPlayAnimation(self, u"bounce"); GameMessages::SendPlayFXEffect(self, -1, u"anim", "bouncin", LWOOBJID_EMPTY, 1, 1, true); self->SetVar(u"playersNearChest", self->GetVar<int32_t>(u"playersNearChest") + 1); - } - else if (status == "LEAVE") - { + } else if (status == "LEAVE") { self->SetVar(u"playersNearChest", self->GetVar<int32_t>(u"playersNearChest") - 1); - if (self->GetVar<int32_t>(u"playersNearChest") < 1) - { + if (self->GetVar<int32_t>(u"playersNearChest") < 1) { GameMessages::SendPlayAnimation(self, u"idle"); GameMessages::SendStopFXEffect(self, true, "bouncin"); self->SetVar<int32_t>(u"playersNearChest", 0); } } -} \ No newline at end of file +} diff --git a/dScripts/ExplodingAsset.h b/dScripts/02_server/Map/General/ExplodingAsset.h similarity index 98% rename from dScripts/ExplodingAsset.h rename to dScripts/02_server/Map/General/ExplodingAsset.h index bd2c2544..9b97ecc7 100644 --- a/dScripts/ExplodingAsset.h +++ b/dScripts/02_server/Map/General/ExplodingAsset.h @@ -7,4 +7,4 @@ public: void OnStartup(Entity* self); void OnHit(Entity* self, Entity* attacker); void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status); -}; \ No newline at end of file +}; diff --git a/dScripts/02_server/Map/General/ForceVolumeServer.cpp b/dScripts/02_server/Map/General/ForceVolumeServer.cpp new file mode 100644 index 00000000..ed9024c1 --- /dev/null +++ b/dScripts/02_server/Map/General/ForceVolumeServer.cpp @@ -0,0 +1,22 @@ +#include "ForceVolumeServer.h" +#include "PhantomPhysicsComponent.h" +#include "EntityManager.h" +#include "ePhysicsEffectType.h" + +void ForceVolumeServer::OnStartup(Entity* self) { + auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); + + if (phantomPhysicsComponent == nullptr) return; + + const auto forceAmount = self->GetVar<float>(u"ForceAmt"); + const auto forceX = self->GetVar<float>(u"ForceX"); + const auto forceY = self->GetVar<float>(u"ForceY"); + const auto forceZ = self->GetVar<float>(u"ForceZ"); + + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); + phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount); + phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ }); + phantomPhysicsComponent->SetPhysicsEffectActive(true); + + EntityManager::Instance()->SerializeEntity(self); +} diff --git a/dScripts/ForceVolumeServer.h b/dScripts/02_server/Map/General/ForceVolumeServer.h similarity index 100% rename from dScripts/ForceVolumeServer.h rename to dScripts/02_server/Map/General/ForceVolumeServer.h diff --git a/dScripts/02_server/Map/General/GrowingFlower.cpp b/dScripts/02_server/Map/General/GrowingFlower.cpp new file mode 100644 index 00000000..ad88528f --- /dev/null +++ b/dScripts/02_server/Map/General/GrowingFlower.cpp @@ -0,0 +1,38 @@ +#include "GrowingFlower.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "Loot.h" + +void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::string& message) { + if (!self->GetVar<bool>(u"blooming") && (message == "waterspray" || message == "shovelgrow")) { + self->SetVar<bool>(u"blooming", true); + self->SetNetworkVar(u"blooming", true); + self->AddTimer("FlowerDie", GrowingFlower::aliveTime); + + const auto mission1 = self->GetVar<int32_t>(u"missionID"); + const auto mission2 = self->GetVar<int32_t>(u"missionID2"); + + LootGenerator::Instance().DropActivityLoot(target, self, self->GetLOT(), 0); + + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + for (const auto mission : achievementIDs) + missionComponent->ForceProgressTaskType(mission, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); + + if (mission1 && missionComponent->GetMissionState(mission1) == eMissionState::ACTIVE) + missionComponent->ForceProgressTaskType(mission1, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); + + if (mission2 && missionComponent->GetMissionState(mission2) == eMissionState::ACTIVE) + missionComponent->ForceProgressTaskType(mission2, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); + } + } +} + +void GrowingFlower::OnTimerDone(Entity* self, std::string message) { + if (message == "FlowerDie") { + self->Smash(); + } +} + +const std::vector<uint32_t> GrowingFlower::achievementIDs = { 143, 152, 153, 1409, 1507, 1544, 1581, 1845 }; diff --git a/dScripts/02_server/Map/General/GrowingFlower.h b/dScripts/02_server/Map/General/GrowingFlower.h new file mode 100644 index 00000000..b7090855 --- /dev/null +++ b/dScripts/02_server/Map/General/GrowingFlower.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class GrowingFlower : public CppScripts::Script { +public: + void OnSkillEventFired(Entity* self, Entity* target, const std::string& message) override; + void OnTimerDone(Entity* self, std::string message) override; +private: + static const std::vector<uint32_t> achievementIDs; + constexpr static const float aliveTime = 16.0f; +}; diff --git a/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp new file mode 100644 index 00000000..8b3da9fa --- /dev/null +++ b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp @@ -0,0 +1,22 @@ +#include "ImaginationBackpackHealServer.h" +#include "GameMessages.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" + +void ImaginationBackpackHealServer::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message == "CastImaginationBackpack") { + auto healMission = self->GetVar<int32_t>(u"FXOffMis"); + if (healMission == 0) + healMission = self->GetVar<int32_t>(u"FXOnMis"); + if (healMission == 0) + return; + + auto* missionComponent = caster->GetComponent<MissionComponent>(); + if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == eMissionState::ACTIVE) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0, + caster->GetObjectID(), "", caster->GetSystemAddress()); + } + } +} diff --git a/dScripts/ImaginationBackpackHealServer.h b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.h similarity index 52% rename from dScripts/ImaginationBackpackHealServer.h rename to dScripts/02_server/Map/General/ImaginationBackpackHealServer.h index 387f38d7..dbe5ab01 100644 --- a/dScripts/ImaginationBackpackHealServer.h +++ b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class ImaginationBackpackHealServer : public CppScripts::Script { - void OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; }; diff --git a/dScripts/InvalidScript.cpp b/dScripts/02_server/Map/General/InvalidScript.cpp similarity index 100% rename from dScripts/InvalidScript.cpp rename to dScripts/02_server/Map/General/InvalidScript.cpp diff --git a/dScripts/InvalidScript.h b/dScripts/02_server/Map/General/InvalidScript.h similarity index 100% rename from dScripts/InvalidScript.h rename to dScripts/02_server/Map/General/InvalidScript.h diff --git a/dScripts/02_server/Map/General/MailBoxServer.cpp b/dScripts/02_server/Map/General/MailBoxServer.cpp new file mode 100644 index 00000000..c2534f3e --- /dev/null +++ b/dScripts/02_server/Map/General/MailBoxServer.cpp @@ -0,0 +1,19 @@ +#include "MailBoxServer.h" +#include "AMFFormat.h" +#include "GameMessages.h" + +void MailBoxServer::OnUse(Entity* self, Entity* user) { + AMFStringValue* value = new AMFStringValue(); + value->SetStringValue("Mail"); + AMFArrayValue args; + args.InsertValue("state", value); + GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); +} + +void MailBoxServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "toggleMail") { + AMFArrayValue args; + args.InsertValue("visible", new AMFFalseValue()); + GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleMail", &args); + } +} diff --git a/dScripts/02_server/Map/General/MailBoxServer.h b/dScripts/02_server/Map/General/MailBoxServer.h new file mode 100644 index 00000000..9ada6a0e --- /dev/null +++ b/dScripts/02_server/Map/General/MailBoxServer.h @@ -0,0 +1,16 @@ +#pragma once + +#include "CppScripts.h" + +class MailBoxServer : public CppScripts::Script { +public: + /** + * When a mailbox is interacted with, this method updates the player game state + * to be in a mailbox. + * + * @param self The object that owns this script. + * @param user The user that interacted with this Entity. + */ + void OnUse(Entity* self, Entity* user) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/General/Ninjago/CMakeLists.txt b/dScripts/02_server/Map/General/Ninjago/CMakeLists.txt new file mode 100644 index 00000000..2b74e921 --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL_NINJAGO + "NjRailActivatorsServer.cpp" + "NjRailPostServer.cpp" + "NjIceRailActivator.cpp" + "NjhubLavaPlayerDeathTrigger.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.cpp b/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.cpp new file mode 100644 index 00000000..2549cd0f --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.cpp @@ -0,0 +1,25 @@ +#include "NjIceRailActivator.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void NjIceRailActivator::OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName, + int32_t waypoint) { + const auto breakPoint = self->GetVar<int32_t>(BreakpointVariable); + if (breakPoint == waypoint) { + const auto& blockGroup = self->GetVar<std::u16string>(BlockGroupVariable); + + for (auto* block : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(blockGroup))) { + GameMessages::SendPlayAnimation(block, u"explode"); + + const auto blockID = block->GetObjectID(); + + self->AddCallbackTimer(1.0f, [self, blockID]() { + auto* block = EntityManager::Instance()->GetEntity(blockID); + + if (block != nullptr) { + block->Kill(self); + } + }); + } + } +} diff --git a/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.h b/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.h new file mode 100644 index 00000000..05927898 --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjIceRailActivator.h @@ -0,0 +1,10 @@ +#pragma once +#include "NjRailActivatorsServer.h" + +class NjIceRailActivator : public NjRailActivatorsServer { + void OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName, int32_t waypoint) override; +private: + std::u16string BreakpointVariable = u"BreakPoint"; + std::u16string BlockGroupVariable = u"BlockGroup"; + std::u16string IceBlockVariable = u"IceBlock"; +}; diff --git a/dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.cpp b/dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.cpp new file mode 100644 index 00000000..5ca726af --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.cpp @@ -0,0 +1,16 @@ +#include "NjRailActivatorsServer.h" +#include "RebuildComponent.h" +#include "Character.h" + +void NjRailActivatorsServer::OnUse(Entity* self, Entity* user) { + const auto flag = self->GetVar<int32_t>(u"RailFlagNum"); + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + // Only allow use if this is not a quick build or the quick build is built + if (rebuildComponent == nullptr || rebuildComponent->GetState() == eRebuildState::COMPLETED) { + auto* character = user->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(flag, true); + } + } +} diff --git a/dScripts/NjRailActivatorsServer.h b/dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.h similarity index 66% rename from dScripts/NjRailActivatorsServer.h rename to dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.h index 3e94f119..6f267705 100644 --- a/dScripts/NjRailActivatorsServer.h +++ b/dScripts/02_server/Map/General/Ninjago/NjRailActivatorsServer.h @@ -2,5 +2,5 @@ #include "NjRailPostServer.h" class NjRailActivatorsServer : public NjRailPostServer { - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.cpp b/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.cpp new file mode 100644 index 00000000..2c435705 --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.cpp @@ -0,0 +1,51 @@ +#include "NjRailPostServer.h" +#include "RebuildComponent.h" +#include "EntityManager.h" + +void NjRailPostServer::OnStartup(Entity* self) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + if (rebuildComponent != nullptr) { + self->SetNetworkVar<bool>(NetworkNotActiveVariable, true); + } +} + +void NjRailPostServer::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, + int32_t param2) { + if (name == "PostRebuilt") { + self->SetNetworkVar<bool>(NetworkNotActiveVariable, false); + } else if (name == "PostDied") { + self->SetNetworkVar<bool>(NetworkNotActiveVariable, true); + } +} + +void NjRailPostServer::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { + auto* relatedRail = GetRelatedRail(self); + if (relatedRail == nullptr) + return; + + relatedRail->NotifyObject(self, "PostRebuilt"); + + if (self->GetVar<bool>(NotActiveVariable)) + return; + + self->SetNetworkVar(NetworkNotActiveVariable, false); + } else if (state == eRebuildState::RESETTING) { + auto* relatedRail = GetRelatedRail(self); + if (relatedRail == nullptr) + return; + + relatedRail->NotifyObject(self, "PostDied"); + } +} + +Entity* NjRailPostServer::GetRelatedRail(Entity* self) { + const auto& railGroup = self->GetVar<std::u16string>(RailGroupVariable); + if (!railGroup.empty()) { + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(railGroup))) { + return entity; + } + } + + return nullptr; +} diff --git a/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.h b/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.h new file mode 100644 index 00000000..3486db87 --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjRailPostServer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class NjRailPostServer : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; +private: + Entity* GetRelatedRail(Entity* self); + const std::u16string NetworkNotActiveVariable = u"NetworkNotActive"; + const std::u16string NotActiveVariable = u"NotActive"; + const std::u16string RailGroupVariable = u"RailGroup"; +}; diff --git a/dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.cpp b/dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.cpp new file mode 100644 index 00000000..e2b889ef --- /dev/null +++ b/dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.cpp @@ -0,0 +1,9 @@ +#include "NjhubLavaPlayerDeathTrigger.h" +#include "Entity.h" + +void NjhubLavaPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target->IsPlayer()) + return; + + target->Smash(self->GetObjectID(), eKillType::VIOLENT, u"drown"); +} diff --git a/dScripts/NjhubLavaPlayerDeathTrigger.h b/dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.h similarity index 60% rename from dScripts/NjhubLavaPlayerDeathTrigger.h rename to dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.h index 48ff85d0..2cf0883f 100644 --- a/dScripts/NjhubLavaPlayerDeathTrigger.h +++ b/dScripts/02_server/Map/General/Ninjago/NjhubLavaPlayerDeathTrigger.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NjhubLavaPlayerDeathTrigger : public CppScripts::Script { - void OnCollisionPhantom(Entity *self, Entity *target) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; }; diff --git a/dScripts/02_server/Map/General/NjRailSwitch.cpp b/dScripts/02_server/Map/General/NjRailSwitch.cpp new file mode 100644 index 00000000..e53445d9 --- /dev/null +++ b/dScripts/02_server/Map/General/NjRailSwitch.cpp @@ -0,0 +1,12 @@ +#include "NjRailSwitch.h" +#include "GameMessages.h" + +void NjRailSwitch::OnUse(Entity* self, Entity* user) { + // const auto path = self->GetVar<std::u16string>(u"rail_path"); + // const auto pathStart = self->GetVar<uint32_t>(u"rail_path_start"); + // const auto pathGoForward = self->GetVar<bool>(u"rail_path_direction"); + // const auto cinematicName = self->GetVar<std::u16string>(u"cinematic"); + // + // GameMessages::SendSetRailMovement(self->GetObjectID(), pathGoForward, path, pathStart, user->GetSystemAddress()); + // GameMessages::SendPlayCinematic(self->GetObjectID(), cinematicName, user->GetSystemAddress()); +} diff --git a/dScripts/NjRailSwitch.h b/dScripts/02_server/Map/General/NjRailSwitch.h similarity index 62% rename from dScripts/NjRailSwitch.h rename to dScripts/02_server/Map/General/NjRailSwitch.h index 453b9650..38ce2095 100644 --- a/dScripts/NjRailSwitch.h +++ b/dScripts/02_server/Map/General/NjRailSwitch.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NjRailSwitch : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/General/PetDigServer.cpp b/dScripts/02_server/Map/General/PetDigServer.cpp new file mode 100644 index 00000000..8c819a8d --- /dev/null +++ b/dScripts/02_server/Map/General/PetDigServer.cpp @@ -0,0 +1,236 @@ +#include "dZoneManager.h" +#include "PetDigServer.h" +#include "MissionComponent.h" +#include "EntityManager.h" +#include "Character.h" +#include "PetComponent.h" +#include "User.h" +#include "eMissionState.h" + +std::vector<LWOOBJID> PetDigServer::treasures{}; + +const DigInfo PetDigServer::defaultDigInfo = DigInfo{ 3495, -1, -1, false, false, false, false }; + +/** + * Summary of all the special treasure behaviors, indexed by their lot + */ +const std::map<LOT, DigInfo> PetDigServer::digInfoMap{ + // Regular treasures + {3495, defaultDigInfo}, + + // Pet cove treasure + {7612, DigInfo { 7612, -1, -1, false, false, false, false }}, + + // Gnarled Forest flag treasure + {7410, DigInfo { 7410, -1, -1, false, true, false, false }}, + + // Gnarled Forest crab treasure + {9308, DigInfo { 9308, 7694, -1, false, false, false, false }}, + + // Avant Gardens mission treasure + {9307, DigInfo { 9307, -1, -1, false, true, false, true }}, + + // Avant Gardens bouncer treasure + {7559, DigInfo { 7559, -1, -1, false, false, true, false }}, + + // Crux Prime dragon treasure + {13098, DigInfo { 13098, 13067, 1298, false, false, false, false }}, + + // Bone treasure (can only be digged using the dragon) + {12192, DigInfo { 12192, -1, -1, true, false, false, false }}, +}; + +void PetDigServer::OnStartup(Entity* self) { + treasures.push_back(self->GetObjectID()); + const auto digInfoIterator = digInfoMap.find(self->GetLOT()); + const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo; + + // Reset any bouncers that might've been created by the previous dig + if (digInfo.bouncer) { + auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber")); + auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber); + auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber); + + for (auto* bouncerSpawner : bouncerSpawners) { + for (auto* bouncer : bouncerSpawner->m_Info.nodes) + bouncerSpawner->Deactivate(); + bouncerSpawner->Reset(); + } + + for (auto* switchSpawner : switchSpawners) { + switchSpawner->Deactivate(); + switchSpawner->Reset(); + } + } +} + +void PetDigServer::OnDie(Entity* self, Entity* killer) { + const auto iterator = std::find(treasures.begin(), treasures.end(), self->GetObjectID()); + if (iterator != treasures.end()) { + treasures.erase(iterator); + } + + auto* owner = killer->GetOwner(); + const auto digInfoIterator = digInfoMap.find(self->GetLOT()); + const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo; + + if (digInfo.spawnLot >= 0) { + PetDigServer::SpawnPet(self, owner, digInfo); + } else if (digInfo.builderOnly) { + + // Some treasures may only be retrieved by the player that built the diggable + auto builder = self->GetVar<LWOOBJID>(u"builder"); // Set by the pet dig build script + if (builder != owner->GetObjectID()) + return; + } else if (digInfo.xBuild) { + PetDigServer::HandleXBuildDig(self, owner, killer); + return; + } else if (digInfo.bouncer) { + PetDigServer::HandleBouncerDig(self, owner); + } + + PetDigServer::ProgressPetDigMissions(owner, self); + + self->SetNetworkVar<bool>(u"treasure_dug", true); + // TODO: Reset other pets + + // Handles smashing leftovers (edge case for the AG X) + auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X")); + if (xObject != nullptr) { + xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT); + } +} + +void PetDigServer::HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet) { + auto playerID = self->GetVar<LWOOBJID>(u"builder"); + if (playerID == LWOOBJID_EMPTY || playerID != owner->GetObjectID()) + return; + + auto* playerEntity = EntityManager::Instance()->GetEntity(playerID); + if (!playerEntity || !playerEntity->GetParentUser() || !playerEntity->GetParentUser()->GetLastUsedChar()) + return; + + auto* player = playerEntity->GetCharacter(); + const auto groupID = self->GetVar<std::u16string>(u"groupID"); + int32_t playerFlag = 0; + + // The flag that the player dug up + if (groupID == u"Flag1") { + playerFlag = 61; + } else if (groupID == u"Flag2") { + playerFlag = 62; + } else if (groupID == u"Flag3") { + playerFlag = 63; + } + + // If the player doesn't have the flag yet + if (playerFlag != 0 && !player->GetPlayerFlag(playerFlag)) { + auto* petComponent = pet->GetComponent<PetComponent>(); + if (petComponent != nullptr) { + // TODO: Pet state = 9 ?? + } + + // Shows the flag object to the player + player->SetPlayerFlag(playerFlag, true); + } + + auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X")); + if (xObject != nullptr) { + xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT); + } +} + +void PetDigServer::HandleBouncerDig(const Entity* self, const Entity* owner) { + auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber")); + auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber); + auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber); + + for (auto* bouncerSpawner : bouncerSpawners) { + bouncerSpawner->Activate(); + } + + for (auto* switchSpawner : switchSpawners) { + switchSpawner->Activate(); + } +} + +/** + * Progresses the Can You Dig It mission and the Pet Excavator Achievement if the player has never completed it yet + * \param owner the owner that just made a pet dig something up + */ +void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* chest) { + auto* missionComponent = owner->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + // Can You Dig It progress + const auto digMissionState = missionComponent->GetMissionState(843); + if (digMissionState == eMissionState::ACTIVE) { + missionComponent->ForceProgress(843, 1216, 1); + } + + // Pet Excavator progress + const auto excavatorMissionState = missionComponent->GetMissionState(505); + if (excavatorMissionState == eMissionState::ACTIVE) { + if (chest->HasVar(u"PetDig")) { + int32_t playerFlag = 1260 + chest->GetVarAs<int32_t>(u"PetDig"); + Character* player = owner->GetCharacter(); + + // check if player flag is set + if (!player->GetPlayerFlag(playerFlag)) { + missionComponent->ForceProgress(505, 767, 1); + player->SetPlayerFlag(playerFlag, 1); + } + } + } + } +} + +/** + * Some treasures spawn special pets, this handles that case + * \param owner the owner that just made a pet dig something up + * \param digInfo information regarding the treasure, will also contain info about the pet to spawn + */ +void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo digInfo) { + // Some treasures require a mission to be active + if (digInfo.requiredMission >= 0) { + auto* missionComponent = owner->GetComponent<MissionComponent>(); + if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < eMissionState::ACTIVE) { + return; + } + } + + EntityInfo info{}; + info.lot = digInfo.spawnLot; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.spawnerID = self->GetSpawnerID(); + info.settings = { + new LDFData<LWOOBJID>(u"tamer", owner->GetObjectID()), + new LDFData<std::string>(u"group", "pet" + std::to_string(owner->GetObjectID())), + new LDFData<std::string>(u"spawnAnim", "spawn-pet"), + new LDFData<float>(u"spawnTimer", 1.0) + }; + + auto* spawnedPet = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(spawnedPet); +} + +Entity* PetDigServer::GetClosestTresure(NiPoint3 position) { + float closestDistance = 0; + Entity* closest = nullptr; + + for (const auto tresureId : treasures) { + auto* tresure = EntityManager::Instance()->GetEntity(tresureId); + + if (tresure == nullptr) continue; + + float distance = Vector3::DistanceSquared(tresure->GetPosition(), position); + + if (closest == nullptr || distance < closestDistance) { + closestDistance = distance; + closest = tresure; + } + } + + return closest; +} diff --git a/dScripts/02_server/Map/General/PetDigServer.h b/dScripts/02_server/Map/General/PetDigServer.h new file mode 100644 index 00000000..1122517b --- /dev/null +++ b/dScripts/02_server/Map/General/PetDigServer.h @@ -0,0 +1,30 @@ +#pragma once +#include "CppScripts.h" + +struct DigInfo { + LOT digLot; // The lot of the chest + LOT spawnLot; // Option lot of pet to spawn + int32_t requiredMission; // Optional mission required before pet can be spawned, if < 0 == don't use + bool specificPet; // This treasure requires a specific pet to be dug up + bool xBuild; // This treasure is retrieved from a buildable cross + bool bouncer; // This treasure spawns a bouncer + bool builderOnly; // Only the builder of this diggable may access the rewards, for example with crosses +}; + +class PetDigServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; + + static Entity* GetClosestTresure(NiPoint3 position); + +private: + static void ProgressPetDigMissions(const Entity* owner, const Entity* chest); + static void SpawnPet(Entity* self, const Entity* owner, DigInfo digInfo); + static void HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet); + static void HandleBouncerDig(const Entity* self, const Entity* owner); + static std::vector<LWOOBJID> treasures; + static const DigInfo defaultDigInfo; + static const std::map<LOT, DigInfo> digInfoMap; +}; diff --git a/dScripts/02_server/Map/General/PropertyDevice.cpp b/dScripts/02_server/Map/General/PropertyDevice.cpp new file mode 100644 index 00000000..0ad9f5c9 --- /dev/null +++ b/dScripts/02_server/Map/General/PropertyDevice.cpp @@ -0,0 +1,26 @@ +#include "PropertyDevice.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "eMissionState.h" + +void PropertyDevice::OnStartup(Entity* self) { + auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + if (zoneControl != nullptr) { + zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); + } +} + +void PropertyDevice::OnRebuildComplete(Entity* self, Entity* target) { + auto propertyOwnerID = self->GetNetworkVar<std::string>(m_PropertyOwnerVariable); + if (propertyOwnerID == std::to_string(LWOOBJID_EMPTY)) + return; + + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + if (missionComponent->GetMissionState(m_PropertyMissionID) == eMissionState::ACTIVE) { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 641, u"create", "callhome"); + missionComponent->ForceProgress(m_PropertyMissionID, 1793, self->GetLOT()); + } + } +} diff --git a/dScripts/02_server/Map/General/PropertyDevice.h b/dScripts/02_server/Map/General/PropertyDevice.h new file mode 100644 index 00000000..87ca10ad --- /dev/null +++ b/dScripts/02_server/Map/General/PropertyDevice.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class PropertyDevice : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + const std::u16string m_PropertyOwnerVariable = u"PropertyOwnerID"; + const uint32_t m_PropertyMissionID = 1291; +}; diff --git a/dScripts/02_server/Map/General/PropertyPlatform.cpp b/dScripts/02_server/Map/General/PropertyPlatform.cpp new file mode 100644 index 00000000..7016db94 --- /dev/null +++ b/dScripts/02_server/Map/General/PropertyPlatform.cpp @@ -0,0 +1,33 @@ +#include "PropertyPlatform.h" +#include "RebuildComponent.h" +#include "GameMessages.h" +#include "MovingPlatformComponent.h" + +void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) { + // auto* movingPlatform = self->GetComponent<MovingPlatformComponent>(); + // if (movingPlatform != nullptr) { + // movingPlatform->StopPathing(); + // movingPlatform->SetNoAutoStart(true); + // } + GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, + 0, 0, eMovementPlatformState::Stationary); +} + +void PropertyPlatform::OnUse(Entity* self, Entity* user) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + if (rebuildComponent != nullptr && rebuildComponent->GetState() == eRebuildState::COMPLETED) { + // auto* movingPlatform = self->GetComponent<MovingPlatformComponent>(); + // if (movingPlatform != nullptr) { + // movingPlatform->GotoWaypoint(1); + // } + GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, + 1, 1, eMovementPlatformState::Moving); + + self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() { + self->SetNetworkVar<float_t>(u"startEffect", dieDelay); + self->AddCallbackTimer(dieDelay, [self]() { + self->Smash(); + }); + }); + } +} diff --git a/dScripts/02_server/Map/General/PropertyPlatform.h b/dScripts/02_server/Map/General/PropertyPlatform.h new file mode 100644 index 00000000..ec863ab0 --- /dev/null +++ b/dScripts/02_server/Map/General/PropertyPlatform.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class PropertyPlatform : public CppScripts::Script { +public: + void OnUse(Entity* self, Entity* user) override; + void OnRebuildComplete(Entity* self, Entity* target) override; +private: + float_t movementDelay = 10.0f; + float_t effectDelay = 5.0f; + float_t dieDelay = 5.0f; + uint32_t desiredWaypoint = 1; +}; diff --git a/dScripts/02_server/Map/General/QbEnemyStunner.cpp b/dScripts/02_server/Map/General/QbEnemyStunner.cpp new file mode 100644 index 00000000..441d743c --- /dev/null +++ b/dScripts/02_server/Map/General/QbEnemyStunner.cpp @@ -0,0 +1,69 @@ +#include "QbEnemyStunner.h" +#include "SkillComponent.h" +#include "CDClientManager.h" +#include "DestroyableComponent.h" + +#include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" + +void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) { + auto* destroyable = self->GetComponent<DestroyableComponent>(); + + if (destroyable != nullptr) { + destroyable->SetFaction(115); + } + + auto skillComponent = self->GetComponent<SkillComponent>(); + if (!skillComponent) return; + + // Get the skill IDs of this object. + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>(); + auto skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); + std::map<uint32_t, uint32_t> skillBehaviorMap; + // For each skill, cast it with the associated behavior ID. + for (auto skill : skills) { + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>(); + CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); + + skillBehaviorMap.insert(std::make_pair(skill.skillID, behaviorData.behaviorID)); + } + + // If there are no skills found, insert a default skill to use. + if (skillBehaviorMap.size() == 0) { + skillBehaviorMap.insert(std::make_pair(499U, 6095U)); + } + + // Start all skills associated with the object next tick + self->AddTimer("TickTime", 0); + + self->AddTimer("PlayEffect", 20); + + self->SetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap", skillBehaviorMap); +} + +void QbEnemyStunner::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "DieTime") { + self->Smash(); + + self->CancelAllTimers(); + } else if (timerName == "PlayEffect") { + self->SetNetworkVar(u"startEffect", 5.0f, UNASSIGNED_SYSTEM_ADDRESS); + + self->AddTimer("DieTime", 5.0f); + } else if (timerName == "TickTime") { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + auto skillBehaviorMap = self->GetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap"); + if (skillBehaviorMap.size() == 0) { + // Should no skills have been found, default to the mermaid stunner + skillComponent->CalculateBehavior(499U, 6095U, LWOOBJID_EMPTY); + } else { + for (auto pair : skillBehaviorMap) { + skillComponent->CalculateBehavior(pair.first, pair.second, LWOOBJID_EMPTY); + } + } + } + self->AddTimer("TickTime", 1); + } +} diff --git a/dScripts/02_server/Map/General/QbEnemyStunner.h b/dScripts/02_server/Map/General/QbEnemyStunner.h new file mode 100644 index 00000000..fd9033d6 --- /dev/null +++ b/dScripts/02_server/Map/General/QbEnemyStunner.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class QbEnemyStunner : public CppScripts::Script +{ +public: + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/General/QbSpawner.cpp b/dScripts/02_server/Map/General/QbSpawner.cpp new file mode 100644 index 00000000..d5c9d001 --- /dev/null +++ b/dScripts/02_server/Map/General/QbSpawner.cpp @@ -0,0 +1,136 @@ +#include "QbSpawner.h" +#include "BaseCombatAIComponent.h" +#include "EntityInfo.h" +#include "MovementAIComponent.h" + +void QbSpawner::OnStartup(Entity* self) { + auto mobNum = self->GetVar<int>(u"mobNum"); + auto spawnDist = self->GetVar<float>(u"spawnDist"); + auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate"); + auto spawnTime = self->GetVar<float>(u"spawnTime"); + + if (!mobNum) self->SetVar<int>(u"mobNum", m_DefaultMobNum); + if (!spawnDist) self->SetVar<float>(u"spawnDist", m_DefaultSpawnDist); + if (!mobTemplate) self->SetVar<LWOOBJID>(u"mobTemplate", m_DefaultMobTemplate); + if (!spawnTime) self->SetVar<float>(u"spawnTime", m_DefaultSpawnTime); + + // go ahead and setup the mob table here + std::vector<LWOOBJID> mobTable; + mobTable.assign(self->GetVar<int>(u"mobNum"), LWOOBJID_EMPTY); + + self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable); +} + +void QbSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + auto gateObjID = sender->GetObjectID(); + if (!gateObjID) return; + if (args == "spawnMobs") { + self->SetVar(u"gateObj", gateObjID); + auto spawnTime = self->GetVar<float>(u"spawnTime"); + self->AddTimer("SpawnMobEnemies", spawnTime); + } +} + +void QbSpawner::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "SpawnMobEnemies") { + auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable"); + + auto spawnDist = self->GetVar<float>(u"spawnDist"); + auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate"); + + auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj"); + if (!gateObjID) return; + + auto* gate = EntityManager::Instance()->GetEntity(gateObjID); + if (!gate) return; + + auto oPos = gate->GetPosition(); + auto oDir = gate->GetRotation().GetForwardVector(); + NiPoint3 newPos( + oPos.x + (oDir.x * spawnDist), + oPos.y, + oPos.z + (oDir.z * spawnDist) + ); + auto newRot = NiQuaternion::LookAt(newPos, oPos); + + for (int i = 0; i < mobTable.size(); i++) { + int posOffset = -10; + if (mobTable[i] == LWOOBJID_EMPTY) { + posOffset = posOffset + 5 * i; + auto newOffset = newPos; + newOffset.z = newOffset.z + posOffset; + + EntityInfo info{}; + info.lot = mobTemplate; + info.pos = newOffset; + info.rot = newRot; + info.spawnerID = self->GetObjectID(); + info.spawnerNodeID = 0; + info.settings = { + new LDFData<bool>(u"no_timed_spawn", true), + new LDFData<float>(u"aggroRadius", 70), + new LDFData<float>(u"softtetherRadius", 80), + new LDFData<float>(u"tetherRadius", 90), + new LDFData<float>(u"wanderRadius", 5), + new LDFData<int>(u"mobTableLoc", i) + }; + + auto* child = EntityManager::Instance()->CreateEntity(info, nullptr, self); + EntityManager::Instance()->ConstructEntity(child); + + OnChildLoaded(self, child); + } else { + auto* mob = EntityManager::Instance()->GetEntity(mobTable[i]); + AggroTargetObject(self, mob); + } + } + + } +} + +void QbSpawner::OnChildLoaded(Entity* self, Entity* child) { + auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable"); + auto tableLoc = child->GetVar<int>(u"mobTableLoc"); + + mobTable[tableLoc] = child->GetObjectID(); + self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable); + + AggroTargetObject(self, child); + + const auto selfID = self->GetObjectID(); + + child->AddDieCallback([this, selfID, child]() { + auto* self = EntityManager::Instance()->GetEntity(selfID); + OnChildRemoved(self, child); + } + ); +} + +void QbSpawner::OnChildRemoved(Entity* self, Entity* child) { + auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable"); + auto tableLoc = child->GetVar<int>(u"mobTableLoc"); + + mobTable[tableLoc] = LWOOBJID_EMPTY; + self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable); +} + +void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) { + auto* baseCombatAIComponent = enemy->GetComponent<BaseCombatAIComponent>(); + if (!baseCombatAIComponent) return; + + auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj"); + if (gateObjID) { + auto* gate = EntityManager::Instance()->GetEntity(gateObjID); + if (gate) { + auto* movementAIComponent = enemy->GetComponent<MovementAIComponent>(); + if (movementAIComponent) movementAIComponent->SetDestination(gate->GetPosition()); + baseCombatAIComponent->Taunt(gateObjID, 1000); + } + } + + auto playerObjID = self->GetVar<LWOOBJID>(u"player"); + if (playerObjID) { + baseCombatAIComponent->Taunt(playerObjID, 100); + } + +} diff --git a/dScripts/02_server/Map/General/QbSpawner.h b/dScripts/02_server/Map/General/QbSpawner.h new file mode 100644 index 00000000..105d0835 --- /dev/null +++ b/dScripts/02_server/Map/General/QbSpawner.h @@ -0,0 +1,17 @@ +#pragma once +#include "CppScripts.h" + +class QbSpawner : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnChildLoaded(Entity* self, Entity* child); + void OnChildRemoved(Entity* self, Entity* child); + void AggroTargetObject(Entity* self, Entity* enemy); +private: + const int m_DefaultMobNum = 3; + const float m_DefaultSpawnDist = 25.0; + const LWOOBJID m_DefaultMobTemplate = 4712; + const float m_DefaultSpawnTime = 2.0; +}; diff --git a/dScripts/StoryBoxInteractServer.cpp b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp similarity index 75% rename from dScripts/StoryBoxInteractServer.cpp rename to dScripts/02_server/Map/General/StoryBoxInteractServer.cpp index e5899f5d..2683ddd4 100644 --- a/dScripts/StoryBoxInteractServer.cpp +++ b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp @@ -5,8 +5,7 @@ #include "AMFFormat.h" void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { - if (self->GetVar<bool>(u"hasCustomText")) - { + if (self->GetVar<bool>(u"hasCustomText")) { const auto& customText = self->GetVar<std::string>(u"customText"); { @@ -18,39 +17,32 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { args.InsertValue("state", state); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); - - delete state; } - user->AddCallbackTimer(0.1f, [user, customText] () { + user->AddCallbackTimer(0.1f, [user, customText]() { AMFArrayValue args; - auto* visiable = new AMFTrueValue(); auto* text = new AMFStringValue(); text->SetStringValue(customText); - args.InsertValue("visible", visiable); + args.InsertValue("visible", new AMFTrueValue()); args.InsertValue("text", text); GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleStoryBox", &args); - - delete visiable; - delete text; - }); + }); return; } - + const auto storyText = self->GetVarAsString(u"storyText"); - + int32_t boxFlag = self->GetVar<int32_t>(u"altFlagID"); - if (boxFlag <= 0) - { - boxFlag = (10000 + Game::server->GetZoneID() +std::stoi(storyText.substr(storyText.length() - 2))); + if (boxFlag <= 0) { + boxFlag = (10000 + Game::server->GetZoneID() + std::stoi(storyText.substr(storyText.length() - 2))); } if (user->GetCharacter()->GetPlayerFlag(boxFlag) == false) { user->GetCharacter()->SetPlayerFlag(boxFlag, true); GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); } -} \ No newline at end of file +} diff --git a/dScripts/StoryBoxInteractServer.h b/dScripts/02_server/Map/General/StoryBoxInteractServer.h similarity index 97% rename from dScripts/StoryBoxInteractServer.h rename to dScripts/02_server/Map/General/StoryBoxInteractServer.h index caa6fd92..913e5185 100644 --- a/dScripts/StoryBoxInteractServer.h +++ b/dScripts/02_server/Map/General/StoryBoxInteractServer.h @@ -4,4 +4,4 @@ class StoryBoxInteractServer : public CppScripts::Script { public: void OnUse(Entity* self, Entity* user); -}; \ No newline at end of file +}; diff --git a/dScripts/TokenConsoleServer.cpp b/dScripts/02_server/Map/General/TokenConsoleServer.cpp similarity index 64% rename from dScripts/TokenConsoleServer.cpp rename to dScripts/02_server/Map/General/TokenConsoleServer.cpp index 378cc17f..e13011cb 100644 --- a/dScripts/TokenConsoleServer.cpp +++ b/dScripts/02_server/Map/General/TokenConsoleServer.cpp @@ -2,11 +2,14 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "Character.h" +#include "eReplicaComponentType.h" +#include "eTerminateType.h" +#include "ePlayerFlag.h" //2021-05-03 - max - added script, omitted some parts related to inheritance in lua which we don't need void TokenConsoleServer::OnUse(Entity* self, Entity* user) { - auto* inv = static_cast<InventoryComponent*>(user->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inv = static_cast<InventoryComponent*>(user->GetComponent(eReplicaComponentType::INVENTORY)); //make sure the user has the required amount of infected bricks if (inv && inv->GetLotCount(6194) >= bricksToTake) { @@ -19,18 +22,18 @@ void TokenConsoleServer::OnUse(Entity* self, Entity* user) { //figure out which faction the player belongs to: auto character = user->GetCharacter(); if (!character) return; - // At this point the player has to be in a faction. + // At this point the player has to be in a faction. LOT tokenLOT = 0; - if (character->GetPlayerFlag(ePlayerFlags::VENTURE_FACTION)) //venture + if (character->GetPlayerFlag(ePlayerFlag::VENTURE_FACTION)) //venture tokenLOT = 8321; - else if (character->GetPlayerFlag(ePlayerFlags::ASSEMBLY_FACTION)) //assembly + else if (character->GetPlayerFlag(ePlayerFlag::ASSEMBLY_FACTION)) //assembly tokenLOT = 8318; - else if (character->GetPlayerFlag(ePlayerFlags::PARADOX_FACTION)) //paradox + else if (character->GetPlayerFlag(ePlayerFlag::PARADOX_FACTION)) //paradox tokenLOT = 8320; - else if (character->GetPlayerFlag(ePlayerFlags::SENTINEL_FACTION)) //sentinel + else if (character->GetPlayerFlag(ePlayerFlag::SENTINEL_FACTION)) //sentinel tokenLOT = 8319; - inv->AddItem(tokenLOT, tokensToGive, eLootSourceType::LOOT_SOURCE_NONE); + inv->AddItem(tokenLOT, tokensToGive, eLootSourceType::NONE); } GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); -} \ No newline at end of file +} diff --git a/dScripts/TokenConsoleServer.h b/dScripts/02_server/Map/General/TokenConsoleServer.h similarity index 98% rename from dScripts/TokenConsoleServer.h rename to dScripts/02_server/Map/General/TokenConsoleServer.h index b6bf8010..ef57287c 100644 --- a/dScripts/TokenConsoleServer.h +++ b/dScripts/02_server/Map/General/TokenConsoleServer.h @@ -7,4 +7,4 @@ class TokenConsoleServer : public CppScripts::Script { private: int bricksToTake = 25; int tokensToGive = 5; -}; \ No newline at end of file +}; diff --git a/dScripts/TouchMissionUpdateServer.cpp b/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp similarity index 63% rename from dScripts/TouchMissionUpdateServer.cpp rename to dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp index baa448af..7b2495d0 100644 --- a/dScripts/TouchMissionUpdateServer.cpp +++ b/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp @@ -3,46 +3,40 @@ #include "Entity.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" -void TouchMissionUpdateServer::OnStartup(Entity* self) -{ +void TouchMissionUpdateServer::OnStartup(Entity* self) { self->SetProximityRadius(20, "touchCheck"); // Those does not have a collider for some reason? } -void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) -{ +void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) { int32_t missionId = self->GetVar<int32_t>(u"TouchCompleteID"); - if (missionId == 0) - { + if (missionId == 0) { return; } - - auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); - if (missionComponent == nullptr) - { + auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); + + if (missionComponent == nullptr) { return; } auto* mission = missionComponent->GetMission(missionId); - if (mission == nullptr) - { + if (mission == nullptr) { return; } const auto state = mission->GetMissionState(); - if (state >= MissionState::MISSION_STATE_COMPLETE || mission->GetCompletions() > 1) - { + if (state >= eMissionState::COMPLETE || mission->GetCompletions() > 1) { return; } - for (auto* task : mission->GetTasks()) - { - if (!task->IsComplete()) - { + for (auto* task : mission->GetTasks()) { + if (!task->IsComplete()) { task->Complete(); } } @@ -50,10 +44,8 @@ void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) mission->CheckCompletion(); } -void TouchMissionUpdateServer::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) -{ - if (name != "touchCheck" || status != "ENTER") - { +void TouchMissionUpdateServer::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) { + if (name != "touchCheck" || status != "ENTER") { return; } diff --git a/dScripts/TouchMissionUpdateServer.h b/dScripts/02_server/Map/General/TouchMissionUpdateServer.h similarity index 100% rename from dScripts/TouchMissionUpdateServer.h rename to dScripts/02_server/Map/General/TouchMissionUpdateServer.h diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp new file mode 100644 index 00000000..58ce1c72 --- /dev/null +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -0,0 +1,47 @@ +#include "WishingWellServer.h" +#include "ScriptedActivityComponent.h" +#include "GameMessages.h" +#include "Loot.h" +#include "EntityManager.h" +#include "eTerminateType.h" + +void WishingWellServer::OnStartup(Entity* self) { +} + +void WishingWellServer::OnUse(Entity* self, Entity* user) { + auto* scriptedActivity = self->GetComponent<ScriptedActivityComponent>(); + + if (!scriptedActivity->TakeCost(user)) { + return; + } + + const auto audio = self->GetVar<std::string>(u"sound1"); + + if (!audio.empty()) { + GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), audio); + } + + LootGenerator::Instance().DropActivityLoot( + user, + self, + static_cast<uint32_t>(scriptedActivity->GetActivityID()), + GeneralUtils::GenerateRandomNumber<int32_t>(1, 1000) + ); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StartCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); + + const auto userID = user->GetObjectID(); + + self->AddCallbackTimer(10, [self, userID]() { + auto* user = EntityManager::Instance()->GetEntity(userID); + + if (user == nullptr) return; + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StopCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); + }); + + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} + +void WishingWellServer::OnTimerDone(Entity* self, std::string timerName) { +} diff --git a/dScripts/WishingWellServer.h b/dScripts/02_server/Map/General/WishingWellServer.h similarity index 74% rename from dScripts/WishingWellServer.h rename to dScripts/02_server/Map/General/WishingWellServer.h index 3660c31e..856fa8a8 100644 --- a/dScripts/WishingWellServer.h +++ b/dScripts/02_server/Map/General/WishingWellServer.h @@ -6,6 +6,6 @@ class WishingWellServer : public CppScripts::Script public: void OnStartup(Entity* self) override; void OnUse(Entity* self, Entity* user) override; - void OnTimerDone(Entity* self, std::string timerName) override; + void OnTimerDone(Entity* self, std::string timerName) override; }; diff --git a/dScripts/02_server/Map/NS/CMakeLists.txt b/dScripts/02_server/Map/NS/CMakeLists.txt new file mode 100644 index 00000000..c815a8c5 --- /dev/null +++ b/dScripts/02_server/Map/NS/CMakeLists.txt @@ -0,0 +1,13 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NS + "NsConcertChoiceBuildManager.cpp" + "NsLegoClubDoor.cpp" + "NsLupTeleport.cpp" + "NsTokenConsoleServer.cpp") + +add_subdirectory(Waves) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS_WAVES}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_NS ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS} "Waves/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NS ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS} PARENT_SCOPE) diff --git a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp new file mode 100644 index 00000000..a338d9c9 --- /dev/null +++ b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp @@ -0,0 +1,65 @@ +#include "NsConcertChoiceBuildManager.h" +#include "EntityInfo.h" +#include "EntityManager.h" + +const std::vector<Crate> NsConcertChoiceBuildManager::crates{ + { "laser", 11203, 5.0, "Concert_Laser_QB_" }, + { "rocket", 11204, 3.0, "Concert_Rocket_QB_" }, + { "speaker", 11205, 5.0, "Concert_Speaker_QB_" }, + { "spotlight", 11206, 5.0, "Concert_Spotlight_QB_" } +}; + +void NsConcertChoiceBuildManager::OnStartup(Entity* self) { + NsConcertChoiceBuildManager::SpawnCrate(self); +} + +void NsConcertChoiceBuildManager::SpawnCrate(Entity* self) { + const auto spawnNumber = self->GetVar<uint32_t>(u"spawnNumber") % crates.size(); + const auto crate = crates[spawnNumber]; + + const auto groups = self->GetGroups(); + if (groups.empty()) + return; + + // Groups are of the form CB_1, CB_2, etc. + auto group = groups.at(0); + const auto splitGroup = GeneralUtils::SplitString(group, '_'); + if (splitGroup.size() < 2) + return; + const auto groupNumber = std::stoi(splitGroup.at(1)); + + EntityInfo info{}; + info.lot = crate.lot; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData<bool>(u"startsQBActivator", true), + new LDFData<std::string>(u"grpNameQBShowBricks", crate.group + std::to_string(groupNumber)), + new LDFData<std::u16string>(u"groupID", GeneralUtils::ASCIIToUTF16("Crate_" + group)), + new LDFData<float>(u"crateTime", crate.time), + }; + + auto* spawnedCrate = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(spawnedCrate); + + spawnedCrate->AddDieCallback([self]() { + self->CancelAllTimers(); // Don't switch if the crate was smashed + self->SetVar<LWOOBJID>(u"currentCrate", LWOOBJID_EMPTY); + }); + + self->SetVar<uint32_t>(u"spawnNumber", spawnNumber + 1); + self->SetVar<float>(u"currentTimer", crate.time); + self->SetVar<LWOOBJID>(u"currentCrate", spawnedCrate->GetObjectID()); + + // Timer that rotates the crates + self->AddCallbackTimer(crate.time, [self]() { + auto crateID = self->GetVar<LWOOBJID>(u"currentCrate"); + if (crateID != LWOOBJID_EMPTY) { + EntityManager::Instance()->DestroyEntity(crateID); + self->SetVar<LWOOBJID>(u"currentCrate", LWOOBJID_EMPTY); + } + + SpawnCrate(self); + }); +} diff --git a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.h b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.h new file mode 100644 index 00000000..4e9ac4ba --- /dev/null +++ b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.h @@ -0,0 +1,17 @@ +#pragma once +#include "CppScripts.h" + +struct Crate { + std::string name; + LOT lot; + float time; + std::string group; +}; + +class NsConcertChoiceBuildManager : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + static void SpawnCrate(Entity* self); +private: + static const std::vector<Crate> crates; +}; diff --git a/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp b/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp new file mode 100644 index 00000000..56a213b8 --- /dev/null +++ b/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp @@ -0,0 +1,152 @@ +#include "NsLegoClubDoor.h" +#include "dZoneManager.h" +#include "GameMessages.h" +#include "AMFFormat.h" + +void NsLegoClubDoor::OnStartup(Entity* self) { + self->SetVar(u"currentZone", (int32_t)dZoneManager::Instance()->GetZoneID().GetMapID()); + self->SetVar(u"choiceZone", m_ChoiceZoneID); + self->SetVar(u"teleportAnim", m_TeleportAnim); + self->SetVar(u"teleportString", m_TeleportString); + self->SetVar(u"spawnPoint", m_SpawnPoint); + + args = {}; + + AMFStringValue* callbackClient = new AMFStringValue(); + callbackClient->SetStringValue(std::to_string(self->GetObjectID())); + args.InsertValue("callbackClient", callbackClient); + + AMFStringValue* strIdentifier = new AMFStringValue(); + strIdentifier->SetStringValue("choiceDoor"); + args.InsertValue("strIdentifier", strIdentifier); + + AMFStringValue* title = new AMFStringValue(); + title->SetStringValue("%[UI_CHOICE_DESTINATION]"); + args.InsertValue("title", title); + + AMFArrayValue* choiceOptions = new AMFArrayValue(); + + { + AMFArrayValue* nsArgs = new AMFArrayValue(); + + AMFStringValue* image = new AMFStringValue(); + image->SetStringValue("textures/ui/zone_thumnails/Nimbus_Station.dds"); + nsArgs->InsertValue("image", image); + + AMFStringValue* caption = new AMFStringValue(); + caption->SetStringValue("%[UI_CHOICE_NS]"); + nsArgs->InsertValue("caption", caption); + + AMFStringValue* identifier = new AMFStringValue(); + identifier->SetStringValue("zoneID_1200"); + nsArgs->InsertValue("identifier", identifier); + + AMFStringValue* tooltipText = new AMFStringValue(); + tooltipText->SetStringValue("%[UI_CHOICE_NS_HOVER]"); + nsArgs->InsertValue("tooltipText", tooltipText); + + choiceOptions->PushBackValue(nsArgs); + } + + { + AMFArrayValue* ntArgs = new AMFArrayValue(); + + AMFStringValue* image = new AMFStringValue(); + image->SetStringValue("textures/ui/zone_thumnails/Nexus_Tower.dds"); + ntArgs->InsertValue("image", image); + + AMFStringValue* caption = new AMFStringValue(); + caption->SetStringValue("%[UI_CHOICE_NT]"); + ntArgs->InsertValue("caption", caption); + + AMFStringValue* identifier = new AMFStringValue(); + identifier->SetStringValue("zoneID_1900"); + ntArgs->InsertValue("identifier", identifier); + + AMFStringValue* tooltipText = new AMFStringValue(); + tooltipText->SetStringValue("%[UI_CHOICE_NT_HOVER]"); + ntArgs->InsertValue("tooltipText", tooltipText); + + choiceOptions->PushBackValue(ntArgs); + } + + options = choiceOptions; + + args.InsertValue("options", choiceOptions); +} + +void NsLegoClubDoor::OnUse(Entity* self, Entity* user) { + auto* player = user; + + if (CheckChoice(self, player)) { + AMFArrayValue* multiArgs = new AMFArrayValue(); + + AMFStringValue* callbackClient = new AMFStringValue(); + callbackClient->SetStringValue(std::to_string(self->GetObjectID())); + multiArgs->InsertValue("callbackClient", callbackClient); + + AMFStringValue* strIdentifier = new AMFStringValue(); + strIdentifier->SetStringValue("choiceDoor"); + multiArgs->InsertValue("strIdentifier", strIdentifier); + + AMFStringValue* title = new AMFStringValue(); + title->SetStringValue("%[UI_CHOICE_DESTINATION]"); + multiArgs->InsertValue("title", title); + + multiArgs->InsertValue("options", options); + + GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs); + } else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID) { + AMFArrayValue* multiArgs = new AMFArrayValue(); + + AMFStringValue* state = new AMFStringValue(); + state->SetStringValue("Lobby"); + multiArgs->InsertValue("state", state); + + AMFArrayValue* context = new AMFArrayValue(); + + AMFStringValue* user = new AMFStringValue(); + user->SetStringValue(std::to_string(player->GetObjectID())); + context->InsertValue("user", user); + + AMFStringValue* callbackObj = new AMFStringValue(); + callbackObj->SetStringValue(std::to_string(self->GetObjectID())); + context->InsertValue("callbackObj", callbackObj); + + AMFStringValue* helpVisible = new AMFStringValue(); + helpVisible->SetStringValue("show"); + context->InsertValue("HelpVisible", helpVisible); + + AMFStringValue* type = new AMFStringValue(); + type->SetStringValue("Lego_Club_Valid"); + context->InsertValue("type", type); + + multiArgs->InsertValue("context", context); + + GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "pushGameState", multiArgs); + } else { + BaseOnUse(self, player); + } +} + +void NsLegoClubDoor::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + std::u16string strIdentifier = identifier; + + if (strIdentifier == u"PlayButton" || strIdentifier == u"CloseButton") { + strIdentifier = u"TransferBox"; + } + + BaseOnMessageBoxResponse(self, sender, button, strIdentifier, userData); +} + +void NsLegoClubDoor::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { + BaseChoiceBoxRespond(self, sender, button, buttonIdentifier, identifier); +} + +void NsLegoClubDoor::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); +} + +void NsLegoClubDoor::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); +} diff --git a/dScripts/02_server/Map/NS/NsLegoClubDoor.h b/dScripts/02_server/Map/NS/NsLegoClubDoor.h new file mode 100644 index 00000000..db1dcae4 --- /dev/null +++ b/dScripts/02_server/Map/NS/NsLegoClubDoor.h @@ -0,0 +1,24 @@ +#pragma once +#include "CppScripts.h" +#include "ChooseYourDestinationNsToNt.h" +#include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" + +class NsLegoClubDoor : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; + void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + +private: + int32_t m_ChoiceZoneID = 1700; + std::string m_SpawnPoint = "NS_LEGO_Club"; + std::u16string m_TeleportAnim = u"lup-teleport"; + std::u16string m_TeleportString = u"ROCKET_TOOLTIP_USE_THE_GATEWAY_TO_TRAVEL_TO_LUP_WORLD"; + AMFArrayValue args = {}; + AMFArrayValue* options = {}; +}; diff --git a/dScripts/02_server/Map/NS/NsLupTeleport.cpp b/dScripts/02_server/Map/NS/NsLupTeleport.cpp new file mode 100644 index 00000000..9cd4359b --- /dev/null +++ b/dScripts/02_server/Map/NS/NsLupTeleport.cpp @@ -0,0 +1,100 @@ +#include "NsLupTeleport.h" +#include "dZoneManager.h" +#include "GameMessages.h" +#include "AMFFormat.h" + +void NsLupTeleport::OnStartup(Entity* self) { + self->SetVar(u"currentZone", (int32_t)dZoneManager::Instance()->GetZoneID().GetMapID()); + self->SetVar(u"choiceZone", m_ChoiceZoneID); + self->SetVar(u"teleportAnim", m_TeleportAnim); + self->SetVar(u"teleportString", m_TeleportString); + self->SetVar(u"spawnPoint", m_SpawnPoint); + + args = {}; + + AMFStringValue* callbackClient = new AMFStringValue(); + callbackClient->SetStringValue(std::to_string(self->GetObjectID())); + args.InsertValue("callbackClient", callbackClient); + + AMFStringValue* strIdentifier = new AMFStringValue(); + strIdentifier->SetStringValue("choiceDoor"); + args.InsertValue("strIdentifier", strIdentifier); + + AMFStringValue* title = new AMFStringValue(); + title->SetStringValue("%[UI_CHOICE_DESTINATION]"); + args.InsertValue("title", title); + + AMFArrayValue* choiceOptions = new AMFArrayValue(); + + { + AMFArrayValue* nsArgs = new AMFArrayValue(); + + AMFStringValue* image = new AMFStringValue(); + image->SetStringValue("textures/ui/zone_thumnails/Nimbus_Station.dds"); + nsArgs->InsertValue("image", image); + + AMFStringValue* caption = new AMFStringValue(); + caption->SetStringValue("%[UI_CHOICE_NS]"); + nsArgs->InsertValue("caption", caption); + + AMFStringValue* identifier = new AMFStringValue(); + identifier->SetStringValue("zoneID_1200"); + nsArgs->InsertValue("identifier", identifier); + + AMFStringValue* tooltipText = new AMFStringValue(); + tooltipText->SetStringValue("%[UI_CHOICE_NS_HOVER]"); + nsArgs->InsertValue("tooltipText", tooltipText); + + choiceOptions->PushBackValue(nsArgs); + } + + { + AMFArrayValue* ntArgs = new AMFArrayValue(); + + AMFStringValue* image = new AMFStringValue(); + image->SetStringValue("textures/ui/zone_thumnails/Nexus_Tower.dds"); + ntArgs->InsertValue("image", image); + + AMFStringValue* caption = new AMFStringValue(); + caption->SetStringValue("%[UI_CHOICE_NT]"); + ntArgs->InsertValue("caption", caption); + + AMFStringValue* identifier = new AMFStringValue(); + identifier->SetStringValue("zoneID_1900"); + ntArgs->InsertValue("identifier", identifier); + + AMFStringValue* tooltipText = new AMFStringValue(); + tooltipText->SetStringValue("%[UI_CHOICE_NT_HOVER]"); + ntArgs->InsertValue("tooltipText", tooltipText); + + choiceOptions->PushBackValue(ntArgs); + } + + args.InsertValue("options", choiceOptions); +} + +void NsLupTeleport::OnUse(Entity* self, Entity* user) { + auto* player = user; + + if (CheckChoice(self, player)) { + GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", &args); + } else { + BaseOnUse(self, player); + } +} + +void NsLupTeleport::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + BaseOnMessageBoxResponse(self, sender, button, identifier, userData); +} + +void NsLupTeleport::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { + BaseChoiceBoxRespond(self, sender, button, buttonIdentifier, identifier); +} + +void NsLupTeleport::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); +} + +void NsLupTeleport::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); +} diff --git a/dScripts/02_server/Map/NS/NsLupTeleport.h b/dScripts/02_server/Map/NS/NsLupTeleport.h new file mode 100644 index 00000000..28bab016 --- /dev/null +++ b/dScripts/02_server/Map/NS/NsLupTeleport.h @@ -0,0 +1,23 @@ +#pragma once +#include "CppScripts.h" +#include "ChooseYourDestinationNsToNt.h" +#include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" + +class NsLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; + void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + +private: + int32_t m_ChoiceZoneID = 1600; + std::string m_SpawnPoint = "NS_LW"; + std::u16string m_TeleportAnim = u"lup-teleport"; + std::u16string m_TeleportString = u"UI_TRAVEL_TO_LUP_STATION"; + AMFArrayValue args = {}; +}; diff --git a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp new file mode 100644 index 00000000..326842d2 --- /dev/null +++ b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp @@ -0,0 +1,61 @@ +#include "NsTokenConsoleServer.h" +#include "InventoryComponent.h" +#include "GameMessages.h" +#include "Character.h" +#include "MissionComponent.h" +#include "RebuildComponent.h" +#include "eTerminateType.h" +#include "ePlayerFlag.h" + +void NsTokenConsoleServer::OnStartup(Entity* self) { + +} + +void NsTokenConsoleServer::OnUse(Entity* self, Entity* user) { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent == nullptr) { + return; + } + + if (rebuildComponent->GetState() != eRebuildState::COMPLETED) { + return; + } + + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + auto* missionComponent = user->GetComponent<MissionComponent>(); + auto* character = user->GetCharacter(); + + if (inventoryComponent == nullptr || missionComponent == nullptr || character == nullptr) { + return; + } + + if (inventoryComponent->GetLotCount(6194) < 25) { + return; + } + + inventoryComponent->RemoveItem(6194, 25); + + const auto useSound = self->GetVar<std::string>(u"sound1"); + + if (!useSound.empty()) { + GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, useSound); + } + + // Player must be in faction to interact with this entity. + LOT tokenLOT = 0; + if (character->GetPlayerFlag(ePlayerFlag::VENTURE_FACTION)) //venture + tokenLOT = 8321; + else if (character->GetPlayerFlag(ePlayerFlag::ASSEMBLY_FACTION)) //assembly + tokenLOT = 8318; + else if (character->GetPlayerFlag(ePlayerFlag::PARADOX_FACTION)) //paradox + tokenLOT = 8320; + else if (character->GetPlayerFlag(ePlayerFlag::SENTINEL_FACTION)) //sentinel + tokenLOT = 8319; + + inventoryComponent->AddItem(tokenLOT, 5, eLootSourceType::NONE); + + missionComponent->ForceProgressTaskType(863, 1, 1, false); + + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/NsTokenConsoleServer.h b/dScripts/02_server/Map/NS/NsTokenConsoleServer.h similarity index 73% rename from dScripts/NsTokenConsoleServer.h rename to dScripts/02_server/Map/NS/NsTokenConsoleServer.h index d0cdb011..364cb714 100644 --- a/dScripts/NsTokenConsoleServer.h +++ b/dScripts/02_server/Map/NS/NsTokenConsoleServer.h @@ -5,5 +5,5 @@ class NsTokenConsoleServer : public CppScripts::Script { public: void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/NS/Waves/CMakeLists.txt b/dScripts/02_server/Map/NS/Waves/CMakeLists.txt new file mode 100644 index 00000000..bb216ee9 --- /dev/null +++ b/dScripts/02_server/Map/NS/Waves/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NS_WAVES + "ZoneNsWaves.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp new file mode 100644 index 00000000..184132fe --- /dev/null +++ b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp @@ -0,0 +1,500 @@ +#include "ZoneNsWaves.h" + +WaveConstants ZoneNsWaves::GetConstants() { + return { + 60, + 2, + 6, + 2, + "surprise", + "intro" + }; +} + +std::vector<std::string> ZoneNsWaves::GetSpawnerNames() { + return { + "Base_MobA", + "Base_MobB", + "Base_MobC", + "MobA_01", + "MobB_01", + "MobC_01", + "MobA_02", + "MobB_02", + "MobC_02", + "MobA_03", + "MobB_03", + "MobC_03", + "Reward_01", + "Base_Reward", + "Obstacle_01", + "Boss", + "Ape_Boss", + "Geyser_01", + "Treasure_01", + "Cavalry_Boss", + "Horseman_01", + "Horseman_02", + "Horseman_03", + "Horseman_04" + }; +} + +std::vector<WaveMission> ZoneNsWaves::GetWaveMissions() { + return { + {190, 7, 1242}, + {240, 7, 1226}, + {450, 15, 1243}, + {600, 15, 1227}, + {720, 22, 1244}, + {840, 22, 1228}, + {1080, 29, 1245}, + {1200, 29, 1229}, + }; +} + +std::vector<Wave> ZoneNsWaves::GetWaves() { + return { + // Wave 1 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling_minifig, 8, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::gf_A) }, + } + }, + + // Wave 2 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling, 8, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, + } + }, + + // Wave 3 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::gf_A) }, + }, + }, + + // Wave 4 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 5 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::stromling, 1, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::stromling, 1, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 6 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 7 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::stromling_boss, 1, GetSpawnerName(SpawnerName::Boss) }, + }, + {1885}, + {}, + "Stromling_Boss", + 5.0f + }, + + // Wave 8 + Wave { + std::vector<MobDefinition> { + {SpawnLOTS::mushroom, 6, GetSpawnerName(SpawnerName::Reward_01) }, + {SpawnLOTS::mushroom, 3, GetSpawnerName(SpawnerName::interior_Reward) }, + }, {}, {}, "", -1.0f, + 25, + }, + + // Wave 9 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 10 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 11 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::gf_C) }, + } + }, + + // Wave 12 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_C) }, + } + }, + + // Wave 13 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 3, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 14 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_C) }, + } + }, + + // Wave 15 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::ape_boss, 1, GetSpawnerName(SpawnerName::Ape_Boss) }, + + }, + {1886}, + {}, + "Gorilla_Boss", + 5.0f + }, + + // Wave 16 + Wave { + std::vector<MobDefinition> { + {SpawnLOTS::outhouse, 3, GetSpawnerName(SpawnerName::interior_Reward) }, + {SpawnLOTS::mushroom, 6, GetSpawnerName(SpawnerName::Reward_01) }, + }, {}, {}, "", -1.0f, + 25, + }, + + // Wave 17 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 18 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::hammerling_melee, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 19 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::hammerling, 4, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::sentry, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::gf_B) }, + } + }, + + // Wave 20 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::sentry, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_C) }, + } + }, + + // Wave 21 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::ronin, 2, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::spiderling_ve, 2, GetSpawnerName(SpawnerName::interior_C) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_C) }, + } + }, + + // Wave 22 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::spiderling_boss, 1, GetSpawnerName(SpawnerName::Cavalry_Boss) }, + }, + {1887}, + {}, + "Spiderling_Boss", + 5.0f + }, + + // Wave 23 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::outhouse, 6, GetSpawnerName(SpawnerName::Reward_01) }, + { SpawnLOTS::outhouse, 3, GetSpawnerName(SpawnerName::interior_Reward) }, + { SpawnLOTS::maelstrom_chest, 4, GetSpawnerName(SpawnerName::Obstacle) }, + }, {}, {}, "", -1.0f, + 25, + }, + + // Wave 24 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::pirate, 3, GetSpawnerName(SpawnerName::ag_A) }, + { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::ronin, 2, GetSpawnerName(SpawnerName::interior_B) }, + } + }, + + // Wave 25 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::cavalry, 2, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::gf_A) }, + { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::concert_A) }, + { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_A) }, + } + }, + + // Wave 26 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_B) }, + { SpawnLOTS::admiral_cp, 2, GetSpawnerName(SpawnerName::gf_C) }, + { SpawnLOTS::admiral_cp, 2, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_C) }, + } + }, + + // Wave 27 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::ronin, 5, GetSpawnerName(SpawnerName::interior_A) }, + { SpawnLOTS::ronin, 4, GetSpawnerName(SpawnerName::interior_B) }, + { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::ag_C) }, + { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::gf_C) }, + { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::concert_C) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::ag_B) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::gf_B) }, + { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_B) }, + } + }, + + // Wave 28 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::dragon_statue, 12, GetSpawnerName(SpawnerName::Reward_01) }, + }, {}, {}, "", -1.0f, + 30, + }, + + // Wave 29 + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::horseman_boss01, 1, GetSpawnerName(SpawnerName::Horseman_01) }, + { SpawnLOTS::horseman_boss02, 1, GetSpawnerName(SpawnerName::Horseman_02) }, + { SpawnLOTS::horseman_boss03, 1, GetSpawnerName(SpawnerName::Horseman_03) }, + { SpawnLOTS::horseman_boss04, 1, GetSpawnerName(SpawnerName::Horseman_04) }, + }, + {1888}, + {1236, 1237, 1249}, + "Horsemen_Boss", + 5.0f + }, + + // Wave 30 (treasure) + Wave { + std::vector<MobDefinition> { + { SpawnLOTS::treasure_chest, 1, GetSpawnerName(SpawnerName::Treasure_01) }, + }, {}, {}, + "Treasure_Camera", + 5.0f, + (uint32_t)-1, + true, + 60, + }, + }; +} + +std::string ZoneNsWaves::GetSpawnerName(SpawnerName spawnerName) { + switch (spawnerName) { + case interior_A: + return "Base_MobA"; + case interior_B: + return "Base_MobB"; + case interior_C: + return "Base_MobC"; + case gf_A: + return "MobA_01"; + case gf_B: + return "MobB_01"; + case gf_C: + return "MobC_01"; + case concert_A: + return "MobA_02"; + case concert_B: + return "MobB_02"; + case concert_C: + return "MobC_02"; + case ag_A: + return "MobA_03"; + case ag_B: + return "MobB_03"; + case ag_C: + return "MobC_03"; + case Reward_01: + return "Reward_01"; + case interior_Reward: + return "Base_Reward"; + case Obstacle: + return "Obstacle_01"; + case Boss: + return "Boss"; + case Ape_Boss: + return "Ape_Boss"; + case Geyser: + return "Geyser_01"; + case Treasure_01: + return "Treasure_01"; + case Cavalry_Boss: + return "Cavalry_Boss"; + case Horseman_01: + return "Horseman_01"; + case Horseman_02: + return "Horseman_02"; + case Horseman_03: + return "Horseman_03"; + case Horseman_04: + return "Horseman_04"; + default: + return ""; + } +} diff --git a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h new file mode 100644 index 00000000..637aceb7 --- /dev/null +++ b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h @@ -0,0 +1,71 @@ +#pragma once +#include "BaseWavesServer.h" + +#include "dCommonVars.h" + +enum SpawnerName { + interior_A, + interior_B, + interior_C, + gf_A, + gf_B, + gf_C, + concert_A, + concert_B, + concert_C, + ag_A, + ag_B, + ag_C, + Reward_01, + interior_Reward, + Obstacle, + Boss, + Ape_Boss, + Geyser, + Treasure_01, + Cavalry_Boss, + Horseman_01, + Horseman_02, + Horseman_03, + Horseman_04, +}; + +enum SpawnLOTS : LOT { + stromling = 12586, + mech = 12587, + spiderling = 12588, + pirate = 12589, + admiral = 12590, + ape_boss = 12591, + stromling_boss = 12600, + hammerling = 12602, + sentry = 12604, + spiderling_ve = 12605, + spiderling_boss = 12609, + ronin = 12610, + cavalry = 12611, + dragon_boss = 12612, + stromling_minifig = 12586, + mushroom = 12614, + maelstrom_chest = 4894, + outhouse = 12616, + dragon_statue = 12617, + treasure_chest = 12423, + hammerling_melee = 12653, + maelstrom_geyser = 10314, + ronin_statue = 12611, + horseman_boss01 = 11999, + horseman_boss02 = 12467, + horseman_boss03 = 12468, + horseman_boss04 = 12469, + admiral_cp = 13523, +}; + +class ZoneNsWaves : public BaseWavesServer { + WaveConstants GetConstants() override; + std::vector<std::string> GetSpawnerNames() override; + std::vector<WaveMission> GetWaveMissions() override; + std::vector<Wave> GetWaves() override; +private: + static std::string GetSpawnerName(SpawnerName spawnerName); +}; diff --git a/dScripts/02_server/Map/NT/CMakeLists.txt b/dScripts/02_server/Map/NT/CMakeLists.txt new file mode 100644 index 00000000..ede9b003 --- /dev/null +++ b/dScripts/02_server/Map/NT/CMakeLists.txt @@ -0,0 +1,26 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NT + "NtCombatChallengeDummy.cpp" + "NtCombatChallengeExplodingDummy.cpp" + "NtCombatChallengeServer.cpp" + "NtAssemblyTubeServer.cpp" + "NtParadoxPanelServer.cpp" + "NtImagBeamBuffer.cpp" + "NtBeamImaginationCollectors.cpp" + "NtDirtCloudServer.cpp" + "NtConsoleTeleportServer.cpp" + "SpawnStegoServer.cpp" + "SpawnSaberCatServer.cpp" + "SpawnShrakeServer.cpp" + "NtDukeServer.cpp" + "NtHaelServer.cpp" + "NtOverbuildServer.cpp" + "NtVandaServer.cpp" + "NtXRayServer.cpp" + "NtSleepingGuard.cpp" + "NtImagimeterVisibility.cpp" + "NtSentinelWalkwayServer.cpp" + "NtDarkitectRevealServer.cpp" + "NtParadoxTeleServer.cpp" + "NtVentureSpeedPadServer.cpp" + "NtVentureCannonServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp new file mode 100644 index 00000000..5f1619ab --- /dev/null +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -0,0 +1,118 @@ +#include "NtAssemblyTubeServer.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eEndBehavior.h" +#include "eStateChangeType.h" + +void NtAssemblyTubeServer::OnStartup(Entity* self) { + self->SetProximityRadius(5, "teleport"); +} + +void NtAssemblyTubeServer::OnPlayerLoaded(Entity* self, Entity* player) { + +} + +void NtAssemblyTubeServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; + + auto* player = entering; + const auto playerID = player->GetObjectID(); + + RunAssemblyTube(self, player); + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } +} + +void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) { + const auto playerID = player->GetObjectID(); + + const auto iter = m_TeleportingPlayerTable.find(playerID); + if (iter == m_TeleportingPlayerTable.end()) m_TeleportingPlayerTable[playerID] = false; + const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; + + if (player->IsPlayer() && !bPlayerBeingTeleported) { + auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); + + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); + + if (!teleCinematic.empty()) { + const auto teleCinematicUname = teleCinematic; + GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(), + true, true, true, false, eEndBehavior::RETURN, false, -1, false, true + ); + } + + GameMessages::SendPlayAnimation(player, u"tube-sucker", 4.0f); + + const auto animTime = 3; + + self->AddCallbackTimer(animTime, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + TeleportPlayer(self, player); + }); + } +} + +void NtAssemblyTubeServer::TeleportPlayer(Entity* self, Entity* player) { + auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); + auto* destination = self; + + if (!destinationGroup.empty()) { + const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); + + if (!groupObjs.empty()) { + destination = groupObjs[0]; + } + } + + const auto destPosition = destination->GetPosition(); + const auto destRotation = destination->GetRotation(); + + GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + + GameMessages::SendPlayAnimation(player, u"tube-resurrect", 4.0f); + + const auto animTime = 2; + + const auto playerID = player->GetObjectID(); + + self->AddCallbackTimer(animTime, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + UnlockPlayer(self, player); + }); + + const auto useSound = self->GetVar<std::string>(u"sound1"); + + if (!useSound.empty()) { + GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); + } +} + +void NtAssemblyTubeServer::UnlockPlayer(Entity* self, Entity* player) { + const auto playerID = player->GetObjectID(); + + m_TeleportingPlayerTable[playerID] = false; + + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); +} diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.h b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.h new file mode 100644 index 00000000..35dcc6f6 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class NtAssemblyTubeServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void RunAssemblyTube(Entity* self, Entity* player); + void TeleportPlayer(Entity* self, Entity* player); + void UnlockPlayer(Entity* self, Entity* player); + +private: + std::map<LWOOBJID, bool> m_TeleportingPlayerTable; +}; diff --git a/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp new file mode 100644 index 00000000..b8036c89 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp @@ -0,0 +1,29 @@ +#include "NtBeamImaginationCollectors.h" +#include "GeneralUtils.h" +#include "GameMessages.h" + +void NtBeamImaginationCollectors::OnStartup(Entity* self) { + self->AddTimer("PlayFX", GetRandomNum()); +} + +int32_t NtBeamImaginationCollectors::GetRandomNum() { + int32_t randNum = m_LastRandom; + + while (randNum == m_LastRandom) { + randNum = GeneralUtils::GenerateRandomNumber<int32_t>(m_RandMin, m_RandMax); + } + + m_LastRandom = randNum; + + return randNum; +} + +void NtBeamImaginationCollectors::OnTimerDone(Entity* self, std::string timerName) { + if (timerName != "PlayFX") { + return; + } + + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, m_FxName, "Beam"); + + self->AddTimer("PlayFX", GetRandomNum()); +} diff --git a/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.h b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.h new file mode 100644 index 00000000..28424766 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class NtBeamImaginationCollectors : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + int32_t GetRandomNum(); + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + int32_t m_LastRandom = 0; + int32_t m_RandMin = 5; + int32_t m_RandMax = 15; + std::u16string m_FxName = u"beam_collect"; +}; diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp new file mode 100644 index 00000000..c9cd8f0a --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp @@ -0,0 +1,26 @@ +#include "NtCombatChallengeDummy.h" +#include "EntityManager.h" + +void NtCombatChallengeDummy::OnDie(Entity* self, Entity* killer) { + const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); + + auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); + + if (challengeObject != nullptr) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { + script->OnDie(challengeObject, killer); + } + } +} + +void NtCombatChallengeDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); + + auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); + + if (challengeObject != nullptr) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { + script->OnHitOrHealResult(challengeObject, attacker, damage); + } + } +} diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeDummy.h b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.h new file mode 100644 index 00000000..bf7d4f04 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class NtCombatChallengeDummy : public CppScripts::Script +{ +public: + void OnDie(Entity* self, Entity* killer) override; + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; +}; diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp new file mode 100644 index 00000000..c117c63a --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp @@ -0,0 +1,32 @@ +#include "NtCombatChallengeExplodingDummy.h" +#include "EntityManager.h" +#include "SkillComponent.h" + +void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) { + const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); + + auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); + + if (challengeObject != nullptr) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { + script->OnDie(challengeObject, killer); + } + } +} + +void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); + + auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); + + if (challengeObject != nullptr) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { + script->OnHitOrHealResult(challengeObject, attacker, damage); + } + } + auto skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID()); + } + self->Kill(attacker); +} diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.h b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.h new file mode 100644 index 00000000..ff48c726 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class NtCombatChallengeExplodingDummy : public CppScripts::Script +{ + void OnDie(Entity* self, Entity* killer) override; + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; +}; diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp new file mode 100644 index 00000000..d27ac1f6 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp @@ -0,0 +1,209 @@ +#include "NtCombatChallengeServer.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "InventoryComponent.h" +#include "MissionComponent.h" + +void NtCombatChallengeServer::OnUse(Entity* self, Entity* user) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Open", 0, 0, user->GetObjectID(), "", user->GetSystemAddress()); +} + +void NtCombatChallengeServer::OnDie(Entity* self, Entity* killer) { + if (killer != self && killer != nullptr) { + SpawnTargetDummy(self); + } +} + + +void NtCombatChallengeServer::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + auto totalDmg = self->GetVar<int32_t>(u"totalDmg"); + + totalDmg += damage; + + self->SetVar(u"totalDmg", totalDmg); + self->SetNetworkVar(u"totalDmg", totalDmg); + + GameMessages::SendPlayNDAudioEmitter(self, attacker->GetSystemAddress(), scoreSound); +} + + +void NtCombatChallengeServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 0, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); +} + + +void NtCombatChallengeServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + if (identifier == u"PlayButton" && button == 1) { + self->SetNetworkVar(u"bInUse", true); + + self->SetVar(u"playerID", sender->GetObjectID()); + + auto* inventoryComponent = sender->GetComponent<InventoryComponent>(); + + if (inventoryComponent != nullptr) { + inventoryComponent->RemoveItem(3039, 1); + } + + GameMessages::SendPlayNDAudioEmitter(self, sender->GetSystemAddress(), startSound); + + self->AddTimer("start_delay", 2.0f); + + GameMessages::SendShowActivityCountdown(self->GetObjectID(), false, false, u"", 0, sender->GetSystemAddress()); + + self->SetNetworkVar(u"toggle", true); + } else if (identifier == u"CloseButton") { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 1, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); + } +} + +void NtCombatChallengeServer::SpawnTargetDummy(Entity* self) { + const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + auto targetNumber = self->GetVar<int32_t>(u"TargetNumber"); + if (targetNumber == 0) targetNumber = 1; + + if (targetNumber > tTargets.size()) targetNumber = tTargets.size(); + + self->SetVar<int32_t>(u"TargetNumber", targetNumber + 1); + + const auto dummyLOT = tTargets[targetNumber - 1]; + + EntityInfo info{}; + info.lot = dummyLOT; + info.spawnerID = self->GetObjectID(); + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.settings = { new LDFData<std::string>(u"custom_script_server", "scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_DUMMY.lua") }; + + auto* dummy = EntityManager::Instance()->CreateEntity(info); + + dummy->SetVar(u"challengeObjectID", self->GetObjectID()); + + EntityManager::Instance()->ConstructEntity(dummy); + + self->SetVar(u"currentDummy", dummy->GetObjectID()); +} + +void NtCombatChallengeServer::SetAttackImmunity(LWOOBJID objID, bool bTurnOn) { + +} + +void NtCombatChallengeServer::OnChildLoaded(Entity* self, Entity* child) { + auto targetNumber = self->GetVar<int32_t>(u"TargetNumber"); + if (targetNumber == 0) targetNumber = 1; + self->SetVar(u"TargetNumber", targetNumber + 1); + + const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + child->SetRotation(NiQuaternion::LookAt(child->GetPosition(), player->GetPosition())); + + self->SetVar(u"currentTargetID", child->GetObjectID()); + + EntityManager::Instance()->SerializeEntity(child); + + child->GetGroups().push_back("targets_" + std::to_string(self->GetObjectID())); +} + +void NtCombatChallengeServer::ResetGame(Entity* self) { + const auto totalDmg = self->GetVar<int32_t>(u"totalDmg"); + const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); + + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player != nullptr) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + for (const auto& mission : tMissions) { + if (totalDmg >= mission.damage) { + missionComponent->ForceProgressTaskType(mission.mission, 1, 1); + } + } + } + } + + self->SetVar(u"TargetNumber", 1); + self->SetVar(u"playerID", LWOOBJID_EMPTY); + self->SetVar(u"totalDmg", 0); + self->SetNetworkVar(u"totalDmg", false); + self->SetNetworkVar(u"update_time", 0); + + const auto& targetObjs = EntityManager::Instance()->GetEntitiesInGroup("targets_" + std::to_string(self->GetObjectID())); + + for (auto* target : targetObjs) { + target->Smash(self->GetObjectID()); + } + + const auto currentID = self->GetVar<LWOOBJID>(u"currentDummy"); + + auto* current = EntityManager::Instance()->GetEntity(currentID); + + if (current != nullptr) { + current->Smash(self->GetObjectID()); + } +} + +void NtCombatChallengeServer::OnActivityTimerUpdate(Entity* self, float timeRemaining) { + self->SetNetworkVar(u"update_time", std::ceil(timeRemaining)); + + if (timeRemaining <= 3) { + GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerLowSound); + } else { + GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerSound); + } +} + +void NtCombatChallengeServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "start_delay") { + self->SetVar(u"game_tick", gameTime); + + SpawnTargetDummy(self); + + self->AddTimer("game_tick", 1); + + self->SetNetworkVar(u"totalTime", gameTime); + } else if (timerName == "game_tick") { + auto gameTick = self->GetVar<float>(u"game_tick"); + + gameTick -= 1; + + self->SetVar(u"game_tick", gameTick); + + if (gameTick <= 0) { + ResetGame(self); + + GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, stopSound); + + self->AddTimer("reset_tick", 5); + } else { + self->AddTimer("game_tick", 1); + + OnActivityTimerUpdate(self, gameTick); + } + } else if (timerName == "reset_tick") { + self->SetNetworkVar(u"toggle", false); + self->SetNetworkVar(u"bInUse", false); + } +} diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.h b/dScripts/02_server/Map/NT/NtCombatChallengeServer.h new file mode 100644 index 00000000..72bb981f --- /dev/null +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.h @@ -0,0 +1,47 @@ +#pragma once +#include "CppScripts.h" + +class NtCombatChallengeServer : public CppScripts::Script +{ +public: + void OnUse(Entity* self, Entity* user) override; + void OnDie(Entity* self, Entity* killer) override; + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; + void SpawnTargetDummy(Entity* self); + void SetAttackImmunity(LWOOBJID objID, bool bTurnOn); + void OnChildLoaded(Entity* self, Entity* child); + void ResetGame(Entity* self); + void OnActivityTimerUpdate(Entity* self, float timeRemaining); + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + float gameTime = 30.0f; + std::string startSound = "{a477f897-30da-4b15-8fce-895c6547adae}"; + std::string stopSound = "{a832b9c5-b000-4c97-820a-2a7d1e68dd9d}"; + std::string timerSound = "{79b38431-4fc7-403b-8ede-eaff700a7ab0}"; + std::string timerLowSound = "{0e1f1284-e1c4-42ed-8ef9-93e8756948f8}"; + std::string scoreSound = "{cfdade40-3d97-4cf5-b53c-862e0b84c1a1}"; + + std::vector<LOT> tTargets = { + 13556, 13556, 13764, 13764, 13765, 13765, + 13766, 13766, 13767, 13767, 13768, 13768, + 13830, 13769, 13769, 13770, 13830, 13770, + 13771, 13771, 13830, 13772 + }; + + struct MissionRequirements + { + int32_t mission; + int32_t damage; + }; + + std::vector<MissionRequirements> tMissions = { + {1010, 25}, + {1340, 100}, + {1341, 240}, + {1342, 290} + }; +}; diff --git a/dScripts/02_server/Map/NT/NtConsoleTeleportServer.cpp b/dScripts/02_server/Map/NT/NtConsoleTeleportServer.cpp new file mode 100644 index 00000000..324a2fc0 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtConsoleTeleportServer.cpp @@ -0,0 +1,28 @@ +#include "NtConsoleTeleportServer.h" +#include "Entity.h" +#include "AMFFormat.h" + +void NtConsoleTeleportServer::OnStartup(Entity* self) { + self->SetVar(u"teleportAnim", m_TeleportAnim); + self->SetVar(u"teleportString", m_TeleportString); +} + +void NtConsoleTeleportServer::OnUse(Entity* self, Entity* user) { + BaseOnUse(self, user); +} + +void NtConsoleTeleportServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + BaseOnMessageBoxResponse(self, sender, button, identifier, userData); +} + +void NtConsoleTeleportServer::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { + +} + +void NtConsoleTeleportServer::OnTimerDone(Entity* self, std::string timerName) { + BaseOnTimerDone(self, timerName); +} + +void NtConsoleTeleportServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); +} diff --git a/dScripts/02_server/Map/NT/NtConsoleTeleportServer.h b/dScripts/02_server/Map/NT/NtConsoleTeleportServer.h new file mode 100644 index 00000000..59ac7bf4 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtConsoleTeleportServer.h @@ -0,0 +1,21 @@ +#pragma once +#include "CppScripts.h" +#include "ChooseYourDestinationNsToNt.h" +#include "BaseConsoleTeleportServer.h" + +class NtConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer +{ +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; + void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + +private: + int32_t m_ChoiceZoneID = 1800; + std::string m_SpawnPoint = "NS_LW"; + std::u16string m_TeleportAnim = u"lup-teleport"; + std::u16string m_TeleportString = u"UI_TRAVEL_TO_CRUX_PRIME"; +}; diff --git a/dScripts/NtDarkitectRevealServer.cpp b/dScripts/02_server/Map/NT/NtDarkitectRevealServer.cpp similarity index 72% rename from dScripts/NtDarkitectRevealServer.cpp rename to dScripts/02_server/Map/NT/NtDarkitectRevealServer.cpp index b8afa510..80ceb91e 100644 --- a/dScripts/NtDarkitectRevealServer.cpp +++ b/dScripts/02_server/Map/NT/NtDarkitectRevealServer.cpp @@ -2,15 +2,13 @@ #include "Darkitect.h" #include "MissionComponent.h" -void NtDarkitectRevealServer::OnUse(Entity* self, Entity* user) -{ +void NtDarkitectRevealServer::OnUse(Entity* self, Entity* user) { Darkitect Baron; Baron.Reveal(self, user); auto* missionComponent = user->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) - { + if (missionComponent != nullptr) { missionComponent->ForceProgressTaskType(1344, 1, 14293); } } diff --git a/dScripts/NtDarkitectRevealServer.h b/dScripts/02_server/Map/NT/NtDarkitectRevealServer.h similarity index 100% rename from dScripts/NtDarkitectRevealServer.h rename to dScripts/02_server/Map/NT/NtDarkitectRevealServer.h diff --git a/dScripts/02_server/Map/NT/NtDirtCloudServer.cpp b/dScripts/02_server/Map/NT/NtDirtCloudServer.cpp new file mode 100644 index 00000000..92175dea --- /dev/null +++ b/dScripts/02_server/Map/NT/NtDirtCloudServer.cpp @@ -0,0 +1,46 @@ +#include "NtDirtCloudServer.h" +#include "MissionComponent.h" + +std::map<std::string, std::vector<int32_t>> NtDirtCloudServer::m_Missions = +{ + {"Dirt_Clouds_Sent", {1333,1253}}, + {"Dirt_Clouds_Assem", {1333,1276}}, + {"Dirt_Clouds_Para", {1333,1277}}, + {"Dirt_Clouds_Halls", {1333,1283}} +}; + +void NtDirtCloudServer::OnStartup(Entity* self) { + self->SetVar(u"CloudOn", true); +} + +void NtDirtCloudServer::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message != "soapspray") { + return; + } + + if (!self->GetVar<bool>(u"CloudOn")) { + return; + } + + const auto mySpawner = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); + + if (m_Missions.count(mySpawner) == 0) { + return; + } + + const auto& myMis = m_Missions[mySpawner]; + + auto* missionComponent = caster->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + return; + } + + for (const auto missionID : myMis) { + missionComponent->ForceProgressTaskType(missionID, 1, 1); + } + + self->SetVar(u"CloudOn", false); + + self->Smash(self->GetObjectID(), eKillType::VIOLENT); +} diff --git a/dScripts/02_server/Map/NT/NtDirtCloudServer.h b/dScripts/02_server/Map/NT/NtDirtCloudServer.h new file mode 100644 index 00000000..150a33df --- /dev/null +++ b/dScripts/02_server/Map/NT/NtDirtCloudServer.h @@ -0,0 +1,12 @@ +#pragma once +#include "CppScripts.h" + +class NtDirtCloudServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; + +private: + static std::map<std::string, std::vector<int32_t>> m_Missions; +}; diff --git a/dScripts/02_server/Map/NT/NtDukeServer.cpp b/dScripts/02_server/Map/NT/NtDukeServer.cpp new file mode 100644 index 00000000..07d17e96 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtDukeServer.cpp @@ -0,0 +1,40 @@ +#include "NtDukeServer.h" +#include "InventoryComponent.h" +#include "MissionComponent.h" +#include "eMissionState.h" +#include "ePlayerFlag.h" + +void NtDukeServer::SetVariables(Entity* self) { + self->SetVar<float_t>(m_SpyProximityVariable, 35.0f); + + self->SetVar<SpyData>(m_SpyDataVariable, { + ePlayerFlag::NT_FACTION_SPY_DUKE, 13548, 1319 + }); + + self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { + { "DUKE_NT_CONVO_1", 0 }, + { "DUKE_NT_CONVO_2", 0 }, + { "DUKE_NT_CONVO_3", 0 }, + }); + + // If there's an alternating conversation, indices should be provided using the conversationID variables + self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); +} + +void NtDukeServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + + // Handles adding and removing the sword for the Crux Prime Sword mission + auto* missionComponent = target->GetComponent<MissionComponent>(); + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + + if (missionComponent != nullptr && inventoryComponent != nullptr) { + auto state = missionComponent->GetMissionState(m_SwordMissionID); + auto lotCount = inventoryComponent->GetLotCount(m_SwordLot); + + if ((state == eMissionState::AVAILABLE || state == eMissionState::ACTIVE) && lotCount < 1) { + inventoryComponent->AddItem(m_SwordLot, 1, eLootSourceType::NONE); + } else if (state == eMissionState::READY_TO_COMPLETE) { + inventoryComponent->RemoveItem(m_SwordLot, lotCount); + } + } +} diff --git a/dScripts/02_server/Map/NT/NtDukeServer.h b/dScripts/02_server/Map/NT/NtDukeServer.h new file mode 100644 index 00000000..2103ba8d --- /dev/null +++ b/dScripts/02_server/Map/NT/NtDukeServer.h @@ -0,0 +1,9 @@ +#pragma once +#include "NtFactionSpyServer.h" + +class NtDukeServer : public NtFactionSpyServer { + void SetVariables(Entity* self) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + const uint32_t m_SwordMissionID = 1448; + const LOT m_SwordLot = 13777; +}; diff --git a/dScripts/02_server/Map/NT/NtHaelServer.cpp b/dScripts/02_server/Map/NT/NtHaelServer.cpp new file mode 100644 index 00000000..c726ae58 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtHaelServer.cpp @@ -0,0 +1,21 @@ +#include "NtHaelServer.h" +#include "Entity.h" +#include "ePlayerFlag.h" + +void NtHaelServer::SetVariables(Entity* self) { + self->SetVar<float_t>(m_SpyProximityVariable, 25.0f); + + self->SetVar<SpyData>(m_SpyDataVariable, { + ePlayerFlag::NT_FACTION_SPY_HAEL, 13892, 1321 + }); + + self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { + { "HAEL_NT_CONVO_1", 0 }, + { "HAEL_NT_CONVO_2", 0 }, + { "HAEL_NT_CONVO_3", 0 }, + { "HAEL_NT_CONVO_4", 0 }, + }); + + // If there's an alternating conversation, indices should be provided using the conversationID variables + self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); +} diff --git a/dScripts/NtHaelServer.h b/dScripts/02_server/Map/NT/NtHaelServer.h similarity index 68% rename from dScripts/NtHaelServer.h rename to dScripts/02_server/Map/NT/NtHaelServer.h index 8e3dbe47..4597198f 100644 --- a/dScripts/NtHaelServer.h +++ b/dScripts/02_server/Map/NT/NtHaelServer.h @@ -2,5 +2,5 @@ #include "NtFactionSpyServer.h" class NtHaelServer : public NtFactionSpyServer { - void SetVariables(Entity *self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/NT/NtImagBeamBuffer.cpp b/dScripts/02_server/Map/NT/NtImagBeamBuffer.cpp new file mode 100644 index 00000000..d98a7403 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtImagBeamBuffer.cpp @@ -0,0 +1,53 @@ +#include "NtImagBeamBuffer.h" +#include "EntityManager.h" +#include "SkillComponent.h" + +void NtImagBeamBuffer::OnStartup(Entity* self) { + self->SetProximityRadius(100, "ImagZone"); + + self->AddTimer("BuffImag", 2.0f); +} + +void NtImagBeamBuffer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name != "ImagZone" || !entering->IsPlayer()) { + return; + } + + if (status == "ENTER") { + const auto& iter = std::find(m_EntitiesInProximity.begin(), m_EntitiesInProximity.end(), entering->GetObjectID()); + + if (iter == m_EntitiesInProximity.end()) { + m_EntitiesInProximity.push_back(entering->GetObjectID()); + } + } else if (status == "LEAVE") { + const auto& iter = std::find(m_EntitiesInProximity.begin(), m_EntitiesInProximity.end(), entering->GetObjectID()); + + if (iter != m_EntitiesInProximity.end()) { + m_EntitiesInProximity.erase(iter); + } + } +} + +void NtImagBeamBuffer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName != "BuffImag") { + return; + } + + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + for (const auto entityID : m_EntitiesInProximity) { + auto* entity = EntityManager::Instance()->GetEntity(entityID); + + if (entity == nullptr) { + continue; + } + + skillComponent->CalculateBehavior(1311, 30235, entityID, true); + } + + self->AddTimer("BuffImag", 2.0f); +} diff --git a/dScripts/02_server/Map/NT/NtImagBeamBuffer.h b/dScripts/02_server/Map/NT/NtImagBeamBuffer.h new file mode 100644 index 00000000..38e3819c --- /dev/null +++ b/dScripts/02_server/Map/NT/NtImagBeamBuffer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class NtImagBeamBuffer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + std::vector<LWOOBJID> m_EntitiesInProximity = {}; +}; diff --git a/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp b/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp new file mode 100644 index 00000000..64493d78 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp @@ -0,0 +1,12 @@ +#include "NtImagimeterVisibility.h" +#include "GameMessages.h" +#include "Entity.h" +#include "Character.h" +#include "ePlayerFlag.h" + +void NTImagimeterVisibility::OnRebuildComplete(Entity* self, Entity* target) { + auto* character = target->GetCharacter(); + if (character) character->SetPlayerFlag(ePlayerFlag::NT_PLINTH_REBUILD, true); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlinthBuilt", 0, 0, LWOOBJID_EMPTY, "", target->GetSystemAddress()); +} diff --git a/dScripts/02_server/Map/NT/NtImagimeterVisibility.h b/dScripts/02_server/Map/NT/NtImagimeterVisibility.h new file mode 100644 index 00000000..04669d4b --- /dev/null +++ b/dScripts/02_server/Map/NT/NtImagimeterVisibility.h @@ -0,0 +1,7 @@ +#pragma once +#include "CppScripts.h" + +class NTImagimeterVisibility : public CppScripts::Script { +public: + void OnRebuildComplete(Entity* self, Entity* target) override; +}; diff --git a/dScripts/02_server/Map/NT/NtOverbuildServer.cpp b/dScripts/02_server/Map/NT/NtOverbuildServer.cpp new file mode 100644 index 00000000..f8520d87 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtOverbuildServer.cpp @@ -0,0 +1,31 @@ +#include "NtOverbuildServer.h" +#include "EntityManager.h" +#include "ePlayerFlag.h" + +void NtOverbuildServer::SetVariables(Entity* self) { + self->SetVar<float_t>(m_SpyProximityVariable, 30.0f); + + self->SetVar<SpyData>(m_SpyDataVariable, { + ePlayerFlag::NT_FACTION_SPY_OVERBUILD, 13891, 1320 + }); + + self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { + { "OVERBUILD_NT_CONVO_1", 0 }, + { "OVERBUILD_NT_CONVO_2", 1 }, + { "OVERBUILD_NT_CONVO_3", 0 }, + { "OVERBUILD_NT_CONVO_4", 1 }, + { "OVERBUILD_NT_CONVO_5", 0 }, + { "OVERBUILD_NT_CONVO_6", 1 }, + { "OVERBUILD_NT_CONVO_7", 0 }, + }); + + // Find the second object Dr. Overbuild interacts with + LWOOBJID otherConvoObjectID = LWOOBJID_EMPTY; + for (auto* otherConvoObject : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(m_OtherEntitiesGroupVariable)))) { + otherConvoObjectID = otherConvoObject->GetObjectID(); + break; + } + + // If there's an alternating conversation, indices should be provided using the conversationID variables + self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID(), otherConvoObjectID }); +} diff --git a/dScripts/02_server/Map/NT/NtOverbuildServer.h b/dScripts/02_server/Map/NT/NtOverbuildServer.h new file mode 100644 index 00000000..a34d117e --- /dev/null +++ b/dScripts/02_server/Map/NT/NtOverbuildServer.h @@ -0,0 +1,7 @@ +#pragma once +#include "NtFactionSpyServer.h" + +class NtOverbuildServer : public NtFactionSpyServer { + void SetVariables(Entity* self) override; + const std::u16string m_OtherEntitiesGroupVariable = u"SpyConvo2Group"; +}; diff --git a/dScripts/NtParadoxPanelServer.cpp b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp similarity index 63% rename from dScripts/NtParadoxPanelServer.cpp rename to dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp index 556002fe..23d336a7 100644 --- a/dScripts/NtParadoxPanelServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp @@ -3,9 +3,11 @@ #include "MissionComponent.h" #include "EntityManager.h" #include "Character.h" +#include "eMissionState.h" +#include "eTerminateType.h" +#include "eStateChangeType.h" -void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) -{ +void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"bActive", 1, 0, user->GetObjectID(), "", user->GetSystemAddress()); GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); @@ -16,18 +18,15 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) const auto playerID = user->GetObjectID(); - for (const auto mission : tPlayerOnMissions) - { - if (missionComponent->GetMissionState(mission) != MissionState::MISSION_STATE_ACTIVE) - { + for (const auto mission : tPlayerOnMissions) { + if (missionComponent->GetMissionState(mission) != eMissionState::ACTIVE) { continue; } - self->AddCallbackTimer(2, [this, self, playerID] () { + self->AddCallbackTimer(2, [this, self, playerID]() { auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - { + if (player == nullptr) { return; } @@ -36,29 +35,28 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) player->GetCharacter()->SetPlayerFlag(flag, true); GameMessages::SendPlayAnimation(player, u"rebuild-celebrate"); - + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); - GameMessages::SendSetStunned(player->GetObjectID(), eStunState::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); self->SetVar(u"bActive", false); - }); + }); GameMessages::SendPlayAnimation(user, u"nexus-powerpanel", 6.0f); - GameMessages::SendSetStunned(user->GetObjectID(), eStunState::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); return; } GameMessages::SendPlayAnimation(user, shockAnim); - const auto dir = self->GetRotation().GetRightVector(); + const auto dir = self->GetRotation().GetRightVector(); - GameMessages::SendKnockback(user->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, {dir.x * 15, 5, dir.z * 15}); + GameMessages::SendKnockback(user->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, { dir.x * 15, 5, dir.z * 15 }); GameMessages::SendPlayFXEffect(self, 6432, u"create", "console_sparks", LWOOBJID_EMPTY, 1.0, 1.0, true); - - self->AddCallbackTimer(2, [this, self, playerID] () { + + self->AddCallbackTimer(2, [this, self, playerID]() { auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - { + if (player == nullptr) { return; } @@ -67,5 +65,5 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) GameMessages::SendStopFXEffect(self, true, "console_sparks"); self->SetVar(u"bActive", false); - }); + }); } diff --git a/dScripts/NtParadoxPanelServer.h b/dScripts/02_server/Map/NT/NtParadoxPanelServer.h similarity index 77% rename from dScripts/NtParadoxPanelServer.h rename to dScripts/02_server/Map/NT/NtParadoxPanelServer.h index e966e376..796a599b 100644 --- a/dScripts/NtParadoxPanelServer.h +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.h @@ -8,6 +8,6 @@ public: private: std::u16string shockAnim = u"knockback-recovery"; float fxTime = 2.0; - std::vector<int32_t> tPlayerOnMissions = {1278, 1279, 1280, 1281}; + std::vector<int32_t> tPlayerOnMissions = { 1278, 1279, 1280, 1281 }; }; diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp new file mode 100644 index 00000000..b19c8c0b --- /dev/null +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp @@ -0,0 +1,115 @@ +#include "NtParadoxTeleServer.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eStateChangeType.h" + +void NtParadoxTeleServer::OnStartup(Entity* self) { + self->SetProximityRadius(5, "teleport"); +} + +void NtParadoxTeleServer::OnPlayerLoaded(Entity* self, Entity* player) { + +} + +void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; + + auto* player = entering; + const auto playerID = player->GetObjectID(); + + const auto iter = m_TeleportingPlayerTable.find(playerID); + if (iter == m_TeleportingPlayerTable.end()) m_TeleportingPlayerTable[playerID] = false; + const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; + + if (player->IsPlayer() && !bPlayerBeingTeleported) { + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); + + GameMessages::SendPlayAnimation(player, u"teledeath", 4.0f); + + const auto animTime = 2; + + self->AddCallbackTimer(animTime, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + TeleportPlayer(self, player); + }); + } + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } +} + +void NtParadoxTeleServer::TeleportPlayer(Entity* self, Entity* player) { + auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); + auto* destination = self; + + if (!destinationGroup.empty()) { + const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); + + if (!groupObjs.empty()) { + destination = groupObjs[0]; + } + } + + const auto destPosition = destination->GetPosition(); + const auto destRotation = destination->GetRotation(); + + auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); + + if (!teleCinematic.empty()) { + const auto teleCinematicUname = teleCinematic; + GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); + } + + GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + + GameMessages::SendPlayAnimation(player, u"paradox-teleport-in", 4.0f); + + const auto animTime = 2; + + const auto playerID = player->GetObjectID(); + + self->AddCallbackTimer(animTime, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + UnlockPlayer(self, player); + }); + + const auto useSound = self->GetVar<std::string>(u"sound1"); + + if (!useSound.empty()) { + GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); + } +} + +void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) { + const auto playerID = player->GetObjectID(); + + m_TeleportingPlayerTable[playerID] = false; + + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); + + auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); + + if (!teleCinematic.empty()) { + const auto teleCinematicUname = teleCinematic; + GameMessages::SendEndCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); + } +} diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.h b/dScripts/02_server/Map/NT/NtParadoxTeleServer.h new file mode 100644 index 00000000..b094411a --- /dev/null +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +class NtParadoxTeleServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void TeleportPlayer(Entity* self, Entity* player); + void UnlockPlayer(Entity* self, Entity* player); + +private: + std::map<LWOOBJID, bool> m_TeleportingPlayerTable; +}; diff --git a/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp new file mode 100644 index 00000000..257bf6da --- /dev/null +++ b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp @@ -0,0 +1,45 @@ +#include "NtSentinelWalkwayServer.h" +#include "PhantomPhysicsComponent.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" + +void NtSentinelWalkwayServer::OnStartup(Entity* self) { + auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); + + if (phantomPhysicsComponent == nullptr) { + return; + } + + auto force = self->GetVar<int32_t>(u"force"); + + if (force == 0) { + force = 115; + } + + const auto forward = self->GetRotation().GetRightVector() * -1; + + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); + phantomPhysicsComponent->SetDirectionalMultiplier(force); + phantomPhysicsComponent->SetDirection(forward); + phantomPhysicsComponent->SetPhysicsEffectActive(true); + + EntityManager::Instance()->SerializeEntity(self); + + self->SetProximityRadius(3, "speedboost"); +} + +void NtSentinelWalkwayServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name != "speedboost" || !entering->IsPlayer() || status != "ENTER") { + return; + } + + auto* player = entering; + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } +} diff --git a/dScripts/NtSentinelWalkwayServer.h b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.h similarity index 100% rename from dScripts/NtSentinelWalkwayServer.h rename to dScripts/02_server/Map/NT/NtSentinelWalkwayServer.h diff --git a/dScripts/NtSleepingGuard.cpp b/dScripts/02_server/Map/NT/NtSleepingGuard.cpp similarity index 79% rename from dScripts/NtSleepingGuard.cpp rename to dScripts/02_server/Map/NT/NtSleepingGuard.cpp index 74bc50f0..145df6c8 100644 --- a/dScripts/NtSleepingGuard.cpp +++ b/dScripts/02_server/Map/NT/NtSleepingGuard.cpp @@ -1,14 +1,12 @@ -#include "NtSleepingGuard.h" +#include "NtSleepingGuard.h" #include "GameMessages.h" #include "MissionComponent.h" -void NtSleepingGuard::OnStartup(Entity* self) -{ +void NtSleepingGuard::OnStartup(Entity* self) { self->SetNetworkVar<bool>(u"asleep", true); } -void NtSleepingGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) -{ +void NtSleepingGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) { if (!self->GetNetworkVar<bool>(u"asleep")) return; @@ -23,18 +21,15 @@ void NtSleepingGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) - { + if (missionComponent != nullptr) { missionComponent->CompleteMission(1346); } self->AddTimer("AsleepAgain", 5.0f); } -void NtSleepingGuard::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "AsleepAgain") - { +void NtSleepingGuard::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "AsleepAgain") { self->SetNetworkVar<bool>(u"asleep", true); } } diff --git a/dScripts/NtSleepingGuard.h b/dScripts/02_server/Map/NT/NtSleepingGuard.h similarity index 96% rename from dScripts/NtSleepingGuard.h rename to dScripts/02_server/Map/NT/NtSleepingGuard.h index 42f7391e..5129ae4f 100644 --- a/dScripts/NtSleepingGuard.h +++ b/dScripts/02_server/Map/NT/NtSleepingGuard.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" class NtSleepingGuard final : public CppScripts::Script diff --git a/dScripts/02_server/Map/NT/NtVandaServer.cpp b/dScripts/02_server/Map/NT/NtVandaServer.cpp new file mode 100644 index 00000000..7750d566 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtVandaServer.cpp @@ -0,0 +1,14 @@ +#include "NtVandaServer.h" +#include "InventoryComponent.h" +#include "eMissionState.h" + +void NtVandaServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + + // Removes the alien parts after completing the mission + if (missionID == m_AlienPartMissionID && missionState == eMissionState::READY_TO_COMPLETE) { + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + for (const auto& alienPartLot : m_AlienPartLots) { + inventoryComponent->RemoveItem(alienPartLot, 1); + } + } +} diff --git a/dScripts/02_server/Map/NT/NtVandaServer.h b/dScripts/02_server/Map/NT/NtVandaServer.h new file mode 100644 index 00000000..58162cd9 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtVandaServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class NtVandaServer : public CppScripts::Script { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + const uint32_t m_AlienPartMissionID = 1183; + const std::vector<LOT> m_AlienPartLots = { 12479, 12480, 12481 }; +}; diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp new file mode 100644 index 00000000..38f929a1 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -0,0 +1,125 @@ +#include "NtVentureCannonServer.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "eEndBehavior.h" +#include "eTerminateType.h" +#include "eStateChangeType.h" + +void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { + auto* player = user; + const auto playerID = player->GetObjectID(); + + auto enterCinematic = self->GetVar<std::u16string>(u"EnterCinematic"); + + if (enterCinematic.empty()) { + return; + } + + self->SetNetworkVar(u"bIsInUse", true); + + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); + + auto destPosition = self->GetPosition(); + + destPosition.y += 5 - 1.57f; + + auto destRotation = self->GetRotation(); + + GameMessages::SendTeleport(playerID, destPosition, destRotation, player->GetSystemAddress(), true); + + GameMessages::SendPlayAnimation(player, u"scale-down", 4.0f); + + const auto enterCinematicUname = enterCinematic; + GameMessages::SendPlayCinematic(player->GetObjectID(), enterCinematicUname, player->GetSystemAddress()); + + GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), "{e8bf79ce-7453-4a7d-b872-fee65e97ff15}"); + + self->AddCallbackTimer(3, [this, self]() { + self->SetNetworkVar(u"bIsInUse", false); + }); + + self->AddCallbackTimer(1.5f, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + EnterCannonEnded(self, player); + }); +} + +void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) { + const auto playerID = player->GetObjectID(); + + const auto& cannonEffectGroup = EntityManager::Instance()->GetEntitiesInGroup("cannonEffect"); + + if (!cannonEffectGroup.empty()) { + auto* cannonEffect = cannonEffectGroup[0]; + + GameMessages::SendPlayFXEffect(cannonEffect, 6036, u"create", "cannon_blast", LWOOBJID_EMPTY, 1, 1, true); + + GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(cannonEffect, u"camshake-bridge", cannonEffect->GetObjectID(), 100); + } + + FirePlayer(self, player); + + auto exitCinematic = self->GetVar<std::u16string>(u"ExitCinematic"); + + if (exitCinematic.empty()) { + UnlockCannonPlayer(self, player); + + return; + } + + const auto exitCinematicUname = exitCinematic; + GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(), + true, true, true, false, eEndBehavior::RETURN, false, 0, false, false + ); + + self->AddCallbackTimer(1.5f, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (player == nullptr) { + return; + } + + ExitCannonEnded(self, player); + }); +} + +void NtVentureCannonServer::ExitCannonEnded(Entity* self, Entity* player) { + UnlockCannonPlayer(self, player); +} + +void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) { + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true + ); + + self->SetNetworkVar(u"bIsInUse", false); + + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} + +void NtVentureCannonServer::FirePlayer(Entity* self, Entity* player) { + auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); + auto* destination = self; + + if (!destinationGroup.empty()) { + const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); + + if (!groupObjs.empty()) { + destination = groupObjs[0]; + } + } + + const auto destPosition = destination->GetPosition(); + const auto destRotation = destination->GetRotation(); + + GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + + GameMessages::SendPlayAnimation(player, u"venture-cannon-out", 4.0f); +} diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.h b/dScripts/02_server/Map/NT/NtVentureCannonServer.h new file mode 100644 index 00000000..a5998f14 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.h @@ -0,0 +1,12 @@ +#pragma once +#include "CppScripts.h" + +class NtVentureCannonServer : public CppScripts::Script +{ +public: + void OnUse(Entity* self, Entity* user) override; + void EnterCannonEnded(Entity* self, Entity* player); + void ExitCannonEnded(Entity* self, Entity* player); + void UnlockCannonPlayer(Entity* self, Entity* player); + void FirePlayer(Entity* self, Entity* player); +}; diff --git a/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp b/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp new file mode 100644 index 00000000..07d33555 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp @@ -0,0 +1,29 @@ +#include "NtVentureSpeedPadServer.h" +#include "SkillComponent.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" + +void NtVentureSpeedPadServer::OnStartup(Entity* self) { + self->SetProximityRadius(3, "speedboost"); +} + + +void NtVentureSpeedPadServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name != "speedboost" || !entering->IsPlayer() || status != "ENTER") { + return; + } + + auto* player = entering; + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + + auto* skillComponent = player->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(927, 18913, player->GetObjectID(), true); + } +} diff --git a/dScripts/NtVentureSpeedPadServer.h b/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.h similarity index 100% rename from dScripts/NtVentureSpeedPadServer.h rename to dScripts/02_server/Map/NT/NtVentureSpeedPadServer.h diff --git a/dScripts/02_server/Map/NT/NtXRayServer.cpp b/dScripts/02_server/Map/NT/NtXRayServer.cpp new file mode 100644 index 00000000..3b281b79 --- /dev/null +++ b/dScripts/02_server/Map/NT/NtXRayServer.cpp @@ -0,0 +1,12 @@ +#include "NtXRayServer.h" +#include "SkillComponent.h" + +void NtXRayServer::OnCollisionPhantom(Entity* self, Entity* target) { + auto* skillComponent = target->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior(1220, 27641, target->GetObjectID()); +} diff --git a/dScripts/NtXRayServer.h b/dScripts/02_server/Map/NT/NtXRayServer.h similarity index 100% rename from dScripts/NtXRayServer.h rename to dScripts/02_server/Map/NT/NtXRayServer.h diff --git a/dScripts/02_server/Map/NT/SpawnSaberCatServer.cpp b/dScripts/02_server/Map/NT/SpawnSaberCatServer.cpp new file mode 100644 index 00000000..3307c522 --- /dev/null +++ b/dScripts/02_server/Map/NT/SpawnSaberCatServer.cpp @@ -0,0 +1,10 @@ +#include "SpawnSaberCatServer.h" +#include "Entity.h" + +void SpawnSaberCatServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 12432); + self->SetVar<std::string>(u"petType", "sabercat"); + self->SetVar<uint32_t>(u"maxPets", 3); + self->SetVar<std::u16string>(u"spawnAnim", u"pq_m_drop-down"); + self->SetVar<std::u16string>(u"spawnCinematic", u"AssemblyPet"); +} diff --git a/dScripts/SpawnSaberCatServer.h b/dScripts/02_server/Map/NT/SpawnSaberCatServer.h similarity index 69% rename from dScripts/SpawnSaberCatServer.h rename to dScripts/02_server/Map/NT/SpawnSaberCatServer.h index 6be6ff5b..a4d1874c 100644 --- a/dScripts/SpawnSaberCatServer.h +++ b/dScripts/02_server/Map/NT/SpawnSaberCatServer.h @@ -2,5 +2,5 @@ #include "SpawnPetBaseServer.h" class SpawnSaberCatServer : public SpawnPetBaseServer { - void SetVariables(Entity *self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/NT/SpawnShrakeServer.cpp b/dScripts/02_server/Map/NT/SpawnShrakeServer.cpp new file mode 100644 index 00000000..cf388ad0 --- /dev/null +++ b/dScripts/02_server/Map/NT/SpawnShrakeServer.cpp @@ -0,0 +1,10 @@ +#include "SpawnShrakeServer.h" +#include "Entity.h" + +void SpawnShrakeServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 12434); + self->SetVar<std::string>(u"petType", "shrake"); + self->SetVar<uint32_t>(u"maxPets", 3); + self->SetVar<std::u16string>(u"spawnAnim", u"mf_u_g_TT_spawn-1"); + self->SetVar<std::u16string>(u"spawnCinematic", u"ParadoxPet"); +} diff --git a/dScripts/SpawnShrakeServer.h b/dScripts/02_server/Map/NT/SpawnShrakeServer.h similarity index 69% rename from dScripts/SpawnShrakeServer.h rename to dScripts/02_server/Map/NT/SpawnShrakeServer.h index 9d7e86bc..de8c7405 100644 --- a/dScripts/SpawnShrakeServer.h +++ b/dScripts/02_server/Map/NT/SpawnShrakeServer.h @@ -2,5 +2,5 @@ #include "SpawnPetBaseServer.h" class SpawnShrakeServer : public SpawnPetBaseServer { - void SetVariables(Entity *self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/NT/SpawnStegoServer.cpp b/dScripts/02_server/Map/NT/SpawnStegoServer.cpp new file mode 100644 index 00000000..9fddeae5 --- /dev/null +++ b/dScripts/02_server/Map/NT/SpawnStegoServer.cpp @@ -0,0 +1,10 @@ +#include "SpawnStegoServer.h" +#include "Entity.h" + +void SpawnStegoServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 12431); + self->SetVar<std::string>(u"petType", "stego"); + self->SetVar<uint32_t>(u"maxPets", 3); + self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); + self->SetVar<std::u16string>(u"spawnCinematic", u"VenturePet"); +} diff --git a/dScripts/SpawnStegoServer.h b/dScripts/02_server/Map/NT/SpawnStegoServer.h similarity index 68% rename from dScripts/SpawnStegoServer.h rename to dScripts/02_server/Map/NT/SpawnStegoServer.h index d5bbd20b..955fd119 100644 --- a/dScripts/SpawnStegoServer.h +++ b/dScripts/02_server/Map/NT/SpawnStegoServer.h @@ -2,5 +2,5 @@ #include "SpawnPetBaseServer.h" class SpawnStegoServer : public SpawnPetBaseServer { - void SetVariables(Entity *self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/PR/CMakeLists.txt b/dScripts/02_server/Map/PR/CMakeLists.txt new file mode 100644 index 00000000..3a32e9f3 --- /dev/null +++ b/dScripts/02_server/Map/PR/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PR + "HydrantBroken.cpp" + "PrSeagullFly.cpp" + "SpawnGryphonServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/PR/HydrantBroken.cpp b/dScripts/02_server/Map/PR/HydrantBroken.cpp new file mode 100644 index 00000000..1409c9fb --- /dev/null +++ b/dScripts/02_server/Map/PR/HydrantBroken.cpp @@ -0,0 +1,37 @@ +#include "HydrantBroken.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void HydrantBroken::OnStartup(Entity* self) { + self->AddTimer("playEffect", 1); + + const auto hydrant = "hydrant" + self->GetVar<std::string>(u"hydrant"); + + const auto bouncers = EntityManager::Instance()->GetEntitiesInGroup(hydrant); + + for (auto* bouncer : bouncers) { + self->SetVar<LWOOBJID>(u"bouncer", bouncer->GetObjectID()); + + GameMessages::SendBouncerActiveStatus(bouncer->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision", UNASSIGNED_SYSTEM_ADDRESS); + } + + self->AddTimer("KillBroken", 25); +} + +void HydrantBroken::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "KillBroken") { + auto* bouncer = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"bouncer")); + + if (bouncer != nullptr) { + GameMessages::SendBouncerActiveStatus(bouncer->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision", UNASSIGNED_SYSTEM_ADDRESS); + } + + self->Kill(); + } else if (timerName == "playEffect") { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 384, u"water", "water", LWOOBJID_EMPTY, 1, 1, true); + } +} diff --git a/dScripts/HydrantBroken.h b/dScripts/02_server/Map/PR/HydrantBroken.h similarity index 75% rename from dScripts/HydrantBroken.h rename to dScripts/02_server/Map/PR/HydrantBroken.h index 65f38604..9ed1f4ab 100644 --- a/dScripts/HydrantBroken.h +++ b/dScripts/02_server/Map/PR/HydrantBroken.h @@ -1,9 +1,9 @@ #pragma once #include "CppScripts.h" -class HydrantBroken : public CppScripts::Script +class HydrantBroken : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnTimerDone(Entity* self, std::string timerName) override; -}; \ No newline at end of file +}; diff --git a/dScripts/PrSeagullFly.cpp b/dScripts/02_server/Map/PR/PrSeagullFly.cpp similarity index 50% rename from dScripts/PrSeagullFly.cpp rename to dScripts/02_server/Map/PR/PrSeagullFly.cpp index a4dd5fcd..5c71f32a 100644 --- a/dScripts/PrSeagullFly.cpp +++ b/dScripts/02_server/Map/PR/PrSeagullFly.cpp @@ -1,24 +1,19 @@ #include "PrSeagullFly.h" #include "Entity.h" -void PrSeagullFly::OnStartup(Entity* self) -{ +void PrSeagullFly::OnStartup(Entity* self) { self->SetVar<int32_t>(u"playersNear", 0); - self->SetProximityRadius(15, "birdMonitor"); + self->SetProximityRadius(15, "birdMonitor"); } -void PrSeagullFly::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (!entering->IsPlayer()) return; +void PrSeagullFly::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (!entering->IsPlayer()) return; - if (status == "ENTER") - { + if (status == "ENTER") { self->SetVar<int32_t>(u"playersNear", self->GetVar<int32_t>(u"playersNear") + 1); - } - else if (status == "LEAVE") - { + } else if (status == "LEAVE") { self->SetVar<int32_t>(u"playersNear", self->GetVar<int32_t>(u"playersNear") - 1); - } + } - self->SetNetworkVar(u"BirdLanded", self->GetVar<int32_t>(u"playersNear") == 0); + self->SetNetworkVar(u"BirdLanded", self->GetVar<int32_t>(u"playersNear") == 0); } diff --git a/dScripts/PrSeagullFly.h b/dScripts/02_server/Map/PR/PrSeagullFly.h similarity index 100% rename from dScripts/PrSeagullFly.h rename to dScripts/02_server/Map/PR/PrSeagullFly.h diff --git a/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp new file mode 100644 index 00000000..cf635fe4 --- /dev/null +++ b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp @@ -0,0 +1,29 @@ +#include "SpawnGryphonServer.h" +#include "InventoryComponent.h" +#include "GameMessages.h" +#include "MissionComponent.h" +#include "eMissionState.h" +#include "eTerminateType.h" + +void SpawnGryphonServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 12433); + self->SetVar<std::string>(u"petType", "gryphon"); + self->SetVar<uint32_t>(u"maxPets", 2); + self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); + self->SetVar<std::u16string>(u"spawnCinematic", u"SentinelPet"); +} + +void SpawnGryphonServer::OnUse(Entity* self, Entity* user) { + auto* missionComponent = user->GetComponent<MissionComponent>(); + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + + // Little extra for handling the case of the egg being placed the first time + if (missionComponent != nullptr && inventoryComponent != nullptr + && missionComponent->GetMissionState(1391) == eMissionState::ACTIVE) { + inventoryComponent->RemoveItem(12483, inventoryComponent->GetLotCount(12483)); + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + return; + } + + SpawnPetBaseServer::OnUse(self, user); +} diff --git a/dScripts/SpawnGryphonServer.h b/dScripts/02_server/Map/PR/SpawnGryphonServer.h similarity index 51% rename from dScripts/SpawnGryphonServer.h rename to dScripts/02_server/Map/PR/SpawnGryphonServer.h index 8f76e1dc..eacf93e4 100644 --- a/dScripts/SpawnGryphonServer.h +++ b/dScripts/02_server/Map/PR/SpawnGryphonServer.h @@ -2,6 +2,6 @@ #include "SpawnPetBaseServer.h" class SpawnGryphonServer : public SpawnPetBaseServer { - void SetVariables(Entity *self) override; - void OnUse(Entity *self, Entity *user) override; + void SetVariables(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/Property/AG_Med/CMakeLists.txt b/dScripts/02_server/Map/Property/AG_Med/CMakeLists.txt new file mode 100644 index 00000000..90985f9f --- /dev/null +++ b/dScripts/02_server/Map/Property/AG_Med/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_AG_MED + "ZoneAgMedProperty.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.cpp b/dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.cpp new file mode 100644 index 00000000..46ec7bbd --- /dev/null +++ b/dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.cpp @@ -0,0 +1,42 @@ +#include "ZoneAgMedProperty.h" +#include "Entity.h" + +void ZoneAgMedProperty::SetGameVariables(Entity* self) { + + self->SetVar<std::string>(ClaimMarkerGroup, "ClaimMarker"); + self->SetVar<std::string>(GeneratorGroup, "Generator"); + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(SpotsGroup, "Spots"); + self->SetVar<std::string>(MSCloudsGroup, "maelstrom"); + self->SetVar<std::string>(EnemiesGroup, "Enemies"); + self->SetVar<std::string>(FXManagerGroup, "FXObject"); + self->SetVar<std::string>(ImagOrbGroup, "Orb"); + self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); + + self->SetVar<std::vector<std::string>>(EnemiesSpawner, { + "StrombieWander", "Strombies", "Mechs", "OtherEnemy" + }); + self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); + self->SetVar<std::string>(GeneratorSpawner, "Generator"); + self->SetVar<std::string>(DamageFXSpawner, "MaelstromFX"); + self->SetVar<std::string>(FXSpotsSpawner, "MaelstromSpots"); + self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); + self->SetVar<std::string>(ImageOrbSpawner, "Orb"); + self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); + self->SetVar<std::string>(SmashablesSpawner, "Smashables"); + self->SetVar<std::string>(FXManagerSpawner, "FXObject"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "BirdFX", "SunBeam" }); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); + + self->SetVar<int32_t>(defeatedProperyFlag, 118); + self->SetVar<int32_t>(placedModelFlag, 119); + self->SetVar<uint32_t>(guardMissionFlag, 1293); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 1294); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 10118); + self->SetVar<LOT>(orbIDFlag, 10226); + self->SetVar<LOT>(behaviorQBID, 10445); +} diff --git a/dScripts/ZoneAgMedProperty.h b/dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.h similarity index 67% rename from dScripts/ZoneAgMedProperty.h rename to dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.h index 83b365fd..95597699 100644 --- a/dScripts/ZoneAgMedProperty.h +++ b/dScripts/02_server/Map/Property/AG_Med/ZoneAgMedProperty.h @@ -2,5 +2,5 @@ #include "BasePropertyServer.h" class ZoneAgMedProperty : public BasePropertyServer { - void SetGameVariables(Entity *self) override; + void SetGameVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/Property/AG_Small/CMakeLists.txt b/dScripts/02_server/Map/Property/AG_Small/CMakeLists.txt new file mode 100644 index 00000000..3d71dc1a --- /dev/null +++ b/dScripts/02_server/Map/Property/AG_Small/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_AG_SMALL + "ZoneAgProperty.cpp" + "EnemySpiderSpawner.cpp" + PARENT_SCOPE) diff --git a/dScripts/EnemySpiderSpawner.cpp b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp similarity index 89% rename from dScripts/EnemySpiderSpawner.cpp rename to dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp index 98524ae1..0d4f568e 100644 --- a/dScripts/EnemySpiderSpawner.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp @@ -1,27 +1,29 @@ #include "EnemySpiderSpawner.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" //---------------------------------------------- //--Initiate egg hatching on call //---------------------------------------------- -void EnemySpiderSpawner::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { +void EnemySpiderSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { if (args == "prepEgg") { // Highlight eggs about to hatch with Maelstrom effect GameMessages::SendPlayFXEffect(self->GetObjectID(), 2856, u"maelstrom", "test", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - + // Make indestructible - auto dest = static_cast<DestroyableComponent*>(self->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto dest = static_cast<DestroyableComponent*>(self->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetFaction(-1); } EntityManager::Instance()->SerializeEntity(self); - + // Keep track of who prepped me self->SetI64(u"SpawnOwner", sender->GetObjectID()); - + } else if (args == "hatchEgg") { // Final countdown to pop self->AddTimer("StartSpawnTime", hatchTime); @@ -36,10 +38,10 @@ void EnemySpiderSpawner::OnTimerDone(Entity* self, std::string timerName) { SpawnSpiderling(self); } else if (timerName == "SpawnSpiderling") { GameMessages::SendPlayFXEffect(self->GetObjectID(), 644, u"create", "egg_puff_b", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - + //TODO: set the aggro radius larger - EntityInfo info {}; + EntityInfo info{}; info.lot = 16197; info.pos = self->GetPosition(); info.spawner = nullptr; @@ -59,7 +61,7 @@ void EnemySpiderSpawner::OnTimerDone(Entity* self, std::string timerName) { } self->ScheduleKillAfterUpdate(); - } + } } //-------------------------------------------------------------- diff --git a/dScripts/EnemySpiderSpawner.h b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.h similarity index 85% rename from dScripts/EnemySpiderSpawner.h rename to dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.h index def08ab1..f850a6eb 100644 --- a/dScripts/EnemySpiderSpawner.h +++ b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.h @@ -16,8 +16,8 @@ class EnemySpiderSpawner final : public CppScripts::Script { public: - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; void OnTimerDone(Entity* self, std::string timerName) override; private: diff --git a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp new file mode 100644 index 00000000..6bf91768 --- /dev/null +++ b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp @@ -0,0 +1,426 @@ +#include "ZoneAgProperty.h" +#include "EntityManager.h" +#include "Character.h" +#include "Entity.h" +#include "GameMessages.h" +#include "dZoneManager.h" +#include "RenderComponent.h" +#include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" + +void ZoneAgProperty::SetGameVariables(Entity* self) { + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(PropertyBorderGroup, "PropertyBorder"); + self->SetVar<std::string>(LandTargetGroup, "Land_Target"); + self->SetVar<std::string>(SpiderScreamGroup, "Spider_Scream"); + self->SetVar<std::vector<std::string>>(ROFTargetsGroup, { "ROF_Targets_00", "ROF_Targets_01", "ROF_Targets_02", "ROF_Targets_03", "ROF_Targets_04" }); + self->SetVar<std::string>(SpiderEggsGroup, "SpiderEggs"); + self->SetVar<std::string>(RocksGroup, "Rocks"); + self->SetVar<std::string>(EnemiesGroup, "SpiderBoss"); + self->SetVar<std::vector<std::string>>(ZoneVolumesGroup, { "Zone1Vol", "Zone2Vol", "Zone3Vol", "Zone4Vol", "Zone5Vol", "Zone6Vol", "Zone7Vol", "Zone8Vol", "AggroVol", "TeleVol" }); + self->SetVar<std::string>(FXManagerGroup, "FXObject"); + + self->SetVar<std::string>(EnemiesSpawner, "SpiderBoss"); + self->SetVar<std::vector<std::string>>(BossSensorSpawner, { "Zone1Vol", "Zone2Vol", "Zone3Vol", "Zone4Vol", "Zone5Vol", "Zone6Vol", "Zone7Vol", "Zone8Vol", "RFS_Targets", "AggroVol", "TeleVol" }); + self->SetVar<std::string>(LandTargetSpawner, "Land_Target"); + self->SetVar<std::string>(SpiderScreamSpawner, "Spider_Scream"); + self->SetVar<std::vector<std::string>>(ROFTargetsSpawner, { "ROF_Targets_00", "ROF_Targets_01", "ROF_Targets_02", "ROF_Targets_03", "ROF_Targets_04" }); + self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); + self->SetVar<std::string>(FXManagerSpawner, "FXObject"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::string>(SpiderEggsSpawner, "SpiderEggs"); + self->SetVar<std::string>(RocksSpawner, "Rocks"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "BirdFX", "SunBeam" }); + self->SetVar<std::vector<std::string>>(SpiderRocketSpawner, { "SpiderRocket_Bot", "SpiderRocket_Mid", "SpiderRocket_Top" }); + self->SetVar<std::string>(MailboxSpawner, "Mailbox"); + self->SetVar<std::string>(LauncherSpawner, "Launcher"); + self->SetVar<std::string>(InstancerSpawner, "Instancer"); + + self->SetVar<int32_t>(defeatedProperyFlag, 71); + self->SetVar<int32_t>(placedModelFlag, 73); + self->SetVar<uint32_t>(guardFirstMissionFlag, 891); + self->SetVar<uint32_t>(guardMissionFlag, 320); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 951); +} + +void ZoneAgProperty::OnStartup(Entity* self) { + LoadProperty(self); +} + +void ZoneAgProperty::OnPlayerLoaded(Entity* self, Entity* player) { + CheckForOwner(self); + + auto rented = self->GetVar<LWOOBJID>(u"PropertyOwner") == LWOOBJID_EMPTY; + self->SetVar<bool>(u"rented", rented); + + if (!rented) { + const auto numberOfPlayers = self->GetVar<int32_t>(u"numberOfPlayers"); + self->SetVar<int32_t>(u"numberOfPlayers", numberOfPlayers + 1); + } + + if (dZoneManager::Instance()->GetZone()->GetZoneID().GetMapID() == 1102) { + GameMessages::SendPlay2DAmbientSound(player, GUIDMaelstrom); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, + LWOOBJID_EMPTY, "", player->GetSystemAddress()); + + self->SetNetworkVar(u"unclaimed", true); + + return; + } + + BasePlayerLoaded(self, player); +} + +void ZoneAgProperty::PropGuardCheck(Entity* self, Entity* player) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; + + const auto state = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)); + const auto firstState = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardFirstMissionFlag)); + + if (firstState < eMissionState::COMPLETE || (state != eMissionState::COMPLETE && state != eMissionState::COMPLETE_READY_TO_COMPLETE)) + ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); +} + +void ZoneAgProperty::OnZoneLoadedInfo(Entity* self) { + LoadProperty(self); +} + +void ZoneAgProperty::LoadInstance(Entity* self) { + SetGameVariables(self); + + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(self->GetVar<std::string>(InstancerSpawner))) { + for (auto* spawnerNode : spawner->m_Info.nodes) { + spawnerNode->config.push_back( + new LDFData<std::string>(u"custom_script_server", + R"(scripts\ai\GENERAL\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua)")); + spawnerNode->config.push_back(new LDFData<std::u16string>(u"transferText", u"SPIDER_QUEEN_EXIT_QUESTION")); + } + } + + ActivateSpawner(self->GetVar<std::string>(InstancerSpawner)); +} + +void ZoneAgProperty::LoadProperty(Entity* self) { + SetGameVariables(self); + ActivateSpawner(self->GetVar<std::string>(LauncherSpawner)); + ActivateSpawner(self->GetVar<std::string>(MailboxSpawner)); +} + +void ZoneAgProperty::ProcessGroupObjects(Entity* self, std::string group) { +} + +void ZoneAgProperty::SpawnSpots(Entity* self) { + for (const auto& spot : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { + ActivateSpawner(spot); + } + + ActivateSpawner(self->GetVar<std::string>(LandTargetSpawner)); +} + +void ZoneAgProperty::KillSpots(Entity* self) { + for (const auto& spot : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { + DeactivateSpawner(spot); + } + + for (const auto& groupName : self->GetVar<std::vector<std::string>>(ROFTargetsGroup)) { + for (auto* spot : EntityManager::Instance()->GetEntitiesInGroup(groupName)) { + spot->Kill(); + } + } + + DeactivateSpawner(self->GetVar<std::string>(LandTargetSpawner)); + for (auto* landTarget : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(LandTargetSpawner))) { + landTarget->Kill(); + } +} + +void ZoneAgProperty::SpawnCrashedRocket(Entity* self) { + for (const auto& rocket : self->GetVar<std::vector<std::string>>(SpiderRocketSpawner)) { + ActivateSpawner(rocket); + } +} + +void ZoneAgProperty::KillCrashedRocket(Entity* self) { + for (const auto& rocket : self->GetVar<std::vector<std::string>>(SpiderRocketSpawner)) { + DeactivateSpawner(rocket); + DestroySpawner(rocket); + } +} + +void ZoneAgProperty::StartMaelstrom(Entity* self, Entity* player) { + ActivateSpawner(self->GetVar<std::string>(EnemiesSpawner)); + for (const auto& sensor : self->GetVar<std::vector<std::string>>(BossSensorSpawner)) { + ActivateSpawner(sensor); + } + + ActivateSpawner(self->GetVar<std::string>(FXManagerSpawner)); + ActivateSpawner(self->GetVar<std::string>(SpiderScreamSpawner)); + ActivateSpawner(self->GetVar<std::string>(SpiderEggsSpawner)); + ActivateSpawner(self->GetVar<std::string>(RocksSpawner)); + + SpawnCrashedRocket(self); + + for (const auto& ambient : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { + DeactivateSpawner(ambient); + DestroySpawner(ambient); + ResetSpawner(ambient); + } + + StartTornadoFx(self); + + if (player != nullptr) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, + "", player->GetSystemAddress()); + } +} + +uint32_t ZoneAgProperty::RetrieveSpawnerId(Entity* self, const std::string& spawner) { + auto spawnerIDs = dZoneManager::Instance()->GetSpawnersByName(spawner); + if (spawnerIDs.empty()) + return 0; + + return spawnerIDs[0]->m_Info.spawnerID; +} + +void ZoneAgProperty::OnTimerDone(Entity* self, std::string timerName) { + BaseTimerDone(self, timerName); +} + +void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { + if (timerName == "GuardFlyAway") { + const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); + if (zoneId != 1150) + return; + + const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GuardGroup)); + if (entities.empty()) + return; + + auto* entity = entities[0]; + + GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, entity->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + LoadProperty(self); + + self->AddTimer("KillGuard", 5); + } else if (timerName == "KillGuard") { + KillGuard(self); + } else if (timerName == "tornadoOff") { + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { + auto* renderComponent = entity->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("TornadoDebris", false); + renderComponent->StopEffect("TornadoVortex", false); + renderComponent->StopEffect("silhouette", false); + } + } + + self->AddTimer("ShowVendor", 1.2f); + self->AddTimer("ShowClearEffects", 2); + } else if (timerName == "ShowClearEffects") { + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { + auto* renderComponent = entity->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->PlayEffect(-1, u"beamOn", "beam"); + } + } + + self->AddTimer("killSpider", 2); + self->AddTimer("turnSkyOff", 1.5f); + self->AddTimer("killFXObject", 8); + } else if (timerName == "turnSkyOff") { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, + "", UNASSIGNED_SYSTEM_ADDRESS); + } else if (timerName == "killSpider") { + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(EnemiesGroup))) { + entity->Kill(); + } + + for (const auto& sensor : self->GetVar<std::vector<std::string>>(BossSensorSpawner)) { + DeactivateSpawner(sensor); + DestroySpawner(sensor); + } + + DeactivateSpawner(self->GetVar<std::string>(SpiderEggsSpawner)); + DestroySpawner(self->GetVar<std::string>(SpiderEggsSpawner)); + + DeactivateSpawner(self->GetVar<std::string>(RocksSpawner)); + DestroySpawner(self->GetVar<std::string>(RocksSpawner)); + + KillSpots(self); + KillCrashedRocket(self); + + DeactivateSpawner(self->GetVar<std::string>(SpiderScreamSpawner)); + DestroySpawner(self->GetVar<std::string>(SpiderScreamSpawner)); + + for (auto* player : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER)) { + GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); + GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + } + } else if (timerName == "ShowVendor") { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + for (const auto& ambient : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { + ActivateSpawner(ambient); + } + } else if (timerName == "BoundsVisOn") { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, + LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + } else if (timerName == "runPlayerLoadedAgain") { + CheckForOwner(self); + } else if (timerName == "pollTornadoFX") { + StartTornadoFx(self); + } else if (timerName == "killFXObject") { + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { + auto* renderComponent = entity->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("beam"); + } + } + + DestroySpawner(self->GetVar<std::string>(FXManagerSpawner)); + + self->SetVar<bool>(u"FXObjectGone", true); + } else if (timerName == "ProcessGroupObj") { + // TODO + } +} + +void ZoneAgProperty::OnZonePropertyRented(Entity* self, Entity* player) { + BaseZonePropertyRented(self, player); + + auto* character = player->GetCharacter(); + if (character == nullptr) + return; + + character->SetPlayerFlag(108, true); +} + +void ZoneAgProperty::OnZonePropertyModelPlaced(Entity* self, Entity* player) { + auto* character = player->GetCharacter(); + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (!character->GetPlayerFlag(101)) { + BaseZonePropertyModelPlaced(self, player); + character->SetPlayerFlag(101, true); + if (missionComponent->GetMissionState(871) == eMissionState::ACTIVE) { + self->SetNetworkVar<std::u16string>(u"Tooltip", u"AnotherModel"); + } + + } else if (!character->GetPlayerFlag(102)) { + character->SetPlayerFlag(102, true); + if (missionComponent->GetMissionState(871) == eMissionState::ACTIVE) { + self->SetNetworkVar<std::u16string>(u"Tooltip", u"TwoMoreModels"); + } + + } else if (!character->GetPlayerFlag(103)) { + character->SetPlayerFlag(103, true); + } else if (!character->GetPlayerFlag(104)) { + character->SetPlayerFlag(104, true); + self->SetNetworkVar<std::u16string>(u"Tooltip", u"TwoMoreModelsOff"); + } else if (self->GetVar<std::string>(u"tutorial") == "place_model") { + self->SetVar<std::string>(u"tutorial", ""); + self->SetNetworkVar<std::u16string>(u"Tooltip", u"PutAway"); + } +} + +void ZoneAgProperty::OnZonePropertyModelPickedUp(Entity* self, Entity* player) { + auto* character = player->GetCharacter(); + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (!character->GetPlayerFlag(109)) { + character->SetPlayerFlag(109, true); + if (missionComponent->GetMissionState(891) == eMissionState::ACTIVE && !character->GetPlayerFlag(110)) { + self->SetNetworkVar<std::u16string>(u"Tooltip", u"Rotate"); + } + } +} + +void ZoneAgProperty::OnZonePropertyModelRemoved(Entity* self, Entity* player) { + auto* character = player->GetCharacter(); + character->SetPlayerFlag(111, true); +} + +void ZoneAgProperty::OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) { + ZoneAgProperty::OnZonePropertyModelRemoved(self, player); +} + +void ZoneAgProperty::OnZonePropertyModelRotated(Entity* self, Entity* player) { + auto* character = player->GetCharacter(); + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (!character->GetPlayerFlag(110)) { + character->SetPlayerFlag(110, true); + + if (missionComponent->GetMissionState(891) == eMissionState::ACTIVE) { + self->SetNetworkVar<std::u16string>(u"Tooltip", u"PlaceModel"); + self->SetVar<std::string>(u"tutorial", "place_model"); + } + } +} + +void ZoneAgProperty::OnZonePropertyModelEquipped(Entity* self) { + self->SetNetworkVar<std::u16string>(u"PlayerAction", u"ModelEquipped"); +} + +void ZoneAgProperty::OnZonePropertyEditBegin(Entity* self) { + self->SetNetworkVar<std::u16string>(u"PlayerAction", u"Enter"); +} + +void ZoneAgProperty::OnZonePropertyEditEnd(Entity* self) { + self->SetNetworkVar<std::u16string>(u"PlayerAction", u"Exit"); +} + +void ZoneAgProperty::OnPlayerExit(Entity* self) { + // TODO: Destroy stuff +} + +void ZoneAgProperty::RemovePlayerRef(Entity* self) { + // TODO: Destroy stuff +} + +void ZoneAgProperty::BaseOnFireEventServerSide(Entity* self, Entity* sender, std::string args) { + if (args == "propertyRented") { + const auto playerId = self->GetVar<LWOOBJID>(u"playerID"); + auto* player = EntityManager::Instance()->GetEntity(playerId); + if (player == nullptr) + return; + + OnZonePropertyRented(self, player); + } else if (args == "RetrieveZoneData") { + self->SetVar<LWOOBJID>(u"SpiderBossID", sender->GetObjectID()); + sender->SetVar<int32_t>(u"SpiderEggNetworkID", RetrieveSpawnerId(self, self->GetVar<std::string>(SpiderEggsSpawner))); + + std::vector<uint32_t> table; + + for (const auto& target : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { + table.push_back(RetrieveSpawnerId(self, target)); + } + + ROFTargetGroupIdTable = table; + + ProcessGroupObjects(self, self->GetVar<std::string>(LandTargetGroup)); + ProcessGroupObjects(self, self->GetVar<std::string>(SpiderScreamGroup)); + // ProcessGroupObjects(self, groups.ZoneVolumes); + } else if (args == "CheckForPropertyOwner") { + sender->SetNetworkVar<std::string>(u"PropertyOwnerID", std::to_string(self->GetVar<LWOOBJID>(u"PropertyOwner"))); + } else if (args == "ClearProperty") { + const auto playerId = self->GetVar<LWOOBJID>(u"playerID"); + auto* player = EntityManager::Instance()->GetEntity(playerId); + if (player == nullptr) + return; + + player->GetCharacter()->SetPlayerFlag(self->GetVar<int32_t>(defeatedProperyFlag), true); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, + LWOOBJID_EMPTY, destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); + + self->AddTimer("tornadoOff", 0.5f); + } +} + +void ZoneAgProperty::NotifyDie(Entity* self) { + // TODO +} diff --git a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.h b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.h new file mode 100644 index 00000000..b1720783 --- /dev/null +++ b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.h @@ -0,0 +1,66 @@ +#pragma once +#include "BasePropertyServer.h" + +class ZoneAgProperty : public BasePropertyServer { +public: + void SetGameVariables(Entity* self) override; + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnZoneLoadedInfo(Entity* self); + void OnZonePropertyRented(Entity* self, Entity* player) override; + void OnZonePropertyModelPlaced(Entity* self, Entity* player) override; + void OnZonePropertyModelPickedUp(Entity* self, Entity* player) override; + void OnZonePropertyModelRemoved(Entity* self, Entity* player) override; + void OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) override; + void OnZonePropertyModelRotated(Entity* self, Entity* player) override; + void OnZonePropertyEditBegin(Entity* self) override; + void OnZonePropertyModelEquipped(Entity* self) override; + void OnZonePropertyEditEnd(Entity* self) override; + void OnPlayerExit(Entity* self); + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override { + BaseOnFireEventServerSide(self, sender, args); + } + virtual void BaseOnFireEventServerSide(Entity* self, Entity* sender, std::string args); + void OnTimerDone(Entity* self, std::string timerName) override; + + void BaseTimerDone(Entity* self, const std::string& timerName) override; + + void PropGuardCheck(Entity* self, Entity* player) override; + void LoadInstance(Entity* self); + void LoadProperty(Entity* self); + + void ProcessGroupObjects(Entity* self, std::string group); + + void SpawnSpots(Entity* self) override; + void KillSpots(Entity* self) override; + void StartMaelstrom(Entity* self, Entity* player) override; + void SpawnCrashedRocket(Entity* self); + void KillCrashedRocket(Entity* self); + + uint32_t RetrieveSpawnerId(Entity* self, const std::string& spawner); + + void NotifyDie(Entity* self); + void RemovePlayerRef(Entity* self); +protected: + std::string destroyedCinematic = "DestroyMaelstrom"; + std::vector<uint32_t> ROFTargetGroupIdTable{}; + std::u16string LandTargetGroup = u"LandTargetGroup"; + std::u16string SpiderScreamGroup = u"SpiderScreamGroup"; + std::u16string ROFTargetsGroup = u"ROFTargetsGroup"; + std::u16string SpiderEggsGroup = u"SpiderEggsGroup"; + std::u16string RocksGroup = u"RocksGroup"; + std::u16string ZoneVolumesGroup = u"ZoneVolumesGroup"; + + std::u16string EnemiesSpawner = u"EnemiesSpawner"; + std::u16string BossSensorSpawner = u"BossSensorSpawner"; + std::u16string LandTargetSpawner = u"LandTargetSpawner"; + std::u16string SpiderScreamSpawner = u"SpiderScreamSpawner"; + std::u16string ROFTargetsSpawner = u"ROFTargetsSpawner"; + std::u16string SpiderEggsSpawner = u"SpiderEggsSpawner"; + std::u16string RocksSpawner = u"RocksSpawner"; + std::u16string SpiderRocketSpawner = u"SpiderRocketSpawner"; + std::u16string MailboxSpawner = u"MailboxSpawner"; + std::u16string LauncherSpawner = u"LauncherSpawner"; + std::u16string InstancerSpawner = u"InstancerSpawner"; +}; diff --git a/dScripts/02_server/Map/Property/CMakeLists.txt b/dScripts/02_server/Map/Property/CMakeLists.txt new file mode 100644 index 00000000..74badb32 --- /dev/null +++ b/dScripts/02_server/Map/Property/CMakeLists.txt @@ -0,0 +1,22 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY + "PropertyBankInteract.cpp") + +add_subdirectory(AG_Med) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_AG_MED}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY} "AG_Med/${file}") +endforeach() + +add_subdirectory(AG_Small) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_AG_SMALL}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY} "AG_Small/${file}") +endforeach() + +add_subdirectory(NS_Med) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_NS_MED}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY} "NS_Med/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY} PARENT_SCOPE) diff --git a/dScripts/02_server/Map/Property/NS_Med/CMakeLists.txt b/dScripts/02_server/Map/Property/NS_Med/CMakeLists.txt new file mode 100644 index 00000000..230bc2cf --- /dev/null +++ b/dScripts/02_server/Map/Property/NS_Med/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_NS_MED + "ZoneNsMedProperty.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.cpp b/dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.cpp new file mode 100644 index 00000000..55bde71c --- /dev/null +++ b/dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.cpp @@ -0,0 +1,40 @@ +#include "ZoneNsMedProperty.h" +#include "Entity.h" + +void ZoneNsMedProperty::SetGameVariables(Entity* self) { + self->SetVar<std::string>(ClaimMarkerGroup, "ClaimMarker"); + self->SetVar<std::string>(GeneratorGroup, "Generator"); + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(SpotsGroup, "Spots"); + self->SetVar<std::string>(MSCloudsGroup, "maelstrom"); + self->SetVar<std::string>(EnemiesGroup, "Enemies"); + self->SetVar<std::string>(FXManagerGroup, "FXObject"); + self->SetVar<std::string>(ImagOrbGroup, "Orb"); + self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); + + self->SetVar<std::vector<std::string>>(EnemiesSpawner, + { "Admirals", "AdmiralsWander", "Mechs", "Ronin", "RoninWander" }); + self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); + self->SetVar<std::string>(GeneratorSpawner, "Generator"); + self->SetVar<std::string>(DamageFXSpawner, "MaelstromFX"); + self->SetVar<std::string>(FXSpotsSpawner, "MaelstromSpots"); + self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); + self->SetVar<std::string>(ImageOrbSpawner, "Orb"); + self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); + self->SetVar<std::string>(SmashablesSpawner, "Smashables"); + self->SetVar<std::string>(FXManagerSpawner, "FXObject"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Rockets" }); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, { }); + + self->SetVar<int32_t>(defeatedProperyFlag, 122); + self->SetVar<int32_t>(placedModelFlag, 123); + self->SetVar<uint32_t>(guardMissionFlag, 1322); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 1294); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 11031); + self->SetVar<LOT>(orbIDFlag, 10226); + self->SetVar<LOT>(behaviorQBID, 10445); +} diff --git a/dScripts/ZoneNsMedProperty.h b/dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.h similarity index 67% rename from dScripts/ZoneNsMedProperty.h rename to dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.h index d25974e1..3aaf6bd8 100644 --- a/dScripts/ZoneNsMedProperty.h +++ b/dScripts/02_server/Map/Property/NS_Med/ZoneNsMedProperty.h @@ -2,5 +2,5 @@ #include "BasePropertyServer.h" class ZoneNsMedProperty : public BasePropertyServer { - void SetGameVariables(Entity *self) override; + void SetGameVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp new file mode 100644 index 00000000..9e727f39 --- /dev/null +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp @@ -0,0 +1,44 @@ +#include "PropertyBankInteract.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "AMFFormat.h" + +void PropertyBankInteract::OnStartup(Entity* self) { + auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + if (zoneControl != nullptr) { + zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); + } +} + +void PropertyBankInteract::OnPlayerLoaded(Entity* self, Entity* player) { + auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + if (zoneControl != nullptr) { + zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); + } +} + +void PropertyBankInteract::OnUse(Entity* self, Entity* user) { + + AMFArrayValue args; + auto* value = new AMFStringValue(); + value->SetStringValue("bank"); + args.InsertValue("state", value); + + GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, + "", user->GetSystemAddress()); +} + +void PropertyBankInteract::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == "ToggleBank") { + AMFArrayValue amfArgs; + amfArgs.InsertValue("visible", new AMFFalseValue()); + + GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &amfArgs); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, + "", sender->GetSystemAddress()); + } +} diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.h b/dScripts/02_server/Map/Property/PropertyBankInteract.h new file mode 100644 index 00000000..d780e486 --- /dev/null +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class PropertyBankInteract : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnUse(Entity* self, Entity* user) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/SS/CMakeLists.txt b/dScripts/02_server/Map/SS/CMakeLists.txt new file mode 100644 index 00000000..49db031f --- /dev/null +++ b/dScripts/02_server/Map/SS/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_SS + "SsModularBuildServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/SsModularBuildServer.cpp b/dScripts/02_server/Map/SS/SsModularBuildServer.cpp similarity index 69% rename from dScripts/SsModularBuildServer.cpp rename to dScripts/02_server/Map/SS/SsModularBuildServer.cpp index 33f8db47..dfb29168 100644 --- a/dScripts/SsModularBuildServer.cpp +++ b/dScripts/02_server/Map/SS/SsModularBuildServer.cpp @@ -1,14 +1,16 @@ #include "SsModularBuildServer.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void SsModularBuildServer::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) { int missionNum = 1732; if (bCompleted) { - MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); Mission* rocketMission = mission->GetMission(missionNum); - - if (rocketMission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE) { + + if (rocketMission->GetMissionState() == eMissionState::ACTIVE) { mission->ForceProgress(missionNum, 2478, 1); } } diff --git a/dScripts/SsModularBuildServer.h b/dScripts/02_server/Map/SS/SsModularBuildServer.h similarity index 100% rename from dScripts/SsModularBuildServer.h rename to dScripts/02_server/Map/SS/SsModularBuildServer.h diff --git a/dScripts/02_server/Map/VE/CMakeLists.txt b/dScripts/02_server/Map/VE/CMakeLists.txt new file mode 100644 index 00000000..ac3a6461 --- /dev/null +++ b/dScripts/02_server/Map/VE/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_VE + "VeMissionConsole.cpp" + "VeEpsilonServer.cpp" + "VeBricksampleServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/VE/VeBricksampleServer.cpp b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp new file mode 100644 index 00000000..0ead6a87 --- /dev/null +++ b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp @@ -0,0 +1,22 @@ +#include "VeBricksampleServer.h" +#include "InventoryComponent.h" +#include "EntityManager.h" +#include "MissionComponent.h" +#include "GameMessages.h" +#include "eMissionState.h" + +void VeBricksampleServer::OnUse(Entity* self, Entity* user) { + auto* missionComponent = user->GetComponent<MissionComponent>(); + if (missionComponent != nullptr && missionComponent->GetMissionState(1183) == eMissionState::ACTIVE) { + const auto loot = self->GetVar<int32_t>(m_LootVariable); + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + + if (loot && inventoryComponent != nullptr && inventoryComponent->GetLotCount(loot) == 0) { + inventoryComponent->AddItem(loot, 1, eLootSourceType::ACTIVITY); + + for (auto* brickEntity : EntityManager::Instance()->GetEntitiesInGroup("Bricks")) { + GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup"); + } + } + } +} diff --git a/dScripts/02_server/Map/VE/VeBricksampleServer.h b/dScripts/02_server/Map/VE/VeBricksampleServer.h new file mode 100644 index 00000000..d9d37133 --- /dev/null +++ b/dScripts/02_server/Map/VE/VeBricksampleServer.h @@ -0,0 +1,7 @@ +#pragma once +#include "CppScripts.h" + +class VeBricksampleServer : public CppScripts::Script { + void OnUse(Entity* self, Entity* user) override; + const std::u16string m_LootVariable = u"Loot"; +}; diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp new file mode 100644 index 00000000..c69f9cc2 --- /dev/null +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp @@ -0,0 +1,28 @@ +#include "VeEpsilonServer.h" +#include "Character.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "eMissionState.h" +#include "Entity.h" + +void VeEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* character = target->GetCharacter(); + if (character == nullptr) + return; + + // Resets the player flags that track which consoles they've used + if ((missionID == m_ConsoleMissionID || missionID == m_ConsoleRepeatMissionID) + && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE)) { + + for (auto i = 0; i < 10; i++) { + character->SetPlayerFlag(m_ConsoleBaseFlag + i, false); + } + } + + // Notify the client that all objects have updated + self->AddCallbackTimer(3.0f, [this]() { + for (const auto* console : EntityManager::Instance()->GetEntitiesInGroup(m_ConsoleGroup)) { + GameMessages::SendNotifyClientObject(console->GetObjectID(), u""); + } + }); +} diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.h b/dScripts/02_server/Map/VE/VeEpsilonServer.h new file mode 100644 index 00000000..d5a53f9e --- /dev/null +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class VeEpsilonServer : public CppScripts::Script { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + const uint32_t m_ConsoleMissionID = 1220; + const uint32_t m_ConsoleRepeatMissionID = 1225; + const int32_t m_ConsoleBaseFlag = 1010; + const std::string m_ConsoleGroup = "Consoles"; +}; diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp new file mode 100644 index 00000000..35061bdf --- /dev/null +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -0,0 +1,27 @@ +#include "VeMissionConsole.h" +#include "InventoryComponent.h" +#include "Character.h" +#include "GameMessages.h" +#include "Loot.h" +#include "eTerminateType.h" + +void VeMissionConsole::OnUse(Entity* self, Entity* user) { + LootGenerator::Instance().DropActivityLoot(user, self, 12551); + + auto* inventoryComponent = user->GetComponent<InventoryComponent>(); + if (inventoryComponent != nullptr) { + inventoryComponent->AddItem(12547, 1, eLootSourceType::ACTIVITY); // Add the panel required for pickup + } + + // The flag to set is 101<number> + const auto flagNumber = self->GetVar<std::u16string>(m_NumberVariable); + const int32_t flag = std::stoi("101" + GeneralUtils::UTF16ToWTF8(flagNumber)); + + auto* character = user->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(flag, true); + } + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u""); + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/VeMissionConsole.h b/dScripts/02_server/Map/VE/VeMissionConsole.h similarity index 51% rename from dScripts/VeMissionConsole.h rename to dScripts/02_server/Map/VE/VeMissionConsole.h index aecabdaa..8a12964f 100644 --- a/dScripts/VeMissionConsole.h +++ b/dScripts/02_server/Map/VE/VeMissionConsole.h @@ -3,7 +3,7 @@ class VeMissionConsole : public CppScripts::Script { public: - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; private: - const std::u16string m_NumberVariable = u"num"; + const std::u16string m_NumberVariable = u"num"; }; diff --git a/dScripts/02_server/Map/njhub/BurningTile.cpp b/dScripts/02_server/Map/njhub/BurningTile.cpp new file mode 100644 index 00000000..8ac3dc5d --- /dev/null +++ b/dScripts/02_server/Map/njhub/BurningTile.cpp @@ -0,0 +1,14 @@ +#include "BurningTile.h" +#include "SkillComponent.h" + +void BurningTile::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "PlayerEntered") { + auto* skillComponent = sender->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior(726, 11723, sender->GetObjectID(), true); + } +} diff --git a/dScripts/02_server/Map/njhub/BurningTile.h b/dScripts/02_server/Map/njhub/BurningTile.h new file mode 100644 index 00000000..024ec6fc --- /dev/null +++ b/dScripts/02_server/Map/njhub/BurningTile.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class BurningTile : public CppScripts::Script +{ +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/njhub/CMakeLists.txt b/dScripts/02_server/Map/njhub/CMakeLists.txt new file mode 100644 index 00000000..2527d1ad --- /dev/null +++ b/dScripts/02_server/Map/njhub/CMakeLists.txt @@ -0,0 +1,31 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB + "BurningTile.cpp" + "CatapultBaseServer.cpp" + "CatapultBouncerServer.cpp" + "CavePrisonCage.cpp" + "EnemySkeletonSpawner.cpp" + "FallingTile.cpp" + "FlameJetServer.cpp" + "ImaginationShrineServer.cpp" + "Lieutenant.cpp" + "MonCoreNookDoors.cpp" + "MonCoreSmashableDoors.cpp" + "NjColeNPC.cpp" + "NjDragonEmblemChestServer.cpp" + "NjEarthDragonPetServer.cpp" + "NjEarthPetServer.cpp" + "NjGarmadonCelebration.cpp" + "NjJayMissionItems.cpp" + "NjNPCMissionSpinjitzuServer.cpp" + "NjNyaMissionitems.cpp" + "NjScrollChestServer.cpp" + "NjWuNPC.cpp" + "RainOfArrows.cpp") + +add_subdirectory(boss_instance) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB_BOSS_INSTANCE}) + set(DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB} "boss_instance/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB} PARENT_SCOPE) diff --git a/dScripts/CatapultBaseServer.cpp b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp similarity index 69% rename from dScripts/CatapultBaseServer.cpp rename to dScripts/02_server/Map/njhub/CatapultBaseServer.cpp index 33539de8..2df32658 100644 --- a/dScripts/CatapultBaseServer.cpp +++ b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp @@ -2,30 +2,25 @@ #include "GameMessages.h" #include "EntityManager.h" -void CatapultBaseServer::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) -{ - if (name == "BouncerBuilt") - { - // start a timer for the arm to player the with bouncer animation - self->AddTimer("PlatAnim", .75); +void CatapultBaseServer::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "BouncerBuilt") { + // start a timer for the arm to player the with bouncer animation + self->AddTimer("PlatAnim", .75); - // set the bouncer so we can use it later - self->SetVar(u"Bouncer", sender->GetObjectID()); + // set the bouncer so we can use it later + self->SetVar(u"Bouncer", sender->GetObjectID()); GameMessages::SendBouncerActiveStatus(sender->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); } } -void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "PlatAnim") - { - // get the arm asset - const auto arm = EntityManager::Instance()->GetEntitiesInGroup(self->GetVarAsString(u"ArmGroup")); +void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "PlatAnim") { + // get the arm asset + const auto arm = EntityManager::Instance()->GetEntitiesInGroup(self->GetVarAsString(u"ArmGroup")); // tell the arm to the play the platform animation, which is just the arm laying there but with bouncer - for (auto* obj : arm) - { + for (auto* obj : arm) { GameMessages::SendPlayAnimation(obj, u"idle-platform"); GameMessages::SendPlayNDAudioEmitter(obj, UNASSIGNED_SYSTEM_ADDRESS, "{8cccf912-69e3-4041-a20b-63e4afafc993}"); // set the art so we can use it again @@ -35,9 +30,7 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) // start a timer till the bouncer actually bounces self->AddTimer("bounce", 3); - } - else if (timerName == "launchAnim") - { + } else if (timerName == "launchAnim") { // get the arm asset auto* arm = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Arm")); if (arm == nullptr) return; @@ -46,9 +39,7 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) auto animTime = 1; self->AddTimer("resetArm", animTime); GameMessages::SendPlayAnimation(arm, u"launch"); - } - else if (timerName == "bounce") - { + } else if (timerName == "bounce") { auto* bouncer = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Bouncer")); if (bouncer == nullptr) return; @@ -56,9 +47,7 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) bouncer->NotifyObject(bouncer, "bounceAllInProximity"); // Likely to trigger server side bounce, bodging this // add a delay to play the animation self->AddTimer("launchAnim", .3); - } - else if (timerName == "resetArm") - { + } else if (timerName == "resetArm") { auto* arm = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Arm")); if (arm == nullptr) return; @@ -70,6 +59,6 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) // kill the bouncer GameMessages::SendNotifyClientObject(bouncer->GetObjectID(), u"TimeToDie"); - bouncer->Smash(self->GetObjectID(), VIOLENT); + bouncer->Smash(self->GetObjectID(), eKillType::VIOLENT); } } diff --git a/dScripts/02_server/Map/njhub/CatapultBaseServer.h b/dScripts/02_server/Map/njhub/CatapultBaseServer.h new file mode 100644 index 00000000..cc5a1907 --- /dev/null +++ b/dScripts/02_server/Map/njhub/CatapultBaseServer.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class CatapultBaseServer : public CppScripts::Script { +public: + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; + + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp b/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp new file mode 100644 index 00000000..89faf001 --- /dev/null +++ b/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp @@ -0,0 +1,15 @@ +#include "CatapultBouncerServer.h" +#include "GameMessages.h" +#include "EntityManager.h" + +void CatapultBouncerServer::OnRebuildComplete(Entity* self, Entity* target) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"Built", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + + self->SetNetworkVar<bool>(u"Built", true); + + const auto base = EntityManager::Instance()->GetEntitiesInGroup(self->GetVarAsString(u"BaseGroup")); + + for (auto* obj : base) { + obj->NotifyObject(self, "BouncerBuilt"); + } +} diff --git a/dScripts/CatapultBouncerServer.h b/dScripts/02_server/Map/njhub/CatapultBouncerServer.h similarity index 61% rename from dScripts/CatapultBouncerServer.h rename to dScripts/02_server/Map/njhub/CatapultBouncerServer.h index 06f03bf4..46ec20ab 100644 --- a/dScripts/CatapultBouncerServer.h +++ b/dScripts/02_server/Map/njhub/CatapultBouncerServer.h @@ -3,5 +3,5 @@ class CatapultBouncerServer : public CppScripts::Script { public: - void OnRebuildComplete(Entity* self, Entity* target) override; + void OnRebuildComplete(Entity* self, Entity* target) override; }; diff --git a/dScripts/02_server/Map/njhub/CavePrisonCage.cpp b/dScripts/02_server/Map/njhub/CavePrisonCage.cpp new file mode 100644 index 00000000..60bd1b88 --- /dev/null +++ b/dScripts/02_server/Map/njhub/CavePrisonCage.cpp @@ -0,0 +1,215 @@ +#include "CavePrisonCage.h" +#include "EntityManager.h" +#include "RebuildComponent.h" +#include "GameMessages.h" +#include "Character.h" +#include "dZoneManager.h" + +void CavePrisonCage::OnStartup(Entity* self) { + const auto& myNum = self->GetVar<std::u16string>(u"myNumber"); + + if (myNum.empty()) { + return; + } + + auto* spawner = dZoneManager::Instance()->GetSpawnersByName("PrisonCounterweight_0" + GeneralUtils::UTF16ToWTF8(myNum))[0]; + + self->SetVar<Spawner*>(u"CWSpawner", spawner); + + Setup(self, spawner); +} + +void CavePrisonCage::Setup(Entity* self, Spawner* spawner) { + SpawnCounterweight(self, spawner); + + NiPoint3 mypos = self->GetPosition(); + NiQuaternion myrot = self->GetRotation(); + + mypos.y += 1.5; + mypos.z -= 0.5; + + EntityInfo info{}; + info.lot = m_Villagers[self->GetVarAs<int32_t>(u"myNumber") - 1]; + info.pos = mypos; + info.rot = myrot; + info.spawnerID = self->GetObjectID(); + + // Spawn the villager inside the jail + auto* entity = EntityManager::Instance()->CreateEntity(info); + + // Save the villeger ID + self->SetVar<LWOOBJID>(u"villager", entity->GetObjectID()); + + // Construct the entity + EntityManager::Instance()->ConstructEntity(entity); +} + +void CavePrisonCage::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state != eRebuildState::RESETTING) { + return; + } + + auto* spawner = self->GetVar<Spawner*>(u"CWSpawner"); + + if (spawner == nullptr) { + return; + } + + spawner->Reset(); + + SpawnCounterweight(self, spawner); +} + +void CavePrisonCage::SpawnCounterweight(Entity* self, Spawner* spawner) { + spawner->Reset(); + + auto* counterweight = spawner->Spawn(); + + self->SetVar<LWOOBJID>(u"Counterweight", counterweight->GetObjectID()); + + auto* rebuildComponent = counterweight->GetComponent<RebuildComponent>(); + + if (rebuildComponent != nullptr) { + rebuildComponent->AddRebuildStateCallback([this, self](eRebuildState state) { + OnRebuildNotifyState(self, state); + }); + + rebuildComponent->AddRebuildCompleteCallback([this, self](Entity* user) { + // The counterweight is a simple mover, which is not implemented, so we'll just set it's position + auto* counterweight = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Counterweight")); + + if (counterweight == nullptr) { + return; + } + + // Move the counterweight down 2 units + counterweight->SetPosition(counterweight->GetPosition() + NiPoint3(0, -2, 0)); + + // Serialize the counterweight + EntityManager::Instance()->SerializeEntity(counterweight); + + // notifyPlatformAtLastWaypoint + + // Save the userID as Builder + self->SetVar<LWOOBJID>(u"Builder", user->GetObjectID()); + + // Get the button and make sure it still exists + auto* button = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Button")); + + if (button == nullptr) { + return; + } + + // Play the 'down' animation on the button + GameMessages::SendPlayAnimation(button, u"down"); + + // Setup a timer named 'buttonGoingDown' to be triggered in 5 seconds + self->AddTimer("buttonGoingDown", 5.0f); + }); + } + + if (self->GetVar<LWOOBJID>(u"Button")) { + return; + } + + GetButton(self); +} + +void CavePrisonCage::GetButton(Entity* self) { + const auto buttons = EntityManager::Instance()->GetEntitiesInGroup("PrisonButton_0" + std::to_string(self->GetVarAs<int32_t>(u"myNumber"))); + + if (buttons.size() == 0) { + // Try again in 0.5 seconds + self->AddCallbackTimer(0.5, [this, self]() { + GetButton(self); + }); + + return; + } + + auto* button = buttons[0]; + + self->SetVar<LWOOBJID>(u"Button", button->GetObjectID()); +} + +void CavePrisonCage::OnTimerDone(Entity* self, std::string timerName) { + // the anim of the button down is over + if (timerName == "buttonGoingDown") { + // Play the 'up' animation + GameMessages::SendPlayAnimation(self, u"up"); + + // Setup a timer named 'CageOpen' to be triggered in 1 second + self->AddTimer("CageOpen", 1.0f); + } else if (timerName == "CageOpen") { + // play the idle open anim + GameMessages::SendPlayAnimation(self, u"idle-up"); + + // Get the villeger + auto* villager = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"villager")); + + if (villager == nullptr) { + return; + } + + GameMessages::SendNotifyClientObject(villager->GetObjectID(), u"TimeToChat", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + + // Get the builder and make sure it still exists + auto* builder = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Builder")); + + if (builder == nullptr) { + return; + } + + const auto flagNum = 2020 + self->GetVarAs<int32_t>(u"myNumber"); + + // Set the flag on the builder character + builder->GetCharacter()->SetPlayerFlag(flagNum, true); + + // Setup a timer named 'VillagerEscape' to be triggered in 5 seconds + self->AddTimer("VillagerEscape", 5.0f); + } else if (timerName == "VillagerEscape") { + // Get the villeger and make sure it still exists + auto* villager = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"villager")); + + if (villager == nullptr) { + return; + } + + // Kill the villager + villager->Kill(); + + // Setup a timer named 'SmashCounterweight' to be triggered in 2 seconds + self->AddTimer("SmashCounterweight", 2.0f); + } else if (timerName == "SmashCounterweight") { + // Get the counterweight and make sure it still exists + auto* counterweight = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Counterweight")); + + if (counterweight == nullptr) { + return; + } + + // Smash the counterweight + counterweight->Smash(); + + // Get the button and make sure it still exists + auto* button = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Button")); + + if (button == nullptr) { + return; + } + + // Play the 'up' animation on the button + GameMessages::SendPlayAnimation(button, u"up"); + + // Setup a timer named 'CageClosed' to be triggered in 1 second + self->AddTimer("CageClosed", 1.0f); + } else if (timerName == "CageClosed") { + // play the idle closed anim + GameMessages::SendPlayAnimation(self, u"idle"); + + // Setup a timer named 'ResetPrison' to be triggered in 10 seconds + self->AddTimer("ResetPrison", 10.0f); + } else if (timerName == "ResetPrison") { + Setup(self, self->GetVar<Spawner*>(u"CWSpawner")); + } +} diff --git a/dScripts/02_server/Map/njhub/CavePrisonCage.h b/dScripts/02_server/Map/njhub/CavePrisonCage.h new file mode 100644 index 00000000..43d826c7 --- /dev/null +++ b/dScripts/02_server/Map/njhub/CavePrisonCage.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class CavePrisonCage : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void Setup(Entity* self, Spawner* spawner); + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; + void SpawnCounterweight(Entity* self, Spawner* spawner); + void GetButton(Entity* self); + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + std::vector<LOT> m_Villagers = { 15851, 15866, 15922, 15924, 15927, 15929 }; + std::vector<int32_t> m_Missions = { 1801, 2039 }; +}; diff --git a/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp new file mode 100644 index 00000000..0e2e4005 --- /dev/null +++ b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp @@ -0,0 +1,76 @@ +#include "EnemySkeletonSpawner.h" +#include "SkillComponent.h" +#include "RenderComponent.h" +#include "EntityManager.h" +#include "EntityInfo.h" + +void EnemySkeletonSpawner::OnStartup(Entity* self) { + self->SetProximityRadius(15, "ronin"); + + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(1127, 24812, LWOOBJID_EMPTY, true); + } +} + +void EnemySkeletonSpawner::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "hatchTime") { + auto* renderComponent = self->GetComponent<RenderComponent>(); + + if (renderComponent != nullptr) { + renderComponent->PlayEffect(644, u"create", "BurstFX1"); + } + + EntityInfo info{}; + info.lot = 14024; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.spawnerID = self->GetObjectID(); + + auto* spawnedEntity = EntityManager::Instance()->CreateEntity(info); + + if (spawnedEntity == nullptr) { + return; + } + + EntityManager::Instance()->ConstructEntity(spawnedEntity); + + spawnedEntity->AddCallbackTimer(60, [spawnedEntity]() { + spawnedEntity->Smash(spawnedEntity->GetObjectID()); + }); + + self->Smash(self->GetObjectID()); + } +} + +void EnemySkeletonSpawner::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (entering->IsPlayer() && name == "ronin" && status == "ENTER" && !self->GetVar<bool>(u"hatching")) { + StartHatching(self); + + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(305, 3568, LWOOBJID_EMPTY); + } + } +} + +void EnemySkeletonSpawner::OnHit(Entity* self, Entity* attacker) { + if (!self->GetVar<bool>(u"hatching")) { + StartHatching(self); + } +} + +void EnemySkeletonSpawner::StartHatching(Entity* self) { + self->SetVar(u"hatching", true); + + auto* renderComponent = self->GetComponent<RenderComponent>(); + + if (renderComponent != nullptr) { + renderComponent->PlayEffect(9017, u"cast", "WakeUpFX1"); + renderComponent->PlayEffect(9018, u"burst", "WakeUpFX1"); + } + + self->AddTimer("hatchTime", 2); +} diff --git a/dScripts/EnemySkeletonSpawner.h b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.h similarity index 51% rename from dScripts/EnemySkeletonSpawner.h rename to dScripts/02_server/Map/njhub/EnemySkeletonSpawner.h index a4a212d2..16bbfdd9 100644 --- a/dScripts/EnemySkeletonSpawner.h +++ b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.h @@ -5,8 +5,8 @@ class EnemySkeletonSpawner final : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnTimerDone(Entity* self, std::string timerName) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnHit(Entity* self, Entity* attacker) override; - void StartHatching(Entity* self); + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnHit(Entity* self, Entity* attacker) override; + void StartHatching(Entity* self); }; diff --git a/dScripts/02_server/Map/njhub/FallingTile.cpp b/dScripts/02_server/Map/njhub/FallingTile.cpp new file mode 100644 index 00000000..7804c8bc --- /dev/null +++ b/dScripts/02_server/Map/njhub/FallingTile.cpp @@ -0,0 +1,55 @@ +#include "FallingTile.h" +#include "MovingPlatformComponent.h" +#include "GameMessages.h" + +void FallingTile::OnStartup(Entity* self) { + auto* movingPlatfromComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatfromComponent == nullptr) { + return; + } + + movingPlatfromComponent->SetSerialized(true); +} + +void FallingTile::OnCollisionPhantom(Entity* self, Entity* target) { + if (self->GetVar<bool>(u"AboutToFall")) { + return; + } + + self->AddTimer("flipTime", 0.75f); + + self->SetVar<bool>(u"AboutToFall", true); + + self->SetNetworkVar<float>(u"startEffect", 2); +} + +void FallingTile::OnWaypointReached(Entity* self, uint32_t waypointIndex) { + if (waypointIndex == 1) { + } else if (waypointIndex == 0) { + } +} + +void FallingTile::OnTimerDone(Entity* self, std::string timerName) { + auto* movingPlatfromComponent = self->GetComponent<MovingPlatformComponent>(); + + if (movingPlatfromComponent == nullptr) { + return; + } + + if (timerName == "flipTime") { + self->AddTimer("flipBack", 2.0f); + + self->SetNetworkVar<float>(u"stopEffect", 3); + + movingPlatfromComponent->GotoWaypoint(1); + + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"down", "down"); + } else if (timerName == "flipBack") { + self->SetVar<bool>(u"AboutToFall", false); + + movingPlatfromComponent->GotoWaypoint(0); + + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"up", "up"); + } +} diff --git a/dScripts/02_server/Map/njhub/FallingTile.h b/dScripts/02_server/Map/njhub/FallingTile.h new file mode 100644 index 00000000..bac1c73b --- /dev/null +++ b/dScripts/02_server/Map/njhub/FallingTile.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class FallingTile : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/njhub/FlameJetServer.cpp b/dScripts/02_server/Map/njhub/FlameJetServer.cpp new file mode 100644 index 00000000..771dd841 --- /dev/null +++ b/dScripts/02_server/Map/njhub/FlameJetServer.cpp @@ -0,0 +1,47 @@ +#include "FlameJetServer.h" +#include "SkillComponent.h" +#include "GameMessages.h" + +void FlameJetServer::OnStartup(Entity* self) { + if (self->GetVar<bool>(u"NotActive")) { + return; + } + + self->SetNetworkVar<bool>(u"FlameOn", true); +} + +void FlameJetServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target->IsPlayer()) { + return; + } + + if (!self->GetNetworkVar<bool>(u"FlameOn")) { + return; + } + + auto* skillComponent = target->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior(726, 11723, target->GetObjectID(), true); + + auto dir = target->GetRotation().GetForwardVector(); + + dir.y = 25; + dir.x = -dir.x * 15; + dir.z = -dir.z * 15; + + GameMessages::SendKnockback(target->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 1000, dir); +} + +void FlameJetServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + Game::logger->Log("FlameJetServer::OnFireEventServerSide", "Event: %s", args.c_str()); + + if (args == "OnActivated") { + self->SetNetworkVar<bool>(u"FlameOn", false); + } else if (args == "OnDectivated") { + self->SetNetworkVar<bool>(u"FlameOn", true); + } +} diff --git a/dScripts/02_server/Map/njhub/FlameJetServer.h b/dScripts/02_server/Map/njhub/FlameJetServer.h new file mode 100644 index 00000000..e8123c43 --- /dev/null +++ b/dScripts/02_server/Map/njhub/FlameJetServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class FlameJetServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/02_server/Map/njhub/ImaginationShrineServer.cpp b/dScripts/02_server/Map/njhub/ImaginationShrineServer.cpp new file mode 100644 index 00000000..1fbfad98 --- /dev/null +++ b/dScripts/02_server/Map/njhub/ImaginationShrineServer.cpp @@ -0,0 +1,16 @@ +#include "ImaginationShrineServer.h" +#include "RebuildComponent.h" + +void ImaginationShrineServer::OnUse(Entity* self, Entity* user) { + // If the rebuild component is complete, use the shrine + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent == nullptr) { + return; + } + + if (rebuildComponent->GetState() == eRebuildState::COMPLETED) { + // Use the shrine + BaseUse(self, user); + } +} diff --git a/dScripts/ImaginationShrineServer.h b/dScripts/02_server/Map/njhub/ImaginationShrineServer.h similarity index 74% rename from dScripts/ImaginationShrineServer.h rename to dScripts/02_server/Map/njhub/ImaginationShrineServer.h index 6bbf84b5..bef137e9 100644 --- a/dScripts/ImaginationShrineServer.h +++ b/dScripts/02_server/Map/njhub/ImaginationShrineServer.h @@ -5,6 +5,6 @@ class ImaginationShrineServer : public BaseInteractDropLootServer { public: - void OnUse(Entity* self, Entity* user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/njhub/Lieutenant.cpp b/dScripts/02_server/Map/njhub/Lieutenant.cpp new file mode 100644 index 00000000..d3b0fc1f --- /dev/null +++ b/dScripts/02_server/Map/njhub/Lieutenant.cpp @@ -0,0 +1,44 @@ +#include "Lieutenant.h" +#include "SkillComponent.h" +#include "dZoneManager.h" + +void Lieutenant::OnStartup(Entity* self) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior(1127, 24812, self->GetObjectID(), true); +} + +void Lieutenant::OnDie(Entity* self, Entity* killer) { + const auto myLOT = self->GetLOT(); + + std::string spawnerName; + + switch (myLOT) { + case 16047: + spawnerName = "EarthShrine_ERail"; + break; + case 16050: + spawnerName = "IceShrine_QBBouncer"; + break; + case 16049: + spawnerName = "LightningShrine_LRail"; + break; + default: + return; + } + + const auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); + + if (spawners.empty()) { + return; + } + + for (auto* spawner : spawners) { + spawner->Reset(); + spawner->Activate(); + } +} diff --git a/dScripts/Lieutenant.h b/dScripts/02_server/Map/njhub/Lieutenant.h similarity index 71% rename from dScripts/Lieutenant.h rename to dScripts/02_server/Map/njhub/Lieutenant.h index 8635671a..ff6212ef 100644 --- a/dScripts/Lieutenant.h +++ b/dScripts/02_server/Map/njhub/Lieutenant.h @@ -6,6 +6,6 @@ class Lieutenant : public CppScripts::Script public: void OnStartup(Entity* self) override; - void OnDie(Entity* self, Entity* killer) override; + void OnDie(Entity* self, Entity* killer) override; }; diff --git a/dScripts/02_server/Map/njhub/MonCoreNookDoors.cpp b/dScripts/02_server/Map/njhub/MonCoreNookDoors.cpp new file mode 100644 index 00000000..dc759c50 --- /dev/null +++ b/dScripts/02_server/Map/njhub/MonCoreNookDoors.cpp @@ -0,0 +1,37 @@ +#include "MonCoreNookDoors.h" +#include "dZoneManager.h" + +void MonCoreNookDoors::OnStartup(Entity* self) { + SpawnDoor(self); +} + +void MonCoreNookDoors::SpawnDoor(Entity* self) { + const auto doorNum = self->GetVarAsString(u"number"); + + if (doorNum.empty()) { + return; + } + + const auto spawners = dZoneManager::Instance()->GetSpawnersByName("MonCoreNookDoor0" + doorNum); + + if (spawners.empty()) { + return; + } + + auto* spawner = spawners[0]; + + spawner->Reset(); + spawner->Activate(); +} + +void MonCoreNookDoors::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "DoorSmashed") { + self->AddTimer("RespawnDoor", 30); + } +} + +void MonCoreNookDoors::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "RespawnDoor") { + SpawnDoor(self); + } +} diff --git a/dScripts/02_server/Map/njhub/MonCoreNookDoors.h b/dScripts/02_server/Map/njhub/MonCoreNookDoors.h new file mode 100644 index 00000000..58661575 --- /dev/null +++ b/dScripts/02_server/Map/njhub/MonCoreNookDoors.h @@ -0,0 +1,14 @@ +#pragma once +#include "CppScripts.h" + +class MonCoreNookDoors : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + + void SpawnDoor(Entity* self); + + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + + void OnTimerDone(Entity* self, std::string timerName) override; +}; + diff --git a/dScripts/MonCoreSmashableDoors.cpp b/dScripts/02_server/Map/njhub/MonCoreSmashableDoors.cpp similarity index 67% rename from dScripts/MonCoreSmashableDoors.cpp rename to dScripts/02_server/Map/njhub/MonCoreSmashableDoors.cpp index 0e7950f5..4ec11e56 100644 --- a/dScripts/MonCoreSmashableDoors.cpp +++ b/dScripts/02_server/Map/njhub/MonCoreSmashableDoors.cpp @@ -1,24 +1,21 @@ #include "MonCoreSmashableDoors.h" #include "EntityManager.h" -void MonCoreSmashableDoors::OnDie(Entity* self, Entity* killer) -{ - auto myNum = self->GetVarAsString(u"spawner_name"); +void MonCoreSmashableDoors::OnDie(Entity* self, Entity* killer) { + auto myNum = self->GetVarAsString(u"spawner_name"); myNum = myNum.substr(myNum.length() - 1, 1); - - auto triggerGroup = "CoreNookTrig0" + myNum; + + auto triggerGroup = "CoreNookTrig0" + myNum; // Get the trigger auto triggers = EntityManager::Instance()->GetEntitiesInGroup(triggerGroup); - if (triggers.empty()) - { + if (triggers.empty()) { return; } - for (auto trigger : triggers) - { + for (auto trigger : triggers) { trigger->OnFireEventServerSide(self, "DoorSmashed"); } } diff --git a/dScripts/MonCoreSmashableDoors.h b/dScripts/02_server/Map/njhub/MonCoreSmashableDoors.h similarity index 66% rename from dScripts/MonCoreSmashableDoors.h rename to dScripts/02_server/Map/njhub/MonCoreSmashableDoors.h index 2c2f28ae..1f205e96 100644 --- a/dScripts/MonCoreSmashableDoors.h +++ b/dScripts/02_server/Map/njhub/MonCoreSmashableDoors.h @@ -3,6 +3,6 @@ class MonCoreSmashableDoors : public CppScripts::Script { public: - void OnDie(Entity* self, Entity* killer) override; + void OnDie(Entity* self, Entity* killer) override; }; diff --git a/dScripts/02_server/Map/njhub/NjColeNPC.cpp b/dScripts/02_server/Map/njhub/NjColeNPC.cpp new file mode 100644 index 00000000..b989f3ee --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjColeNPC.cpp @@ -0,0 +1,49 @@ +#include "NjColeNPC.h" +#include "MissionComponent.h" +#include "InventoryComponent.h" +#include "eMissionState.h" + +void NjColeNPC::OnEmoteReceived(Entity* self, int32_t emote, Entity* target) { + if (emote != 393) { + return; + } + + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + + if (inventoryComponent == nullptr) { + return; + } + + if (!inventoryComponent->IsEquipped(14499) && !inventoryComponent->IsEquipped(16644)) { + return; + } + + auto* missionComponent = target->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) { + return; + } + + missionComponent->ForceProgressTaskType(1818, 1, 1); +} + +void NjColeNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); + + if (missionID == 1818 && missionState >= eMissionState::READY_TO_COMPLETE) { + auto* missionComponent = target->GetComponent<MissionComponent>(); + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + + if (missionComponent == nullptr || inventoryComponent == nullptr) { + return; + } + + if (inventoryComponent->GetLotCount(14499) > 0) { + inventoryComponent->RemoveItem(14499, 1); + } else { + return; + } + + inventoryComponent->AddItem(16644, 1, eLootSourceType::NONE); + } +} diff --git a/dScripts/02_server/Map/njhub/NjColeNPC.h b/dScripts/02_server/Map/njhub/NjColeNPC.h new file mode 100644 index 00000000..a2536e32 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjColeNPC.h @@ -0,0 +1,7 @@ +#include "NjNPCMissionSpinjitzuServer.h" + +class NjColeNPC : public NjNPCMissionSpinjitzuServer { + void OnEmoteReceived(Entity* self, int32_t emote, Entity* target) override; + + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +}; diff --git a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp new file mode 100644 index 00000000..931cfe56 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp @@ -0,0 +1,19 @@ +#include "NjDragonEmblemChestServer.h" +#include "Character.h" +#include "EntityInfo.h" +#include "Loot.h" +#include "Entity.h" +#include "DestroyableComponent.h" +#include "ePlayerFlag.h" + +void NjDragonEmblemChestServer::OnUse(Entity* self, Entity* user) { + auto* character = user->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(ePlayerFlag::NJ_WU_SHOW_DAILY_CHEST, false); + } + + auto* destroyable = self->GetComponent<DestroyableComponent>(); + if (destroyable != nullptr) { + LootGenerator::Instance().DropLoot(user, self, destroyable->GetLootMatrixID(), 0, 0); + } +} diff --git a/dScripts/NjDragonEmblemChestServer.h b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.h similarity index 66% rename from dScripts/NjDragonEmblemChestServer.h rename to dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.h index ab0abc05..b1c59a22 100644 --- a/dScripts/NjDragonEmblemChestServer.h +++ b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NjDragonEmblemChestServer : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/njhub/NjEarthDragonPetServer.cpp b/dScripts/02_server/Map/njhub/NjEarthDragonPetServer.cpp new file mode 100644 index 00000000..87f3dd4b --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjEarthDragonPetServer.cpp @@ -0,0 +1,10 @@ +#include "NjEarthDragonPetServer.h" +#include "Entity.h" + +void NjEarthDragonPetServer::SetVariables(Entity* self) { + self->SetVar<LOT>(u"petLOT", 16210); + self->SetVar<std::string>(u"petType", "earthpet"); + self->SetVar<uint32_t>(u"maxPets", 3); + self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); + self->SetVar<std::u16string>(u"spawnCinematic", u"EarthPetSpawn"); +} diff --git a/dScripts/NjEarthDragonPetServer.h b/dScripts/02_server/Map/njhub/NjEarthDragonPetServer.h similarity index 70% rename from dScripts/NjEarthDragonPetServer.h rename to dScripts/02_server/Map/njhub/NjEarthDragonPetServer.h index 2227bbb6..51e84c34 100644 --- a/dScripts/NjEarthDragonPetServer.h +++ b/dScripts/02_server/Map/njhub/NjEarthDragonPetServer.h @@ -2,5 +2,5 @@ #include "SpawnPetBaseServer.h" class NjEarthDragonPetServer : public SpawnPetBaseServer { - void SetVariables(Entity* self) override; + void SetVariables(Entity* self) override; }; diff --git a/dScripts/02_server/Map/njhub/NjEarthPetServer.cpp b/dScripts/02_server/Map/njhub/NjEarthPetServer.cpp new file mode 100644 index 00000000..36655c63 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjEarthPetServer.cpp @@ -0,0 +1,12 @@ +#include "NjEarthPetServer.h" +#include "PetComponent.h" + +void NjEarthPetServer::OnStartup(Entity* self) { + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwnerId() != LWOOBJID_EMPTY) + return; + + // Removes the chocolate bars + petComponent->SetPreconditions(const_cast<std::string&>(m_Precondition)); + PetFromObjectServer::OnStartup(self); +} diff --git a/dScripts/NjEarthPetServer.h b/dScripts/02_server/Map/njhub/NjEarthPetServer.h similarity index 53% rename from dScripts/NjEarthPetServer.h rename to dScripts/02_server/Map/njhub/NjEarthPetServer.h index 0e327168..3423c019 100644 --- a/dScripts/NjEarthPetServer.h +++ b/dScripts/02_server/Map/njhub/NjEarthPetServer.h @@ -2,6 +2,6 @@ #include "PetFromObjectServer.h" class NjEarthPetServer : public PetFromObjectServer { - void OnStartup(Entity *self) override; - const std::string m_Precondition = "279"; + void OnStartup(Entity* self) override; + const std::string m_Precondition = "279"; }; diff --git a/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp new file mode 100644 index 00000000..d3e54be1 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp @@ -0,0 +1,18 @@ +#include "NjGarmadonCelebration.h" +#include "Character.h" +#include "GameMessages.h" +#include "ePlayerFlag.h" + +void NjGarmadonCelebration::OnCollisionPhantom(Entity* self, Entity* target) { + auto* character = target->GetCharacter(); + + if (character == nullptr) { + return; + } + + if (!character->GetPlayerFlag(ePlayerFlag::NJ_GARMADON_CINEMATIC_SEEN)) { + character->SetPlayerFlag(ePlayerFlag::NJ_GARMADON_CINEMATIC_SEEN, true); + + GameMessages::SendStartCelebrationEffect(target, target->GetSystemAddress(), GarmadonCelebrationID); + } +} diff --git a/dScripts/02_server/Map/njhub/NjGarmadonCelebration.h b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.h new file mode 100644 index 00000000..fe08a169 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class NjGarmadonCelebration : public CppScripts::Script { + void OnCollisionPhantom(Entity* self, Entity* target) override; +private: + const int32_t GarmadonCelebrationID = 23; +}; diff --git a/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp b/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp new file mode 100644 index 00000000..46131446 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp @@ -0,0 +1,13 @@ +#include "NjJayMissionItems.h" + +void NjJayMissionItems::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); + NPCAddRemoveItem::OnMissionDialogueOK(self, target, missionID, missionState); +} + +std::map<uint32_t, std::vector<ItemSetting>> NjJayMissionItems::GetSettings() { + return { + {1789, {{{14474},false, true}}}, + {1927, {{{14493},false, true}}} + }; +} diff --git a/dScripts/NjJayMissionItems.h b/dScripts/02_server/Map/njhub/NjJayMissionItems.h similarity index 52% rename from dScripts/NjJayMissionItems.h rename to dScripts/02_server/Map/njhub/NjJayMissionItems.h index 19cb4f40..bdaee3ea 100644 --- a/dScripts/NjJayMissionItems.h +++ b/dScripts/02_server/Map/njhub/NjJayMissionItems.h @@ -5,6 +5,6 @@ #include <map> class NjJayMissionItems : public NjNPCMissionSpinjitzuServer, NPCAddRemoveItem { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - std::map<uint32_t, std::vector<ItemSetting>> GetSettings() override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + std::map<uint32_t, std::vector<ItemSetting>> GetSettings() override; }; diff --git a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp new file mode 100644 index 00000000..30bba804 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp @@ -0,0 +1,24 @@ +#include "NjNPCMissionSpinjitzuServer.h" +#include "Character.h" +#include "EntityManager.h" +#include "eMissionState.h" + +void NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + + const auto& element = self->GetVar<std::u16string>(ElementVariable); + if (missionID == ElementMissions.at(element) && missionState >= eMissionState::READY_TO_COMPLETE) { + + const auto targetID = target->GetObjectID(); + + // Wait for an animation to complete and flag that the player has learned spinjitzu + self->AddCallbackTimer(5.0f, [targetID, element]() { + auto* target = EntityManager::Instance()->GetEntity(targetID); + if (target != nullptr) { + auto* character = target->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(ElementFlags.at(element), true); + } + } + }); + } +} diff --git a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h new file mode 100644 index 00000000..116ecc93 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h @@ -0,0 +1,25 @@ +#pragma once +#include "CppScripts.h" +#include <map> +#include "ePlayerFlag.h" + +static std::map<std::u16string, ePlayerFlag> ElementFlags = { + {u"earth", ePlayerFlag::NJ_EARTH_SPINJITZU}, + {u"lightning", ePlayerFlag::NJ_LIGHTNING_SPINJITZU}, + {u"ice", ePlayerFlag::NJ_ICE_SPINJITZU}, + {u"fire", ePlayerFlag::NJ_FIRE_SPINJITZU} +}; + +static std::map<std::u16string, uint32_t> ElementMissions = { + {u"earth", 1796}, + {u"lightning", 1952}, + {u"ice", 1959}, + {u"fire", 1962}, +}; + +class NjNPCMissionSpinjitzuServer : public CppScripts::Script { +public: + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +private: + const std::u16string ElementVariable = u"element"; +}; diff --git a/dScripts/NjNyaMissionitems.cpp b/dScripts/02_server/Map/njhub/NjNyaMissionitems.cpp similarity index 52% rename from dScripts/NjNyaMissionitems.cpp rename to dScripts/02_server/Map/njhub/NjNyaMissionitems.cpp index 11ec74bd..4e5304d8 100644 --- a/dScripts/NjNyaMissionitems.cpp +++ b/dScripts/02_server/Map/njhub/NjNyaMissionitems.cpp @@ -1,8 +1,8 @@ #include "NjNyaMissionitems.h" std::map<uint32_t, std::vector<ItemSetting>> NjNyaMissionitems::GetSettings() { - return { - {1809, {{{14472}, true, false}}}, - {1821, {{{14500}, false, true}}} - }; + return { + {1809, {{{14472}, true, false}}}, + {1821, {{{14500}, false, true}}} + }; } diff --git a/dScripts/NjNyaMissionitems.h b/dScripts/02_server/Map/njhub/NjNyaMissionitems.h similarity index 64% rename from dScripts/NjNyaMissionitems.h rename to dScripts/02_server/Map/njhub/NjNyaMissionitems.h index 5e2bbc7b..11b78ebd 100644 --- a/dScripts/NjNyaMissionitems.h +++ b/dScripts/02_server/Map/njhub/NjNyaMissionitems.h @@ -4,5 +4,5 @@ #include <vector> class NjNyaMissionitems : public NPCAddRemoveItem { - std::map<uint32_t, std::vector<ItemSetting>> GetSettings() override; + std::map<uint32_t, std::vector<ItemSetting>> GetSettings() override; }; diff --git a/dScripts/02_server/Map/njhub/NjScrollChestServer.cpp b/dScripts/02_server/Map/njhub/NjScrollChestServer.cpp new file mode 100644 index 00000000..7156b368 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjScrollChestServer.cpp @@ -0,0 +1,17 @@ +#include "NjScrollChestServer.h" +#include "InventoryComponent.h" + +void NjScrollChestServer::OnUse(Entity* self, Entity* user) { + const auto keyLOT = self->GetVar<LOT>(u"KeyNum"); + const auto rewardItemLOT = self->GetVar<LOT>(u"openItemID"); + + auto* playerInventory = user->GetComponent<InventoryComponent>(); + if (playerInventory != nullptr && playerInventory->GetLotCount(keyLOT) == 1) { + + // Check for the key and remove + playerInventory->RemoveItem(keyLOT, 1); + + // Reward the player with the item set + playerInventory->AddItem(rewardItemLOT, 1, eLootSourceType::NONE); + } +} diff --git a/dScripts/NjScrollChestServer.h b/dScripts/02_server/Map/njhub/NjScrollChestServer.h similarity index 64% rename from dScripts/NjScrollChestServer.h rename to dScripts/02_server/Map/njhub/NjScrollChestServer.h index c2891ab5..39a64473 100644 --- a/dScripts/NjScrollChestServer.h +++ b/dScripts/02_server/Map/njhub/NjScrollChestServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NjScrollChestServer : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.cpp b/dScripts/02_server/Map/njhub/NjWuNPC.cpp new file mode 100644 index 00000000..f4969074 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjWuNPC.cpp @@ -0,0 +1,65 @@ +#include "NjWuNPC.h" +#include "MissionComponent.h" +#include "Character.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "eMissionState.h" +#include "ePlayerFlag.h" + +void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + + // The Dragon statue daily mission + if (missionID == m_MainDragonMissionID) { + auto* character = target->GetCharacter(); + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (character == nullptr || missionComponent == nullptr) + return; + + switch (missionState) { + case eMissionState::AVAILABLE: + case eMissionState::COMPLETE_AVAILABLE: + { + // Reset the sub missions + for (const auto& subMissionID : m_SubDragonMissionIDs) { + missionComponent->RemoveMission(subMissionID); + missionComponent->AcceptMission(subMissionID); + } + + character->SetPlayerFlag(ePlayerFlag::NJ_WU_SHOW_DAILY_CHEST, false); + + // Hide the chest + for (auto* chest : EntityManager::Instance()->GetEntitiesInGroup(m_DragonChestGroup)) { + GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 0, -1, + target->GetObjectID(), "", target->GetSystemAddress()); + } + + return; + } + case eMissionState::READY_TO_COMPLETE: + case eMissionState::COMPLETE_READY_TO_COMPLETE: + { + character->SetPlayerFlag(ePlayerFlag::NJ_WU_SHOW_DAILY_CHEST, true); + + // Show the chest + for (auto* chest : EntityManager::Instance()->GetEntitiesInGroup(m_DragonChestGroup)) { + GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 1, -1, + target->GetObjectID(), "", target->GetSystemAddress()); + } + + auto playerID = target->GetObjectID(); + self->AddCallbackTimer(5.0f, [this, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + return; + + // Stop the dragon effects + for (auto* dragon : EntityManager::Instance()->GetEntitiesInGroup(m_DragonStatueGroup)) { + GameMessages::SendStopFXEffect(dragon, true, "on"); + } + }); + } + default: + return; + } + } +} diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.h b/dScripts/02_server/Map/njhub/NjWuNPC.h new file mode 100644 index 00000000..f8c52303 --- /dev/null +++ b/dScripts/02_server/Map/njhub/NjWuNPC.h @@ -0,0 +1,13 @@ +#pragma once +#include "AmTemplateSkillVolume.h" + +class NjWuNPC : public AmTemplateSkillVolume { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + const uint32_t m_MainDragonMissionID = 2040; + const std::vector<uint32_t> m_SubDragonMissionIDs = { 2064, 2065, 2066, 2067 }; + + // Groups and variables + const std::string m_DragonChestGroup = "DragonEmblemChest"; + const std::string m_DragonStatueGroup = "Minidragons"; + const std::u16string m_ShowChestNotification = u"showChest"; +}; diff --git a/dScripts/02_server/Map/njhub/RainOfArrows.cpp b/dScripts/02_server/Map/njhub/RainOfArrows.cpp new file mode 100644 index 00000000..b7c4c074 --- /dev/null +++ b/dScripts/02_server/Map/njhub/RainOfArrows.cpp @@ -0,0 +1,71 @@ +#include "RainOfArrows.h" +#include "EntityManager.h" +#include "SkillComponent.h" +#include "EntityInfo.h" +#include "GameMessages.h" + +void RainOfArrows::OnStartup(Entity* self) { + +} + +void RainOfArrows::OnRebuildComplete(Entity* self, Entity* target) { + auto myPos = self->GetPosition(); + auto myRot = self->GetRotation(); + + EntityInfo info; + info.lot = m_ArrowFXObject; + info.pos = myPos; + info.rot = myRot; + info.spawnerID = self->GetObjectID(); + + auto* entity = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(entity); + + self->SetVar<LWOOBJID>(u"ChildFX", entity->GetObjectID()); + self->SetVar<LWOOBJID>(u"playerID", target->GetObjectID()); + + self->AddTimer("ArrowsIncoming", m_ArrowDelay); + self->AddTimer("PlayArrowSound", m_ArrowDelay - 4); +} + +void RainOfArrows::OnTimerDone(Entity* self, std::string timerName) { + auto* child = EntityManager::Instance()->GetEntity( + self->GetVar<LWOOBJID>(u"ChildFX") + ); + + auto* player = EntityManager::Instance()->GetEntity( + self->GetVar<LWOOBJID>(u"playerID") + ); + + if (timerName == "ArrowsIncoming") { + if (child == nullptr) { + return; + } + + auto* skillComponent = child->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + skillComponent->CalculateBehavior( + m_ArrowSkill, + m_ArrowBehavior, + LWOOBJID_EMPTY, + true, + false, + player != nullptr ? player->GetObjectID() : LWOOBJID_EMPTY + ); + + self->AddTimer("FireSkill", 0.7f); + } else if (timerName == "PlayArrowSound") { + GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, m_ArrowsGUID); + } else if (timerName == "FireSkill") { + if (child != nullptr) { + child->Smash(); + } + + self->Smash(player != nullptr ? player->GetObjectID() : LWOOBJID_EMPTY); + } +} diff --git a/dScripts/02_server/Map/njhub/RainOfArrows.h b/dScripts/02_server/Map/njhub/RainOfArrows.h new file mode 100644 index 00000000..778ddfea --- /dev/null +++ b/dScripts/02_server/Map/njhub/RainOfArrows.h @@ -0,0 +1,17 @@ +#pragma once +#include "CppScripts.h" + +class RainOfArrows : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + LOT m_ArrowFXObject = 15850; + int32_t m_ArrowSkill = 1482; + int32_t m_ArrowBehavior = 36680; + int32_t m_ArrowDelay = 6; + std::string m_ArrowsGUID = "{532cba3c-54da-446c-986b-128af9647bdb}"; +}; diff --git a/dScripts/02_server/Map/njhub/boss_instance/CMakeLists.txt b/dScripts/02_server/Map/njhub/boss_instance/CMakeLists.txt new file mode 100644 index 00000000..22bb541d --- /dev/null +++ b/dScripts/02_server/Map/njhub/boss_instance/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB_BOSS_INSTANCE + "NjMonastryBossInstance.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp new file mode 100644 index 00000000..4de7638f --- /dev/null +++ b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp @@ -0,0 +1,523 @@ +#include "NjMonastryBossInstance.h" +#include "RebuildComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "dZoneManager.h" +#include "GameMessages.h" +#include "BaseCombatAIComponent.h" +#include "BuffComponent.h" +#include "SkillComponent.h" +#include "TeamManager.h" +#include <algorithm> + +// // // // // // // +// Event handling // +// // // // // // // + +void NjMonastryBossInstance::OnStartup(Entity* self) { + auto spawnerNames = std::vector<std::string>{ LedgeFrakjawSpawner, LowerFrakjawSpawner, BaseEnemiesSpawner + std::to_string(1), + BaseEnemiesSpawner + std::to_string(2), BaseEnemiesSpawner + std::to_string(3), + BaseEnemiesSpawner + std::to_string(4), CounterweightSpawner }; + + // Add a notification request for all the spawned entities, corresponds to notifySpawnedObjectLoaded + for (const auto& spawnerName : spawnerNames) { + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { + spawner->AddEntitySpawnedCallback([self, this](Entity* entity) { + const auto lot = entity->GetLOT(); + switch (lot) { + case LedgedFrakjawLOT: + NjMonastryBossInstance::HandleLedgedFrakjawSpawned(self, entity); + return; + case CounterWeightLOT: + NjMonastryBossInstance::HandleCounterWeightSpawned(self, entity); + return; + case LowerFrakjawLOT: + NjMonastryBossInstance::HandleLowerFrakjawSpawned(self, entity); + return; + default: + NjMonastryBossInstance::HandleWaveEnemySpawned(self, entity); + return; + } + }); + } + } +} + +void NjMonastryBossInstance::OnPlayerLoaded(Entity* self, Entity* player) { + ActivityTimerStop(self, WaitingForPlayersTimer); + + // Join the player in the activity + UpdatePlayer(self, player->GetObjectID()); + + // Buff the player + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetHealth((int32_t)destroyableComponent->GetMaxHealth()); + destroyableComponent->SetArmor((int32_t)destroyableComponent->GetMaxArmor()); + destroyableComponent->SetImagination((int32_t)destroyableComponent->GetMaxImagination()); + } + + // Add player ID to instance + auto totalPlayersLoaded = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable); + totalPlayersLoaded.push_back(player->GetObjectID()); + + // Properly position the player + self->SetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable, totalPlayersLoaded); + // This was always spawning all players at position one before and other values cause players to be invisible. + TeleportPlayer(player, 1); + + // Large teams face a tougher challenge + if (totalPlayersLoaded.size() >= 3) + self->SetVar<bool>(LargeTeamVariable, true); + + // Start the game if all players in the team have loaded + auto* team = TeamManager::Instance()->GetTeam(player->GetObjectID()); + if (team == nullptr || totalPlayersLoaded.size() == team->members.size()) { + StartFight(self); + return; + } + + self->AddCallbackTimer(0.0f, [self, player]() { + if (player != nullptr) { + // If we don't have enough players yet, wait for the others to load and notify the client to play a cool cinematic + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLoaded", 0, 0, + player->GetObjectID(), "", player->GetSystemAddress()); + } + }); + + ActivityTimerStart(self, WaitingForPlayersTimer, 45.0f, 45.0f); +} + +void NjMonastryBossInstance::OnPlayerExit(Entity* self, Entity* player) { + UpdatePlayer(self, player->GetObjectID(), true); + // Fetch the total players loaded from the vars + auto totalPlayersLoaded = self->GetVar<std::vector<LWOOBJID> >(TotalPlayersLoadedVariable); + + // Find the player to remove + auto playerToRemove = std::find(totalPlayersLoaded.begin(), totalPlayersLoaded.end(), player->GetObjectID()); + + // If we found the player remove them from out list of players + if (playerToRemove != totalPlayersLoaded.end()) { + totalPlayersLoaded.erase(playerToRemove); + } else { + Game::logger->Log("NjMonastryBossInstance", "Failed to remove player at exit."); + } + + // Set the players loaded var back + self->SetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable, totalPlayersLoaded); + + // Since this is an exit method, check if enough players have left. If enough have left + // resize the instance to account for such. + if (totalPlayersLoaded.size() <= 2) self->SetVar<bool>(LargeTeamVariable, false); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); +} + +void NjMonastryBossInstance::OnActivityTimerDone(Entity* self, const std::string& name) { + auto split = GeneralUtils::SplitString(name, TimerSplitChar); + auto timerName = split[0]; + auto objectID = split.size() > 1 ? (LWOOBJID)std::stoull(split[1]) : LWOOBJID_EMPTY; + + if (timerName == WaitingForPlayersTimer) { + StartFight(self); + } else if (timerName == SpawnNextWaveTimer) { + auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); + if (frakjaw != nullptr) { + SummonWave(self, frakjaw); + } + } else if (timerName == SpawnWaveTimer) { + auto wave = self->GetVar<uint32_t>(WaveNumberVariable); + self->SetVar<uint32_t>(WaveNumberVariable, wave + 1); + self->SetVar<uint32_t>(TotalAliveInWaveVariable, 0); + + if (wave < m_Waves.size()) { + auto waves = m_Waves.at(wave); + auto counter = 0; + + for (const auto& waveEnemy : waves) { + const auto numberToSpawn = self->GetVar<bool>(LargeTeamVariable) + ? waveEnemy.largeNumber : waveEnemy.smallNumber; + + auto spawnIndex = counter % 4 + 1; + SpawnOnNetwork(self, waveEnemy.lot, numberToSpawn, BaseEnemiesSpawner + std::to_string(spawnIndex)); + counter++; + } + } + } else if (timerName + TimerSplitChar == UnstunTimer) { + auto* entity = EntityManager::Instance()->GetEntity(objectID); + if (entity != nullptr) { + auto* combatAI = entity->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetDisabled(false); + } + } + } else if (timerName == SpawnCounterWeightTimer) { + auto spawners = dZoneManager::Instance()->GetSpawnersByName(CounterweightSpawner); + if (!spawners.empty()) { + // Spawn the counter weight at a specific waypoint, there's one for each round + auto* spawner = spawners.front(); + + spawner->Spawn({ + spawner->m_Info.nodes.at((self->GetVar<uint32_t>(WaveNumberVariable) - 1) % 3) + }, true); + } + } else if (timerName == LowerFrakjawCamTimer) { + // Destroy the frakjaw on the ledge + auto* ledgeFrakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); + if (ledgeFrakjaw != nullptr) { + ledgeFrakjaw->Kill(); + } + + ActivityTimerStart(self, SpawnLowerFrakjawTimer, 1.0f, 1.0f); + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, + LWOOBJID_EMPTY, BottomFrakSpawn, UNASSIGNED_SYSTEM_ADDRESS); + } else if (timerName == SpawnLowerFrakjawTimer) { + auto spawners = dZoneManager::Instance()->GetSpawnersByName(LowerFrakjawSpawner); + if (!spawners.empty()) { + auto* spawner = spawners.front(); + spawner->Activate(); + } + } else if (timerName == SpawnRailTimer) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, + LWOOBJID_EMPTY, FireRailSpawn, UNASSIGNED_SYSTEM_ADDRESS); + + auto spawners = dZoneManager::Instance()->GetSpawnersByName(FireRailSpawner); + if (!spawners.empty()) { + auto* spawner = spawners.front(); + spawner->Activate(); + } + } else if (timerName + TimerSplitChar == FrakjawSpawnInTimer) { + auto* lowerFrakjaw = EntityManager::Instance()->GetEntity(objectID); + if (lowerFrakjaw != nullptr) { + LowerFrakjawSummon(self, lowerFrakjaw); + } + } else if (timerName == WaveOverTimer) { + WaveOver(self); + } else if (timerName == FightOverTimer) { + FightOver(self); + } +} + +// // // // // // // // +// Custom functions // +// // // // // // // // + +void NjMonastryBossInstance::StartFight(Entity* self) { + if (self->GetVar<bool>(FightStartedVariable)) + return; + + self->SetVar<bool>(FightStartedVariable, true); + + // Activate the frakjaw spawner + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(LedgeFrakjawSpawner)) { + spawner->Activate(); + } +} + +void NjMonastryBossInstance::HandleLedgedFrakjawSpawned(Entity* self, Entity* ledgedFrakjaw) { + self->SetVar<LWOOBJID>(LedgeFrakjawVariable, ledgedFrakjaw->GetObjectID()); + SummonWave(self, ledgedFrakjaw); +} + +void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity* self, Entity* counterWeight) { + auto* rebuildComponent = counterWeight->GetComponent<RebuildComponent>(); + if (rebuildComponent != nullptr) { + rebuildComponent->AddRebuildStateCallback([this, self, counterWeight](eRebuildState state) { + + switch (state) { + case eRebuildState::BUILDING: + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, + 0, 0, counterWeight->GetObjectID(), + BaseCounterweightQB + std::to_string(self->GetVar<uint32_t>(WaveNumberVariable)), + UNASSIGNED_SYSTEM_ADDRESS); + return; + case eRebuildState::INCOMPLETE: + GameMessages::SendNotifyClientObject(self->GetObjectID(), EndCinematicNotification, + 0, 0, LWOOBJID_EMPTY, "", + UNASSIGNED_SYSTEM_ADDRESS); + return; + case eRebuildState::RESETTING: + ActivityTimerStart(self, SpawnCounterWeightTimer, 0.0f, 0.0f); + return; + case eRebuildState::COMPLETED: { + // TODO: Move the platform? + + // The counterweight is actually a moving platform and we should listen to the last waypoint event here + // 0.5f is a rough estimate of that path, though, and results in less needed logic + self->AddCallbackTimer(0.5f, [this, self, counterWeight]() { + if (counterWeight != nullptr) { + counterWeight->Kill(); + } + + auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); + if (frakjaw == nullptr) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, + 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + return; + } + + auto* skillComponent = frakjaw->GetComponent<SkillComponent>(); + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(1635, 39097, frakjaw->GetObjectID(), true, false); + } + + GameMessages::SendPlayAnimation(frakjaw, StunnedAnimation); + GameMessages::SendPlayNDAudioEmitter(frakjaw, UNASSIGNED_SYSTEM_ADDRESS, CounterSmashAudio); + + // Before wave 4 we should lower frakjaw from the ledge + if (self->GetVar<uint32_t>(WaveNumberVariable) == 3) { + LowerFrakjaw(self, frakjaw); + return; + } + + ActivityTimerStart(self, SpawnNextWaveTimer, 2.0f, 2.0f); + }); + } + default: + return; + } + }); + } +} + +void NjMonastryBossInstance::HandleLowerFrakjawSpawned(Entity* self, Entity* lowerFrakjaw) { + GameMessages::SendPlayAnimation(lowerFrakjaw, TeleportInAnimation); + self->SetVar<LWOOBJID>(LowerFrakjawVariable, lowerFrakjaw->GetObjectID()); + + auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetDisabled(true); + } + + auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->AddOnHitCallback([this, self, lowerFrakjaw](Entity* attacker) { + NjMonastryBossInstance::HandleLowerFrakjawHit(self, lowerFrakjaw, attacker); + }); + } + + lowerFrakjaw->AddDieCallback([this, self, lowerFrakjaw]() { + NjMonastryBossInstance::HandleLowerFrakjawDied(self, lowerFrakjaw); + }); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0, + LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + + if (self->GetVar<bool>(LargeTeamVariable)) { + // Double frakjaws health for large teams + if (destroyableComponent != nullptr) { + const auto doubleHealth = destroyableComponent->GetHealth() * 2; + destroyableComponent->SetHealth(doubleHealth); + destroyableComponent->SetMaxHealth((float_t)doubleHealth); + } + + ActivityTimerStart(self, FrakjawSpawnInTimer + std::to_string(lowerFrakjaw->GetObjectID()), + 2.0f, 2.0f); + ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), + 7.0f, 7.0f); + } else { + ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), + 5.0f, 5.0f); + } +} + +void NjMonastryBossInstance::HandleLowerFrakjawHit(Entity* self, Entity* lowerFrakjaw, Entity* attacker) { + auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>(); + if (destroyableComponent == nullptr) + return; + + // Progress the fight to the last wave if frakjaw has less than 50% of his health left + if (destroyableComponent->GetHealth() <= (uint32_t)destroyableComponent->GetMaxHealth() / 2 && !self->GetVar<bool>(OnLastWaveVarbiale)) { + self->SetVar<bool>(OnLastWaveVarbiale, true); + + // Stun frakjaw during the cinematic + auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetDisabled(true); + } + ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), 5.0f, 5.0f); + + const auto trashMobsAlive = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); + std::vector<LWOOBJID> newTrashMobs = {}; + + for (const auto& trashMobID : trashMobsAlive) { + auto* trashMob = EntityManager::Instance()->GetEntity(trashMobID); + if (trashMob != nullptr) { + newTrashMobs.push_back(trashMobID); + + // Stun all the enemies until the cinematic is over + auto* trashMobCombatAI = trashMob->GetComponent<BaseCombatAIComponent>(); + if (trashMobCombatAI != nullptr) { + trashMobCombatAI->SetDisabled(true); + } + ActivityTimerStart(self, UnstunTimer + std::to_string(trashMobID), 5.0f, 5.0f); + } + } + + self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, newTrashMobs); + + LowerFrakjawSummon(self, lowerFrakjaw); + RemovePoison(self); + } +} + +void NjMonastryBossInstance::HandleLowerFrakjawDied(Entity* self, Entity* lowerFrakjaw) { + ActivityTimerStart(self, FightOverTimer, 2.0f, 2.0f); +} + +void NjMonastryBossInstance::HandleWaveEnemySpawned(Entity* self, Entity* waveEnemy) { + waveEnemy->AddDieCallback([this, self, waveEnemy]() { + NjMonastryBossInstance::HandleWaveEnemyDied(self, waveEnemy); + }); + + auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); + waveEnemies.push_back(waveEnemy->GetObjectID()); + self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies); + + auto* combatAI = waveEnemy->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetDisabled(true); + ActivityTimerStart(self, UnstunTimer + std::to_string(waveEnemy->GetObjectID()), 3.0f, 3.0f); + } +} + +void NjMonastryBossInstance::HandleWaveEnemyDied(Entity* self, Entity* waveEnemy) { + auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); + waveEnemies.erase(std::remove(waveEnemies.begin(), waveEnemies.end(), waveEnemy->GetObjectID()), waveEnemies.end()); + self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies); + + if (waveEnemies.empty()) { + ActivityTimerStart(self, WaveOverTimer, 2.0f, 2.0f); + } +} + +void NjMonastryBossInstance::TeleportPlayer(Entity* player, uint32_t position) { + for (const auto* spawnPoint : EntityManager::Instance()->GetEntitiesInGroup("SpawnPoint" + std::to_string(position))) { + GameMessages::SendTeleport(player->GetObjectID(), spawnPoint->GetPosition(), spawnPoint->GetRotation(), + player->GetSystemAddress(), true); + } +} + +void NjMonastryBossInstance::SummonWave(Entity* self, Entity* frakjaw) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, + LedgeFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendPlayAnimation(frakjaw, SummonAnimation); + + // Stop the music for the first, fourth and fifth wave + const auto wave = self->GetVar<uint32_t>(WaveNumberVariable); + if (wave >= 1 || wave < (m_Waves.size() - 1)) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, + LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave - 1), + UNASSIGNED_SYSTEM_ADDRESS); + } + + // After frakjaw moves down the music stays the same + if (wave < (m_Waves.size() - 1)) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), StartMusicNotification, 0, 0, + LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave), + UNASSIGNED_SYSTEM_ADDRESS); + } + + ActivityTimerStart(self, SpawnWaveTimer, 4.0f, 4.0f); +} + +void NjMonastryBossInstance::LowerFrakjawSummon(Entity* self, Entity* frakjaw) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, + LWOOBJID_EMPTY, BottomFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); + ActivityTimerStart(self, SpawnWaveTimer, 2.0f, 2.0f); + GameMessages::SendPlayAnimation(frakjaw, SummonAnimation); +} + +void NjMonastryBossInstance::RemovePoison(Entity* self) { + const auto& totalPlayer = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable); + for (const auto& playerID : totalPlayer) { + + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + + auto* buffComponent = player->GetComponent<BuffComponent>(); + if (buffComponent != nullptr) { + buffComponent->RemoveBuff(PoisonBuff); + } + } + } +} + +void NjMonastryBossInstance::LowerFrakjaw(Entity* self, Entity* frakjaw) { + GameMessages::SendPlayAnimation(frakjaw, TeleportOutAnimation); + ActivityTimerStart(self, LowerFrakjawCamTimer, 2.0f, 2.0f); + + GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StopMusicNotification, 0, 0, + LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 3), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StartMusicNotification, 0, 0, + LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), UNASSIGNED_SYSTEM_ADDRESS); +} + +void NjMonastryBossInstance::SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName) { + auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); + if (spawners.empty() || numberToSpawn <= 0) + return; + + auto* spawner = spawners.front(); + + // Spawn the lot N times + spawner->SetSpawnLot(toSpawn); + for (auto i = 0; i < numberToSpawn; i++) + spawner->Spawn({ spawner->m_Info.nodes.at(i % spawner->m_Info.nodes.size()) }, true); +} + +void NjMonastryBossInstance::WaveOver(Entity* self) { + auto wave = self->GetVar<uint32_t>(WaveNumberVariable); + if (wave >= m_Waves.size() - 1) + return; + + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, + LWOOBJID_EMPTY, BaseCounterweightSpawn + std::to_string(wave), + UNASSIGNED_SYSTEM_ADDRESS); + ActivityTimerStart(self, SpawnCounterWeightTimer, 1.5f, 1.5f); + RemovePoison(self); +} + +void NjMonastryBossInstance::FightOver(Entity* self) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"GroundFrakjawDead", 0, 0, + LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + + // Remove all the enemies from the battlefield + for (auto i = 1; i < 5; i++) { + auto spawners = dZoneManager::Instance()->GetSpawnersByName(BaseEnemiesSpawner + std::to_string(i)); + if (!spawners.empty()) { + auto* spawner = spawners.front(); + spawner->Deactivate(); + spawner->Reset(); + } + } + + RemovePoison(self); + ActivityTimerStart(self, SpawnRailTimer, 1.5f, 1.5f); + + // Set the music to play the victory music + GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, + LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), + UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendNotifyClientObject(self->GetObjectID(), FlashMusicNotification, 0, 0, + LWOOBJID_EMPTY, "Monastery_Frakjaw_Battle_Win", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, + LWOOBJID_EMPTY, TreasureChestSpawning, UNASSIGNED_SYSTEM_ADDRESS); + + auto treasureChests = EntityManager::Instance()->GetEntitiesInGroup(ChestSpawnpointGroup); + for (auto* treasureChest : treasureChests) { + auto info = EntityInfo{}; + + info.lot = ChestLOT; + info.pos = treasureChest->GetPosition(); + info.rot = treasureChest->GetRotation(); + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData<LWOOBJID>(u"parent_tag", self->GetObjectID()) + }; + + // Finally spawn a treasure chest at the correct spawn point + auto* chestObject = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(chestObject); + } +} diff --git a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.h b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.h new file mode 100644 index 00000000..86553c18 --- /dev/null +++ b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.h @@ -0,0 +1,157 @@ +#pragma once +#include "ActivityManager.h" + +enum FrakjawEnemies { + BoneWolf = 16191, + BlackSmith = 14007, + Marksman = 14008, + Commando = 14009, + MadScientist = 16511 +}; + +enum FrakjawLots : LOT { + ChestLOT = 16486, + LedgedFrakjawLOT = 16289, + LowerFrakjawLOT = 16048, + CounterWeightLOT = 16141 +}; + +struct FrakjawWaveEnemy { + LOT lot; + uint32_t largeNumber; + uint32_t smallNumber; +}; + +class NjMonastryBossInstance : public ActivityManager { +public: + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnPlayerExit(Entity* self, Entity* player) override; + void OnActivityTimerDone(Entity* self, const std::string& name) override; +private: + void StartFight(Entity* self); + void WaveOver(Entity* self); + void FightOver(Entity* self); + void SummonWave(Entity* self, Entity* frakjaw); + void LowerFrakjaw(Entity* self, Entity* frakjaw); + void LowerFrakjawSummon(Entity* self, Entity* frakjaw); + void RemovePoison(Entity* self); + static void SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName); + static void TeleportPlayer(Entity* player, uint32_t position); + + // Event handlers for anything spawned by the main spawner + void HandleLedgedFrakjawSpawned(Entity* self, Entity* ledgedFrakjaw); + void HandleCounterWeightSpawned(Entity* self, Entity* counterWeight); + void HandleLowerFrakjawSpawned(Entity* self, Entity* lowerFrakjaw); + void HandleWaveEnemySpawned(Entity* self, Entity* waveEnemy); + void HandleWaveEnemyDied(Entity* self, Entity* waveEnemy); + void HandleLowerFrakjawHit(Entity* self, Entity* lowerFrakjaw, Entity* attacker); + void HandleLowerFrakjawDied(Entity* self, Entity* lowerFrakjaw); + + const std::vector<std::vector<FrakjawWaveEnemy>> m_Waves = { + // Wave 1 + { + { FrakjawEnemies::Marksman, 2, 1}, + { FrakjawEnemies::BlackSmith, 4, 3}, + { FrakjawEnemies::Commando, 2, 1}, + { FrakjawEnemies::MadScientist, 1, 0}, + }, + + // Wave 2 + { + { FrakjawEnemies::BoneWolf, 1, 0}, + { FrakjawEnemies::BlackSmith, 2, 2}, + { FrakjawEnemies::Marksman, 2, 1}, + { FrakjawEnemies::MadScientist, 1, 1}, + }, + + // Wave 3 + { + { FrakjawEnemies::BoneWolf, 2, 1}, + { FrakjawEnemies::Marksman, 2, 1}, + { FrakjawEnemies::Commando, 2, 2}, + { FrakjawEnemies::MadScientist, 1, 0}, + }, + + // Wave 4 + { + { FrakjawEnemies::BlackSmith, 2, 2}, + { FrakjawEnemies::BoneWolf, 1, 1}, + { FrakjawEnemies::Commando, 3, 1}, + { FrakjawEnemies::Marksman, 2, 0}, + }, + + // Wave 5 + { + { FrakjawEnemies::MadScientist, 1, 0}, + { FrakjawEnemies::BoneWolf, 2, 0}, + { FrakjawEnemies::Commando, 3, 0}, + { FrakjawEnemies::Marksman, 2, 0}, + } + }; + + const int32_t PoisonBuff = 60; + + // Variables + const std::u16string TotalPlayersLoadedVariable = u"TotalPlayersLoaded"; + const std::u16string LargeTeamVariable = u"LargeTeam"; + const std::u16string FightStartedVariable = u"FightStarted"; + const std::u16string LedgeFrakjawVariable = u"LedgeFrakjaw"; + const std::u16string LowerFrakjawVariable = u"LowerFrakjaw"; + const std::u16string WaveNumberVariable = u"WaveNumber"; + const std::u16string OnLastWaveVarbiale = u"OnLastWave"; + const std::u16string TrashMobsAliveVariable = u"TrashMobsAlive"; + const std::u16string TotalAliveInWaveVariable = u"TotalAliveInWave"; + + // Timers + const char TimerSplitChar = '+'; + const std::string WaitingForPlayersTimer = "WaitingForPlayers"; + const std::string SpawnWaveTimer = "SpawnWave"; + const std::string SpawnNextWaveTimer = "SpawnNextWave"; + const std::string UnstunTimer = "Unstun+"; + const std::string FrakjawSpawnInTimer = "LowerFrakjawSpawnIn+"; + const std::string WaveOverTimer = "WaveOverTimer"; + const std::string FightOverTimer = "FightOver"; + const std::string LowerFrakjawCamTimer = "StartLowerFrakjawCam"; + const std::string SpawnCounterWeightTimer = "SpawnQB"; + const std::string SpawnRailTimer = "SpawnRailQB"; + const std::string SpawnLowerFrakjawTimer = "SpawnLowerFrakjaw"; + + // Groups + const std::string ChestSpawnpointGroup = "ChestSpawnPoint"; + + // Spawner network names + const std::string LedgeFrakjawSpawner = "LedgeFrakjaw"; + const std::string LowerFrakjawSpawner = "LowerFrakjaw"; + const std::string BaseEnemiesSpawner = "EnemySpawnPoints_"; + const std::string CounterweightSpawner = "Counterweights"; + const std::string FireRailSpawner = "FireRailActivatorQB"; + const std::string ExtraRocks = "ExtraRocks"; + + // Cinematics + const std::string LedgeFrakSummon = "FrakjawSummoning"; + const std::string BaseCounterweightQB = "CounterweightQB"; + const std::string BaseCounterweightSpawn = "CWQBSpawn"; + const std::string BottomFrakSummon = "BottomFrakjawSummoning"; + const std::string BottomFrakSpawn = "BottomFrakjawSpawning"; + const std::string TreasureChestSpawning = "TreasureChestSpawning"; + const std::string FireRailSpawn = "RailQBSpawn"; + + // Notifications + const std::u16string StopMusicNotification = u"StopMusic"; + const std::u16string StartMusicNotification = u"StartMusic"; + const std::u16string FlashMusicNotification = u"FlashMusic"; + const std::u16string PlayCinematicNotification = u"PlayCinematic"; + const std::u16string EndCinematicNotification = u"EndCinematic"; + + // Animations + const std::u16string SummonAnimation = u"summon"; + const std::u16string TeleportOutAnimation = u"teleport-out"; + const std::u16string TeleportInAnimation = u"teleport-in"; + const std::u16string StunnedAnimation = u"stunned"; + + // Audio cues + const std::string AudioWaveAudio = "Monastery_Frakjaw_Battle_"; + const std::string BattleOverAudio = "Monastery_Frakjaw_Battle_Win"; + const std::string CounterSmashAudio = "{d76d7b9d-9dc2-4e52-a315-69b25ef521ca}"; +}; diff --git a/dScripts/02_server/Minigame/CMakeLists.txt b/dScripts/02_server/Minigame/CMakeLists.txt new file mode 100644 index 00000000..e8cb4402 --- /dev/null +++ b/dScripts/02_server/Minigame/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MINIGAME) + +add_subdirectory(General) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MINIGAME_GENERAL}) + set(DSCRIPTS_SOURCES_02_SERVER_MINIGAME ${DSCRIPTS_SOURCES_02_SERVER_MINIGAME} "General/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_02_SERVER_MINIGAME ${DSCRIPTS_SOURCES_02_SERVER_MINIGAME} PARENT_SCOPE) diff --git a/dScripts/02_server/Minigame/General/CMakeLists.txt b/dScripts/02_server/Minigame/General/CMakeLists.txt new file mode 100644 index 00000000..55d2e595 --- /dev/null +++ b/dScripts/02_server/Minigame/General/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_02_SERVER_MINIGAME_GENERAL + "MinigameTreasureChestServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp new file mode 100644 index 00000000..7df8fc12 --- /dev/null +++ b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp @@ -0,0 +1,65 @@ +#include "MinigameTreasureChestServer.h" +#include "ScriptedActivityComponent.h" +#include "TeamManager.h" +#include "EntityManager.h" +#include "dZoneManager.h" +#include "Loot.h" + +void MinigameTreasureChestServer::OnUse(Entity* self, Entity* user) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return; + + if (self->GetVar<bool>(u"used")) + return; + self->SetVar<bool>(u"used", true); + + if (!IsPlayerInActivity(self, user->GetObjectID())) + UpdatePlayer(self, user->GetObjectID()); + + auto* team = TeamManager::Instance()->GetTeam(user->GetObjectID()); + uint32_t activityRating = 0; + if (team != nullptr) { + for (const auto& teamMemberID : team->members) { + auto* teamMember = EntityManager::Instance()->GetEntity(teamMemberID); + if (teamMember != nullptr) { + activityRating = CalculateActivityRating(self, teamMemberID); + + if (self->GetLOT() == frakjawChestId) activityRating = team->members.size(); + + LootGenerator::Instance().DropActivityLoot(teamMember, self, sac->GetActivityID(), activityRating); + } + } + } else { + activityRating = CalculateActivityRating(self, user->GetObjectID()); + + if (self->GetLOT() == frakjawChestId) activityRating = 1; + + LootGenerator::Instance().DropActivityLoot(user, self, sac->GetActivityID(), activityRating); + } + + sac->PlayerRemove(user->GetObjectID()); + + auto* zoneControl = dZoneManager::Instance()->GetZoneControlObject(); + if (zoneControl != nullptr) { + zoneControl->OnFireEventServerSide(self, "Survival_Update", 0); + } + + self->Smash(self->GetObjectID()); +} + +uint32_t MinigameTreasureChestServer::CalculateActivityRating(Entity* self, LWOOBJID playerID) { + auto* team = TeamManager::Instance()->GetTeam(playerID); + return team != nullptr ? team->members.size() * 100 : ActivityManager::CalculateActivityRating(self, playerID) * 100; +} + +void MinigameTreasureChestServer::OnStartup(Entity* self) { + + // BONS treasure chest thinks it's on FV, causing it to start a lobby + if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1204) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac != nullptr) { + sac->SetInstanceMapID(1204); + } + } +} diff --git a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.h b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.h new file mode 100644 index 00000000..3159e70e --- /dev/null +++ b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.h @@ -0,0 +1,11 @@ +#pragma once +#include "ActivityManager.h" + +class MinigameTreasureChestServer : public ActivityManager { +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + uint32_t CalculateActivityRating(Entity* self, LWOOBJID playerID) override; +private: + const uint32_t frakjawChestId = 16486; +}; diff --git a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp new file mode 100644 index 00000000..4d3482c4 --- /dev/null +++ b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp @@ -0,0 +1,65 @@ +#include "AgSurvivalBuffStation.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "SkillComponent.h" +#include "TeamManager.h" + +void AgSurvivalBuffStation::OnRebuildComplete(Entity* self, Entity* target) { + auto destroyableComponent = self->GetComponent<DestroyableComponent>(); + // We set the faction to 1 so that the buff station sees players as friendly targets to buff + if (destroyableComponent != nullptr) destroyableComponent->SetFaction(1); + + auto skillComponent = self->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) skillComponent->CalculateBehavior(skillIdForBuffStation, behaviorIdForBuffStation, self->GetObjectID()); + + self->AddCallbackTimer(smashTimer, [self]() { + self->Smash(); + }); + self->AddTimer("DropArmor", dropArmorTimer); + self->AddTimer("DropLife", dropLifeTimer); + self->AddTimer("Dropimagination", dropImaginationTimer); + // Since all survival players should be on the same team, we get the team. + auto team = TeamManager::Instance()->GetTeam(target->GetObjectID()); + + std::vector<LWOOBJID> builderTeam; + // Not on a team + if (team == nullptr) { + builderTeam.push_back(target->GetObjectID()); + self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", builderTeam); + return; + } + + for (auto memberID : team->members) { + builderTeam.push_back(memberID); + } + self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", builderTeam); +} + +void AgSurvivalBuffStation::OnTimerDone(Entity* self, std::string timerName) { + uint32_t powerupToDrop = lifePowerup; + if (timerName == "DropArmor") { + powerupToDrop = armorPowerup; + self->AddTimer("DropArmor", dropArmorTimer); + } + if (timerName == "DropLife") { + powerupToDrop = lifePowerup; + self->AddTimer("DropLife", dropLifeTimer); + } + if (timerName == "Dropimagination") { + powerupToDrop = imaginationPowerup; + self->AddTimer("Dropimagination", dropImaginationTimer); + } + auto team = self->GetVar<std::vector<LWOOBJID>>(u"BuilderTeam"); + for (auto memberID : team) { + auto member = EntityManager::Instance()->GetEntity(memberID); + if (member != nullptr && !member->GetIsDead()) { + GameMessages::SendDropClientLoot(member, self->GetObjectID(), powerupToDrop, 0, self->GetPosition()); + } else { + // If player left the team or left early erase them from the team variable. + team.erase(std::find(team.begin(), team.end(), memberID)); + self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", team); + } + } +} diff --git a/dScripts/02_server/Objects/AgSurvivalBuffStation.h b/dScripts/02_server/Objects/AgSurvivalBuffStation.h new file mode 100644 index 00000000..5434b0cd --- /dev/null +++ b/dScripts/02_server/Objects/AgSurvivalBuffStation.h @@ -0,0 +1,52 @@ +#pragma once +#include "CppScripts.h" + +class AgSurvivalBuffStation : public CppScripts::Script +{ +public: + /** + * @brief When the rebuild of self is complete, we calculate the behavior that is assigned to self in the database. + * + * @param self The Entity that called this script. + * @param target The target of the self that called this script. + */ + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + /** + * Skill ID for the buff station. + */ + uint32_t skillIdForBuffStation = 201; + /** + * Behavior ID for the buff station. + */ + uint32_t behaviorIdForBuffStation = 1784; + /** + * Timer for dropping armor. + */ + float dropArmorTimer = 6.0f; + /** + * Timer for dropping life. + */ + float dropLifeTimer = 3.0f; + /** + * Timer for dropping imagination. + */ + float dropImaginationTimer = 4.0f; + /** + * Timer for smashing. + */ + float smashTimer = 25.0f; + /** + * LOT for armor powerup. + */ + LOT armorPowerup = 6431; + /** + * LOT for life powerup. + */ + LOT lifePowerup = 177; + /** + * LOT for imagination powerup. + */ + LOT imaginationPowerup = 935; +}; diff --git a/dScripts/02_server/Objects/CMakeLists.txt b/dScripts/02_server/Objects/CMakeLists.txt new file mode 100644 index 00000000..1b96d79f --- /dev/null +++ b/dScripts/02_server/Objects/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_02_SERVER_OBJECTS + "AgSurvivalBuffStation.cpp" + "StinkyFishTarget.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Objects/StinkyFishTarget.cpp b/dScripts/02_server/Objects/StinkyFishTarget.cpp new file mode 100644 index 00000000..459e0bbe --- /dev/null +++ b/dScripts/02_server/Objects/StinkyFishTarget.cpp @@ -0,0 +1,45 @@ +#include "StinkyFishTarget.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "Entity.h" + +void StinkyFishTarget::OnStartup(Entity* self) { + auto position = self->GetPosition(); + position.SetY(position.GetY() - 0.5f); + self->SetPosition(position); +} + +void StinkyFishTarget::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message != "stinkfish" || self->GetVar<bool>(u"used")) + return; + + self->SetVar<bool>(u"used", true); + self->SetVar<LWOOBJID>(u"player", caster->GetObjectID()); + + EntityInfo entityInfo{}; + entityInfo.lot = SHARK_LOT; + entityInfo.pos = self->GetPosition(); + entityInfo.rot = self->GetRotation(); + entityInfo.spawnerID = self->GetObjectID(); + entityInfo.settings = { + new LDFData<bool>(u"no_timed_spawn", true) + }; + + auto* fish = EntityManager::Instance()->CreateEntity(entityInfo); + EntityManager::Instance()->ConstructEntity(fish); + + self->SetVar<LWOOBJID>(u"fish", fish->GetObjectID()); + self->AddTimer("smash", 5.0f); +} + +void StinkyFishTarget::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "smash") { + const auto playerID = self->GetVar<LWOOBJID>(u"player"); + auto* fish = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"fish")); + + if (fish) { + fish->Smash(playerID); + self->Smash(playerID); + } + } +} diff --git a/dScripts/02_server/Objects/StinkyFishTarget.h b/dScripts/02_server/Objects/StinkyFishTarget.h new file mode 100644 index 00000000..b8f9e9ae --- /dev/null +++ b/dScripts/02_server/Objects/StinkyFishTarget.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class StinkyFishTarget : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT SHARK_LOT = 8570; +}; diff --git a/dScripts/02_server/Pets/CMakeLists.txt b/dScripts/02_server/Pets/CMakeLists.txt new file mode 100644 index 00000000..8820a82e --- /dev/null +++ b/dScripts/02_server/Pets/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_02_SERVER_PETS + "PetFromDigServer.cpp" + "PetFromObjectServer.cpp" + "DamagingPets.cpp" + PARENT_SCOPE) diff --git a/dScripts/02_server/Pets/DamagingPets.cpp b/dScripts/02_server/Pets/DamagingPets.cpp new file mode 100644 index 00000000..6fd8c560 --- /dev/null +++ b/dScripts/02_server/Pets/DamagingPets.cpp @@ -0,0 +1,146 @@ +#include "DamagingPets.h" +#include "PetComponent.h" +#include "DestroyableComponent.h" +#include "BaseCombatAIComponent.h" +#include "RenderComponent.h" +#include "ePetTamingNotifyType.h" + +void DamagingPets::OnStartup(Entity* self) { + + // Make the pet hostile or non-hostile based on whether or not it is tamed + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { + self->AddTimer("GoEvil", 0.5f); + } +} + +void DamagingPets::OnPlayerLoaded(Entity* self, Entity* player) { + + // Makes it so that new players also see the effect + self->AddCallbackTimer(2.5f, [self]() { + if (self != nullptr) { + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr && petComponent->GetOwner() == nullptr && self->GetVar<bool>(u"IsEvil")) { + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + auto counter = 1; + for (const auto petEffect : GetPetInfo(self).effect) { + renderComponent->PlayEffect(petEffect, u"create", "FXname" + std::to_string(counter)); + counter++; + } + } + } + } + }); +} + +void DamagingPets::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) { + switch (type) { + case ePetTamingNotifyType::SUCCESS: + case ePetTamingNotifyType::BEGIN: + self->CancelAllTimers(); + ClearEffects(self); + break; + case ePetTamingNotifyType::FAILED: + case ePetTamingNotifyType::QUIT: + { + self->SetNetworkVar<bool>(u"bIAmTamable", false); + self->AddTimer("GoEvil", 1.0f); + break; + } + default: + break; + } +} + +void DamagingPets::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + const auto infoForPet = GetPetInfo(self); + if (infoForPet.skill == message) { + + // Only make pets tamable that aren't tamed yet + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr && petComponent->GetOwner() == nullptr && self->GetVar<bool>(u"IsEvil")) { + ClearEffects(self); + self->AddTimer("GoEvil", 30.0f); + self->SetNetworkVar<bool>(u"bIAmTamable", true); + } + } +} + +void DamagingPets::OnTimerDone(Entity* self, std::string message) { + if (message == "GoEvil") { + MakeUntamable(self); + } +} + +void DamagingPets::MakeUntamable(Entity* self) { + auto* petComponent = self->GetComponent<PetComponent>(); + + // If the pet is currently not being tamed, make it hostile + if (petComponent != nullptr && petComponent->GetStatus() != 5) { + self->SetNetworkVar<bool>(u"bIAmTamable", false); + self->SetVar<bool>(u"IsEvil", true); + petComponent->SetStatus(1); + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(false); + } + + // Special faction that can attack the player but the player can't attack + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetFaction(114); + destroyableComponent->SetHealth(5); + } + + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + auto counter = 1; + for (const auto petEffect : GetPetInfo(self).effect) { + renderComponent->PlayEffect(petEffect, u"create", "FXname" + std::to_string(counter)); + counter++; + } + } + } +} + +void DamagingPets::ClearEffects(Entity* self) { + self->SetVar<bool>(u"IsEvil", false); + + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr) { + petComponent->SetStatus(67108866); + } + + auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); + if (combatAIComponent != nullptr) { + combatAIComponent->SetDisabled(true); + } + + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetFaction(99); + } + + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + auto counter = 1; + for (const auto petEffect : GetPetInfo(self).effect) { + renderComponent->StopEffect("FXname" + std::to_string(counter)); + counter++; + } + } +} + +PetInfo DamagingPets::GetPetInfo(Entity* self) { + const auto infoForPet = petInfo.find(self->GetLOT()); + return infoForPet != petInfo.end() ? infoForPet->second : petInfo.begin()->second; +} + +// Does not compile on Win32 with name specifiers +const std::map<LOT, PetInfo> DamagingPets::petInfo = { + { 5639, { /*.effect =*/ { 3170, 4058 }, /*.skill =*/ "waterspray"}}, // Red dragon + { 5641, { /*.effect =*/ { 3170, 4058 }, /*.skill =*/ "waterspray"}}, // Green dragon + { 3261, { /*.effect =*/ { 1490 }, /*.skill =*/ "waterspray"}}, // Skunk +}; diff --git a/dScripts/02_server/Pets/DamagingPets.h b/dScripts/02_server/Pets/DamagingPets.h new file mode 100644 index 00000000..303bff52 --- /dev/null +++ b/dScripts/02_server/Pets/DamagingPets.h @@ -0,0 +1,24 @@ +#pragma once +#include "CppScripts.h" + +/** + * Information about pets regarding which effect to play when a skill is cast + */ +struct PetInfo { + const std::vector<uint32_t> effect; + const std::string skill; +}; + +class DamagingPets : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string message) override; + void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) override; + void OnSkillEventFired(Entity* self, Entity* target, const std::string& message) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; +private: + static void MakeUntamable(Entity* self); + static PetInfo GetPetInfo(Entity* self); + static void ClearEffects(Entity* self); + static const std::map<LOT, PetInfo> petInfo; +}; diff --git a/dScripts/02_server/Pets/PetFromDigServer.cpp b/dScripts/02_server/Pets/PetFromDigServer.cpp new file mode 100644 index 00000000..525f3e94 --- /dev/null +++ b/dScripts/02_server/Pets/PetFromDigServer.cpp @@ -0,0 +1,45 @@ +#include "PetFromDigServer.h" +#include "PetComponent.h" +#include "ePetTamingNotifyType.h" + +void PetFromDigServer::OnStartup(Entity* self) { + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + return; + + // Triggers the local dig pet script for taming etc. + auto tamer = self->GetVar<LWOOBJID>(u"tamer"); + + // Client compares this with player:GetID() which is a string, so we'll have to give it a string + self->SetNetworkVar(u"pettamer", std::to_string(tamer)); + + // Kill if the player decides that the dig pet is not worthy + self->AddTimer("killself", 45.0f); +} + +void PetFromDigServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "killself") { + + // Don't accidentally kill a pet that is already owned + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + return; + + self->Smash(self->GetObjectID(), eKillType::SILENT); + } +} + +void PetFromDigServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) { + if (type == ePetTamingNotifyType::BEGIN) { + self->CancelTimer("killself"); + } else if (type == ePetTamingNotifyType::QUIT || type == ePetTamingNotifyType::FAILED) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } else if (type == ePetTamingNotifyType::SUCCESS) { + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr) + return; + // TODO: Remove custom group? + // Command the pet to the player as it may otherwise go to its spawn point which is non existant + // petComponent->Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 6, 202, true); + } +} diff --git a/dScripts/02_server/Pets/PetFromDigServer.h b/dScripts/02_server/Pets/PetFromDigServer.h new file mode 100644 index 00000000..aaf31728 --- /dev/null +++ b/dScripts/02_server/Pets/PetFromDigServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class PetFromDigServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) override; +}; diff --git a/dScripts/02_server/Pets/PetFromObjectServer.cpp b/dScripts/02_server/Pets/PetFromObjectServer.cpp new file mode 100644 index 00000000..0a78d7ec --- /dev/null +++ b/dScripts/02_server/Pets/PetFromObjectServer.cpp @@ -0,0 +1,35 @@ +#include "PetFromObjectServer.h" +#include "PetComponent.h" +#include "ePetTamingNotifyType.h" + +void PetFromObjectServer::OnStartup(Entity* self) { + self->SetNetworkVar(u"pettamer", std::to_string(self->GetVar<LWOOBJID>(u"tamer"))); + self->AddTimer("killSelf", 45.0f); +} + +void PetFromObjectServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "killSelf") { + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + return; + self->Smash(self->GetObjectID(), eKillType::SILENT); + } +} + +void PetFromObjectServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) { + switch (type) { + case ePetTamingNotifyType::BEGIN: + self->CancelAllTimers(); + break; + case ePetTamingNotifyType::QUIT: + case ePetTamingNotifyType::FAILED: + self->Smash(self->GetObjectID(), eKillType::SILENT); + break; + case ePetTamingNotifyType::SUCCESS: + // TODO: Remove from groups? + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UpdateSuccessPicking", 0, + 0, tamer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + default: + break; + } +} diff --git a/dScripts/02_server/Pets/PetFromObjectServer.h b/dScripts/02_server/Pets/PetFromObjectServer.h new file mode 100644 index 00000000..67cd5eb0 --- /dev/null +++ b/dScripts/02_server/Pets/PetFromObjectServer.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class PetFromObjectServer : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) override; +}; diff --git a/dScripts/ActMine.h b/dScripts/ActMine.h deleted file mode 100644 index ae6ef17e..00000000 --- a/dScripts/ActMine.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class ActMine : public CppScripts::Script { - public: - void OnStartup(Entity* self) override; - void OnRebuildNotifyState(Entity* self, eRebuildState state) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnTimerDone(Entity* self, std::string timerName) override; - private: - int MAX_WARNINGS = 3; - float MINE_RADIUS = 10.0; - float TICK_TIME = 0.25; - float BLOWED_UP_TIME = 0.1; - uint32_t SKILL_ID = 317; - uint32_t BEHAVIOR_ID = 3719; -}; - diff --git a/dScripts/ActNinjaTurret.cpp b/dScripts/ActNinjaTurret.cpp deleted file mode 100644 index 8c361ad7..00000000 --- a/dScripts/ActNinjaTurret.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "ActNinjaTurret.h" - -void ActNinjaTurret::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == eRebuildState::REBUILD_COMPLETED) - { - self->SetVar(u"AmBuilt", true); - } - else if (state == eRebuildState::REBUILD_RESETTING) - { - self->SetVar(u"AmBuilt", false); - } -} - -void -ActNinjaTurret::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) -{ - if (args == "ISpawned" && self->GetVar<bool>(u"AmBuilt")) - { - sender->Smash(); - } -} diff --git a/dScripts/ActParadoxPipeFix.cpp b/dScripts/ActParadoxPipeFix.cpp deleted file mode 100644 index 2b592512..00000000 --- a/dScripts/ActParadoxPipeFix.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "ActParadoxPipeFix.h" -#include "EntityManager.h" -#include "RebuildComponent.h" -#include "GameMessages.h" -#include "MissionComponent.h" - -void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) -{ - const auto myGroup = "AllPipes"; - - const auto groupObjs = EntityManager::Instance()->GetEntitiesInGroup(myGroup); - - auto indexCount = 0; - - self->SetVar(u"PlayerID", target->GetObjectID()); - - for (auto* object : groupObjs) - { - if (object == self) - { - continue; - } - - auto* rebuildComponent = object->GetComponent<RebuildComponent>(); - - if (rebuildComponent->GetState() == REBUILD_COMPLETED) - { - indexCount++; - } - } - - if (indexCount >= 2) - { - const auto refinery = EntityManager::Instance()->GetEntitiesInGroup("Paradox"); - - if (!refinery.empty()) - { - GameMessages::SendPlayFXEffect(refinery[0]->GetObjectID(), 3999, u"create", "pipeFX"); - } - - for (auto* object : groupObjs) - { - auto* player = EntityManager::Instance()->GetEntity(object->GetVar<LWOOBJID>(u"PlayerID")); - - if (player != nullptr) - { - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->ForceProgressTaskType(769, 1, 1, false); - } - - GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, 0, false, 2.0f); - } - - object->SetVar(u"PlayerID", LWOOBJID_EMPTY); - } - } -} - -void ActParadoxPipeFix::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == REBUILD_RESETTING) - { - const auto refinery = EntityManager::Instance()->GetEntitiesInGroup("Paradox"); - - if (!refinery.empty()) - { - GameMessages::SendStopFXEffect(refinery[0], true, "pipeFX"); - } - } -} diff --git a/dScripts/ActVehicleDeathTrigger.cpp b/dScripts/ActVehicleDeathTrigger.cpp deleted file mode 100644 index 9a970a35..00000000 --- a/dScripts/ActVehicleDeathTrigger.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "ActVehicleDeathTrigger.h" -#include "PossessableComponent.h" -#include "GameMessages.h" -#include "RacingControlComponent.h" -#include "dZoneManager.h" -#include "EntityManager.h" -#include "PossessorComponent.h" - - -void ActVehicleDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) -{ - auto* possessableComponent = target->GetComponent<PossessableComponent>(); - - Entity* vehicle; - Entity* player; - - if (possessableComponent != nullptr) - { - auto* player = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - - if (player == nullptr) - { - return; - } - - return; - } - else if (target->IsPlayer()) - { - auto* possessorComponent = target->GetComponent<PossessorComponent>(); - - if (possessorComponent == nullptr) - { - return; - } - - vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - - if (vehicle == nullptr) - { - return; - } - - player = target; - } - else - { - return; - } - - - GameMessages::SendDie(vehicle, self->GetObjectID(), LWOOBJID_EMPTY, true, VIOLENT, u"", 0, 0, 0, true, false, 0); - - auto* zoneController = dZoneManager::Instance()->GetZoneControlObject(); - - auto* racingControlComponent = zoneController->GetComponent<RacingControlComponent>(); - - if (racingControlComponent != nullptr) - { - racingControlComponent->OnRequestDie(player); - } -} diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index e464b20d..078a7a02 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -5,216 +5,214 @@ #include "GameMessages.h" #include <algorithm> #include "dLogger.h" +#include "Loot.h" -bool ActivityManager::IsPlayerInActivity(Entity *self, LWOOBJID playerID) { - const auto* sac = self->GetComponent<ScriptedActivityComponent>(); - return sac != nullptr && sac->IsPlayedBy(playerID); +bool ActivityManager::IsPlayerInActivity(Entity* self, LWOOBJID playerID) { + const auto* sac = self->GetComponent<ScriptedActivityComponent>(); + return sac != nullptr && sac->IsPlayedBy(playerID); } -void ActivityManager::UpdatePlayer(Entity *self, LWOOBJID playerID, const bool remove) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return; +void ActivityManager::UpdatePlayer(Entity* self, LWOOBJID playerID, const bool remove) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return; - if (remove) { - sac->PlayerRemove(playerID); - } else { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - sac->PlayerJoin(player); - SetActivityScore(self, playerID, 0); - } - } + if (remove) { + sac->PlayerRemove(playerID); + } else { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + sac->PlayerJoin(player); + SetActivityScore(self, playerID, 0); + } + } } -void ActivityManager::SetActivityScore(Entity *self, LWOOBJID playerID, uint32_t score) { - SetActivityValue(self, playerID, 0, score); +void ActivityManager::SetActivityScore(Entity* self, LWOOBJID playerID, uint32_t score) { + SetActivityValue(self, playerID, 0, score); } -void ActivityManager::SetActivityValue(Entity *self, const LWOOBJID playerID, const uint32_t valueIndex, - const float_t value) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return; +void ActivityManager::SetActivityValue(Entity* self, const LWOOBJID playerID, const uint32_t valueIndex, + const float_t value) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return; - sac->SetActivityValue(playerID, valueIndex, value); + sac->SetActivityValue(playerID, valueIndex, value); } -float_t ActivityManager::GetActivityValue(Entity *self, const LWOOBJID playerID, const uint32_t valueIndex) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return -1.0f; +float_t ActivityManager::GetActivityValue(Entity* self, const LWOOBJID playerID, const uint32_t valueIndex) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return -1.0f; - return sac->GetActivityValue(playerID, valueIndex); + return sac->GetActivityValue(playerID, valueIndex); } -void ActivityManager::StopActivity(Entity *self, const LWOOBJID playerID, const uint32_t score, - const uint32_t value1, const uint32_t value2, bool quit) { - int32_t gameID = 0; - - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) { - gameID = self->GetLOT(); - } - else { - gameID = sac->GetActivityID(); - } +void ActivityManager::StopActivity(Entity* self, const LWOOBJID playerID, const uint32_t score, + const uint32_t value1, const uint32_t value2, bool quit) { + int32_t gameID = 0; - if (quit) { - UpdatePlayer(self, playerID, true); - } else { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - return; + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) { + gameID = self->GetLOT(); + } else { + gameID = sac->GetActivityID(); + } - SetActivityScore(self, playerID, score); - SetActivityValue(self, playerID, 1, value1); - SetActivityValue(self, playerID, 2, value2); + if (quit) { + UpdatePlayer(self, playerID, true); + } else { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + return; - LootGenerator::Instance().GiveActivityLoot(player, self, gameID, CalculateActivityRating(self, playerID)); + SetActivityScore(self, playerID, score); + SetActivityValue(self, playerID, 1, value1); + SetActivityValue(self, playerID, 2, value2); - // Save the new score to the leaderboard and show the leaderboard to the player - LeaderboardManager::SaveScore(playerID, gameID, score, value1); - const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, InfoType::Standings, - false, player->GetObjectID()); - GameMessages::SendActivitySummaryLeaderboardData(self->GetObjectID(), leaderboard, player->GetSystemAddress()); - delete leaderboard; + LootGenerator::Instance().GiveActivityLoot(player, self, gameID, CalculateActivityRating(self, playerID)); - // Makes the leaderboard show up for the player - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", - gameID,0, playerID, "", - player->GetSystemAddress()); + // Save the new score to the leaderboard and show the leaderboard to the player + LeaderboardManager::SaveScore(playerID, gameID, score, value1); + const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, InfoType::Standings, + false, player->GetObjectID()); + GameMessages::SendActivitySummaryLeaderboardData(self->GetObjectID(), leaderboard, player->GetSystemAddress()); + delete leaderboard; - if (sac != nullptr) { - sac->PlayerRemove(player->GetObjectID()); - } - } + // Makes the leaderboard show up for the player + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", + gameID, 0, playerID, "", + player->GetSystemAddress()); + + if (sac != nullptr) { + sac->PlayerRemove(player->GetObjectID()); + } + } } -bool ActivityManager::TakeActivityCost(const Entity *self, const LWOOBJID playerID) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return false; +bool ActivityManager::TakeActivityCost(const Entity* self, const LWOOBJID playerID) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return false; - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - return false; + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + return false; - return sac->TakeCost(player); + return sac->TakeCost(player); } -uint32_t ActivityManager::CalculateActivityRating(Entity *self, const LWOOBJID playerID) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return 0; +uint32_t ActivityManager::CalculateActivityRating(Entity* self, const LWOOBJID playerID) { + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) + return 0; - return sac->GetInstance(playerID)->GetParticipants().size(); + return sac->GetInstance(playerID)->GetParticipants().size(); } uint32_t ActivityManager::GetActivityID(const Entity* self) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - return sac != nullptr ? sac->GetActivityID() : 0; + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + return sac != nullptr ? sac->GetActivityID() : 0; } -void ActivityManager::GetLeaderboardData(Entity *self, const LWOOBJID playerID, const uint32_t activityID, uint32_t numResults) { - LeaderboardManager::SendLeaderboard(activityID, Standings, false, self->GetObjectID(), playerID); +void ActivityManager::GetLeaderboardData(Entity* self, const LWOOBJID playerID, const uint32_t activityID, uint32_t numResults) { + LeaderboardManager::SendLeaderboard(activityID, Standings, false, self->GetObjectID(), playerID); } -void ActivityManager::ActivityTimerStart(Entity *self, const std::string& timerName, const float_t updateInterval, - const float_t stopTime) { - auto* timer = new ActivityTimer { timerName, updateInterval, stopTime }; - activeTimers.push_back(timer); +void ActivityManager::ActivityTimerStart(Entity* self, const std::string& timerName, const float_t updateInterval, + const float_t stopTime) { + auto* timer = new ActivityTimer{ timerName, updateInterval, stopTime }; + activeTimers.push_back(timer); - Game::logger->Log("ActivityManager", "Starting timer '%s', %f, %f\n", timerName.c_str(), updateInterval, stopTime); + Game::logger->LogDebug("ActivityManager", "Starting timer '%s', %f, %f", timerName.c_str(), updateInterval, stopTime); - self->AddTimer(GetPrefixedName(timer->name), timer->updateInterval); + self->AddTimer(GetPrefixedName(timer->name), timer->updateInterval); } void ActivityManager::ActivityTimerStopAllTimers(Entity* self) { - for (auto* timer : activeTimers) { - self->CancelTimer(GetPrefixedName(timer->name)); - delete timer; - } + for (auto* timer : activeTimers) { + self->CancelTimer(GetPrefixedName(timer->name)); + delete timer; + } - activeTimers.clear(); + activeTimers.clear(); } -float_t ActivityManager::ActivityTimerGetCurrentTime(Entity *self, const std::string &timerName) const { - auto* timer = GetTimer(timerName); - return timer != nullptr ? timer->runTime : 0.0f; +float_t ActivityManager::ActivityTimerGetCurrentTime(Entity* self, const std::string& timerName) const { + auto* timer = GetTimer(timerName); + return timer != nullptr ? timer->runTime : 0.0f; } -int32_t ActivityManager::GetGameID(Entity *self) const -{ - int32_t gameID = 0; - - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) { - gameID = self->GetLOT(); - } - else { - gameID = sac->GetActivityID(); - } +int32_t ActivityManager::GetGameID(Entity* self) const { + int32_t gameID = 0; - return gameID; + auto* sac = self->GetComponent<ScriptedActivityComponent>(); + if (sac == nullptr) { + gameID = self->GetLOT(); + } else { + gameID = sac->GetActivityID(); + } + + return gameID; } -float_t ActivityManager::ActivityTimerGetRemainingTime(Entity *self, const std::string &timerName) const { - auto* timer = GetTimer(timerName); - return timer != nullptr ? std::min(timer->stopTime - timer->runTime, 0.0f) : 0.0f; +float_t ActivityManager::ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const { + auto* timer = GetTimer(timerName); + return timer != nullptr ? std::min(timer->stopTime - timer->runTime, 0.0f) : 0.0f; } -void ActivityManager::ActivityTimerReset(Entity *self, const std::string &timerName) { - auto* timer = GetTimer(timerName); - if (timer != nullptr) { - timer->runTime = 0.0f; - } +void ActivityManager::ActivityTimerReset(Entity* self, const std::string& timerName) { + auto* timer = GetTimer(timerName); + if (timer != nullptr) { + timer->runTime = 0.0f; + } } -ActivityTimer* ActivityManager::GetTimer(const std::string &name) const { - for (auto* timer : activeTimers) { - if (timer->name == name) - return timer; - } +ActivityTimer* ActivityManager::GetTimer(const std::string& name) const { + for (auto* timer : activeTimers) { + if (timer->name == name) + return timer; + } - return nullptr; + return nullptr; } -void ActivityManager::ActivityTimerStop(Entity *self, const std::string &timerName) { - auto* timer = GetTimer(timerName); - if (timer != nullptr) { - self->CancelTimer(GetPrefixedName(timer->name)); +void ActivityManager::ActivityTimerStop(Entity* self, const std::string& timerName) { + auto* timer = GetTimer(timerName); + if (timer != nullptr) { + self->CancelTimer(GetPrefixedName(timer->name)); - activeTimers.erase(std::remove(activeTimers.begin(), activeTimers.end(), timer), - activeTimers.end()); - delete timer; - } + activeTimers.erase(std::remove(activeTimers.begin(), activeTimers.end(), timer), + activeTimers.end()); + delete timer; + } } -std::string ActivityManager::GetPrefixedName(const std::string &name) const { - return TimerPrefix + "_" + name; +std::string ActivityManager::GetPrefixedName(const std::string& name) const { + return TimerPrefix + "_" + name; } -void ActivityManager::OnTimerDone(Entity *self, std::string timerName) { - auto nameSplit = GeneralUtils::SplitString(timerName, '_'); - if (nameSplit.size() > 1 && nameSplit.at(0) == TimerPrefix) { - const auto& activityTimerName = nameSplit.at(1); - auto* timer = GetTimer(activityTimerName); +void ActivityManager::OnTimerDone(Entity* self, std::string timerName) { + auto nameSplit = GeneralUtils::SplitString(timerName, '_'); + if (nameSplit.size() > 1 && nameSplit.at(0) == TimerPrefix) { + const auto& activityTimerName = nameSplit.at(1); + auto* timer = GetTimer(activityTimerName); - if (timer != nullptr) { - timer->runTime += timer->updateInterval; + if (timer != nullptr) { + timer->runTime += timer->updateInterval; - if (timer->stopTime != -1.0f && timer->runTime >= timer->stopTime) { - activeTimers.erase(std::remove(activeTimers.begin(), activeTimers.end(), timer), - activeTimers.end()); - delete timer; - Game::logger->Log("ActivityManager", "Executing timer '%s'\n", activityTimerName.c_str()); - OnActivityTimerDone(self, activityTimerName); - } else { - Game::logger->Log("ActivityManager", "Updating timer '%s'\n", activityTimerName.c_str()); - OnActivityTimerUpdate(self, timer->name, timer->stopTime - timer->runTime, timer->runTime); - self->AddTimer(GetPrefixedName(timer->name), timer->updateInterval); - } - } - } + if (timer->stopTime != -1.0f && timer->runTime >= timer->stopTime) { + activeTimers.erase(std::remove(activeTimers.begin(), activeTimers.end(), timer), + activeTimers.end()); + delete timer; + Game::logger->LogDebug("ActivityManager", "Executing timer '%s'", activityTimerName.c_str()); + OnActivityTimerDone(self, activityTimerName); + } else { + Game::logger->LogDebug("ActivityManager", "Updating timer '%s'", activityTimerName.c_str()); + OnActivityTimerUpdate(self, timer->name, timer->stopTime - timer->runTime, timer->runTime); + self->AddTimer(GetPrefixedName(timer->name), timer->updateInterval); + } + } + } } diff --git a/dScripts/ActivityManager.h b/dScripts/ActivityManager.h index 3b5783ad..640cf4bf 100644 --- a/dScripts/ActivityManager.h +++ b/dScripts/ActivityManager.h @@ -2,41 +2,41 @@ #include "CppScripts.h" struct ActivityTimer { - std::string name; - float_t updateInterval; - float_t stopTime; - float_t runTime = 0; + std::string name; + float_t updateInterval; + float_t stopTime; + float_t runTime = 0; }; class ActivityManager : public CppScripts::Script { public: - static bool IsPlayerInActivity(Entity *self, LWOOBJID playerID); - static void UpdatePlayer(Entity *self, LWOOBJID playerID, bool remove = false); - static void SetActivityScore(Entity *self, LWOOBJID playerID, uint32_t score); - static void SetActivityValue(Entity *self, LWOOBJID playerID, uint32_t valueIndex, float_t value); - static float_t GetActivityValue(Entity *self, LWOOBJID playerID, uint32_t valueIndex) ; - static bool TakeActivityCost(const Entity* self, LWOOBJID playerID); - static uint32_t GetActivityID(const Entity* self); - void StopActivity(Entity *self, LWOOBJID playerID, uint32_t score, uint32_t value1 = 0, uint32_t value2 = 0, bool quit = false); - virtual uint32_t CalculateActivityRating(Entity* self, LWOOBJID playerID); - static void GetLeaderboardData(Entity *self, LWOOBJID playerID, uint32_t activityID, uint32_t numResults = 0); -// void FreezePlayer(Entity *self, const LWOOBJID playerID, const bool state) const; + static bool IsPlayerInActivity(Entity* self, LWOOBJID playerID); + static void UpdatePlayer(Entity* self, LWOOBJID playerID, bool remove = false); + static void SetActivityScore(Entity* self, LWOOBJID playerID, uint32_t score); + static void SetActivityValue(Entity* self, LWOOBJID playerID, uint32_t valueIndex, float_t value); + static float_t GetActivityValue(Entity* self, LWOOBJID playerID, uint32_t valueIndex); + static bool TakeActivityCost(const Entity* self, LWOOBJID playerID); + static uint32_t GetActivityID(const Entity* self); + void StopActivity(Entity* self, LWOOBJID playerID, uint32_t score, uint32_t value1 = 0, uint32_t value2 = 0, bool quit = false); + virtual uint32_t CalculateActivityRating(Entity* self, LWOOBJID playerID); + static void GetLeaderboardData(Entity* self, LWOOBJID playerID, uint32_t activityID, uint32_t numResults = 0); + // void FreezePlayer(Entity *self, const LWOOBJID playerID, const bool state) const; - // Activity timer - void OnTimerDone(Entity *self, std::string timerName) override; - virtual void OnActivityTimerDone(Entity* self, const std::string& name) {}; - virtual void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) {}; - void ActivityTimerStart(Entity *self, const std::string& timerName, float_t updateInterval, float_t stopTime = -1.0f); - void ActivityTimerReset(Entity *self, const std::string& timerName); - void ActivityTimerStop(Entity* self, const std::string& timerName); - void ActivityTimerStopAllTimers(Entity* self); - float_t ActivityTimerGetRemainingTime(Entity *self, const std::string& timerName) const; - float_t ActivityTimerGetCurrentTime(Entity *self, const std::string& timerName) const; - int32_t GetGameID(Entity* self) const; + // Activity timer + void OnTimerDone(Entity* self, std::string timerName) override; + virtual void OnActivityTimerDone(Entity* self, const std::string& name) {}; + virtual void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) {}; + void ActivityTimerStart(Entity* self, const std::string& timerName, float_t updateInterval, float_t stopTime = -1.0f); + void ActivityTimerReset(Entity* self, const std::string& timerName); + void ActivityTimerStop(Entity* self, const std::string& timerName); + void ActivityTimerStopAllTimers(Entity* self); + float_t ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const; + float_t ActivityTimerGetCurrentTime(Entity* self, const std::string& timerName) const; + int32_t GetGameID(Entity* self) const; private: - std::string GetPrefixedName(const std::string& name) const; - [[nodiscard]] ActivityTimer* GetTimer(const std::string& name) const; - std::vector<ActivityTimer*> activeTimers {}; + std::string GetPrefixedName(const std::string& name) const; + [[nodiscard]] ActivityTimer* GetTimer(const std::string& name) const; + std::vector<ActivityTimer*> activeTimers{}; - std::string TimerPrefix = "ActivityTimer"; + std::string TimerPrefix = "ActivityTimer"; }; diff --git a/dScripts/AgBugsprayer.cpp b/dScripts/AgBugsprayer.cpp deleted file mode 100644 index cfea5cf4..00000000 --- a/dScripts/AgBugsprayer.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "AgBugsprayer.h" -#include "SkillComponent.h" - -void AgBugsprayer::OnRebuildComplete(Entity* self, Entity* target) -{ - self->AddTimer("castSkill", 1); - self->SetOwnerOverride(target->GetObjectID()); -} - -void AgBugsprayer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "castSkill") - { - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) return; - - skillComponent->CalculateBehavior(1435, 36581, LWOOBJID_EMPTY); - } -} \ No newline at end of file diff --git a/dScripts/AgDarkSpiderling.cpp b/dScripts/AgDarkSpiderling.cpp deleted file mode 100644 index 55ef62ec..00000000 --- a/dScripts/AgDarkSpiderling.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "AgDarkSpiderling.h" -#include "BaseCombatAIComponent.h" - -void AgDarkSpiderling::OnStartup(Entity *self) { - auto* combatAI = self->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetStunImmune(true); - } -} diff --git a/dScripts/AgJetEffectServer.cpp b/dScripts/AgJetEffectServer.cpp deleted file mode 100644 index 599f4d01..00000000 --- a/dScripts/AgJetEffectServer.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "AgJetEffectServer.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "SkillComponent.h" - -void AgJetEffectServer::OnUse(Entity* self, Entity* user) -{ - if (inUse) - { - return; - } - - GameMessages::SendNotifyClientObject( - self->GetObjectID(), - u"isInUse", - 0, - 0, - LWOOBJID_EMPTY, - "", - UNASSIGNED_SYSTEM_ADDRESS - ); - - inUse = true; - - auto entities = EntityManager::Instance()->GetEntitiesInGroup("Jet_FX"); - - if (entities.empty()) - { - return; - } - - auto* effect = entities[0]; - - GameMessages::SendPlayFXEffect(effect, 641, u"create", "radarDish", LWOOBJID_EMPTY, 1, 1, true); - - self->AddTimer("radarDish", 2); - self->AddTimer("CineDone", 9); -} - -void AgJetEffectServer::OnRebuildComplete(Entity* self, Entity* target) -{ - auto entities = EntityManager::Instance()->GetEntitiesInGroup("Jet_FX"); - - if (entities.empty()) - { - return; - } - - auto* effect = entities[0]; - - auto groups = self->GetGroups(); - - if (groups.empty()) - { - return; - } - - builder = target->GetObjectID(); - - const auto group = groups[0]; - - GameMessages::SendPlayAnimation(effect, u"jetFX"); - - self->AddTimer("PlayEffect", 2.5f); - - if (group == "Base_Radar") - { - self->AddTimer("CineDone", 5); - } -} - -void AgJetEffectServer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "radarDish") - { - GameMessages::SendStopFXEffect(self, true, "radarDish"); - - return; - } - - if (timerName == "PlayEffect") - { - auto entities = EntityManager::Instance()->GetEntitiesInGroup("mortarMain"); - - if (entities.empty()) - { - return; - } - - const auto size = entities.size(); - - if (size == 0) - { - return; - } - - const auto selected = GeneralUtils::GenerateRandomNumber<int>(0, size - 1); - - auto* mortar = entities[selected]; - - Game::logger->Log("AgJetEffectServer", "Mortar (%i) (&d)\n", mortar->GetLOT(), mortar->HasComponent(COMPONENT_TYPE_SKILL)); - - mortar->SetOwnerOverride(builder); - - SkillComponent* skillComponent; - if (!mortar->TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) - { - return; - } - - skillComponent->CalculateBehavior(318, 3727, LWOOBJID_EMPTY, true); - - return; - } - - if (timerName == "CineDone") - { - GameMessages::SendNotifyClientObject( - self->GetObjectID(), - u"toggleInUse", - -1, - 0, - LWOOBJID_EMPTY, - "", - UNASSIGNED_SYSTEM_ADDRESS - ); - - inUse = false; - } -} diff --git a/dScripts/AgMonumentRaceCancel.cpp b/dScripts/AgMonumentRaceCancel.cpp deleted file mode 100644 index 205aee57..00000000 --- a/dScripts/AgMonumentRaceCancel.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "AgMonumentRaceCancel.h" -#include "EntityManager.h" - -void AgMonumentRaceCancel::OnCollisionPhantom(Entity *self, Entity *target) { - auto managers = EntityManager::Instance()->GetEntitiesInGroup("race_manager"); - if (!managers.empty()) { - managers[0]->OnFireEventServerSide(target, "course_cancel"); - } -} diff --git a/dScripts/AgMonumentRaceGoal.cpp b/dScripts/AgMonumentRaceGoal.cpp deleted file mode 100644 index 13122695..00000000 --- a/dScripts/AgMonumentRaceGoal.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "AgMonumentRaceGoal.h" -#include "EntityManager.h" - - -void AgMonumentRaceGoal::OnStartup(Entity* self) -{ - self->SetProximityRadius(15, "RaceGoal"); -} - -void AgMonumentRaceGoal::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (name == "RaceGoal" && entering->IsPlayer() && status == "ENTER") - { - auto* manager = EntityManager::Instance()->GetEntitiesInGroup("race_manager")[0]; - - manager->OnFireEventServerSide(entering, "course_finish"); - } -} diff --git a/dScripts/AgPicnicBlanket.cpp b/dScripts/AgPicnicBlanket.cpp deleted file mode 100644 index 3d13cb40..00000000 --- a/dScripts/AgPicnicBlanket.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "AgPicnicBlanket.h" -#include "GameMessages.h" - -void AgPicnicBlanket::OnUse(Entity *self, Entity *user) { - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); - if (self->GetVar<bool>(u"active")) - return; - self->SetVar<bool>(u"active", true); - - auto lootTable = std::unordered_map<LOT, int32_t> {{935, 3}}; - LootGenerator::Instance().DropLoot(user, self, lootTable, 0, 0); - - self->AddCallbackTimer(5.0f, [self]() { - self->SetVar<bool>(u"active", false); - }); -} diff --git a/dScripts/AgPropGuard.cpp b/dScripts/AgPropGuard.cpp deleted file mode 100644 index b05eef4f..00000000 --- a/dScripts/AgPropGuard.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "AgPropGuard.h" -#include "Entity.h" -#include "Character.h" -#include "EntityManager.h" -#include "InventoryComponent.h" -#include "MissionComponent.h" -#include "Item.h" - -void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - auto* character = target->GetCharacter(); - auto* missionComponent = target->GetComponent<MissionComponent>(); - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - - const auto state = missionComponent->GetMissionState(320); - if (missionID == 768 && missionState == MissionState::MISSION_STATE_AVAILABLE) - { - if (!character->GetPlayerFlag(71)) - { - // TODO: Cinematic "MissionCam" - } - } - else if (missionID == 768 && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) - { - //remove the inventory items - for (int item : gearSets) - { - auto* id = inventoryComponent->FindItemByLot(item); - - if (id) - { - inventoryComponent->UnEquipItem(id); - inventoryComponent->RemoveItem(id->GetLot(), id->GetCount()); - } - } - } - else if ( - (missionID == 320 && state == MissionState::MISSION_STATE_AVAILABLE) /*|| - (state == MissionState::MISSION_STATE_COMPLETE && missionID == 891 && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE)*/ - ) - { - //GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", target->GetObjectID(), 0, target->GetObjectID(), "", target->GetSystemAddress()); - - target->GetCharacter()->SetPlayerFlag(113, true); - - EntityManager::Instance()->GetZoneControlEntity()->AddTimer("GuardFlyAway", 1.0f); - } -} diff --git a/dScripts/AgPropguards.cpp b/dScripts/AgPropguards.cpp deleted file mode 100644 index 4170defe..00000000 --- a/dScripts/AgPropguards.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "AgPropguards.h" -#include "Character.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "dZoneManager.h" - -void AgPropguards::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - auto* character = target->GetCharacter(); - if (character == nullptr) - return; - - const auto flag = GetFlagForMission(missionID); - if (flag == 0) - return; - - if ((missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_ACTIVE) - && !character->GetPlayerFlag(flag)) { - // If the player just started the mission, play a cinematic highlighting the target - GameMessages::SendPlayCinematic(target->GetObjectID(), u"MissionCam", target->GetSystemAddress()); - } else if (missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { - // Makes the guard disappear once the mission has been completed - const auto zoneControlID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); - GameMessages::SendNotifyClientObject(zoneControlID, u"GuardChat", 0, 0, self->GetObjectID(), - "", UNASSIGNED_SYSTEM_ADDRESS); - - self->AddCallbackTimer(5.0f, [self]() { - auto spawnerName = self->GetVar<std::string>(u"spawner_name"); - if (spawnerName.empty()) - spawnerName = "Guard"; - - auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - for (auto* spawner : spawners) { - spawner->Deactivate(); - } - - self->Smash(); - }); - } -} - -uint32_t AgPropguards::GetFlagForMission(uint32_t missionID) { - switch (missionID) { - case 872: - return 97; - case 873: - return 98; - case 874: - return 99; - case 1293: - return 118; - case 1322: - return 122; - default: - return 0; - } -} diff --git a/dScripts/AgPropguards.h b/dScripts/AgPropguards.h deleted file mode 100644 index 710096ce..00000000 --- a/dScripts/AgPropguards.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AgPropguards : public CppScripts::Script { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; -private: - static uint32_t GetFlagForMission(uint32_t missionID); -}; diff --git a/dScripts/AgStagePlatforms.cpp b/dScripts/AgStagePlatforms.cpp deleted file mode 100644 index cb401647..00000000 --- a/dScripts/AgStagePlatforms.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "AgStagePlatforms.h" -#include "MovingPlatformComponent.h" - -void AgStagePlatforms::OnStartup(Entity *self) { - auto* component = self->GetComponent<MovingPlatformComponent>(); - if (component) { - component->SetNoAutoStart(true); - component->StopPathing(); - } -} - -void AgStagePlatforms::OnWaypointReached(Entity* self, uint32_t waypointIndex) { - auto* component = self->GetComponent<MovingPlatformComponent>(); - if (waypointIndex == 0 && component) - component->StopPathing(); -} diff --git a/dScripts/AgStagePlatforms.h b/dScripts/AgStagePlatforms.h deleted file mode 100644 index e315664a..00000000 --- a/dScripts/AgStagePlatforms.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AgStagePlatforms : public CppScripts::Script { -public: - void OnStartup(Entity* self) override; - void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; -}; diff --git a/dScripts/AgStromlingProperty.cpp b/dScripts/AgStromlingProperty.cpp deleted file mode 100644 index b1b8d45f..00000000 --- a/dScripts/AgStromlingProperty.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "AgStromlingProperty.h" -#include "MovementAIComponent.h" - -void AgStromlingProperty::OnStartup(Entity *self) { - auto movementInfo = MovementAIInfo { - "Wander", - 71, - 3, - 100, - 1, - 4 - }; - - auto* movementAIComponent = new MovementAIComponent(self, movementInfo); - self->AddComponent(COMPONENT_TYPE_MOVEMENT_AI, movementAIComponent); -} diff --git a/dScripts/AgSurvivalBuffStation.cpp b/dScripts/AgSurvivalBuffStation.cpp deleted file mode 100644 index 8a6cfb05..00000000 --- a/dScripts/AgSurvivalBuffStation.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "AgSurvivalBuffStation.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "SkillComponent.h" -#include "TeamManager.h" - -void AgSurvivalBuffStation::OnRebuildComplete(Entity* self, Entity* target) { - auto destroyableComponent = self->GetComponent<DestroyableComponent>(); - // We set the faction to 1 so that the buff station sees players as friendly targets to buff - if (destroyableComponent != nullptr) destroyableComponent->SetFaction(1); - - auto skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) skillComponent->CalculateBehavior(skillIdForBuffStation, behaviorIdForBuffStation, self->GetObjectID()); - - self->AddCallbackTimer(smashTimer, [self]() { - self->Smash(); - }); - self->AddTimer("DropArmor", dropArmorTimer); - self->AddTimer("DropLife", dropLifeTimer); - self->AddTimer("Dropimagination", dropImaginationTimer); - // Since all survival players should be on the same team, we get the team. - auto team = TeamManager::Instance()->GetTeam(target->GetObjectID()); - - std::vector<LWOOBJID> builderTeam; - // Not on a team - if (team == nullptr) { - builderTeam.push_back(target->GetObjectID()); - self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", builderTeam); - return; - } - - for (auto memberID : team->members) { - builderTeam.push_back(memberID); - } - self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", builderTeam); -} - -void AgSurvivalBuffStation::OnTimerDone(Entity* self, std::string timerName) { - uint32_t powerupToDrop = lifePowerup; - if (timerName == "DropArmor") { - powerupToDrop = armorPowerup; - self->AddTimer("DropArmor", dropArmorTimer); - } - if (timerName == "DropLife") { - powerupToDrop = lifePowerup; - self->AddTimer("DropLife", dropLifeTimer); - } - if (timerName == "Dropimagination") { - powerupToDrop = imaginationPowerup; - self->AddTimer("Dropimagination", dropImaginationTimer); - } - auto team = self->GetVar<std::vector<LWOOBJID>>(u"BuilderTeam"); - for (auto memberID : team) { - auto member = EntityManager::Instance()->GetEntity(memberID); - if (member != nullptr && !member->GetIsDead()) { - GameMessages::SendDropClientLoot(member, self->GetObjectID(), powerupToDrop, 0, self->GetPosition()); - } else { - // If player left the team or left early erase them from the team variable. - team.erase(std::find(team.begin(), team.end(), memberID)); - self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", team); - } - } -} diff --git a/dScripts/AgSurvivalBuffStation.h b/dScripts/AgSurvivalBuffStation.h deleted file mode 100644 index b2beaba6..00000000 --- a/dScripts/AgSurvivalBuffStation.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AgSurvivalBuffStation : public CppScripts::Script -{ -public: - /** - * @brief When the rebuild of self is complete, we calculate the behavior that is assigned to self in the database. - * - * @param self The Entity that called this script. - * @param target The target of the self that called this script. - */ - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; -private: - /** - * Skill ID for the buff station. - */ - uint32_t skillIdForBuffStation = 201; - /** - * Behavior ID for the buff station. - */ - uint32_t behaviorIdForBuffStation = 1784; - /** - * Timer for dropping armor. - */ - float dropArmorTimer = 6.0f; - /** - * Timer for dropping life. - */ - float dropLifeTimer = 3.0f; - /** - * Timer for dropping imagination. - */ - float dropImaginationTimer = 4.0f; - /** - * Timer for smashing. - */ - float smashTimer = 25.0f; - /** - * LOT for armor powerup. - */ - LOT armorPowerup = 6431; - /** - * LOT for life powerup. - */ - LOT lifePowerup = 177; - /** - * LOT for imagination powerup. - */ - LOT imaginationPowerup = 935; -}; \ No newline at end of file diff --git a/dScripts/AgSurvivalMech.cpp b/dScripts/AgSurvivalMech.cpp deleted file mode 100644 index e31c8aba..00000000 --- a/dScripts/AgSurvivalMech.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "AgSurvivalMech.h" -#include "DestroyableComponent.h" - -void AgSurvivalMech::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - auto* destroyable = self->GetComponent<DestroyableComponent>(); - if (destroyable != nullptr) { - destroyable->SetFaction(4); - } -} - -uint32_t AgSurvivalMech::GetPoints() { - return 200; -} diff --git a/dScripts/AgSurvivalSpiderling.cpp b/dScripts/AgSurvivalSpiderling.cpp deleted file mode 100644 index d44455d8..00000000 --- a/dScripts/AgSurvivalSpiderling.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "AgSurvivalSpiderling.h" -#include "BaseCombatAIComponent.h" - -void AgSurvivalSpiderling::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - auto* combatAI = self->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetStunImmune(true); - } -} - -uint32_t AgSurvivalSpiderling::GetPoints() { - return 300; -} diff --git a/dScripts/AmBlueX.cpp b/dScripts/AmBlueX.cpp deleted file mode 100644 index db464186..00000000 --- a/dScripts/AmBlueX.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "AmBlueX.h" -#include "SkillComponent.h" -#include "EntityManager.h" -#include "Character.h" - -void AmBlueX::OnUse(Entity *self, Entity *user) { - auto* skillComponent = user->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->CalculateBehavior(m_SwordSkill, m_SwordBehavior, self->GetObjectID()); - } -} - -void AmBlueX::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - if (message == "FireDukesStrike") { - self->SetNetworkVar<bool>(m_XUsedVariable, true); - self->SetNetworkVar<bool>(m_StartEffectVariable, true); - - auto* character = caster->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(self->GetVar<int32_t>(m_FlagVariable), true); - } - - EntityInfo info {}; - info.lot = m_FXObject; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.spawnerID = self->GetObjectID(); - - auto* fxObject = EntityManager::Instance()->CreateEntity(info, nullptr, self); - EntityManager::Instance()->ConstructEntity(fxObject); - - auto fxObjectID = fxObject->GetObjectID(); - auto playerID = caster->GetObjectID(); - - // Add a callback for the bomb to explode - self->AddCallbackTimer(m_BombTime, [this, self, fxObjectID, playerID]() { - auto* fxObject = EntityManager::Instance()->GetEntity(fxObjectID); - auto* player = EntityManager::Instance()->GetEntity(playerID); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - return; - - // Cast the skill that destroys the object - if (player != nullptr) { - skillComponent->CalculateBehavior(m_AOESkill, m_AOEBehavior, LWOOBJID_EMPTY, false, false, playerID); - } else { - skillComponent->CalculateBehavior(m_AOESkill, m_AOEBehavior, LWOOBJID_EMPTY); - } - - fxObject->Smash(); - self->Smash(); - }); - } -} diff --git a/dScripts/AmBlueX.h b/dScripts/AmBlueX.h deleted file mode 100644 index 99f6ede4..00000000 --- a/dScripts/AmBlueX.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmBlueX : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; - void OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) override; -private: - const float_t m_BombTime = 3.3f; - const uint32_t m_MissionID = 1448; - const uint32_t m_SwordSkill = 1259; - const uint32_t m_SwordBehavior = 29305; - const uint32_t m_AOESkill = 1258; - const uint32_t m_AOEBehavior = 29301; - const LOT m_FXObject = 13808; - - // Variables - const std::u16string m_XUsedVariable = u"XUsed"; - const std::u16string m_FlagVariable = u"flag"; - const std::u16string m_StartEffectVariable = u"startEffect"; -}; diff --git a/dScripts/AmBridge.cpp b/dScripts/AmBridge.cpp deleted file mode 100644 index e2e21033..00000000 --- a/dScripts/AmBridge.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "AmBridge.h" -#include "EntityManager.h" - -void AmBridge::OnStartup(Entity* self) -{ - -} - -void AmBridge::OnRebuildComplete(Entity* self, Entity* target) -{ - const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console" + GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"bridge"))); - - if (consoles.empty()) - { - return; - } - - auto* console = consoles[0]; - - console->NotifyObject(self, "BridgeBuilt"); - - self->AddTimer("SmashBridge", 50); -} - -void AmBridge::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName != "SmashBridge") - { - return; - } - - self->Smash(self->GetObjectID(), VIOLENT); -} diff --git a/dScripts/AmBridge.h b/dScripts/AmBridge.h deleted file mode 100644 index bae35624..00000000 --- a/dScripts/AmBridge.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmBridge : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; -}; diff --git a/dScripts/AmConsoleTeleportServer.cpp b/dScripts/AmConsoleTeleportServer.cpp deleted file mode 100644 index 5087aae2..00000000 --- a/dScripts/AmConsoleTeleportServer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "AmConsoleTeleportServer.h" -#include "ChooseYourDestinationNsToNt.h" -#include "AMFFormat.h" - -void AmConsoleTeleportServer::OnStartup(Entity* self) -{ - self->SetVar(u"teleportAnim", m_TeleportAnim); - self->SetVar(u"teleportString", m_TeleportString); - self->SetVar(u"teleportEffectID", m_TeleportEffectID); - self->SetVar(u"teleportEffectTypes", m_TeleportEffectTypes); -} - -void AmConsoleTeleportServer::OnUse(Entity* self, Entity* user) -{ - BaseOnUse(self, user); -} - -void AmConsoleTeleportServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - BaseOnMessageBoxResponse(self, sender, button, identifier, userData); -} - -void AmConsoleTeleportServer::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - -} - -void AmConsoleTeleportServer::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); -} - -void AmConsoleTeleportServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); -} diff --git a/dScripts/AmConsoleTeleportServer.h b/dScripts/AmConsoleTeleportServer.h deleted file mode 100644 index 8236e67e..00000000 --- a/dScripts/AmConsoleTeleportServer.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseConsoleTeleportServer.h" - -class AmConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - -private: - int32_t m_ChoiceZoneID = 1900; - std::string m_SpawnPoint = "NS_LW"; - std::u16string m_TeleportAnim = u"nexus-teleport"; - std::u16string m_TeleportString = u"UI_TRAVEL_TO_NEXUS_TOWER"; - int32_t m_TeleportEffectID = 6478; - std::vector<std::u16string> m_TeleportEffectTypes = {u"teleportRings", u"teleportBeam"}; -}; diff --git a/dScripts/AmDarklingDragon.cpp b/dScripts/AmDarklingDragon.cpp deleted file mode 100644 index 94066167..00000000 --- a/dScripts/AmDarklingDragon.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "AmDarklingDragon.h" -#include "BaseCombatAIComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "SkillComponent.h" -#include "BaseCombatAIComponent.h" - -void AmDarklingDragon::OnStartup(Entity* self) { - self->SetVar<int32_t>(u"weakspot", 0); - - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - - if (baseCombatAIComponent != nullptr) { - baseCombatAIComponent->SetStunImmune(true); - } -} - -void AmDarklingDragon::OnDie(Entity* self, Entity* killer) { - if (self->GetVar<bool>(u"bDied")) { - return; - } - - self->SetVar<bool>(u"bDied", true); - - auto golemId = self->GetVar<LWOOBJID>(u"Golem"); - - auto* golem = EntityManager::Instance()->GetEntity(golemId); - - if (golem != nullptr) { - golem->Smash(self->GetObjectID()); - } -} - -void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { - GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); - - if (true) { - auto weakpoint = self->GetVar<int32_t>(u"weakspot"); - - if (weakpoint == 1) - { - self->Smash(attacker->GetObjectID()); - } - } - - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) { - if (destroyableComponent->GetArmor() > 0) return; - - auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); - - if (weakpoint == 0) { - self->AddTimer("ReviveTimer", 12); - - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (baseCombatAIComponent != nullptr) { - baseCombatAIComponent->SetDisabled(true); - baseCombatAIComponent->SetStunned(true); - } - - if (skillComponent != nullptr) { - skillComponent->Interrupt(); - } - - self->SetVar<int32_t>(u"weakpoint", 2); - - GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); - - self->AddTimer("timeToStunLoop", 1); - - auto position = self->GetPosition(); - auto forward = self->GetRotation().GetForwardVector(); - auto backwards = forward * -1; - - forward.x *= 10; - forward.z *= 10; - - auto rotation = self->GetRotation(); - - auto objectPosition = NiPoint3(); - - objectPosition.y = position.y; - objectPosition.x = position.x - (backwards.x * 8); - objectPosition.z = position.z - (backwards.z * 8); - - auto golem = self->GetVar<int32_t>(u"DragonSmashingGolem"); - - EntityInfo info {}; - info.lot = golem != 0 ? golem : 8340; - info.pos = objectPosition; - info.rot = rotation; - info.spawnerID = self->GetObjectID(); - info.settings = { - new LDFData<std::string>(u"rebuild_activators", - std::to_string(objectPosition.x + forward.x) + "\x1f" + - std::to_string(objectPosition.y) + "\x1f" + - std::to_string(objectPosition.z + forward.z) - ), - new LDFData<int32_t>(u"respawn", 100000), - new LDFData<float>(u"rebuild_reset_time", 15), - new LDFData<bool>(u"no_timed_spawn", true), - new LDFData<LWOOBJID>(u"Dragon", self->GetObjectID()) - }; - - auto* golemObject = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(golemObject); - } - } -} - -void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "ReviveHeldTimer") { - self->AddTimer("backToAttack", 2.5); - } - else if (timerName == "ExposeWeakSpotTimer") { - self->SetVar<int32_t>(u"weakspot", 1); - } - else if (timerName == "timeToStunLoop") { - GameMessages::SendPlayAnimation(self, u"stunloop", 1.8f); - } - else if (timerName == "ReviveTimer") { - GameMessages::SendPlayAnimation(self, u"stunend", 2.0f); - self->AddTimer("backToAttack", 1); - } - else if (timerName == "backToAttack") { - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->SetDisabled(false); - baseCombatAIComponent->SetStunned(false); - } - if (skillComponent != nullptr) - { - skillComponent->Interrupt(); - } - self->SetVar<int32_t>(u"weakspot", -1); - GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); - } -} - -void AmDarklingDragon::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { - if (args != "rebuildDone") return; - - self->AddTimer("ExposeWeakSpotTimer", 3.8f); - - self->CancelTimer("ReviveTimer"); - - self->AddTimer("ReviveHeldTimer", 10.5f); - - self->SetVar<LWOOBJID>(u"Golem", sender->GetObjectID()); - - GameMessages::SendPlayAnimation(self, u"quickbuildhold", 1.9f); -} \ No newline at end of file diff --git a/dScripts/AmDarklingDragon.h b/dScripts/AmDarklingDragon.h deleted file mode 100644 index ea4c2a19..00000000 --- a/dScripts/AmDarklingDragon.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmDarklingDragon : public CppScripts::Script -{ -public: - /** - * @brief When called, this function will make self immune to stuns and initialize a weakspot boolean to false. - * - * @param self The Entity that called this function. - */ - void OnStartup(Entity* self) override; - /** - * @brief When called, this function will destroy the golem if it was alive, otherwise returns immediately. - * - * @param self The Entity that called this function. - * @param killer The Entity that killed self. - */ - void OnDie(Entity* self, Entity* killer) override; - /** - * @brief When self is hit or healed, this function will check if self is at zero armor. If self is at zero armor, a golem Entity Quick Build - * is spawned that, when built, will reveal a weakpoint on the dragon that if hit will smash the dragon instantly. If at more than zero armor, - * this function returns early. - * - * @param self The Entity that was hit. - * @param attacker The Entity that attacked self. - * @param damage The amount of damage attacker did to self. - */ - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; - /** - * @brief Called when self has a timer that ended. - * - * @param self The Entity who owns a timer that finished. - * @param timerName The name of a timer attacked to self that has ended. - */ - void OnTimerDone(Entity* self, std::string timerName) override; - /** - * @brief When the Client has finished rebuilding the Golem for the dragon, this function exposes the weak spot for a set amount of time. - * - * @param self The Entity that called this script. - * @param sender The Entity that sent a fired event. - * @param args The argument that tells us what event has been fired off. - * @param param1 Unused in this script. - * @param param2 Unused in this script. - * @param param3 Unused in this script. - */ - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; -}; diff --git a/dScripts/AmDarklingMech.cpp b/dScripts/AmDarklingMech.cpp deleted file mode 100644 index 33c3fcbf..00000000 --- a/dScripts/AmDarklingMech.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "AmDarklingMech.h" - -void AmDarklingMech::OnStartup(Entity* self) -{ - BaseEnemyMech::OnStartup(self); - qbTurretLOT = 13171; -} diff --git a/dScripts/AmDrawBridge.cpp b/dScripts/AmDrawBridge.cpp deleted file mode 100644 index 8e52e3e4..00000000 --- a/dScripts/AmDrawBridge.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "AmDrawBridge.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "SimplePhysicsComponent.h" - -void AmDrawBridge::OnStartup(Entity* self) -{ - self->SetNetworkVar(u"InUse", false); - self->SetVar(u"BridgeDown", false); -} - -void AmDrawBridge::OnUse(Entity* self, Entity* user) -{ - auto* bridge = GetBridge(self); - - if (bridge == nullptr) - { - return; - } - - if (!self->GetNetworkVar<bool>(u"InUse")) - { - self->SetNetworkVar(u"startEffect", 5); - - self->AddTimer("ChangeBridge", 5); - - self->SetNetworkVar(u"InUse", true); - } - - auto* player = user; - - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} - -void AmDrawBridge::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "ChangeBridge") - { - auto* bridge = GetBridge(self); - - if (bridge == nullptr) - { - return; - } - - if (!self->GetVar<bool>(u"BridgeDown")) - { - self->SetVar(u"BridgeDown", true); - - MoveBridgeDown(self, bridge, true); - } - else - { - self->SetVar(u"BridgeDown", false); - - MoveBridgeDown(self, bridge, false); - } - - self->SetNetworkVar(u"BridgeLeaving", true); - self->SetVar(u"BridgeDown", false); - } - else if (timerName == "SmashEffectBridge") - { - self->SetNetworkVar(u"SmashBridge", 5); - } - else if (timerName == "rotateBridgeDown") - { - auto* bridge = GetBridge(self); - - if (bridge == nullptr) - { - return; - } - - self->SetNetworkVar(u"BridgeLeaving", false); - - auto* simplePhysicsComponent = bridge->GetComponent<SimplePhysicsComponent>(); - - if (simplePhysicsComponent == nullptr) - { - return; - } - - simplePhysicsComponent->SetAngularVelocity(NiPoint3::ZERO); - - EntityManager::Instance()->SerializeEntity(bridge); - } -} - -void AmDrawBridge::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) -{ - if (name == "BridgeBuilt") - { - self->SetVar(u"BridgeID", sender->GetObjectID()); - - self->AddTimer("SmashEffectBridge", 45); - - self->SetNetworkVar(u"BridgeDead", true); - - sender->AddDieCallback([this, self, sender] () { - NotifyDie(self, sender); - }); - } -} - -void AmDrawBridge::MoveBridgeDown(Entity* self, Entity* bridge, bool down) -{ - auto* simplePhysicsComponent = bridge->GetComponent<SimplePhysicsComponent>(); - - if (simplePhysicsComponent == nullptr) - { - return; - } - - auto forwardVect = simplePhysicsComponent->GetRotation().GetForwardVector(); - - auto degrees = down ? 90.0f : -90.0f; - - const auto travelTime = 2.0f; - - forwardVect = forwardVect * (float) ((degrees / travelTime) * (3.14f / 180.0f)); - - simplePhysicsComponent->SetAngularVelocity(forwardVect); - - EntityManager::Instance()->SerializeEntity(bridge); - - self->AddTimer("rotateBridgeDown", travelTime); -} - -void AmDrawBridge::NotifyDie(Entity* self, Entity* other) -{ - self->SetNetworkVar(u"InUse", false); - self->SetVar(u"BridgeDown", false); - - self->CancelAllTimers(); -} - -Entity* AmDrawBridge::GetBridge(Entity* self) -{ - const auto bridgeID = self->GetVar<LWOOBJID>(u"BridgeID"); - - return EntityManager::Instance()->GetEntity(bridgeID); -} diff --git a/dScripts/AmDrawBridge.h b/dScripts/AmDrawBridge.h deleted file mode 100644 index e7b801df..00000000 --- a/dScripts/AmDrawBridge.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmDrawBridge : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; - - void MoveBridgeDown(Entity* self, Entity* bridge, bool down); - void NotifyDie(Entity* self, Entity* other); - - Entity* GetBridge(Entity* self); -}; diff --git a/dScripts/AmDropshipComputer.cpp b/dScripts/AmDropshipComputer.cpp deleted file mode 100644 index d25bd4f2..00000000 --- a/dScripts/AmDropshipComputer.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "AmDropshipComputer.h" -#include "MissionComponent.h" -#include "RebuildComponent.h" -#include "InventoryComponent.h" -#include "dZoneManager.h" - -void AmDropshipComputer::OnStartup(Entity* self) -{ - self->AddTimer("reset", 45.0f); -} - -void AmDropshipComputer::OnUse(Entity* self, Entity* user) -{ - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent == nullptr || rebuildComponent->GetState() != REBUILD_COMPLETED) - { - return; - } - - auto* missionComponent = user->GetComponent<MissionComponent>(); - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - - if (missionComponent == nullptr || inventoryComponent == nullptr) - { - return; - } - - if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == MissionState::MISSION_STATE_COMPLETE) - { - return; - } - - inventoryComponent->AddItem(m_NexusTalonDataCard, 1, eLootSourceType::LOOT_SOURCE_NONE); -} - -void AmDropshipComputer::OnDie(Entity* self, Entity* killer) -{ - const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); - - int32_t pipeNum = 0; - if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) - { - return; - } - - const auto pipeGroup = myGroup.substr(0, 10); - - const auto nextPipeNum = pipeNum + 1; - - const auto samePipeSpawners = dZoneManager::Instance()->GetSpawnersByName(myGroup); - - if (!samePipeSpawners.empty()) - { - samePipeSpawners[0]->SoftReset(); - - samePipeSpawners[0]->Deactivate(); - } - - if (killer != nullptr && killer->IsPlayer()) - { - const auto nextPipe = pipeGroup + std::to_string(nextPipeNum); - - const auto nextPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); - - if (!nextPipeSpawners.empty()) - { - nextPipeSpawners[0]->Activate(); - } - } - else - { - const auto nextPipe = pipeGroup + "1"; - - const auto firstPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); - - if (!firstPipeSpawners.empty()) - { - firstPipeSpawners[0]->Activate(); - } - } -} - -void AmDropshipComputer::OnTimerDone(Entity* self, std::string timerName) -{ - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent == nullptr) - { - return; - } - - if (timerName == "reset" && rebuildComponent->GetState() == REBUILD_OPEN) - { - self->Smash(self->GetObjectID(), SILENT); - } -} diff --git a/dScripts/AmDropshipComputer.h b/dScripts/AmDropshipComputer.h deleted file mode 100644 index 620770af..00000000 --- a/dScripts/AmDropshipComputer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmDropshipComputer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnDie(Entity* self, Entity* killer) override; - void OnTimerDone(Entity* self, std::string timerName) override; -private: - const LOT m_NexusTalonDataCard = 12323; -}; diff --git a/dScripts/AmScrollReaderServer.cpp b/dScripts/AmScrollReaderServer.cpp deleted file mode 100644 index 280833c2..00000000 --- a/dScripts/AmScrollReaderServer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "AmScrollReaderServer.h" -#include "MissionComponent.h" - -void AmScrollReaderServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - if (identifier == u"story_end") - { - auto* missionComponent = sender->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - return; - } - - missionComponent->ForceProgressTaskType(969, 1, 1, false); - } -} diff --git a/dScripts/AmScrollReaderServer.h b/dScripts/AmScrollReaderServer.h deleted file mode 100644 index b9e5943d..00000000 --- a/dScripts/AmScrollReaderServer.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmScrollReaderServer : public CppScripts::Script -{ -public: - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; -}; diff --git a/dScripts/AmShieldGenerator.cpp b/dScripts/AmShieldGenerator.cpp deleted file mode 100644 index 0e942612..00000000 --- a/dScripts/AmShieldGenerator.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "AmShieldGenerator.h" -#include "EntityManager.h" -#include "DestroyableComponent.h" -#include "GameMessages.h" -#include "MovementAIComponent.h" -#include "BaseCombatAIComponent.h" -#include "SkillComponent.h" - -void AmShieldGenerator::OnStartup(Entity* self) -{ - self->SetProximityRadius(20, "shield"); - self->SetProximityRadius(21, "buffer"); - - StartShield(self); -} - -void AmShieldGenerator::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - auto* destroyableComponent = entering->GetComponent<DestroyableComponent>(); - - if (status == "ENTER" && name == "shield") - { - if (destroyableComponent->HasFaction(4)) - { - EnemyEnteredShield(self, entering); - } - } - - if (name != "buffer" || !entering->IsPlayer()) - { - return; - } - - auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - if (status == "ENTER") - { - const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); - - if (iter == entitiesInProximity.end()) - { - entitiesInProximity.push_back(entering->GetObjectID()); - } - } - else if (status == "LEAVE") - { - const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); - - if (iter != entitiesInProximity.end()) - { - entitiesInProximity.erase(iter); - } - } - - self->SetVar<std::vector<LWOOBJID>>(u"Players", entitiesInProximity); -} - -void AmShieldGenerator::OnDie(Entity* self, Entity* killer) -{ - self->CancelAllTimers(); - - auto* child = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Child")); - - if (child != nullptr) - { - child->Kill(); - } -} - -void AmShieldGenerator::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "BuffPlayers") - { - BuffPlayers(self); - - self->AddTimer("BuffPlayers", 3.0f); - } - else if (timerName == "PlayFX") - { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); - - self->AddTimer("PlayFX", 1.5f); - } - else if (timerName == "RefreshEnemies") - { - auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); - - for (const auto enemyID : enemiesInProximity) - { - auto* enemy = EntityManager::Instance()->GetEntity(enemyID); - - if (enemy != nullptr) - { - EnemyEnteredShield(self, enemy); - } - } - - self->AddTimer("RefreshEnemies", 1.5f); - } -} - -void AmShieldGenerator::StartShield(Entity* self) -{ - self->AddTimer("PlayFX", 1.5f); - self->AddTimer("BuffPlayers", 3.0f); - self->AddTimer("RefreshEnemies", 1.5f); - - const auto myPos = self->GetPosition(); - const auto myRot = self->GetRotation(); - - EntityInfo info {}; - info.lot = 13111; - info.pos = myPos; - info.rot = myRot; - info.spawnerID = self->GetObjectID(); - - auto* child = EntityManager::Instance()->CreateEntity(info); - - self->SetVar(u"Child", child->GetObjectID()); - - BuffPlayers(self); -} - -void AmShieldGenerator::BuffPlayers(Entity* self) -{ - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - for (const auto playerID : entitiesInProximity) - { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(1200, 27024, playerID, true); - } -} - -void AmShieldGenerator::EnemyEnteredShield(Entity* self, Entity* intruder) -{ - auto* baseCombatAIComponent = intruder->GetComponent<BaseCombatAIComponent>(); - auto* movementAIComponent = intruder->GetComponent<MovementAIComponent>(); - - if (baseCombatAIComponent == nullptr || movementAIComponent == nullptr) - { - return; - } - - auto dir = intruder->GetRotation().GetForwardVector() * -1; - dir.y += 15; - dir.x *= 50; - dir.z *= 50; - - // TODO: Figure out how todo knockback, I'll stun them for now - - if (NiPoint3::DistanceSquared(self->GetPosition(), movementAIComponent->GetCurrentPosition()) < 20 * 20) - { - baseCombatAIComponent->Stun(2.0f); - movementAIComponent->SetDestination(baseCombatAIComponent->GetStartPosition()); - } - - baseCombatAIComponent->ClearThreat(); -} diff --git a/dScripts/AmShieldGenerator.h b/dScripts/AmShieldGenerator.h deleted file mode 100644 index b88a89cb..00000000 --- a/dScripts/AmShieldGenerator.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmShieldGenerator : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnDie(Entity* self, Entity* killer) override; - void OnTimerDone(Entity* self, std::string timerName) override; - - void StartShield(Entity* self); - void BuffPlayers(Entity* self); - void EnemyEnteredShield(Entity* self, Entity* intruder); -}; diff --git a/dScripts/AmShieldGeneratorQuickbuild.cpp b/dScripts/AmShieldGeneratorQuickbuild.cpp deleted file mode 100644 index aa80148c..00000000 --- a/dScripts/AmShieldGeneratorQuickbuild.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "AmShieldGeneratorQuickbuild.h" -#include "EntityManager.h" -#include "DestroyableComponent.h" -#include "GameMessages.h" -#include "MovementAIComponent.h" -#include "BaseCombatAIComponent.h" -#include "SkillComponent.h" -#include "RebuildComponent.h" -#include "MissionComponent.h" - -void AmShieldGeneratorQuickbuild::OnStartup(Entity* self) -{ - self->SetProximityRadius(20, "shield"); - self->SetProximityRadius(21, "buffer"); -} - -void AmShieldGeneratorQuickbuild::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - auto* destroyableComponent = entering->GetComponent<DestroyableComponent>(); - - if (name == "shield") - { - if (!destroyableComponent->HasFaction(4) || entering->IsPlayer()) - { - return; - } - - auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); - - if (status == "ENTER") - { - EnemyEnteredShield(self, entering); - - const auto& iter = std::find(enemiesInProximity.begin(), enemiesInProximity.end(), entering->GetObjectID()); - - if (iter == enemiesInProximity.end()) - { - enemiesInProximity.push_back(entering->GetObjectID()); - } - } - else if (status == "LEAVE") - { - const auto& iter = std::find(enemiesInProximity.begin(), enemiesInProximity.end(), entering->GetObjectID()); - - if (iter != enemiesInProximity.end()) - { - enemiesInProximity.erase(iter); - } - } - - self->SetVar<std::vector<LWOOBJID>>(u"Enemies", enemiesInProximity); - } - - if (name != "buffer" || !entering->IsPlayer()) - { - return; - } - - auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - if (status == "ENTER") - { - const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); - - if (iter == entitiesInProximity.end()) - { - entitiesInProximity.push_back(entering->GetObjectID()); - } - } - else if (status == "LEAVE") - { - const auto& iter = std::find(entitiesInProximity.begin(), entitiesInProximity.end(), entering->GetObjectID()); - - if (iter != entitiesInProximity.end()) - { - entitiesInProximity.erase(iter); - } - } - - self->SetVar<std::vector<LWOOBJID>>(u"Players", entitiesInProximity); -} - -void AmShieldGeneratorQuickbuild::OnDie(Entity* self, Entity* killer) -{ - self->CancelAllTimers(); - - auto* child = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Child")); - - if (child != nullptr) - { - child->Kill(); - } -} - -void AmShieldGeneratorQuickbuild::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "BuffPlayers") - { - BuffPlayers(self); - - self->AddTimer("BuffPlayers", 3.0f); - } - else if (timerName == "PlayFX") - { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); - - self->AddTimer("PlayFX", 1.5f); - } - else if (timerName == "RefreshEnemies") - { - auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); - - for (const auto enemyID : enemiesInProximity) - { - auto* enemy = EntityManager::Instance()->GetEntity(enemyID); - - if (enemy != nullptr) - { - EnemyEnteredShield(self, enemy); - } - } - - self->AddTimer("RefreshEnemies", 1.5f); - } -} - -void AmShieldGeneratorQuickbuild::OnRebuildComplete(Entity* self, Entity* target) -{ - StartShield(self); - - auto enemiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Enemies"); - - for (const auto enemyID : enemiesInProximity) - { - auto* enemy = EntityManager::Instance()->GetEntity(enemyID); - - if (enemy != nullptr) - { - enemy->Smash(); - } - } - - auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - for (const auto playerID : entitiesInProximity) - { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - continue; - } - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - return; - } - - missionComponent->ForceProgressTaskType(987, 1, 1, false); - } -} - -void AmShieldGeneratorQuickbuild::StartShield(Entity* self) -{ - self->AddTimer("PlayFX", 1.5f); - self->AddTimer("BuffPlayers", 3.0f); - self->AddTimer("RefreshEnemies", 1.5f); - - const auto myPos = self->GetPosition(); - const auto myRot = self->GetRotation(); - - EntityInfo info {}; - info.lot = 13111; - info.pos = myPos; - info.rot = myRot; - info.spawnerID = self->GetObjectID(); - - auto* child = EntityManager::Instance()->CreateEntity(info); - - self->SetVar(u"Child", child->GetObjectID()); - - BuffPlayers(self); -} - -void AmShieldGeneratorQuickbuild::BuffPlayers(Entity* self) -{ - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - auto entitiesInProximity = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - for (const auto playerID : entitiesInProximity) - { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(1200, 27024, playerID, true); - } -} - -void AmShieldGeneratorQuickbuild::EnemyEnteredShield(Entity* self, Entity* intruder) -{ - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent == nullptr || rebuildComponent->GetState() != REBUILD_COMPLETED) - { - return; - } - - auto* baseCombatAIComponent = intruder->GetComponent<BaseCombatAIComponent>(); - auto* movementAIComponent = intruder->GetComponent<MovementAIComponent>(); - - if (baseCombatAIComponent == nullptr || movementAIComponent == nullptr) - { - return; - } - - auto dir = intruder->GetRotation().GetForwardVector() * -1; - dir.y += 15; - dir.x *= 50; - dir.z *= 50; - - // TODO: Figure out how todo knockback, I'll stun them for now - - if (NiPoint3::DistanceSquared(self->GetPosition(), movementAIComponent->GetCurrentPosition()) < 20 * 20) - { - baseCombatAIComponent->Stun(2.0f); - movementAIComponent->SetDestination(baseCombatAIComponent->GetStartPosition()); - } - - baseCombatAIComponent->ClearThreat(); -} diff --git a/dScripts/AmShieldGeneratorQuickbuild.h b/dScripts/AmShieldGeneratorQuickbuild.h deleted file mode 100644 index 3a8ab61e..00000000 --- a/dScripts/AmShieldGeneratorQuickbuild.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmShieldGeneratorQuickbuild : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnDie(Entity* self, Entity* killer) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - - void StartShield(Entity* self); - void BuffPlayers(Entity* self); - void EnemyEnteredShield(Entity* self, Entity* intruder); -}; diff --git a/dScripts/AmSkeletonEngineer.cpp b/dScripts/AmSkeletonEngineer.cpp deleted file mode 100644 index 9ef27d75..00000000 --- a/dScripts/AmSkeletonEngineer.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "AmSkeletonEngineer.h" -#include "DestroyableComponent.h" -#include "SkillComponent.h" - -void AmSkeletonEngineer::OnHit(Entity* self, Entity* attacker) -{ - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (destroyableComponent == nullptr || skillComponent == nullptr) - { - return; - } - - if (destroyableComponent->GetHealth() < 12 && !self->GetVar<bool>(u"injured")) - { - self->SetVar(u"injured", true); - - skillComponent->CalculateBehavior(953, 19864, self->GetObjectID(), true); - - const auto attackerID = attacker->GetObjectID(); - - self->AddCallbackTimer(4.5f, [this, self, attackerID] () { - self->Smash(attackerID); - }); - } -} diff --git a/dScripts/AmSkullkinDrill.cpp b/dScripts/AmSkullkinDrill.cpp deleted file mode 100644 index d5b7e7e6..00000000 --- a/dScripts/AmSkullkinDrill.cpp +++ /dev/null @@ -1,376 +0,0 @@ -#include "AmSkullkinDrill.h" -#include "GameMessages.h" -#include "MovingPlatformComponent.h" -#include "DestroyableComponent.h" -#include "ProximityMonitorComponent.h" -#include "MissionComponent.h" - -void AmSkullkinDrill::OnStartup(Entity* self) -{ - self->SetNetworkVar(u"bIsInUse", false); - self->SetVar(u"bActive", true); - - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); - - auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatformComponent == nullptr) - { - return; - } - - movingPlatformComponent->SetSerialized(true); - - movingPlatformComponent->GotoWaypoint(0); - - auto* standObj = GetStandObj(self); - - if (standObj != nullptr) - { - standObj->SetVar(u"bActive", true); - } - - self->SetProximityRadius(5, "spin_distance"); -} - -Entity* AmSkullkinDrill::GetStandObj(Entity* self) -{ - const auto& myGroup = self->GetGroups(); - - if (myGroup.empty()) - { - return nullptr; - } - - std::string groupName = "Drill_Stand_"; - - groupName.push_back(myGroup[0][myGroup[0].size() - 1]); - - const auto standObjs = EntityManager::Instance()->GetEntitiesInGroup(groupName); - - if (standObjs.empty()) - { - return nullptr; - } - - return standObjs[0]; -} - -void AmSkullkinDrill::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) -{ - if (message != "NinjagoSpinEvent" || self->GetNetworkVar<bool>(u"bIsInUse")) - { - return; - } - - auto* proximityMonitorComponent = self->GetComponent<ProximityMonitorComponent>(); - - if (proximityMonitorComponent == nullptr || !proximityMonitorComponent->IsInProximity("spin_distance", caster->GetObjectID())) - { - return; - } - - self->SetVar(u"activaterID", caster->GetObjectID()); - - self->SetNetworkVar(u"bIsInUse", true); - - TriggerDrill(self); -} - -void AmSkullkinDrill::TriggerDrill(Entity* self) -{ - GameMessages::SendPlayAnimation(self, u"slowdown"); - - self->AddTimer("killDrill", 10.0f); - - auto* standObj = GetStandObj(self); - - if (standObj != nullptr) - { - standObj->SetVar(u"bActive", false); - } - - auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatformComponent == nullptr) - { - return; - } - - movingPlatformComponent->GotoWaypoint(1); -} - -void AmSkullkinDrill::OnWaypointReached(Entity* self, uint32_t waypointIndex) -{ - if (waypointIndex == 1) - { - auto myPos = self->GetPosition(); - auto myRot = self->GetRotation(); - - myPos.y -= 21; - - EntityInfo info = {}; - info.lot = 12346; - info.pos = myPos; - info.rot = myRot; - info.scale = 3; // Needs the scale, otherwise attacks fail - info.spawnerID = self->GetObjectID(); - - auto* child = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(child); - - self->SetVar(u"ChildSmash", child->GetObjectID()); - - child->AddDieCallback([this, self] () { - const auto& userID = self->GetVar<LWOOBJID>(u"activaterID"); - - auto* player = EntityManager::Instance()->GetEntity(userID); - - if (player == nullptr) - { - return; - } - - OnHitOrHealResult(self, player, 1); - }); - } - - OnArrived(self, waypointIndex); -} - -void AmSkullkinDrill::OnUse(Entity* self, Entity* user) -{ - if (self->GetNetworkVar<bool>(u"bIsInUse")) - { - return; - } - - self->SetNetworkVar(u"bIsInUse", true); - - GameMessages::SendPlayFXEffect(user->GetObjectID(), 5499, u"on-anim", "tornado"); - GameMessages::SendPlayFXEffect(user->GetObjectID(), 5502, u"on-anim", "staff"); - - const auto userID = user->GetObjectID(); - - self->SetVar(u"userID", userID); - self->SetVar(u"activaterID", userID); - - PlayAnim(self, user, "spinjitzu-staff-windup"); - PlayCinematic(self); - - FreezePlayer(self, user, true); -} - -void AmSkullkinDrill::FreezePlayer(Entity* self, Entity* player, bool bFreeze) -{ - eStunState eChangeType = POP; - - if (bFreeze) - { - if (player->GetIsDead()) - { - return; - } - - eChangeType = PUSH; - } - else - { - if (player->GetIsDead()) - { - // - } - } - - GameMessages::SendSetStunned(player->GetObjectID(), eChangeType, player->GetSystemAddress(), self->GetObjectID(), - true, false, true, false, true, false, true - ); -} - -void AmSkullkinDrill::OnArrived(Entity* self, uint32_t waypointIndex) -{ - auto* standObj = GetStandObj(self); - - if (waypointIndex == 1) - { - GameMessages::SendPlayAnimation(self, u"no-spin"); - GameMessages::SendStopFXEffect(self, true, "active"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"indicator", "indicator"); - - self->SetVar(u"bActive", false); - - const auto playerID = self->GetVar<LWOOBJID>(u"userID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player != nullptr) - { - PlayAnim(self, player, "spinjitzu-staff-end"); - } - - if (standObj != nullptr) - { - standObj->SetVar(u"bActive", false); - } - - return; - } - else - { - GameMessages::SendPlayAnimation(self, u"idle"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); - GameMessages::SendStopFXEffect(self, true, "indicator"); - } -} - -void AmSkullkinDrill::PlayCinematic(Entity* self) -{ - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"userID")); - - if (player == nullptr) - { - return; - } - - const auto& cine = self->GetVar<std::u16string>(u"cinematic"); - - if (cine.empty()) - { - return; - } - - GameMessages::SendPlayCinematic(player->GetObjectID(), cine, player->GetSystemAddress()); -} - -void AmSkullkinDrill::PlayAnim(Entity* self, Entity* player, const std::string& animName) -{ - const auto animTime = animName == "spinjitzu-staff-end" ? 0.5f : 1.0f; - - GameMessages::SendPlayAnimation(player, GeneralUtils::ASCIIToUTF16(animName)); - - self->AddTimer("AnimDone_" + animName, animTime); -} - -void AmSkullkinDrill::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) -{ - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - - if (destroyableComponent == nullptr || !attacker->IsPlayer()) - { - return; - } - - if (self->GetVar<bool>(u"bActive")) - { - return; - } - - const auto activaterID = self->GetVar<LWOOBJID>(u"activaterID"); - - auto* activator = EntityManager::Instance()->GetEntity(activaterID); - - // TODO: Missions - if (activator != nullptr) - { - auto* missionComponent = activator->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - for (const auto missionID : m_MissionsToUpdate) - { - missionComponent->ForceProgressValue(missionID, 1, self->GetLOT()); - } - } - } - - self->Smash(attacker->GetObjectID(), SILENT); - - self->CancelAllTimers(); - - auto* standObj = GetStandObj(self); - - if (standObj != nullptr) - { - GameMessages::SendPlayFXEffect(standObj->GetObjectID(), 4946, u"explode", "explode"); - } -} - -void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "killDrill") - { - const auto childID = self->GetVar<LWOOBJID>(u"ChildSmash"); - - auto* child = EntityManager::Instance()->GetEntity(childID); - - if (child != nullptr) - { - child->Smash(self->GetObjectID(), SILENT); - } - - self->SetNetworkVar(u"bIsInUse", false); - self->SetVar(u"bActive", true); - self->SetVar(u"activaterID", LWOOBJID_EMPTY); - - auto* standObj = GetStandObj(self); - - if (standObj != nullptr) - { - standObj->SetVar(u"bActive", true); - } - - auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatformComponent == nullptr) - { - return; - } - - movingPlatformComponent->GotoWaypoint(0); - - return; - } - - const auto& data = GeneralUtils::SplitString(timerName, '_'); - - if (data.empty()) - { - return; - } - - if (data[0] == "AnimDone") - { - const auto& animName = data[1]; - - const auto playerID = self->GetVar<LWOOBJID>(u"userID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - if (animName == "spinjitzu-staff-windup") - { - TriggerDrill(self); - - GameMessages::SendPlayAnimation(player, u"spinjitzu-staff-loop"); - } - else if (animName == "spinjitzu-staff-end") - { - FreezePlayer(self, player, false); - - self->SetVar(u"userID", LWOOBJID_EMPTY); - - GameMessages::SendStopFXEffect(player, true, "tornado"); - GameMessages::SendStopFXEffect(player, true, "staff"); - } - - } - else if (data[0] == "TryUnFreezeAgain") - { - - } -} diff --git a/dScripts/AmSkullkinDrill.h b/dScripts/AmSkullkinDrill.h deleted file mode 100644 index a996cefd..00000000 --- a/dScripts/AmSkullkinDrill.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmSkullkinDrill : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - - Entity* GetStandObj(Entity* self); - - void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; - - void TriggerDrill(Entity* self); - - void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; - - void OnUse(Entity* self, Entity* user) override; - - void FreezePlayer(Entity* self, Entity* player, bool bFreeze); - - void OnArrived(Entity* self, uint32_t waypointIndex); - - void PlayCinematic(Entity* self); - - void PlayAnim(Entity* self, Entity* player, const std::string& animName); - - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; - - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - std::vector<int32_t> m_MissionsToUpdate = {972, 1305, 1308}; -}; diff --git a/dScripts/AmSkullkinDrillStand.cpp b/dScripts/AmSkullkinDrillStand.cpp deleted file mode 100644 index ddae2f60..00000000 --- a/dScripts/AmSkullkinDrillStand.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "AmSkullkinDrillStand.h" -#include "GameMessages.h" -#include "dpEntity.h" - -void AmSkullkinDrillStand::OnStartup(Entity* self) -{ - self->SetVar(u"bActive", true); - - self->SetProximityRadius(new dpEntity(self->GetObjectID(), {6, 14, 6}), "knockback"); -} - -void AmSkullkinDrillStand::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) -{ - -} - -void AmSkullkinDrillStand::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (!self->GetVar<bool>(u"bActive")) - { - return; - } - - if (!entering->IsPlayer() || status != "ENTER" || name != "knockback") - { - return; - } - - auto myPos = self->GetPosition(); - - auto objPos = entering->GetPosition(); - - NiPoint3 newVec = {(objPos.x - myPos.x) * 4.5f, 15, (objPos.z - myPos.z) * 4.5f}; - - GameMessages::SendKnockback(entering->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, newVec); - - GameMessages::SendPlayFXEffect(entering->GetObjectID(), 1378, u"create", "pushBack"); - - GameMessages::SendPlayAnimation(entering, u"knockback-recovery"); -} diff --git a/dScripts/AmSkullkinDrillStand.h b/dScripts/AmSkullkinDrillStand.h deleted file mode 100644 index 3879b3b4..00000000 --- a/dScripts/AmSkullkinDrillStand.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmSkullkinDrillStand : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - - void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; - - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; -}; diff --git a/dScripts/AmSkullkinTower.cpp b/dScripts/AmSkullkinTower.cpp deleted file mode 100644 index 1b9e8c6d..00000000 --- a/dScripts/AmSkullkinTower.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include "AmSkullkinTower.h" -#include "EntityManager.h" -#include "DestroyableComponent.h" -#include "MovingPlatformComponent.h" -#include "GameMessages.h" -#include "MissionComponent.h" - -void AmSkullkinTower::OnStartup(Entity* self) -{ - self->SetProximityRadius(20, "Tower"); - - // onPhysicsComponentReady - - auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatformComponent != nullptr) - { - movingPlatformComponent->StopPathing(); - } - - SpawnLegs(self, "Left"); - SpawnLegs(self, "Right"); - SpawnLegs(self, "Rear"); -} - -void AmSkullkinTower::SpawnLegs(Entity* self, const std::string& loc) -{ - auto pos = self->GetPosition(); - auto rot = self->GetRotation(); - pos.y += self->GetVarAs<float>(u"vert_offset"); - - auto newRot = rot; - auto offset = self->GetVarAs<float>(u"hort_offset"); - - auto legLOT = self->GetVar<LOT>(u"legLOT"); - - if (legLOT == 0) - { - return; - } - - std::vector<LDFBaseData*> config = { new LDFData<std::string>(u"Leg", loc) }; - - EntityInfo info {}; - info.lot = legLOT; - info.spawnerID = self->GetObjectID(); - info.settings = config; - info.rot = newRot; - - if (loc == "Right") - { - const auto dir = rot.GetForwardVector(); - pos.x += dir.x * offset; - pos.z += dir.z * offset; - info.pos = pos; - } - else if (loc == "Rear") - { - const auto dir = rot.GetRightVector(); - pos.x += dir.x * offset; - pos.z += dir.z * offset; - info.pos = pos; - } - else if (loc == "Left") - { - const auto dir = rot.GetForwardVector() * -1; - pos.x += dir.x * offset; - pos.z += dir.z * offset; - info.pos = pos; - } - - info.rot = NiQuaternion::LookAt(info.pos, self->GetPosition()); - - auto* entity = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(entity); - - OnChildLoaded(self, entity); -} - -void AmSkullkinTower::OnChildLoaded(Entity* self, Entity* child) -{ - auto legTable = self->GetVar<std::vector<LWOOBJID>>(u"legTable"); - - legTable.push_back(child->GetObjectID()); - - self->SetVar(u"legTable", legTable); - - const auto selfID = self->GetObjectID(); - - child->AddDieCallback([this, selfID, child] () { - auto* self = EntityManager::Instance()->GetEntity(selfID); - auto* destroyableComponent = child->GetComponent<DestroyableComponent>(); - - if (destroyableComponent == nullptr || self == nullptr) - { - return; - } - - NotifyDie(self, child, destroyableComponent->GetKiller()); - }); -} - -void AmSkullkinTower::NotifyDie(Entity* self, Entity* other, Entity* killer) -{ - auto players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - const auto& iter = std::find(players.begin(), players.end(), killer->GetObjectID()); - - if (iter == players.end()) - { - players.push_back(killer->GetObjectID()); - } - - self->SetVar(u"Players", players); - - OnChildRemoved(self, other); -} - -void AmSkullkinTower::OnChildRemoved(Entity* self, Entity* child) -{ - auto legTable = self->GetVar<std::vector<LWOOBJID>>(u"legTable"); - - const auto& iter = std::find(legTable.begin(), legTable.end(), child->GetObjectID()); - - if (iter != legTable.end()) - { - legTable.erase(iter); - } - - self->SetVar(u"legTable", legTable); - - if (legTable.size() == 2) - { - GameMessages::SendPlayAnimation(self, u"wobble-1"); - } - else if (legTable.size() == 1) - { - GameMessages::SendPlayAnimation(self, u"wobble-2"); - } - else if (legTable.empty()) - { - const auto animTime = 2.5f; - - GameMessages::SendPlayAnimation(self, u"fall"); - - self->AddTimer("spawnGuys", animTime - 0.2f); - - self->CancelTimer("RespawnLeg"); - self->CancelTimer("RespawnLeg"); - self->CancelTimer("RespawnLeg"); - - std::vector<int32_t> missionIDs; - - auto missionsString = self->GetVar<std::u16string>(u"missions"); - - if (!missionsString.empty()) - { - // Split the missions string by '_' - const auto missions = GeneralUtils::SplitString( - GeneralUtils::UTF16ToWTF8(missionsString), - '_' - ); - - for (const auto& mission : missions) - { - int32_t missionID = 0; - - if (!GeneralUtils::TryParse(mission, missionID)) - { - continue; - } - - missionIDs.push_back(missionID); - } - } - - const auto& players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - for (const auto& playerID : players) - { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - continue; - } - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - continue; - } - - for (const auto missionID : missionIDs) - { - missionComponent->ForceProgressValue(missionID, 1, self->GetLOT()); - } - - //missionComponent->ForceProgressValue(1305, 1, self->GetLOT()); - } - } - - auto deadLegs = self->GetVar<std::vector<std::string>>(u"DeadLegs"); - - const auto& leg = child->GetVar<std::string>(u"Leg"); - - const auto& legIter = std::find(deadLegs.begin(), deadLegs.end(), leg); - - if (legIter == deadLegs.end()) - { - deadLegs.push_back(leg); - } - - self->SetVar(u"DeadLegs", deadLegs); - - self->AddTimer("RespawnLeg", 20); -} - -void AmSkullkinTower::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (status != "LEAVE") - { - return; - } - - auto players = self->GetVar<std::vector<LWOOBJID>>(u"Players"); - - const auto& iter = std::find(players.begin(), players.end(), entering->GetObjectID()); - - if (iter != players.end()) - { - players.erase(iter); - } - - self->SetVar(u"Players", players); -} - -void AmSkullkinTower::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "RespawnLeg") - { - auto deadLegs = self->GetVar<std::vector<std::string>>(u"DeadLegs"); - - if (deadLegs.empty()) - { - return; - } - - SpawnLegs(self, deadLegs[0]); - - deadLegs.erase(deadLegs.begin()); - - self->SetVar<std::vector<std::string>>(u"DeadLegs", deadLegs); - } - else if (timerName == "spawnGuys") - { - EntityInfo info {}; - info.lot = self->GetVar<LOT>(u"enemyToSpawn"); - auto pos = self->GetPosition(); - pos.y += 7; - info.pos = pos; - info.rot = self->GetRotation(); - info.spawnerID = self->GetObjectID(); - - for (size_t i = 0; i < 2; i++) - { - info.pos.x += i * 2; // Just to set the apart a bit - - auto* entity = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(entity); - } - - self->AddTimer("killTower", 0.7f); - } - else if (timerName == "killTower") - { - self->Smash(self->GetObjectID()); - } -} diff --git a/dScripts/AmSkullkinTower.h b/dScripts/AmSkullkinTower.h deleted file mode 100644 index c7d6a732..00000000 --- a/dScripts/AmSkullkinTower.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmSkullkinTower : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - - void SpawnLegs(Entity* self, const std::string& loc); - - void OnChildLoaded(Entity* self, Entity* child); - - void NotifyDie(Entity* self, Entity* other, Entity* killer); - - void OnChildRemoved(Entity* self, Entity* child); - - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - - void OnTimerDone(Entity* self, std::string timerName) override; -}; diff --git a/dScripts/AmTeapotServer.cpp b/dScripts/AmTeapotServer.cpp deleted file mode 100644 index 17b95eeb..00000000 --- a/dScripts/AmTeapotServer.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "AmTeapotServer.h" -#include "InventoryComponent.h" -#include "GameMessages.h" - - -void AmTeapotServer::OnUse(Entity* self, Entity* user) { - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - if (!inventoryComponent) return; - - if (inventoryComponent->GetLotCount(BLUE_FLOWER_LEAVES) >= 10){ - inventoryComponent->RemoveItem(BLUE_FLOWER_LEAVES, 10); - inventoryComponent->AddItem(WU_S_IMAGINATION_TEA, 1); - } - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} diff --git a/dScripts/AmTeapotServer.h b/dScripts/AmTeapotServer.h deleted file mode 100644 index 19cb5639..00000000 --- a/dScripts/AmTeapotServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmTeapotServer : public CppScripts::Script { - public: - void OnUse(Entity* self, Entity* user) override; - private: - LOT BLUE_FLOWER_LEAVES = 12317; - LOT WU_S_IMAGINATION_TEA = 12109; -}; diff --git a/dScripts/AmTemplateSkillVolume.cpp b/dScripts/AmTemplateSkillVolume.cpp deleted file mode 100644 index a0d2a95e..00000000 --- a/dScripts/AmTemplateSkillVolume.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "AmTemplateSkillVolume.h" -#include "MissionComponent.h" - -void AmTemplateSkillVolume::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) -{ - if (message != "NinjagoSpinAttackEvent") - { - return; - } - - auto* missionComponent = caster->GetComponent<MissionComponent>(); - - const auto missionIDsVariable = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"missions")); - const auto missionIDs = GeneralUtils::SplitString(missionIDsVariable, '_'); - - for (const auto& missionIDStr : missionIDs) - { - int32_t missionID = 0; - - if (!GeneralUtils::TryParse(missionIDStr, missionID)) - { - continue; - } - - missionComponent->ForceProgressTaskType(missionID, 1, 1, false); - } -} diff --git a/dScripts/AnvilOfArmor.cpp b/dScripts/AnvilOfArmor.cpp deleted file mode 100644 index f3712ff2..00000000 --- a/dScripts/AnvilOfArmor.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "AnvilOfArmor.h" - -void AnvilOfArmor::OnStartup(Entity *self) { - self->SetVar<uint32_t>(u"numCycles", 8); - self->SetVar<float_t>(u"secPerCycle", 25.0f); - self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); - self->SetVar<float_t>(u"deathDelay", 25.0f); - self->SetVar<uint32_t>(u"numberOfPowerups", 4); - self->SetVar<LOT>(u"lootLOT", 6431); - - // Initiate the actual script - OnTemplateStartup(self); -} diff --git a/dScripts/BankInteractServer.cpp b/dScripts/BankInteractServer.cpp deleted file mode 100644 index 9bea375a..00000000 --- a/dScripts/BankInteractServer.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "BankInteractServer.h" -#include "GameMessages.h" - -void BankInteractServer::OnUse(Entity* self, Entity* user) -{ - AMFArrayValue args; - AMFStringValue* bank = new AMFStringValue(); - bank->SetStringValue("bank"); - args.InsertValue("state", bank); - - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); - - delete bank; -} - -void BankInteractServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) -{ - if (args == "ToggleBank") - { - AMFArrayValue args; - AMFFalseValue* amfFalse = new AMFFalseValue(); - args.InsertValue("visible", amfFalse); - - GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &args); - - delete amfFalse; - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); - } -} diff --git a/dScripts/BankInteractServer.h b/dScripts/BankInteractServer.h deleted file mode 100644 index 45a40fe0..00000000 --- a/dScripts/BankInteractServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class BankInteractServer : public CppScripts::Script -{ -public: - void OnUse(Entity* self, Entity* user) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index 6475e025..4a059535 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -1,121 +1,104 @@ #include "BaseConsoleTeleportServer.h" #include "GameMessages.h" #include "Player.h" +#include "eTerminateType.h" +#include "eStateChangeType.h" -void BaseConsoleTeleportServer::BaseOnUse(Entity* self, Entity* user) -{ - auto* player = user; +void BaseConsoleTeleportServer::BaseOnUse(Entity* self, Entity* user) { + auto* player = user; - const auto& teleportLocString = self->GetVar<std::u16string>(u"teleportString"); + const auto& teleportLocString = self->GetVar<std::u16string>(u"teleportString"); - GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, teleportLocString, u"", player->GetSystemAddress()); + GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, teleportLocString, u"", player->GetSystemAddress()); } -void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - auto* player = sender; +void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + auto* player = sender; - if (button == 1) - { + if (button == 1) { - GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), player->GetObjectID(), - true, true, true, true, true, true, true - ); + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), player->GetObjectID(), + true, true, true, true, true, true, true + ); - const auto teleportFXID = self->GetVar<int32_t>(u"teleportEffectID"); + const auto teleportFXID = self->GetVar<int32_t>(u"teleportEffectID"); - if (teleportFXID != 0) - { - const auto& teleportFXs = self->GetVar<std::vector<std::u16string>>(u"teleportEffectTypes"); + if (teleportFXID != 0) { + const auto& teleportFXs = self->GetVar<std::vector<std::u16string>>(u"teleportEffectTypes"); - for (const auto& type : teleportFXs) - { - GameMessages::SendPlayFXEffect(player->GetObjectID(), teleportFXID, type, "FX" + GeneralUtils::UTF16ToWTF8(type)); - } - } + for (const auto& type : teleportFXs) { + GameMessages::SendPlayFXEffect(player->GetObjectID(), teleportFXID, type, "FX" + GeneralUtils::UTF16ToWTF8(type)); + } + } - const auto& teleIntroAnim = self->GetVar<std::u16string>(u"teleportAnim"); + const auto& teleIntroAnim = self->GetVar<std::u16string>(u"teleportAnim"); - if (!teleIntroAnim.empty()) - { - GameMessages::SendPlayAnimation(player, teleIntroAnim); - } + if (!teleIntroAnim.empty()) { + GameMessages::SendPlayAnimation(player, teleIntroAnim); + } - const auto animTime = 3.32999992370605f; + const auto animTime = 3.32999992370605f; - UpdatePlayerTable(self, player, true); + UpdatePlayerTable(self, player, true); - const auto playerID = player->GetObjectID(); + const auto playerID = player->GetObjectID(); - self->AddCallbackTimer(animTime, [playerID, self] () { - auto* player = EntityManager::Instance()->GetEntity(playerID); + self->AddCallbackTimer(animTime, [playerID, self]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - { - return; - } + if (player == nullptr) { + return; + } - GameMessages::SendDisplayZoneSummary(playerID, player->GetSystemAddress(), false, false, self->GetObjectID()); - }); - } - else if (button == -1 || button == 0) - { - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, player->GetObjectID()); - } + GameMessages::SendDisplayZoneSummary(playerID, player->GetSystemAddress(), false, false, self->GetObjectID()); + }); + } else if (button == -1 || button == 0) { + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()); + } } -void BaseConsoleTeleportServer::UpdatePlayerTable(Entity* self, Entity* player, bool bAdd) -{ - const auto iter = std::find(m_Players.begin(), m_Players.end(), player->GetObjectID()); +void BaseConsoleTeleportServer::UpdatePlayerTable(Entity* self, Entity* player, bool bAdd) { + const auto iter = std::find(m_Players.begin(), m_Players.end(), player->GetObjectID()); - if (iter == m_Players.end() && bAdd) - { - m_Players.push_back(player->GetObjectID()); - } - else if (iter != m_Players.end() && !bAdd) - { - m_Players.erase(iter); - } + if (iter == m_Players.end() && bAdd) { + m_Players.push_back(player->GetObjectID()); + } else if (iter != m_Players.end() && !bAdd) { + m_Players.erase(iter); + } } -bool BaseConsoleTeleportServer::CheckPlayerTable(Entity* self, Entity* player) -{ - const auto iter = std::find(m_Players.begin(), m_Players.end(), player->GetObjectID()); +bool BaseConsoleTeleportServer::CheckPlayerTable(Entity* self, Entity* player) { + const auto iter = std::find(m_Players.begin(), m_Players.end(), player->GetObjectID()); - return iter != m_Players.end(); + return iter != m_Players.end(); } -void BaseConsoleTeleportServer::BaseOnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - if (args == "summaryComplete") - { - TransferPlayer(self, sender, 0); - } +void BaseConsoleTeleportServer::BaseOnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "summaryComplete") { + TransferPlayer(self, sender, 0); + } } -void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int32_t altMapID) -{ - if (player == nullptr || !CheckPlayerTable(self, player)) - { - return; - } +void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int32_t altMapID) { + if (player == nullptr || !CheckPlayerTable(self, player)) { + return; + } - // Ignoring extra effects for now + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), player->GetObjectID(), + true, true, true, true, true, true, true + ); - /*GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), player->GetObjectID(), - true, true, true, true, true, true, true - );*/ + GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()); - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, player->GetObjectID()); + const auto& teleportZone = self->GetVar<std::u16string>(u"transferZoneID"); - const auto& teleportZone = self->GetVar<std::u16string>(u"transferZoneID"); + static_cast<Player*>(player)->SendToZone(std::stoi(GeneralUtils::UTF16ToWTF8(teleportZone))); - static_cast<Player*>(player)->SendToZone(std::stoi(GeneralUtils::UTF16ToWTF8(teleportZone))); - - UpdatePlayerTable(self, player, false); + UpdatePlayerTable(self, player, false); } -void BaseConsoleTeleportServer::BaseOnTimerDone(Entity* self, const std::string& timerName) -{ - +void BaseConsoleTeleportServer::BaseOnTimerDone(Entity* self, const std::string& timerName) { + } diff --git a/dScripts/BaseConsoleTeleportServer.h b/dScripts/BaseConsoleTeleportServer.h index 086586e3..60c70d75 100644 --- a/dScripts/BaseConsoleTeleportServer.h +++ b/dScripts/BaseConsoleTeleportServer.h @@ -4,14 +4,14 @@ class BaseConsoleTeleportServer { public: - void BaseOnUse(Entity* self, Entity* user); - void BaseOnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); - void UpdatePlayerTable(Entity* self, Entity* player, bool bAdd); - bool CheckPlayerTable(Entity* self, Entity* player); - void BaseOnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3); - void TransferPlayer(Entity* self, Entity* player, int32_t altMapID); - void BaseOnTimerDone(Entity* self, const std::string& timerName); + void BaseOnUse(Entity* self, Entity* user); + void BaseOnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); + void UpdatePlayerTable(Entity* self, Entity* player, bool bAdd); + bool CheckPlayerTable(Entity* self, Entity* player); + void BaseOnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3); + void TransferPlayer(Entity* self, Entity* player, int32_t altMapID); + void BaseOnTimerDone(Entity* self, const std::string& timerName); private: - std::vector<LWOOBJID> m_Players = {}; + std::vector<LWOOBJID> m_Players = {}; }; diff --git a/dScripts/BaseEnemyApe.cpp b/dScripts/BaseEnemyApe.cpp deleted file mode 100644 index 9aa391d1..00000000 --- a/dScripts/BaseEnemyApe.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "BaseEnemyApe.h" -#include "BaseCombatAIComponent.h" -#include "DestroyableComponent.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "SkillComponent.h" - -void BaseEnemyApe::OnStartup(Entity *self) { - self->SetVar<uint32_t>(u"timesStunned", 2); - self->SetVar<bool>(u"knockedOut", false); -} - -void BaseEnemyApe::OnDie(Entity *self, Entity *killer) { - auto* anchor = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"QB")); - if (anchor != nullptr && !anchor->GetIsDead()) { - anchor->Smash(self->GetObjectID(), SILENT); - } -} - -void BaseEnemyApe::OnSkillCast(Entity *self, uint32_t skillID) { - const auto groundPoundSkill = self->GetVar<uint32_t>(u"GroundPoundSkill") != 0 ? self->GetVar<uint32_t>(u"GroundPoundSkill") : 725; - const auto spawnQuickBuildTime = self->GetVar<float_t>(u"spawnQBTime") != 0.0f ? self->GetVar<float_t>(u"spawnQBTime") : 5.0f; - - if (skillID == groundPoundSkill && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) { - self->AddTimer("spawnQBTime", spawnQuickBuildTime); - } -} - -void BaseEnemyApe::OnHit(Entity *self, Entity *attacker) { - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { - StunApe(self, true); - self->CancelTimer("spawnQBTime"); - - GameMessages::SendPlayAnimation(self, u"disable", 1.7f); - - const auto reviveTime = self->GetVar<float_t>(u"reviveTime") != 0.0f - ? self->GetVar<float_t>(u"reviveTime") : 12.0f; - self->AddTimer("reviveTime", reviveTime); - } -} - -void BaseEnemyApe::OnTimerDone(Entity *self, std::string timerName) { - if (timerName == "reviveTime") { - - // Revives the ape, giving it back some armor - const auto timesStunned = self->GetVar<uint32_t>(u"timesStunned"); - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); - } - EntityManager::Instance()->SerializeEntity(self); - self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1); - StunApe(self, false); - - } else if (timerName == "spawnQBTime" && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) { - // Spawn QB in front of ape. - const auto position = self->GetPosition(); - const auto rotation = self->GetRotation(); - - const auto backwardVector = rotation.GetForwardVector() * -1; - const auto objectPosition = NiPoint3( - position.GetX() - (backwardVector.GetX() * 8), - position.GetY(), - position.GetZ() - (backwardVector.GetZ() * 8) - ); - - EntityInfo entityInfo {}; - - entityInfo.pos = position; - entityInfo.rot = rotation; - entityInfo.pos.SetY(entityInfo.pos.GetY() + 13.0f); - - entityInfo.spawnerID = self->GetObjectID(); - entityInfo.lot = self->GetVar<LOT>(u"QuickbuildAnchorLOT") != 0 - ? self->GetVar<LOT>(u"QuickbuildAnchorLOT") : 7549; - entityInfo.settings = { - new LDFData<std::string>(u"rebuild_activators", - std::to_string(objectPosition.GetX()) + "\x1f" + - std::to_string(objectPosition.GetY()) + "\x1f" + - std::to_string(objectPosition.GetZ()) - ), - new LDFData<bool>(u"no_timed_spawn", true), - new LDFData<LWOOBJID>(u"ape", self->GetObjectID()) - }; - - auto* anchor = EntityManager::Instance()->CreateEntity(entityInfo); - EntityManager::Instance()->ConstructEntity(anchor); - self->SetVar<LWOOBJID>(u"QB", anchor->GetObjectID()); - - } else if (timerName == "anchorDamageTimer") { - - // Attacks the ape with some god skill - const auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"smasher")); - if (player == nullptr) { - return; - } - - auto* skillComponent = self->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->CalculateBehavior(1273, 29446, self->GetObjectID(), true, false, player->GetObjectID()); - } - - self->SetVar<LWOOBJID>(u"QB", LWOOBJID_EMPTY); - } -} - -void BaseEnemyApe::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "rebuildDone" && sender != nullptr) { - self->SetVar<LWOOBJID>(u"smasher", sender->GetObjectID()); - const auto anchorDamageDelayTime = self->GetVar<float_t>(u"AnchorDamageDelayTime") != 0.0f ? self->GetVar<float_t>(u"AnchorDamageDelayTime") : 0.5f; - self->AddTimer("anchorDamageTimer", anchorDamageDelayTime); - } -} - -void BaseEnemyApe::StunApe(Entity *self, bool stunState) { - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(stunState); - combatAIComponent->SetStunned(stunState); - - auto* skillComponent = self->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->Interrupt(); - } - - GameMessages::SendSetStunned(self->GetObjectID(), stunState ? PUSH : POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), - true, true, true, true, true, - true, true, true, true); - - self->SetBoolean(u"knockedOut", stunState); - } -} diff --git a/dScripts/BaseEnemyApe.h b/dScripts/BaseEnemyApe.h deleted file mode 100644 index 1553d3ae..00000000 --- a/dScripts/BaseEnemyApe.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class BaseEnemyApe : public CppScripts::Script { -public: - void OnStartup(Entity *self) override; - void OnDie(Entity *self, Entity *killer) override; - void OnSkillCast(Entity *self, uint32_t skillID) override; - void OnHit(Entity *self, Entity *attacker) override; - void OnTimerDone(Entity *self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -private: - static void StunApe(Entity* self, bool stunState); -}; diff --git a/dScripts/BaseFootRaceManager.cpp b/dScripts/BaseFootRaceManager.cpp deleted file mode 100644 index 0da51bc5..00000000 --- a/dScripts/BaseFootRaceManager.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "BaseFootRaceManager.h" -#include "EntityManager.h" -#include "Character.h" - -void BaseFootRaceManager::OnStartup(Entity *self) { - // TODO: Add to FootRaceStarter group -} - -void BaseFootRaceManager::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - const auto splitArguments = GeneralUtils::SplitString(args, '_'); - if (splitArguments.size() > 1) { - - const auto eventName = splitArguments[0]; - const auto player = EntityManager::Instance()->GetEntity(std::stoull(splitArguments[1])); - - if (player != nullptr) { - if (eventName == "updatePlayer") { - UpdatePlayer(self, player->GetObjectID()); - } else if (IsPlayerInActivity(self, player->GetObjectID())) { - if (eventName == "initialActivityScore") { - auto* character = player->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(115, true); - } - - SetActivityScore(self, player->GetObjectID(), 1); - } else if (eventName == "updatePlayerTrue") { - auto* character = player->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(115, false); - } - - UpdatePlayer(self, player->GetObjectID(), true); - } else if (eventName == "PlayerWon") { - auto* character = player->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(115, false); - if (param2 != -1) // Certain footraces set a flag - character->SetPlayerFlag(param2, true); - } - - StopActivity(self, player->GetObjectID(), 0, param1); - } - } - } - } -} diff --git a/dScripts/BaseFootRaceManager.h b/dScripts/BaseFootRaceManager.h deleted file mode 100644 index 1a76cf19..00000000 --- a/dScripts/BaseFootRaceManager.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ActivityManager.h" -#include "CppScripts.h" - -class BaseFootRaceManager : public ActivityManager { - void OnStartup(Entity* self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/BaseInteractDropLootServer.cpp b/dScripts/BaseInteractDropLootServer.cpp deleted file mode 100644 index 0dbce047..00000000 --- a/dScripts/BaseInteractDropLootServer.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "BaseInteractDropLootServer.h" -#include "Loot.h" -#include "GameMessages.h" - -void BaseInteractDropLootServer::OnUse(Entity* self, Entity* user) -{ - BaseUse(self, user); -} - -void BaseInteractDropLootServer::BaseUse(Entity* self, Entity* user) -{ - auto cooldownTime = self->GetVar<float>(u"cooldownTime"); - if (cooldownTime == 0) cooldownTime = 5; - - uint32_t lootMatrix = self->GetVar<int32_t>(u"UseLootMatrix"); - if (lootMatrix == 0) lootMatrix = self->GetVar<int32_t>(u"smashable_loot_matrix"); - if (lootMatrix == 0) lootMatrix = 715; - - auto useSound = self->GetVar<std::string>(u"sound1"); - - if (!useSound.empty()) - { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound); - } - - self->SetNetworkVar(u"bInUse", true); - - LootGenerator::Instance().DropLoot(user, self, lootMatrix, 0, 0); - - self->AddCallbackTimer(cooldownTime, [this, self] () { - self->SetNetworkVar(u"bInUse", false); - }); -} diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index e7a95844..72cce09f 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -8,62 +8,64 @@ #include "RenderComponent.h" #include "PropertyManagementComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" -void BasePropertyServer::SetGameVariables(Entity *self) { - self->SetVar<std::string>(ClaimMarkerGroup, ""); - self->SetVar<std::string>(GeneratorGroup, ""); - self->SetVar<std::string>(GuardGroup, ""); - self->SetVar<std::string>(PropertyPlaqueGroup, ""); - self->SetVar<std::string>(PropertyVendorGroup, ""); - self->SetVar<std::string>(SpotsGroup, ""); - self->SetVar<std::string>(MSCloudsGroup, ""); - self->SetVar<std::string>(EnemiesGroup, ""); - self->SetVar<std::string>(FXManagerGroup, ""); - self->SetVar<std::string>(ImagOrbGroup, ""); - self->SetVar<std::string>(GeneratorFXGroup, ""); +void BasePropertyServer::SetGameVariables(Entity* self) { + self->SetVar<std::string>(ClaimMarkerGroup, ""); + self->SetVar<std::string>(GeneratorGroup, ""); + self->SetVar<std::string>(GuardGroup, ""); + self->SetVar<std::string>(PropertyPlaqueGroup, ""); + self->SetVar<std::string>(PropertyVendorGroup, ""); + self->SetVar<std::string>(SpotsGroup, ""); + self->SetVar<std::string>(MSCloudsGroup, ""); + self->SetVar<std::string>(EnemiesGroup, ""); + self->SetVar<std::string>(FXManagerGroup, ""); + self->SetVar<std::string>(ImagOrbGroup, ""); + self->SetVar<std::string>(GeneratorFXGroup, ""); - self->SetVar<std::vector<std::string>>(EnemiesSpawner, {}); - self->SetVar<std::string>(ClaimMarkerSpawner, ""); - self->SetVar<std::string>(GeneratorSpawner, ""); - self->SetVar<std::string>(DamageFXSpawner, ""); - self->SetVar<std::string>(FXSpotsSpawner, ""); - self->SetVar<std::string>(PropertyMGSpawner, ""); - self->SetVar<std::string>(ImageOrbSpawner, ""); - self->SetVar<std::string>(GeneratorFXSpawner, ""); - self->SetVar<std::string>(SmashablesSpawner, ""); - self->SetVar<std::string>(FXManagerSpawner, ""); - self->SetVar<std::string>(PropObjsSpawner, ""); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, {}); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); + self->SetVar<std::vector<std::string>>(EnemiesSpawner, {}); + self->SetVar<std::string>(ClaimMarkerSpawner, ""); + self->SetVar<std::string>(GeneratorSpawner, ""); + self->SetVar<std::string>(DamageFXSpawner, ""); + self->SetVar<std::string>(FXSpotsSpawner, ""); + self->SetVar<std::string>(PropertyMGSpawner, ""); + self->SetVar<std::string>(ImageOrbSpawner, ""); + self->SetVar<std::string>(GeneratorFXSpawner, ""); + self->SetVar<std::string>(SmashablesSpawner, ""); + self->SetVar<std::string>(FXManagerSpawner, ""); + self->SetVar<std::string>(PropObjsSpawner, ""); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, {}); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); - self->SetVar<uint32_t>(defeatedProperyFlag, 0); - self->SetVar<uint32_t>(placedModelFlag, 0); - self->SetVar<uint32_t>(guardMissionFlag, 0); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 0); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 0); - self->SetVar<LOT>(orbIDFlag, 0); - self->SetVar<LOT>(behaviorQBID, 0); + self->SetVar<int32_t>(defeatedProperyFlag, 0); + self->SetVar<int32_t>(placedModelFlag, 0); + self->SetVar<uint32_t>(guardMissionFlag, 0); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 0); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 0); + self->SetVar<LOT>(orbIDFlag, 0); + self->SetVar<LOT>(behaviorQBID, 0); } void BasePropertyServer::CheckForOwner(Entity* self) { - if (EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(PropertyPlaqueGroup)).empty()) { - self->AddTimer(RunPlayerLoadedAgainTimer, 0.5f); - return; - } + if (EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(PropertyPlaqueGroup)).empty()) { + self->AddTimer(RunPlayerLoadedAgainTimer, 0.5f); + return; + } self->SetI64(PropertyOwnerVariable, GetOwner()); } -void BasePropertyServer::OnStartup(Entity *self) { - SetGameVariables(self); +void BasePropertyServer::OnStartup(Entity* self) { + SetGameVariables(self); } -void BasePropertyServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - if (args == CheckForPropertyOwnerEvent) { - sender->SetNetworkVar<std::string>(PropertyOwnerIDVariable, std::to_string(self->GetVar<LWOOBJID>(PropertyOwnerVariable))); - } +void BasePropertyServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == CheckForPropertyOwnerEvent) { + sender->SetNetworkVar<std::string>(PropertyOwnerIDVariable, std::to_string(self->GetVar<LWOOBJID>(PropertyOwnerVariable))); + } } void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { @@ -73,7 +75,7 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { auto propertyOwner = PropertyManagementComponent::Instance()->GetOwnerId(); self->OnFireEventServerSide(self, CheckForPropertyOwnerEvent); - + if (propertyOwner > 0) { rented = true; } @@ -85,21 +87,19 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { self->SetNetworkVar(PropertyOwnerIDVariable, propertyOwner); if (rented) { - auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); - for (auto* plaque : plaques) { - EntityManager::Instance()->DestructEntity(plaque); - } + auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); + for (auto* plaque : plaques) { + EntityManager::Instance()->DestructEntity(plaque); + } const auto& mapID = dZoneManager::Instance()->GetZone()->GetZoneID(); - if (propertyOwner > 0) - { + if (propertyOwner > 0) { auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) - { + if (missionComponent != nullptr) { missionComponent->Progress( - MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY, + eMissionTaskType::VISIT_PROPERTY, mapID.GetMapID(), mapID.GetCloneID() ); @@ -115,7 +115,7 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { if (!self->GetBoolean(FXObjectsGoneVariable)) { self->AddTimer(KillFXObjectTimer, 1.0f); } - + GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); // activate property safe spawner network @@ -127,10 +127,10 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { if (player->GetObjectID() != propertyOwner) return; } else { - const auto defeatedFlag = player->GetCharacter()->GetPlayerFlag(self->GetVar<uint32_t>(defeatedProperyFlag)); + const auto defeatedFlag = player->GetCharacter()->GetPlayerFlag(self->GetVar<int32_t>(defeatedProperyFlag)); self->SetNetworkVar(UnclaimedVariable, true); - self->SetVar<LWOOBJID>(PlayerIDVariable, player->GetObjectID()); + self->SetVar<LWOOBJID>(PlayerIDVariable, player->GetObjectID()); if (!defeatedFlag) { StartMaelstrom(self, player); @@ -152,28 +152,27 @@ void BasePropertyServer::PropGuardCheck(Entity* self, Entity* player) { auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr - && missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)) != MissionState::MISSION_STATE_COMPLETE) { - ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); + && missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)) != eMissionState::COMPLETE) { + ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); } } void BasePropertyServer::BaseZonePropertyRented(Entity* self, Entity* player) const { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "ShowProperty", - UNASSIGNED_SYSTEM_ADDRESS); + UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer(BoundsVisOnTimer, 2); self->SetVar<LWOOBJID>(PropertyOwnerVariable, player->GetObjectID()); - - auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); - for (auto* plaque : plaques) { - EntityManager::Instance()->DestructEntity(plaque); - } - if (self->GetVar<int32_t>(brickLinkMissionIDFlag) != 0) { - auto plaques = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(PropertyPlaqueGroup)); - for (auto* plaque : plaques) { - EntityManager::Instance()->DestructEntity(plaque); - } + auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); + for (auto* plaque : plaques) { + EntityManager::Instance()->DestructEntity(plaque); + } + + auto brickLinkMissionID = self->GetVar<uint32_t>(brickLinkMissionIDFlag); + if (brickLinkMissionID != 0) { + auto missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent) missionComponent->CompleteMission(brickLinkMissionID, true); } ActivateSpawner(self->GetVar<std::string>(PropObjsSpawner)); @@ -186,7 +185,7 @@ void BasePropertyServer::BaseZonePropertyModelPlaced(Entity* self, Entity* playe auto flag = self->GetVar<int32_t>(placedModelFlag); if (flag) - character->SetPlayerFlag(flag, true); + character->SetPlayerFlag(flag, true); } void BasePropertyServer::KillClouds(Entity* self) { @@ -204,13 +203,13 @@ void BasePropertyServer::KillSpots(Entity* self) { } void BasePropertyServer::StartMaelstrom(Entity* self, Entity* player) { - for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { - ActivateSpawner(enemySpawner); - } + for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { + ActivateSpawner(enemySpawner); + } - for (const auto& behaviorObjectSpawner : self->GetVar<std::vector<std::string>>(BehaviorObjsSpawner)) { - ActivateSpawner(behaviorObjectSpawner); - } + for (const auto& behaviorObjectSpawner : self->GetVar<std::vector<std::string>>(BehaviorObjsSpawner)) { + ActivateSpawner(behaviorObjectSpawner); + } ActivateSpawner(self->GetVar<std::string>(DamageFXSpawner)); ActivateSpawner(self->GetVar<std::string>(GeneratorSpawner)); @@ -222,13 +221,13 @@ void BasePropertyServer::StartMaelstrom(Entity* self, Entity* player) { DestroySpawner(self->GetVar<std::string>(ClaimMarkerSpawner)); for (const auto& ambientFXSpawner : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { - DestroySpawner(ambientFXSpawner); + DestroySpawner(ambientFXSpawner); } StartTornadoFx(self); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); + "", player->GetSystemAddress()); self->AddTimer(StartGeneratorTimer, 0.0f); self->AddTimer(StartOrbTimer, 0.0f); @@ -242,20 +241,20 @@ void BasePropertyServer::StartTornadoFx(Entity* self) const { } for (auto* entity : entities) { - auto* renderComponent = entity->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->PlayEffect(-1, u"debrisOn", "TornadoDebris"); - renderComponent->PlayEffect(-1, u"VortexOn", "TornadoVortex"); - renderComponent->PlayEffect(-1, u"onSilhouette", "silhouette"); - } + auto* renderComponent = entity->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->PlayEffect(-1, u"debrisOn", "TornadoDebris"); + renderComponent->PlayEffect(-1, u"VortexOn", "TornadoVortex"); + renderComponent->PlayEffect(-1, u"onSilhouette", "silhouette"); + } } } -void BasePropertyServer::BasePlayerExit(Entity *self, Entity *player) { +void BasePropertyServer::BasePlayerExit(Entity* self, Entity* player) { if (self->GetBoolean(UnclaimedVariable)) { - if (player->GetObjectID() == self->GetVar<LWOOBJID>(PlayerIDVariable)) { - // Destroy all spawners - } + if (player->GetObjectID() == self->GetVar<LWOOBJID>(PlayerIDVariable)) { + // Destroy all spawners + } } } @@ -275,7 +274,7 @@ void BasePropertyServer::RequestDie(Entity* self, Entity* other) { if (destroyable == nullptr) return; - destroyable->Smash(other->GetObjectID(), SILENT); + destroyable->Smash(other->GetObjectID(), eKillType::SILENT); } void BasePropertyServer::ActivateSpawner(const std::string& spawnerName) { @@ -285,9 +284,9 @@ void BasePropertyServer::ActivateSpawner(const std::string& spawnerName) { } void BasePropertyServer::DeactivateSpawner(const std::string& spawnerName) { - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - spawner->Deactivate(); - } + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { + spawner->Deactivate(); + } } void BasePropertyServer::TriggerSpawner(const std::string& spawnerName) { @@ -297,27 +296,17 @@ void BasePropertyServer::TriggerSpawner(const std::string& spawnerName) { } void BasePropertyServer::ResetSpawner(const std::string& spawnerName) { - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - spawner->Reset(); - } + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { + spawner->Reset(); + } } void BasePropertyServer::DestroySpawner(const std::string& spawnerName) { - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - for (auto* node : spawner->m_Info.nodes) { - for (const auto& element : node->entities) { - auto* entity = EntityManager::Instance()->GetEntity(element); - if (entity == nullptr) - continue; - - entity->Kill(); - } - - node->entities.clear(); - } - - spawner->Deactivate(); - } + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { + if (!spawner) return; + spawner->DestroyAllEntities(); + spawner->Deactivate(); + } } LWOOBJID BasePropertyServer::GetOwner() { @@ -326,194 +315,194 @@ LWOOBJID BasePropertyServer::GetOwner() { } void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerName) { - if (timerName == StartGeneratorTimer) { - HandleGeneratorTimer(self); - } else if (timerName == StartOrbTimer) { - HandleOrbsTimer(self); - } else if (timerName == StartQuickbuildTimer) { - HandleQuickBuildTimer(self); - } else if (timerName == "GuardFlyAway") { - const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); + if (timerName == StartGeneratorTimer) { + HandleGeneratorTimer(self); + } else if (timerName == StartOrbTimer) { + HandleOrbsTimer(self); + } else if (timerName == StartQuickbuildTimer) { + HandleQuickBuildTimer(self); + } else if (timerName == "GuardFlyAway") { + const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); - // No guard for the spider instance fight - if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1150) - return; + // No guard for the spider instance fight + if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1150) + return; - const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GuardGroup)); - if (entities.empty()) - return; + const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GuardGroup)); + if (entities.empty()) + return; - auto* guard = entities[0]; - GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), - u"GuardChat", 0, 0, guard->GetObjectID(), - "", UNASSIGNED_SYSTEM_ADDRESS); + auto* guard = entities[0]; + GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), + u"GuardChat", 0, 0, guard->GetObjectID(), + "", UNASSIGNED_SYSTEM_ADDRESS); - self->AddTimer(KillGuardTimer, 5.0f); - } else if (timerName == KillGuardTimer) { - KillGuard(self); - } else if (timerName == TornadoOffTimer) { - auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); + self->AddTimer(KillGuardTimer, 5.0f); + } else if (timerName == KillGuardTimer) { + KillGuard(self); + } else if (timerName == TornadoOffTimer) { + auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); - for (auto *fxManager : fxManagers) { - auto *renderComponent = fxManager->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("TornadoDebris", false); - renderComponent->StopEffect("TornadoVortex", false); - renderComponent->StopEffect("silhouette", false); - } - } + for (auto* fxManager : fxManagers) { + auto* renderComponent = fxManager->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("TornadoDebris", false); + renderComponent->StopEffect("TornadoVortex", false); + renderComponent->StopEffect("silhouette", false); + } + } - self->AddTimer(ShowClearEffectsTimer, 2); - } else if (timerName == ShowClearEffectsTimer) { - auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); + self->AddTimer(ShowClearEffectsTimer, 2); + } else if (timerName == ShowClearEffectsTimer) { + auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); - for (auto *fxManager : fxManagers) { - auto *renderComponent = fxManager->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) - renderComponent->PlayEffect(-1, u"beamOn", "beam"); - } + for (auto* fxManager : fxManagers) { + auto* renderComponent = fxManager->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) + renderComponent->PlayEffect(-1, u"beamOn", "beam"); + } - self->AddTimer(KillStrombiesTimer, 2.0f); - self->AddTimer(TurnSkyOffTimer, 1.5f); - self->AddTimer(KillFXObjectTimer, 8.0f); - } else if (timerName == TurnSkyOffTimer) { - auto* controller = dZoneManager::Instance()->GetZoneControlObject(); - GameMessages::SendNotifyClientObject(controller->GetObjectID(), u"SkyOff", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - } else if (timerName == KillStrombiesTimer) { - const auto enemies = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(EnemiesGroup)); - for (auto* enemy : enemies) { - RequestDie(self, enemy); - } + self->AddTimer(KillStrombiesTimer, 2.0f); + self->AddTimer(TurnSkyOffTimer, 1.5f); + self->AddTimer(KillFXObjectTimer, 8.0f); + } else if (timerName == TurnSkyOffTimer) { + auto* controller = dZoneManager::Instance()->GetZoneControlObject(); + GameMessages::SendNotifyClientObject(controller->GetObjectID(), u"SkyOff", 0, 0, + LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + } else if (timerName == KillStrombiesTimer) { + const auto enemies = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(EnemiesGroup)); + for (auto* enemy : enemies) { + RequestDie(self, enemy); + } - DestroySpawner(self->GetVar<std::string>(SmashablesSpawner)); - KillSpots(self); + DestroySpawner(self->GetVar<std::string>(SmashablesSpawner)); + KillSpots(self); - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player == nullptr) - return; + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player == nullptr) + return; - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); + GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); - self->AddTimer(ShowVendorTimer, 5.0f); - } else if (timerName == KillMarkerTimer) { - DestroySpawner(self->GetVar<std::string>(ClaimMarkerSpawner)); + self->AddTimer(ShowVendorTimer, 5.0f); + } else if (timerName == KillMarkerTimer) { + DestroySpawner(self->GetVar<std::string>(ClaimMarkerSpawner)); - for (const auto& behaviorObjectSpawner : self->GetVar<std::vector<std::string>>(BehaviorObjsSpawner)) { - DestroySpawner(behaviorObjectSpawner); - } + for (const auto& behaviorObjectSpawner : self->GetVar<std::vector<std::string>>(BehaviorObjsSpawner)) { + DestroySpawner(behaviorObjectSpawner); + } - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ImagOrbGroup))) { - entity->Smash(); - } + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ImagOrbGroup))) { + entity->Smash(); + } - DestroySpawner(self->GetVar<std::string>(ImageOrbSpawner)); + DestroySpawner(self->GetVar<std::string>(ImageOrbSpawner)); - self->AddTimer(ShowVendorTimer, 1.0f); - } else if (timerName == ShowVendorTimer) { - GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), - u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", - UNASSIGNED_SYSTEM_ADDRESS); + self->AddTimer(ShowVendorTimer, 1.0f); + } else if (timerName == ShowVendorTimer) { + GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), + u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", + UNASSIGNED_SYSTEM_ADDRESS); - for (const auto& ambientFXSpawner : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { - ActivateSpawner(ambientFXSpawner); - } - } else if (timerName == BoundsVisOnTimer) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - } else if (timerName == RunPlayerLoadedAgainTimer) { - CheckForOwner(self); - } else if (timerName == PollTornadoFXTimer) { - StartTornadoFx(self); - } else if (timerName == KillFXObjectTimer) { - const auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); - if (fxManagers.empty()) { - self->AddTimer(KillFXObjectTimer, 1.0f); - return; - } + for (const auto& ambientFXSpawner : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { + ActivateSpawner(ambientFXSpawner); + } + } else if (timerName == BoundsVisOnTimer) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, + LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + } else if (timerName == RunPlayerLoadedAgainTimer) { + CheckForOwner(self); + } else if (timerName == PollTornadoFXTimer) { + StartTornadoFx(self); + } else if (timerName == KillFXObjectTimer) { + const auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup)); + if (fxManagers.empty()) { + self->AddTimer(KillFXObjectTimer, 1.0f); + return; + } - for (auto* fxManager : fxManagers) { - auto* renderComponent = fxManager->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("beam"); - } - } + for (auto* fxManager : fxManagers) { + auto* renderComponent = fxManager->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("beam"); + } + } - DestroySpawner(self->GetVar<std::string>(FXManagerSpawner)); - self->SetVar<bool>(u"FXObjectGone", true); - } + DestroySpawner(self->GetVar<std::string>(FXManagerSpawner)); + self->SetVar<bool>(u"FXObjectGone", true); + } } void BasePropertyServer::HandleOrbsTimer(Entity* self) { - self->SetVar<bool>(CollidedVariable, false); - auto orbs = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ImagOrbGroup)); - if (orbs.empty()) { - self->AddTimer(StartOrbTimer, 0.5f); - return; - } + self->SetVar<bool>(CollidedVariable, false); + auto orbs = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ImagOrbGroup)); + if (orbs.empty()) { + self->AddTimer(StartOrbTimer, 0.5f); + return; + } - for (auto* orb : orbs) { - orb->AddCollisionPhantomCallback([self, this](Entity* other) { - if (other != nullptr && other->IsPlayer() && !self->GetVar<bool>(CollidedVariable)) { - self->SetVar<bool>(CollidedVariable, true); + for (auto* orb : orbs) { + orb->AddCollisionPhantomCallback([self, this](Entity* other) { + if (other != nullptr && other->IsPlayer() && !self->GetVar<bool>(CollidedVariable)) { + self->SetVar<bool>(CollidedVariable, true); - KillClouds(self); - DeactivateSpawner(self->GetVar<std::string>(GeneratorSpawner)); + KillClouds(self); + DeactivateSpawner(self->GetVar<std::string>(GeneratorSpawner)); - for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { - DeactivateSpawner(enemySpawner); - } + for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { + DeactivateSpawner(enemySpawner); + } - DestroySpawner(self->GetVar<std::string>(GeneratorFXSpawner)); - GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), - u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, - "DestroyMaelstrom", UNASSIGNED_SYSTEM_ADDRESS); + DestroySpawner(self->GetVar<std::string>(GeneratorFXSpawner)); + GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), + u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, + "DestroyMaelstrom", UNASSIGNED_SYSTEM_ADDRESS); - // Notifies the client that the property has been claimed with a flag, completes missions too - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - auto* character = player->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(self->GetVar<uint32_t>(defeatedProperyFlag), true); - } - } + // Notifies the client that the property has been claimed with a flag, completes missions too + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + auto* character = player->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(self->GetVar<int32_t>(defeatedProperyFlag), true); + } + } - self->AddTimer(TornadoOffTimer, 0.5f); - self->AddTimer(KillMarkerTimer, 0.7f); - } - }); - } + self->AddTimer(TornadoOffTimer, 0.5f); + self->AddTimer(KillMarkerTimer, 0.7f); + } + }); + } } void BasePropertyServer::HandleGeneratorTimer(Entity* self) { - auto generators = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GeneratorGroup)); - if (generators.empty()) { - self->AddTimer(StartGeneratorTimer, 0.5f); - return; - } + auto generators = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GeneratorGroup)); + if (generators.empty()) { + self->AddTimer(StartGeneratorTimer, 0.5f); + return; + } - for (auto* generator : generators) { - generator->AddDieCallback([self, this]() { - ActivateSpawner(self->GetVar<std::string>(ClaimMarkerSpawner)); - self->AddTimer(StartQuickbuildTimer, 0.0f); + for (auto* generator : generators) { + generator->AddDieCallback([self, this]() { + ActivateSpawner(self->GetVar<std::string>(ClaimMarkerSpawner)); + self->AddTimer(StartQuickbuildTimer, 0.0f); - for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { - DeactivateSpawner(enemySpawner); - } - DeactivateSpawner(self->GetVar<std::string>(GeneratorSpawner)); - }); - } + for (const auto& enemySpawner : self->GetVar<std::vector<std::string>>(EnemiesSpawner)) { + DeactivateSpawner(enemySpawner); + } + DeactivateSpawner(self->GetVar<std::string>(GeneratorSpawner)); + }); + } } void BasePropertyServer::HandleQuickBuildTimer(Entity* self) { - auto claimMarkers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ClaimMarkerGroup)); - if (claimMarkers.empty()) { - self->AddTimer(StartQuickbuildTimer, 0.5f); - return; - } + auto claimMarkers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(ClaimMarkerGroup)); + if (claimMarkers.empty()) { + self->AddTimer(StartQuickbuildTimer, 0.5f); + return; + } - for (auto* claimMarker : claimMarkers) { - // TODO: Send password? - } + for (auto* claimMarker : claimMarkers) { + // TODO: Send password? + } } diff --git a/dScripts/BasePropertyServer.h b/dScripts/BasePropertyServer.h index 79a52f54..da2d315b 100644 --- a/dScripts/BasePropertyServer.h +++ b/dScripts/BasePropertyServer.h @@ -4,24 +4,24 @@ class BasePropertyServer : public CppScripts::Script { public: - virtual void SetGameVariables(Entity* self); - virtual void CheckForOwner(Entity* self); - virtual void PropGuardCheck(Entity* self, Entity* player); + virtual void SetGameVariables(Entity* self); + virtual void CheckForOwner(Entity* self); + virtual void PropGuardCheck(Entity* self, Entity* player); - void OnStartup(Entity *self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; - void OnPlayerLoaded(Entity *self, Entity *player) override { BasePlayerLoaded(self, player); }; - void OnPlayerExit(Entity *self, Entity *player) override { BasePlayerExit(self, player); }; - void OnZonePropertyModelPlaced(Entity *self, Entity *player) override { BaseZonePropertyModelPlaced(self, player); } - void OnZonePropertyRented(Entity *self, Entity* renter) override { BaseZonePropertyRented(self, renter); }; - void OnTimerDone(Entity *self, std::string timerName) override { BaseTimerDone(self, timerName); }; + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; + void OnPlayerLoaded(Entity* self, Entity* player) override { BasePlayerLoaded(self, player); }; + void OnPlayerExit(Entity* self, Entity* player) override { BasePlayerExit(self, player); }; + void OnZonePropertyModelPlaced(Entity* self, Entity* player) override { BaseZonePropertyModelPlaced(self, player); } + void OnZonePropertyRented(Entity* self, Entity* renter) override { BaseZonePropertyRented(self, renter); }; + void OnTimerDone(Entity* self, std::string timerName) override { BaseTimerDone(self, timerName); }; virtual void BasePlayerLoaded(Entity* self, Entity* player); virtual void BaseZonePropertyRented(Entity* self, Entity* player) const; virtual void BaseZonePropertyModelPlaced(Entity* self, Entity* player) const; - virtual void BasePlayerExit(Entity *self, Entity *player); - virtual void BaseTimerDone(Entity* self, const std::string& timerName); + virtual void BasePlayerExit(Entity* self, Entity* player); + virtual void BaseTimerDone(Entity* self, const std::string& timerName); void KillClouds(Entity* self); virtual void SpawnSpots(Entity* self); @@ -39,79 +39,79 @@ public: static LWOOBJID GetOwner(); protected: - void HandleOrbsTimer(Entity* self); - void HandleGeneratorTimer(Entity* self); - void HandleQuickBuildTimer(Entity* self); + void HandleOrbsTimer(Entity* self); + void HandleGeneratorTimer(Entity* self); + void HandleQuickBuildTimer(Entity* self); - // GUIDs - std::string GUIDMaelstrom = "{7881e0a1-ef6d-420c-8040-f59994aa3357}"; - std::string GUIDPeaceful = "{c5725665-58d0-465f-9e11-aeb1d21842ba}"; + // GUIDs + std::string GUIDMaelstrom = "{7881e0a1-ef6d-420c-8040-f59994aa3357}"; + std::string GUIDPeaceful = "{c5725665-58d0-465f-9e11-aeb1d21842ba}"; - // Groups - std::u16string PropertyPlaqueGroup = u"PropertyPlaqueGroup"; - std::u16string PropertyVendorGroup = u"PropertyVendorGroup"; - std::u16string PropertyBorderGroup = u"PropertyBorderGroup"; - std::u16string SpotsGroup = u"SpotsGroup"; - std::u16string MSCloudsGroup = u"MSCloudsGroup"; - std::u16string GeneratorFXGroup = u"GeneratorFXGroup"; - std::u16string GeneratorGroup = u"GeneratorGroup"; - std::u16string ImagOrbGroup = u"ImagOrbGroup"; - std::u16string FXManagerGroup = u"FXManagerGroup"; - std::u16string ClaimMarkerGroup = u"ClaimMarkerGroup"; - std::u16string GuardGroup = u"GuardGroup"; - std::u16string EnemiesGroup = u"EnemiesGroup"; + // Groups + std::u16string PropertyPlaqueGroup = u"PropertyPlaqueGroup"; + std::u16string PropertyVendorGroup = u"PropertyVendorGroup"; + std::u16string PropertyBorderGroup = u"PropertyBorderGroup"; + std::u16string SpotsGroup = u"SpotsGroup"; + std::u16string MSCloudsGroup = u"MSCloudsGroup"; + std::u16string GeneratorFXGroup = u"GeneratorFXGroup"; + std::u16string GeneratorGroup = u"GeneratorGroup"; + std::u16string ImagOrbGroup = u"ImagOrbGroup"; + std::u16string FXManagerGroup = u"FXManagerGroup"; + std::u16string ClaimMarkerGroup = u"ClaimMarkerGroup"; + std::u16string GuardGroup = u"GuardGroup"; + std::u16string EnemiesGroup = u"EnemiesGroup"; - // Spawners - std::u16string EnemiesSpawner = u"EnemiesSpawner"; - std::u16string PropObjsSpawner = u"PropObjsSpawner"; - std::u16string PropertyMGSpawner = u"PropertyMGSpawner"; - std::u16string DamageFXSpawner = u"DamageFXSpawner"; - std::u16string FXSpotsSpawner = u"FXSpotsSpawner"; - std::u16string GeneratorSpawner = u"GeneratorSpawner"; - std::u16string GeneratorFXSpawner = u"GeneratorFXSpawner"; - std::u16string FXManagerSpawner = u"FXManagerSpawner"; - std::u16string ImageOrbSpawner = u"ImageOrbSpawner"; - std::u16string AmbientFXSpawner = u"AmbientFXSpawners"; - std::u16string SmashablesSpawner = u"SmashablesSpawner"; - std::u16string ClaimMarkerSpawner = u"ClaimMarkerSpawner"; - std::u16string BehaviorObjsSpawner = u"BehaviorObjsSpawner"; + // Spawners + std::u16string EnemiesSpawner = u"EnemiesSpawner"; + std::u16string PropObjsSpawner = u"PropObjsSpawner"; + std::u16string PropertyMGSpawner = u"PropertyMGSpawner"; + std::u16string DamageFXSpawner = u"DamageFXSpawner"; + std::u16string FXSpotsSpawner = u"FXSpotsSpawner"; + std::u16string GeneratorSpawner = u"GeneratorSpawner"; + std::u16string GeneratorFXSpawner = u"GeneratorFXSpawner"; + std::u16string FXManagerSpawner = u"FXManagerSpawner"; + std::u16string ImageOrbSpawner = u"ImageOrbSpawner"; + std::u16string AmbientFXSpawner = u"AmbientFXSpawners"; + std::u16string SmashablesSpawner = u"SmashablesSpawner"; + std::u16string ClaimMarkerSpawner = u"ClaimMarkerSpawner"; + std::u16string BehaviorObjsSpawner = u"BehaviorObjsSpawner"; - //Flags / constants - std::u16string guardFirstMissionFlag = u"guardFirstMissionFlag"; - std::u16string guardMissionFlag = u"guardMissionFlag"; - std::u16string brickLinkMissionIDFlag = u"brickLinkMissionIDFlag"; - std::u16string placedModelFlag = u"placedModelFlag"; - std::u16string generatorIdFlag = u"generatorIdFlag"; - std::u16string defeatedProperyFlag = u"defeatedProperyFlag"; - std::u16string passwordFlag = u"passwordFlag"; - std::u16string orbIDFlag = u"orbIDFlag"; - std::u16string behaviorQBID = u"behaviorQBID"; + //Flags / constants + std::u16string guardFirstMissionFlag = u"guardFirstMissionFlag"; + std::u16string guardMissionFlag = u"guardMissionFlag"; + std::u16string brickLinkMissionIDFlag = u"brickLinkMissionIDFlag"; + std::u16string placedModelFlag = u"placedModelFlag"; + std::u16string generatorIdFlag = u"generatorIdFlag"; + std::u16string defeatedProperyFlag = u"defeatedProperyFlag"; + std::u16string passwordFlag = u"passwordFlag"; + std::u16string orbIDFlag = u"orbIDFlag"; + std::u16string behaviorQBID = u"behaviorQBID"; - // Variables - std::u16string PlayerIDVariable = u"playerID"; - std::u16string CollidedVariable = u"collided"; - std::u16string PropertyOwnerVariable = u"PropertyOwner"; - std::u16string PropertyOwnerIDVariable = u"PropertyOwnerID"; - std::u16string FXObjectsGoneVariable = u"FXObjectGone"; - std::u16string RenterVariable = u"renter"; - std::u16string UnclaimedVariable = u"unclaimed"; + // Variables + std::u16string PlayerIDVariable = u"playerID"; + std::u16string CollidedVariable = u"collided"; + std::u16string PropertyOwnerVariable = u"PropertyOwner"; + std::u16string PropertyOwnerIDVariable = u"PropertyOwnerID"; + std::u16string FXObjectsGoneVariable = u"FXObjectGone"; + std::u16string RenterVariable = u"renter"; + std::u16string UnclaimedVariable = u"unclaimed"; - // Events - std::string CheckForPropertyOwnerEvent = "CheckForPropertyOwner"; + // Events + std::string CheckForPropertyOwnerEvent = "CheckForPropertyOwner"; - // Timers - std::string StartGeneratorTimer = "startGenerator"; - std::string StartOrbTimer = "startOrb"; - std::string StartQuickbuildTimer = "startQuickbuild"; - std::string TornadoOffTimer = "tornadoOff"; - std::string KillMarkerTimer = "killMarker"; - std::string KillGuardTimer = "KillGuard"; - std::string ShowClearEffectsTimer = "ShowClearEffects"; - std::string TurnSkyOffTimer = "turnSkyOff"; - std::string KillStrombiesTimer = "killStrombies"; - std::string KillFXObjectTimer = "killFXObject"; - std::string ShowVendorTimer = "ShowVendor"; - std::string BoundsVisOnTimer = "BoundsVisOn"; - std::string RunPlayerLoadedAgainTimer = "runPlayerLoadedAgain"; - std::string PollTornadoFXTimer = "pollTornadoFX"; + // Timers + std::string StartGeneratorTimer = "startGenerator"; + std::string StartOrbTimer = "startOrb"; + std::string StartQuickbuildTimer = "startQuickbuild"; + std::string TornadoOffTimer = "tornadoOff"; + std::string KillMarkerTimer = "killMarker"; + std::string KillGuardTimer = "KillGuard"; + std::string ShowClearEffectsTimer = "ShowClearEffects"; + std::string TurnSkyOffTimer = "turnSkyOff"; + std::string KillStrombiesTimer = "killStrombies"; + std::string KillFXObjectTimer = "killFXObject"; + std::string ShowVendorTimer = "ShowVendor"; + std::string BoundsVisOnTimer = "BoundsVisOn"; + std::string RunPlayerLoadedAgainTimer = "runPlayerLoadedAgain"; + std::string PollTornadoFXTimer = "pollTornadoFX"; }; diff --git a/dScripts/BaseRandomServer.cpp b/dScripts/BaseRandomServer.cpp index 7026178c..8cc4f993 100644 --- a/dScripts/BaseRandomServer.cpp +++ b/dScripts/BaseRandomServer.cpp @@ -4,199 +4,169 @@ #include "dLogger.h" #include "Entity.h" -void BaseRandomServer::BaseStartup(Entity* self) -{ - self->SetVar<std::string>(u"SpawnState", "min"); - self->SetVar<bool>(u"JustChanged", false); +void BaseRandomServer::BaseStartup(Entity* self) { + self->SetVar<std::string>(u"SpawnState", "min"); + self->SetVar<bool>(u"JustChanged", false); - CheckEvents(self); - SpawnMapZones(self); + CheckEvents(self); + SpawnMapZones(self); } -void BaseRandomServer::CheckEvents(Entity* self) -{ - // TODO: Add events? +void BaseRandomServer::CheckEvents(Entity* self) { + // TODO: Add events? } -void BaseRandomServer::SpawnMapZones(Entity* self) -{ - for (const auto& pair : sectionMultipliers) - { - const auto sectionName = zonePrefix + "_" + zoneName + "_" + pair.first; +void BaseRandomServer::SpawnMapZones(Entity* self) { + for (const auto& pair : sectionMultipliers) { + const auto sectionName = zonePrefix + "_" + zoneName + "_" + pair.first; - SpawnSection(self, sectionName, pair.second); - } + SpawnSection(self, sectionName, pair.second); + } - if (zoneName == "str") - { - SpawnNamedEnemy(self); - } + if (zoneName == "str") { + SpawnNamedEnemy(self); + } - self->SetVar(u"bInit", true); + self->SetVar(u"bInit", true); } -void BaseRandomServer::SpawnSection(Entity* self, const std::string& sectionName, float iMultiplier) -{ - Zone* spawnLoad = GetRandomLoad(self, sectionName); +void BaseRandomServer::SpawnSection(Entity* self, const std::string& sectionName, float iMultiplier) { + Zone* spawnLoad = GetRandomLoad(self, sectionName); - if (spawnLoad == nullptr) - { - Game::logger->Log("BaseRandomServer", "Failed to find section: %s\n", sectionName.c_str()); + if (spawnLoad == nullptr) { + Game::logger->Log("BaseRandomServer", "Failed to find section: %s", sectionName.c_str()); - return; - } + return; + } - for (const auto& spawnerData : spawnLoad->entries) - { - if (spawnerData.name.empty()) - { - continue; - } + for (const auto& spawnerData : spawnLoad->entries) { + if (spawnerData.name.empty()) { + continue; + } - const auto spawnNum = std::floor(spawnerData.num * iMultiplier); - const auto spawnerName = sectionName + "_" + spawnerData.name; + const auto spawnNum = std::floor(spawnerData.num * iMultiplier); + const auto spawnerName = sectionName + "_" + spawnerData.name; - SetSpawnerNetwork(self, spawnerName, spawnNum, spawnerData.lot); - } + SetSpawnerNetwork(self, spawnerName, spawnNum, spawnerData.lot); + } } -void BaseRandomServer::SetSpawnerNetwork(Entity* self, const std::string& spawnerName, int32_t spawnNum, LOT spawnLOT) -{ - const auto& spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); +void BaseRandomServer::SetSpawnerNetwork(Entity* self, const std::string& spawnerName, int32_t spawnNum, LOT spawnLOT) { + const auto& spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - if (spawnLOT == 11217 && spawnNum > 1) - { - spawnNum = 1; - } + if (spawnLOT == 11217 && spawnNum > 1) { + spawnNum = 1; + } - if (spawners.empty()) - { - Game::logger->Log("BaseRandomServer", "Failed to find spawner: %s\n", spawnerName.c_str()); + if (spawners.empty()) { + Game::logger->Log("BaseRandomServer", "Failed to find spawner: %s", spawnerName.c_str()); - return; - } + return; + } - auto* spawner = spawners[0]; + auto* spawner = spawners[0]; - if (spawnLOT != 0) - { - spawner->SetSpawnLot(spawnLOT); - spawner->SetRespawnTime(respawnTime); - } + if (spawnLOT != 0) { + spawner->SetSpawnLot(spawnLOT); + spawner->SetRespawnTime(respawnTime); + } - if (spawnNum != 0) - { - spawner->SetNumToMaintain(spawnNum); - } + if (spawnNum != 0) { + spawner->SetNumToMaintain(spawnNum); + } - if (spawnerName == "Named_Enemies") - { - spawner->SoftReset(); - } + if (spawnerName == "Named_Enemies") { + spawner->SoftReset(); + } - spawner->Activate(); + spawner->Activate(); - if (std::find(spawnersWatched.begin(), spawnersWatched.end(), spawner) != spawnersWatched.end()) - { - return; - } + if (std::find(spawnersWatched.begin(), spawnersWatched.end(), spawner) != spawnersWatched.end()) { + return; + } - spawner->AddSpawnedEntityDieCallback([this, self, spawner] () { - NotifySpawnerOfDeath(self, spawner); - }); + spawner->AddSpawnedEntityDieCallback([this, self, spawner]() { + NotifySpawnerOfDeath(self, spawner); + }); - spawnersWatched.push_back(spawner); + spawnersWatched.push_back(spawner); } -BaseRandomServer::Zone* BaseRandomServer::GetRandomLoad(Entity* self, const std::string& sectionName) -{ - const auto zoneInfo = GeneralUtils::SplitString(sectionName, '_'); +BaseRandomServer::Zone* BaseRandomServer::GetRandomLoad(Entity* self, const std::string& sectionName) { + const auto zoneInfo = GeneralUtils::SplitString(sectionName, '_'); - int32_t totalWeight = 0; + int32_t totalWeight = 0; - for (const auto& load : zones) - { - totalWeight += load.iChance; - } + for (const auto& load : zones) { + totalWeight += load.iChance; + } - const auto randWeight = GeneralUtils::GenerateRandomNumber<int32_t>(0, totalWeight); + const auto randWeight = GeneralUtils::GenerateRandomNumber<int32_t>(0, totalWeight); - int32_t weight = 0; - for (auto& zone : zones) - { - weight += zone.iChance; + int32_t weight = 0; + for (auto& zone : zones) { + weight += zone.iChance; - if (randWeight <= weight) - { - return &zone; - } - } + if (randWeight <= weight) { + return &zone; + } + } - return nullptr; + return nullptr; } -void BaseRandomServer::NotifySpawnerOfDeath(Entity* self, Spawner* spawner) -{ - const auto& spawnerName = spawner->GetName(); +void BaseRandomServer::NotifySpawnerOfDeath(Entity* self, Spawner* spawner) { + const auto& spawnerName = spawner->GetName(); - if (spawnerName == "Named_Enemies") - { - NamedEnemyDeath(self, spawner); + if (spawnerName == "Named_Enemies") { + NamedEnemyDeath(self, spawner); - return; - } + return; + } - const auto& sectionName = spawnerName.substr(0, spawnerName.size() - 7); + const auto& sectionName = spawnerName.substr(0, spawnerName.size() - 7); - const auto variableName = u"mobsDead" + GeneralUtils::ASCIIToUTF16(sectionName); + const auto variableName = u"mobsDead" + GeneralUtils::ASCIIToUTF16(sectionName); - auto mobDeathCount = self->GetVar<int32_t>(variableName); + auto mobDeathCount = self->GetVar<int32_t>(variableName); - mobDeathCount++; + mobDeathCount++; - if (mobDeathCount >= mobDeathResetNumber) - { - const auto& zoneInfo = GeneralUtils::SplitString(sectionName, '_'); + if (mobDeathCount >= mobDeathResetNumber) { + const auto& zoneInfo = GeneralUtils::SplitString(sectionName, '_'); - SpawnSection(self, sectionName, sectionMultipliers[zoneInfo[sectionIDConst - 1]]); - } + SpawnSection(self, sectionName, sectionMultipliers[zoneInfo[sectionIDConst - 1]]); + } - self->SetVar(variableName, mobDeathCount); + self->SetVar(variableName, mobDeathCount); } -void BaseRandomServer::NamedEnemyDeath(Entity* self, Spawner* spawner) -{ - const auto spawnDelay = GeneralUtils::GenerateRandomNumber<float>(1, 2) * 450; +void BaseRandomServer::NamedEnemyDeath(Entity* self, Spawner* spawner) { + const auto spawnDelay = GeneralUtils::GenerateRandomNumber<float>(1, 2) * 450; - self->AddTimer("SpawnNewEnemy", spawnDelay); + self->AddTimer("SpawnNewEnemy", spawnDelay); } -void BaseRandomServer::SpawnersUp(Entity* self) -{ +void BaseRandomServer::SpawnersUp(Entity* self) { } -void BaseRandomServer::SpawnersDown(Entity* self) -{ +void BaseRandomServer::SpawnersDown(Entity* self) { } -void BaseRandomServer::BaseOnTimerDone(Entity* self, const std::string& timerName) -{ - NamedTimerDone(self, timerName); +void BaseRandomServer::BaseOnTimerDone(Entity* self, const std::string& timerName) { + NamedTimerDone(self, timerName); } -void BaseRandomServer::SpawnNamedEnemy(Entity* self) -{ - const auto enemy = namedMobs[GeneralUtils::GenerateRandomNumber<int32_t>(0, namedMobs.size() - 1)]; +void BaseRandomServer::SpawnNamedEnemy(Entity* self) { + const auto enemy = namedMobs[GeneralUtils::GenerateRandomNumber<int32_t>(0, namedMobs.size() - 1)]; - SetSpawnerNetwork(self, "Named_Enemies", 1, enemy); + SetSpawnerNetwork(self, "Named_Enemies", 1, enemy); } -void BaseRandomServer::NamedTimerDone(Entity* self, const std::string& timerName) -{ - if (timerName == "SpawnNewEnemy") - { - SpawnNamedEnemy(self); - } +void BaseRandomServer::NamedTimerDone(Entity* self, const std::string& timerName) { + if (timerName == "SpawnNewEnemy") { + SpawnNamedEnemy(self); + } } diff --git a/dScripts/BaseRandomServer.h b/dScripts/BaseRandomServer.h index 68aadf30..bc5d6b21 100644 --- a/dScripts/BaseRandomServer.h +++ b/dScripts/BaseRandomServer.h @@ -6,54 +6,54 @@ class Spawner; class BaseRandomServer { public: - struct ZoneEntry - { - LOT lot; - int32_t num; - std::string name; - }; + struct ZoneEntry + { + LOT lot; + int32_t num; + std::string name; + }; - struct Zone - { - std::vector<BaseRandomServer::ZoneEntry> entries; - int32_t iChance; - }; + struct Zone + { + std::vector<BaseRandomServer::ZoneEntry> entries; + int32_t iChance; + }; - void BaseStartup(Entity* self); - void CheckEvents(Entity* self); - void SpawnMapZones(Entity* self); - void SpawnSection(Entity* self, const std::string& sectionName, float iMultiplier); - void SetSpawnerNetwork(Entity* self, const std::string& spawnerName, int32_t spawnNum, LOT spawnLOT); - BaseRandomServer::Zone* GetRandomLoad(Entity* self, const std::string& sectionName); - void SpawnersUp(Entity* self); - void SpawnersDown(Entity* self); - void BaseOnTimerDone(Entity* self, const std::string& timerName); - - void NotifySpawnerOfDeath(Entity* self, Spawner* spawner); - void NamedEnemyDeath(Entity* self, Spawner* spawner); + void BaseStartup(Entity* self); + void CheckEvents(Entity* self); + void SpawnMapZones(Entity* self); + void SpawnSection(Entity* self, const std::string& sectionName, float iMultiplier); + void SetSpawnerNetwork(Entity* self, const std::string& spawnerName, int32_t spawnNum, LOT spawnLOT); + BaseRandomServer::Zone* GetRandomLoad(Entity* self, const std::string& sectionName); + void SpawnersUp(Entity* self); + void SpawnersDown(Entity* self); + void BaseOnTimerDone(Entity* self, const std::string& timerName); - void SpawnNamedEnemy(Entity* self); + void NotifySpawnerOfDeath(Entity* self, Spawner* spawner); + void NamedEnemyDeath(Entity* self, Spawner* spawner); - void NamedTimerDone(Entity* self, const std::string& timerName); + void SpawnNamedEnemy(Entity* self); + + void NamedTimerDone(Entity* self, const std::string& timerName); protected: - std::vector<int32_t> namedMobs = { - 11988, // Ronin - 11984, // Spiderling - 12654, // Horsemen - 11986, // Admiral - 11983, // Mech - 11982, // Stromling - 11985 // Pirate - }; - std::map<std::string, float> sectionMultipliers = {}; - int32_t mobDeathResetNumber = 30; - std::string zonePrefix = "em"; - int32_t zoneNameConst = 2; - int32_t sectionIDConst = 3; - std::string zoneName = "fin"; - std::vector<Zone> zones = {}; - int32_t changeNum = 15; - int32_t respawnTime = 80; - std::vector<Spawner*> spawnersWatched; + std::vector<int32_t> namedMobs = { + 11988, // Ronin + 11984, // Spiderling + 12654, // Horsemen + 11986, // Admiral + 11983, // Mech + 11982, // Stromling + 11985 // Pirate + }; + std::map<std::string, float> sectionMultipliers = {}; + int32_t mobDeathResetNumber = 30; + std::string zonePrefix = "em"; + int32_t zoneNameConst = 2; + int32_t sectionIDConst = 3; + std::string zoneName = "fin"; + std::vector<Zone> zones = {}; + int32_t changeNum = 15; + int32_t respawnTime = 80; + std::vector<Spawner*> spawnersWatched; }; diff --git a/dScripts/BaseSurvivalServer.cpp b/dScripts/BaseSurvivalServer.cpp index f6a326e8..3d72628d 100644 --- a/dScripts/BaseSurvivalServer.cpp +++ b/dScripts/BaseSurvivalServer.cpp @@ -4,574 +4,571 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include "Character.h" -void BaseSurvivalServer::SetGameVariables(Entity *self) { - this->constants = std::move(GetConstants()); - this->mobSets = std::move(GetMobSets()); - this->spawnerNetworks = std::move(GetSpawnerNetworks()); - this->missionsToUpdate = std::move(GetMissionsToUpdate()); +void BaseSurvivalServer::SetGameVariables(Entity* self) { + this->constants = std::move(GetConstants()); + this->mobSets = std::move(GetMobSets()); + this->spawnerNetworks = std::move(GetSpawnerNetworks()); + this->missionsToUpdate = std::move(GetMissionsToUpdate()); } void BaseSurvivalServer::BasePlayerLoaded(Entity* self, Entity* player) { - const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); - const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); + const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); + const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); - if (waitingIter != state.waitingPlayers.end() || playersIter != state.players.end()) - { - static_cast<Player*>(player)->SendToZone(player->GetCharacter()->GetLastNonInstanceZoneID()); + if (waitingIter != state.waitingPlayers.end() || playersIter != state.players.end()) { + static_cast<Player*>(player)->SendToZone(player->GetCharacter()->GetLastNonInstanceZoneID()); - return; - } + return; + } - state.waitingPlayers.push_back(player->GetObjectID()); - state.players.push_back(player->GetObjectID()); + state.waitingPlayers.push_back(player->GetObjectID()); + state.players.push_back(player->GetObjectID()); - self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1); - self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); + self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1); + self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); - // Notify the players of all other players - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - auto counter = 1; - for (const auto& playerID : state.players) { - self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); - counter++; - } + // Notify the players of all other players + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + auto counter = 1; + for (const auto& playerID : state.players) { + self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); + counter++; + } - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); - } + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); + } - SetPlayerSpawnPoints(); + SetPlayerSpawnPoints(); - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - PlayerConfirmed(self); - } else { - UpdatePlayer(self, player->GetObjectID()); - GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50); - ResetStats(player->GetObjectID()); - } + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + PlayerConfirmed(self); + } else { + UpdatePlayer(self, player->GetObjectID()); + GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50); + ResetStats(player->GetObjectID()); + } - player->AddCallbackTimer(5.0f, [this, self, player] () { - self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)); - self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - auto counter = 1; - for (const auto& playerID : state.players) { - self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); - counter++; - } + player->AddCallbackTimer(5.0f, [this, self, player]() { + self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)); + self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + auto counter = 1; + for (const auto& playerID : state.players) { + self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); + counter++; + } - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); - } - }); + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); + } + }); } void BaseSurvivalServer::BaseStartup(Entity* self) { - self->SetVar<uint32_t>(PlayersAcceptedVariable, 0); - self->SetVar<bool>(PlayersReadyVariable, false); + self->SetVar<uint32_t>(PlayersAcceptedVariable, 0); + self->SetVar<bool>(PlayersReadyVariable, false); } void BaseSurvivalServer::BasePlayerExit(Entity* self, Entity* player) { - const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); - const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); + const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); + const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); - if (waitingIter != state.waitingPlayers.end()) - { - state.waitingPlayers.erase(waitingIter); - } + if (waitingIter != state.waitingPlayers.end()) { + state.waitingPlayers.erase(waitingIter); + } - if (playersIter != state.players.end()) - { - state.players.erase(playersIter); - } + if (playersIter != state.players.end()) { + state.players.erase(playersIter); + } - if (waitingIter == state.waitingPlayers.end() && playersIter == state.players.end()) - { - return; - } + if (waitingIter == state.waitingPlayers.end() && playersIter == state.players.end()) { + return; + } - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - PlayerConfirmed(self); + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + PlayerConfirmed(self); - if (state.players.empty()) - return; + if (state.players.empty()) + return; - if (state.waitingPlayers.empty()) { - ActivityTimerStopAllTimers(self); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay); - } else if (state.players.size() > state.waitingPlayers.size()) { - if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { - self->SetVar<bool>(AcceptedDelayStartedVariable, true); - ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay); - } - } - } else { - UpdatePlayer(self, player->GetObjectID(), true); - if (CheckAllPlayersDead()) { - GameOver(self); - } - } + if (state.waitingPlayers.empty()) { + ActivityTimerStopAllTimers(self); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay); + } else if (state.players.size() > state.waitingPlayers.size()) { + if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { + self->SetVar<bool>(AcceptedDelayStartedVariable, true); + ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay); + } + } + } else { + UpdatePlayer(self, player->GetObjectID(), true); + if (CheckAllPlayersDead()) { + GameOver(self); + } + } - SetActivityValue(self, player->GetObjectID(), 1, 0); - self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, - std::min((uint32_t) 0, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1)); + SetActivityValue(self, player->GetObjectID(), 1, 0); + self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, + std::min((uint32_t)0, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1)); } void BaseSurvivalServer::BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "start") { - StartWaves(self); - } else if (args == "DeactivateRewards") { - SpawnerReset(spawnerNetworks.rewardNetworks); - } else if (sender != nullptr && IsPlayerInActivity(self, sender->GetObjectID())) { - auto currentScore = GetActivityValue(self, sender->GetObjectID(), 0); - SetActivityValue(self, sender->GetObjectID(), 0, currentScore + param1); - } + int32_t param3) { + if (args == "start") { + StartWaves(self); + } else if (args == "DeactivateRewards") { + SpawnerReset(spawnerNetworks.rewardNetworks); + } else if (sender != nullptr && IsPlayerInActivity(self, sender->GetObjectID())) { + auto currentScore = GetActivityValue(self, sender->GetObjectID(), 0); + SetActivityValue(self, sender->GetObjectID(), 0, currentScore + param1); + } } void BaseSurvivalServer::BasePlayerDied(Entity* self, Entity* player) { - if (self->GetNetworkVar<bool>(WavesStartedVariable)) { - const auto finalTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); - SetActivityValue(self, player->GetObjectID(), 1, finalTime); + if (self->GetNetworkVar<bool>(WavesStartedVariable)) { + const auto finalTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); + SetActivityValue(self, player->GetObjectID(), 1, finalTime); - auto paramString = CheckAllPlayersDead() ? "true" : "false"; - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0, - player->GetObjectID(), paramString, player->GetSystemAddress()); - GameOver(self); - } else { - player->Resurrect(); - SetPlayerSpawnPoints(); - } + auto paramString = CheckAllPlayersDead() ? "true" : "false"; + GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0, + player->GetObjectID(), paramString, player->GetSystemAddress()); + GameOver(self); + } else { + player->Resurrect(); + SetPlayerSpawnPoints(); + } } -void BaseSurvivalServer::BasePlayerResurrected(Entity *self, Entity *player) { - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); +void BaseSurvivalServer::BasePlayerResurrected(Entity* self, Entity* player) { + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); } void BaseSurvivalServer::BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button, - const std::u16string &identifier, const std::u16string &userData) { - if (identifier == u"RePlay") { - PlayerAccepted(self, sender->GetObjectID()); - PlayerConfirmed(self); - } else if (identifier == u"Exit_Question" && button == 1) { - ResetStats(sender->GetObjectID()); - self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID())); + const std::u16string& identifier, const std::u16string& userData) { + if (identifier == u"RePlay") { + PlayerAccepted(self, sender->GetObjectID()); + PlayerConfirmed(self); + } else if (identifier == u"Exit_Question" && button == 1) { + ResetStats(sender->GetObjectID()); + self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID())); - if (sender->IsPlayer()) { - auto* character = sender->GetCharacter(); - if (character != nullptr) { - auto* player = dynamic_cast<Player*>(sender); - player->SendToZone(character->GetLastNonInstanceZoneID()); - } - } - } + if (sender->IsPlayer()) { + auto* character = sender->GetCharacter(); + if (character != nullptr) { + auto* player = dynamic_cast<Player*>(sender); + player->SendToZone(character->GetLastNonInstanceZoneID()); + } + } + } } -void BaseSurvivalServer::OnActivityTimerUpdate(Entity *self, const std::string &name, float_t remainingTime, float_t elapsedTime) { - if (name == AcceptedDelayTimer) { - self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, remainingTime); - } else if (name == ClockTickTimer) { - self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime); - } else if (name == SpawnTickTimer && !self->GetVar<bool>(IsCooldownVariable)) { - SpawnMobs(self); - } +void BaseSurvivalServer::OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) { + if (name == AcceptedDelayTimer) { + self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, remainingTime); + } else if (name == ClockTickTimer) { + self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime); + } else if (name == SpawnTickTimer && !self->GetVar<bool>(IsCooldownVariable)) { + SpawnMobs(self); + } } -void BaseSurvivalServer::OnActivityTimerDone(Entity *self, const std::string &name) { - auto cooldownTime = constants.rewardInterval * constants.waveTime; +void BaseSurvivalServer::OnActivityTimerDone(Entity* self, const std::string& name) { + auto cooldownTime = constants.rewardInterval * constants.waveTime; - if (name == AcceptedDelayTimer) { - self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, 0); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1); - } else if (name == AllAcceptedDelayTimer) { - self->SetNetworkVar<bool>(ClearScoreboardVariable, true); - ActivityTimerStart(self, StartDelayTimer, 3, 3); + if (name == AcceptedDelayTimer) { + self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, 0); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1); + } else if (name == AllAcceptedDelayTimer) { + self->SetNetworkVar<bool>(ClearScoreboardVariable, true); + ActivityTimerStart(self, StartDelayTimer, 3, 3); - StartWaves(self); - } else if (name == StartDelayTimer) { - ActivityTimerStart(self, ClockTickTimer, 1); - ActivityTimerStart(self, SpawnTickTimer, constants.waveTime); - SpawnMobs(self); - ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); - ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime); - } else if (name == CoolDownStartTimer) { - self->SetVar<bool>(IsCooldownVariable, true); + StartWaves(self); + } else if (name == StartDelayTimer) { + ActivityTimerStart(self, ClockTickTimer, 1); + ActivityTimerStart(self, SpawnTickTimer, constants.waveTime); + SpawnMobs(self); + ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); + ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime); + } else if (name == CoolDownStartTimer) { + self->SetVar<bool>(IsCooldownVariable, true); - ActivityTimerStop(self, SpawnTickTimer); - ActivityTimerStart(self, CoolDownStopTimer, 1, constants.coolDownTime); + ActivityTimerStop(self, SpawnTickTimer); + ActivityTimerStart(self, CoolDownStopTimer, 1, constants.coolDownTime); - ActivateSpawnerNetwork(spawnerNetworks.rewardNetworks); - SpawnerReset(spawnerNetworks.baseNetworks, false); - SpawnerReset(spawnerNetworks.randomNetworks, false); - } else if (name == CoolDownStopTimer) { - self->SetVar<bool>(IsCooldownVariable, false); + ActivateSpawnerNetwork(spawnerNetworks.rewardNetworks); + SpawnerReset(spawnerNetworks.baseNetworks, false); + SpawnerReset(spawnerNetworks.randomNetworks, false); + } else if (name == CoolDownStopTimer) { + self->SetVar<bool>(IsCooldownVariable, false); - ActivityTimerStart(self, SpawnTickTimer, constants.waveTime); - ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime); + ActivityTimerStart(self, SpawnTickTimer, constants.waveTime); + ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime); - SpawnMobs(self); - ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); - } else if (name == PlaySpawnSoundTimer) { - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); - } - } - } + SpawnMobs(self); + ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); + } else if (name == PlaySpawnSoundTimer) { + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); + } + } + } } void BaseSurvivalServer::ResetStats(LWOOBJID playerID) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { - // Boost all the player stats when loading in - auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); - destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); - destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination()); - } - } + // Boost all the player stats when loading in + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); + destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); + destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination()); + } + } } void BaseSurvivalServer::PlayerConfirmed(Entity* self) { - std::vector<LWOOBJID> confirmedPlayers {}; + std::vector<LWOOBJID> confirmedPlayers{}; - for (const auto& playerID : state.players) { - auto pass = false; - for (const auto& waitingPlayerID : state.waitingPlayers) { - if (waitingPlayerID == playerID) - pass = true; - } + for (const auto& playerID : state.players) { + auto pass = false; + for (const auto& waitingPlayerID : state.waitingPlayers) { + if (waitingPlayerID == playerID) + pass = true; + } - if (!pass) - confirmedPlayers.push_back(playerID); - } + if (!pass) + confirmedPlayers.push_back(playerID); + } - auto playerIndex = 1; - for (const auto& playerID : confirmedPlayers) { - self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID)); - playerIndex++; - } + auto playerIndex = 1; + for (const auto& playerID : confirmedPlayers) { + self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID)); + playerIndex++; + } } -void BaseSurvivalServer::PlayerAccepted(Entity *self, LWOOBJID playerID) { - const auto& iter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID); +void BaseSurvivalServer::PlayerAccepted(Entity* self, LWOOBJID playerID) { + const auto& iter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID); - if (iter == state.waitingPlayers.end()) { - return; - } + if (iter == state.waitingPlayers.end()) { + return; + } - state.waitingPlayers.erase(iter); + state.waitingPlayers.erase(iter); - if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) { - ActivityTimerStopAllTimers(self); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay); - } else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { - self->SetVar<bool>(AcceptedDelayStartedVariable, true); - ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay); - } + if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) { + ActivityTimerStopAllTimers(self); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay); + } else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { + self->SetVar<bool>(AcceptedDelayStartedVariable, true); + ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay); + } } -void BaseSurvivalServer::StartWaves(Entity *self) { - GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); +void BaseSurvivalServer::StartWaves(Entity* self) { + GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - self->SetVar<bool>(PlayersReadyVariable, true); - self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0); - self->SetVar<uint32_t>(RandMobSetIndexVariable, 0); - self->SetVar<bool>(AcceptedDelayStartedVariable, false); + self->SetVar<bool>(PlayersReadyVariable, true); + self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0); + self->SetVar<uint32_t>(RandMobSetIndexVariable, 0); + self->SetVar<bool>(AcceptedDelayStartedVariable, false); - state.waitingPlayers.clear(); + state.waitingPlayers.clear(); - for (const auto& playerID : state.players) { - const auto player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - state.waitingPlayers.push_back(playerID); - UpdatePlayer(self, playerID); - GetLeaderboardData(self, playerID, GetActivityID(self), 50); - ResetStats(playerID); + for (const auto& playerID : state.players) { + const auto player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + state.waitingPlayers.push_back(playerID); + UpdatePlayer(self, playerID); + GetLeaderboardData(self, playerID, GetActivityID(self), 50); + ResetStats(playerID); - if (!self->GetVar<bool>(FirstTimeDoneVariable)) { - TakeActivityCost(self, playerID); - } + if (!self->GetVar<bool>(FirstTimeDoneVariable)) { + TakeActivityCost(self, playerID); + } - GameMessages::SendPlayerSetCameraCyclingMode(playerID, player->GetSystemAddress()); - } - } + GameMessages::SendPlayerSetCameraCyclingMode(playerID, player->GetSystemAddress()); + } + } - self->SetVar<bool>(FirstTimeDoneVariable, true); - self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team"); + self->SetVar<bool>(FirstTimeDoneVariable, true); + self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team"); - ActivateSpawnerNetwork(spawnerNetworks.smashNetworks); - self->SetNetworkVar<bool>(WavesStartedVariable, true); - self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!"); + ActivateSpawnerNetwork(spawnerNetworks.smashNetworks); + self->SetNetworkVar<bool>(WavesStartedVariable, true); + self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!"); } bool BaseSurvivalServer::CheckAllPlayersDead() { - auto deadPlayers = 0; + auto deadPlayers = 0; - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr || player->GetIsDead()) { - deadPlayers++; - } - } + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr || player->GetIsDead()) { + deadPlayers++; + } + } - return deadPlayers >= state.players.size(); + return deadPlayers >= state.players.size(); } void BaseSurvivalServer::SetPlayerSpawnPoints() { - auto spawnerIndex = 1; - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); - if (!possibleSpawners.empty()) { - auto* spawner = possibleSpawners.at(0); - GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); - } - } + auto spawnerIndex = 1; + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); + if (!possibleSpawners.empty()) { + auto* spawner = possibleSpawners.at(0); + GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); + } + } - spawnerIndex++; - } + spawnerIndex++; + } } -void BaseSurvivalServer::GameOver(Entity *self) { - if (!CheckAllPlayersDead()) - return; +void BaseSurvivalServer::GameOver(Entity* self) { + if (!CheckAllPlayersDead()) + return; - ActivityTimerStopAllTimers(self); + ActivityTimerStopAllTimers(self); - // Reset all the spawners - SpawnerReset(spawnerNetworks.baseNetworks); - SpawnerReset(spawnerNetworks.randomNetworks); - SpawnerReset(spawnerNetworks.rewardNetworks); + // Reset all the spawners + SpawnerReset(spawnerNetworks.baseNetworks); + SpawnerReset(spawnerNetworks.randomNetworks); + SpawnerReset(spawnerNetworks.rewardNetworks); - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - continue; + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + continue; - const auto score = GetActivityValue(self, playerID, 0); - const auto time = GetActivityValue(self, playerID, 1); + const auto score = GetActivityValue(self, playerID, 0); + const auto time = GetActivityValue(self, playerID, 1); - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, - playerID, std::to_string(score), UNASSIGNED_SYSTEM_ADDRESS); - player->Resurrect(); + GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, + playerID, std::to_string(score), UNASSIGNED_SYSTEM_ADDRESS); + player->Resurrect(); - // Update all mission progression - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, time, self->GetObjectID(), - self->GetVar<std::string>(MissionTypeVariable)); + // Update all mission progression + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(), + self->GetVar<std::string>(MissionTypeVariable)); - for (const auto& survivalMission : missionsToUpdate) { - auto* mission = missionComponent->GetMission(survivalMission.first); - if (mission != nullptr && (uint32_t) time >= survivalMission.second - && (mission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE - || mission->GetMissionState() == MissionState::MISSION_STATE_COMPLETE_ACTIVE)) { + for (const auto& survivalMission : missionsToUpdate) { + auto* mission = missionComponent->GetMission(survivalMission.first); + if (mission != nullptr && (uint32_t)time >= survivalMission.second + && (mission->GetMissionState() == eMissionState::ACTIVE + || mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - } - } + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + } + } - StopActivity(self, playerID, score, time); - } + StopActivity(self, playerID, score, time); + } - state.waveNumber = 1; - state.rewardTick = 1; - state.totalSpawned = 0; + state.waveNumber = 1; + state.rewardTick = 1; + state.totalSpawned = 0; - self->SetNetworkVar<bool>(WavesStartedVariable, false); + self->SetNetworkVar<bool>(WavesStartedVariable, false); - if (constants.useMobLots) { - constants.lotPhase = 0; - UpdateMobLots(spawnerNetworks.baseNetworks); - UpdateMobLots(spawnerNetworks.randomNetworks); - } + if (constants.useMobLots) { + constants.lotPhase = 0; + UpdateMobLots(spawnerNetworks.baseNetworks); + UpdateMobLots(spawnerNetworks.randomNetworks); + } - SetPlayerSpawnPoints(); + SetPlayerSpawnPoints(); } void BaseSurvivalServer::SpawnerReset(SpawnerNetworkCollection& spawnerNetworkCollection, bool hardReset) { - auto totalSpawned = 0; + auto totalSpawned = 0; - for (auto& spawner : spawnerNetworkCollection.networks) { - for (auto& spawnerName : spawner.names) { - auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); - if (!spawners.empty()) { - auto* spawnerObject = spawners.at(0); + for (auto& spawner : spawnerNetworkCollection.networks) { + for (auto& spawnerName : spawner.names) { + auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); + if (!spawners.empty()) { + auto* spawnerObject = spawners.at(0); - auto amountSpawned = spawnerObject->GetAmountSpawned(); - totalSpawned += amountSpawned; + auto amountSpawned = spawnerObject->GetAmountSpawned(); + totalSpawned += amountSpawned; - spawner.isActive = false; - if (hardReset) { - spawnerObject->Reset(); - } else { - spawnerObject->SoftReset(); - } + spawner.isActive = false; + if (hardReset) { + spawnerObject->Reset(); + } else { + spawnerObject->SoftReset(); + } - spawnerObject->Deactivate(); - } - } - } + spawnerObject->Deactivate(); + } + } + } - state.totalSpawned = std::max((uint32_t) totalSpawned, state.totalSpawned); + state.totalSpawned = std::max((uint32_t)totalSpawned, state.totalSpawned); } void BaseSurvivalServer::SpawnerUpdate(Entity* self, SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t amount) { - if (spawnerNetworkCollection.networks.empty()) - return; + if (spawnerNetworkCollection.networks.empty()) + return; - // If we want to spawn something specific now - if (amount != 0) { - auto spawnerNetwork = spawnerNetworkCollection.networks.at(0); - auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerNetwork.names.at(0) + spawnerNetwork.number); - if (!possibleSpawners.empty()) { - SpawnNow(possibleSpawners.at(0), amount); - return; - } - } + // If we want to spawn something specific now + if (amount != 0) { + auto spawnerNetwork = spawnerNetworkCollection.networks.at(0); + auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerNetwork.names.at(0) + spawnerNetwork.number); + if (!possibleSpawners.empty()) { + SpawnNow(possibleSpawners.at(0), amount); + return; + } + } - auto setNumber = self->GetVar<uint32_t>(GeneralUtils::ASCIIToUTF16(spawnerNetworkCollection.mobSetName + "Num")); - auto newSet = GetRandomMobSet(spawnerNetworkCollection, setNumber); + auto setNumber = self->GetVar<uint32_t>(GeneralUtils::ASCIIToUTF16(spawnerNetworkCollection.mobSetName + "Num")); + auto newSet = GetRandomMobSet(spawnerNetworkCollection, setNumber); - if (!newSet.empty()) { - auto spawnerNetwork = GetRandomSpawner(spawnerNetworkCollection); - for (auto i = 0; i < spawnerNetwork.names.size(); i++) { - const auto& name = spawnerNetwork.names.at(i); - const auto& toSpawn = newSet.at(i); + if (!newSet.empty()) { + auto spawnerNetwork = GetRandomSpawner(spawnerNetworkCollection); + for (auto i = 0; i < spawnerNetwork.names.size(); i++) { + const auto& name = spawnerNetwork.names.at(i); + const auto& toSpawn = newSet.at(i); - auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(name + spawnerNetwork.number); - if (!possibleSpawners.empty()) { - SpawnNow(possibleSpawners.front(), toSpawn); - } - } - } + auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(name + spawnerNetwork.number); + if (!possibleSpawners.empty()) { + SpawnNow(possibleSpawners.front(), toSpawn); + } + } + } } -void BaseSurvivalServer::SpawnNow(Spawner *spawner, uint32_t amount) { - if (spawner != nullptr) { - if (!spawner->m_Active) { - spawner->m_Info.amountMaintained = amount; - spawner->Activate(); - } else { - spawner->m_Info.amountMaintained = amount; - } - } +void BaseSurvivalServer::SpawnNow(Spawner* spawner, uint32_t amount) { + if (spawner != nullptr) { + if (!spawner->m_Active) { + spawner->m_Info.amountMaintained = amount; + spawner->Activate(); + } else { + spawner->m_Info.amountMaintained = amount; + } + } } std::vector<uint32_t> BaseSurvivalServer::GetRandomMobSet(SpawnerNetworkCollection& spawnerNetworkCollection, - uint32_t setNumber) { + uint32_t setNumber) { - if (mobSets.sets.find(spawnerNetworkCollection.mobSetName) != mobSets.sets.end()) { - auto mobSet = mobSets.sets.at(spawnerNetworkCollection.mobSetName); - if (setNumber < mobSet.size()) { - return mobSet.at(setNumber).at(rand() % mobSet.at(setNumber).size()); - } - } + if (mobSets.sets.find(spawnerNetworkCollection.mobSetName) != mobSets.sets.end()) { + auto mobSet = mobSets.sets.at(spawnerNetworkCollection.mobSetName); + if (setNumber < mobSet.size()) { + return mobSet.at(setNumber).at(rand() % mobSet.at(setNumber).size()); + } + } - return {}; + return {}; } SpawnerNetwork BaseSurvivalServer::GetRandomSpawner(SpawnerNetworkCollection& spawnerNetworkCollection) { - std::vector<SpawnerNetwork> validSpawners {}; - for (const auto& spawner : spawnerNetworkCollection.networks) { - if (!spawner.isLocked) - validSpawners.push_back(spawner); - } + std::vector<SpawnerNetwork> validSpawners{}; + for (const auto& spawner : spawnerNetworkCollection.networks) { + if (!spawner.isLocked) + validSpawners.push_back(spawner); + } - if (!validSpawners.empty()) { - auto spawner = validSpawners.at(rand() % validSpawners.size()); - spawner.isActive = true; - return spawner; - } + if (!validSpawners.empty()) { + auto spawner = validSpawners.at(rand() % validSpawners.size()); + spawner.isActive = true; + return spawner; + } - return {}; + return {}; } void BaseSurvivalServer::ActivateSpawnerNetwork(SpawnerNetworkCollection& spawnerNetworkCollection) { - for (auto& spawner : spawnerNetworkCollection.networks) { - for (const auto& spawnerName : spawner.names) { - auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); - if (!possibleSpawners.empty()) { - auto* spawnerObject = possibleSpawners.at(0); - spawnerObject->Activate(); - spawnerObject->Reset(); - } - } - } + for (auto& spawner : spawnerNetworkCollection.networks) { + for (const auto& spawnerName : spawner.names) { + auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); + if (!possibleSpawners.empty()) { + auto* spawnerObject = possibleSpawners.at(0); + spawnerObject->Activate(); + spawnerObject->Reset(); + } + } + } } void BaseSurvivalServer::UpdateMobLots(SpawnerNetworkCollection& spawnerNetworkCollection) { - for (auto& spawner : spawnerNetworkCollection.networks) { - for (auto& spawnerName : spawner.names) { - if (!spawnerName.empty()) { - auto spawnerObjects = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); - if (!spawnerObjects.empty()) { - auto splitName = GeneralUtils::SplitString(spawnerName, '_'); - auto cleanName = splitName.size() > 1 ? splitName.at(1) : splitName.at(0); + for (auto& spawner : spawnerNetworkCollection.networks) { + for (auto& spawnerName : spawner.names) { + if (!spawnerName.empty()) { + auto spawnerObjects = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number); + if (!spawnerObjects.empty()) { + auto splitName = GeneralUtils::SplitString(spawnerName, '_'); + auto cleanName = splitName.size() > 1 ? splitName.at(1) : splitName.at(0); - if (!cleanName.empty()) { - auto spawnerObject = spawnerObjects.at(0); - spawnerObject->SetSpawnLot(mobSets.mobLots.at(cleanName).at(constants.lotPhase)); - } - } - } - } - } + if (!cleanName.empty()) { + auto spawnerObject = spawnerObjects.at(0); + spawnerObject->SetSpawnLot(mobSets.mobLots.at(cleanName).at(constants.lotPhase)); + } + } + } + } + } } -void BaseSurvivalServer::SpawnMobs(Entity *self) { - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) - return; +void BaseSurvivalServer::SpawnMobs(Entity* self) { + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) + return; - state.waveNumber++; - auto spawnNumber = state.waveNumber > constants.rewardInterval ? state.waveNumber - state.rewardTick - 1 : state.waveNumber; + state.waveNumber++; + auto spawnNumber = state.waveNumber > constants.rewardInterval ? state.waveNumber - state.rewardTick - 1 : state.waveNumber; - for (const auto& tier : constants.baseMobsStartTier) { - if (tier == spawnNumber) - self->SetVar<uint32_t>(BaseMobSetIndexVariable, (self->GetVar<uint32_t>(BaseMobSetIndexVariable) + 1) - % (constants.baseMobsStartTier.size() - 1)); - } + for (const auto& tier : constants.baseMobsStartTier) { + if (tier == spawnNumber) + self->SetVar<uint32_t>(BaseMobSetIndexVariable, (self->GetVar<uint32_t>(BaseMobSetIndexVariable) + 1) + % (constants.baseMobsStartTier.size() - 1)); + } - for (const auto& tier : constants.randMobsStartTier) { - if (tier == spawnNumber) - self->SetVar<uint32_t>(RandMobSetIndexVariable, (self->GetVar<uint32_t>(RandMobSetIndexVariable) + 1) - % (constants.randMobsStartTier.size() - 1)); - } + for (const auto& tier : constants.randMobsStartTier) { + if (tier == spawnNumber) + self->SetVar<uint32_t>(RandMobSetIndexVariable, (self->GetVar<uint32_t>(RandMobSetIndexVariable) + 1) + % (constants.randMobsStartTier.size() - 1)); + } - if (state.waveNumber == constants.unlockNetwork3) - spawnerNetworks.randomNetworks.networks.at(2).isLocked = false; + if (state.waveNumber == constants.unlockNetwork3) + spawnerNetworks.randomNetworks.networks.at(2).isLocked = false; - SpawnerReset(spawnerNetworks.baseNetworks, false); - SpawnerReset(spawnerNetworks.randomNetworks, false); - SpawnerUpdate(self, spawnerNetworks.baseNetworks); + SpawnerReset(spawnerNetworks.baseNetworks, false); + SpawnerReset(spawnerNetworks.randomNetworks, false); + SpawnerUpdate(self, spawnerNetworks.baseNetworks); - if (spawnNumber >= constants.mobSet2Wave) { - if (spawnNumber == constants.mobSet2Wave) - self->SetNetworkVar<std::string>(SpawnMobVariable, "2"); - SpawnerUpdate(self, spawnerNetworks.randomNetworks); - } + if (spawnNumber >= constants.mobSet2Wave) { + if (spawnNumber == constants.mobSet2Wave) + self->SetNetworkVar<std::string>(SpawnMobVariable, "2"); + SpawnerUpdate(self, spawnerNetworks.randomNetworks); + } - if (spawnNumber >= constants.mobSet3Wave) { - if (spawnNumber == constants.mobSet3Wave) - self->SetNetworkVar<std::string>(SpawnMobVariable, "3"); - SpawnerUpdate(self, spawnerNetworks.randomNetworks); - } + if (spawnNumber >= constants.mobSet3Wave) { + if (spawnNumber == constants.mobSet3Wave) + self->SetNetworkVar<std::string>(SpawnMobVariable, "3"); + SpawnerUpdate(self, spawnerNetworks.randomNetworks); + } - // If we reached the end of the spawn phase we increase the lost to make it more difficult - if (constants.useMobLots && constants.lotPhase < (mobSets.mobLots.begin()->second.size() - 1) - && spawnNumber >= constants.baseMobsStartTier.back()) { - state.waveNumber = 1; - constants.lotPhase++; + // If we reached the end of the spawn phase we increase the lost to make it more difficult + if (constants.useMobLots && constants.lotPhase < (mobSets.mobLots.begin()->second.size() - 1) + && spawnNumber >= constants.baseMobsStartTier.back()) { + state.waveNumber = 1; + constants.lotPhase++; - UpdateMobLots(spawnerNetworks.baseNetworks); - UpdateMobLots(spawnerNetworks.randomNetworks); - } + UpdateMobLots(spawnerNetworks.baseNetworks); + UpdateMobLots(spawnerNetworks.randomNetworks); + } } diff --git a/dScripts/BaseSurvivalServer.h b/dScripts/BaseSurvivalServer.h index c85f1bbf..a7c9a95a 100644 --- a/dScripts/BaseSurvivalServer.h +++ b/dScripts/BaseSurvivalServer.h @@ -5,149 +5,152 @@ * State for each active game */ struct GameState { - std::vector<LWOOBJID> players {}; - std::vector<LWOOBJID> waitingPlayers {}; - uint32_t totalSpawned = 0; - uint32_t rewardTick = 0; - uint32_t waveNumber = 1; + std::vector<LWOOBJID> players{}; + std::vector<LWOOBJID> waitingPlayers{}; + uint32_t totalSpawned = 0; + uint32_t rewardTick = 0; + uint32_t waveNumber = 1; }; /** * Constants that have to be set for each game */ struct Constants { - uint32_t acceptedDelay = 0; - uint32_t startDelay = 0; - uint32_t waveTime = 0; - uint32_t rewardInterval = 0; - uint32_t coolDownTime = 0; - uint32_t mobSet2Wave = 0; - uint32_t mobSet3Wave = 0; - uint32_t unlockNetwork3 = 0; - uint32_t lotPhase = 0; - bool useMobLots = false; - std::vector<uint32_t> baseMobsStartTier {}; - std::vector<uint32_t> randMobsStartTier {}; + uint32_t acceptedDelay = 0; + uint32_t startDelay = 0; + uint32_t waveTime = 0; + uint32_t rewardInterval = 0; + uint32_t coolDownTime = 0; + uint32_t mobSet2Wave = 0; + uint32_t mobSet3Wave = 0; + uint32_t unlockNetwork3 = 0; + uint32_t lotPhase = 0; + bool useMobLots = false; + std::vector<uint32_t> baseMobsStartTier{}; + std::vector<uint32_t> randMobsStartTier{}; }; /** * The lots of the mobs to spawn along with amounts to spawn for each wave */ struct MobSets { - std::map<std::string, std::vector<LOT>> mobLots {}; - std::map<std::string, std::vector<std::vector<std::vector<uint32_t>>>> sets {}; + std::map<std::string, std::vector<LOT>> mobLots{}; + std::map<std::string, std::vector<std::vector<std::vector<uint32_t>>>> sets{}; }; struct SpawnerNetwork { - std::vector<std::string> names {}; - std::string number; - bool isLocked = false; - bool isActive = false; + std::vector<std::string> names{}; + std::string number; + bool isLocked = false; + bool isActive = false; }; struct SpawnerNetworkCollection { - std::string mobSetName; - std::vector<SpawnerNetwork> networks {}; + std::string mobSetName; + std::vector<SpawnerNetwork> networks{}; }; struct SpawnerNetworks { - SpawnerNetworkCollection baseNetworks {}; - SpawnerNetworkCollection randomNetworks {}; - SpawnerNetworkCollection rewardNetworks {}; - SpawnerNetworkCollection smashNetworks {}; + SpawnerNetworkCollection baseNetworks{}; + SpawnerNetworkCollection randomNetworks{}; + SpawnerNetworkCollection rewardNetworks{}; + SpawnerNetworkCollection smashNetworks{}; }; class BaseSurvivalServer : public ActivityManager { public: - void OnStartup(Entity* self) override { SetGameVariables(self); BaseStartup(self); }; - void OnPlayerLoaded(Entity* self, Entity* player) override { BasePlayerLoaded(self, player); }; - void OnPlayerExit(Entity* self, Entity* player) override { BasePlayerExit(self, player); }; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override { BaseFireEvent(self, sender, args, param1, param2, param3); }; - void OnPlayerDied(Entity* self, Entity* player) override { BasePlayerDied(self, player); }; - void OnPlayerResurrected(Entity* self, Entity* player) override { BasePlayerResurrected(self, player); }; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, - const std::u16string& userData) override - { BaseMessageBoxResponse(self, sender, button, identifier, userData); }; + void OnStartup(Entity* self) override { SetGameVariables(self); BaseStartup(self); }; + void OnPlayerLoaded(Entity* self, Entity* player) override { BasePlayerLoaded(self, player); }; + void OnPlayerExit(Entity* self, Entity* player) override { BasePlayerExit(self, player); }; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override { + BaseFireEvent(self, sender, args, param1, param2, param3); + }; + void OnPlayerDied(Entity* self, Entity* player) override { BasePlayerDied(self, player); }; + void OnPlayerResurrected(Entity* self, Entity* player) override { BasePlayerResurrected(self, player); }; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, + const std::u16string& userData) override { + BaseMessageBoxResponse(self, sender, button, identifier, userData); + }; - void BasePlayerLoaded(Entity* self, Entity* player); + void BasePlayerLoaded(Entity* self, Entity* player); void BaseStartup(Entity* self); void BasePlayerExit(Entity* self, Entity* player); - void BaseFireEvent(Entity *self, Entity *sender, const std::string& args, int32_t param1, int32_t param2, - int32_t param3); + void BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2, + int32_t param3); void BasePlayerDied(Entity* self, Entity* player); void BasePlayerResurrected(Entity* self, Entity* player); void BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); - void OnActivityTimerDone(Entity *self, const std::string &name) override; - void OnActivityTimerUpdate(Entity *self, const std::string &name, float_t remainingTime, float_t elapsedTime) override; + void OnActivityTimerDone(Entity* self, const std::string& name) override; + void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) override; protected: - virtual Constants GetConstants() { return Constants(); }; - virtual MobSets GetMobSets() { return MobSets(); }; - virtual SpawnerNetworks GetSpawnerNetworks() { return SpawnerNetworks(); }; - virtual std::map<uint32_t, uint32_t> GetMissionsToUpdate() { return {}; }; - GameState state {}; + virtual Constants GetConstants() { return Constants(); }; + virtual MobSets GetMobSets() { return MobSets(); }; + virtual SpawnerNetworks GetSpawnerNetworks() { return SpawnerNetworks(); }; + virtual std::map<uint32_t, uint32_t> GetMissionsToUpdate() { return {}; }; + GameState state{}; - // Mob set default names - std::string BaseMobSet = "baseMobSet"; - std::string RandMobSet = "randMobSet"; + // Mob set default names + std::string BaseMobSet = "baseMobSet"; + std::string RandMobSet = "randMobSet"; - // Variable names - std::u16string WavesStartedVariable = u"wavesStarted"; - std::u16string ShowScoreboardVariable = u"Show_ScoreBoard"; - std::u16string ClearScoreboardVariable = u"Clear_Scoreboard"; - std::u16string DefinePlayerToUIVariable = u"Define_Player_To_UI"; - std::u16string UpdateScoreboardPlayersVariable = u"Update_ScoreBoard_Players."; - std::u16string PlayerConfirmVariable = u"PlayerConfirm_ScoreBoard."; - std::u16string PlayersAcceptedVariable = u"playersAccepted"; - std::u16string PlayersReadyVariable = u"playersReady"; - std::u16string BaseMobSetIndexVariable = u"baseMobSetNum"; - std::u16string RandMobSetIndexVariable = u"randMobSetNum"; - std::u16string AcceptedDelayStartedVariable = u"AcceptedDelayStarted"; - std::u16string NumberOfPlayersVariable = u"NumberOfPlayers"; - std::u16string FirstTimeDoneVariable = u"firstTimeDone"; - std::u16string MissionTypeVariable = u"missionType"; - std::u16string StartWaveMessageVariable = u"Start_Wave_Message"; - std::u16string ExitWavesVariable = u"Exit_waves"; - std::u16string UpdateDefaultStartTimerVariable = u"Update_Default_Start_Timer"; - std::u16string UpdateTimerVariable = u"Update_Timer"; - std::u16string IsCooldownVariable = u"isCoolDown"; - std::u16string SpawnMobVariable = u"Spawn_Mob"; + // Variable names + std::u16string WavesStartedVariable = u"wavesStarted"; + std::u16string ShowScoreboardVariable = u"Show_ScoreBoard"; + std::u16string ClearScoreboardVariable = u"Clear_Scoreboard"; + std::u16string DefinePlayerToUIVariable = u"Define_Player_To_UI"; + std::u16string UpdateScoreboardPlayersVariable = u"Update_ScoreBoard_Players."; + std::u16string PlayerConfirmVariable = u"PlayerConfirm_ScoreBoard."; + std::u16string PlayersAcceptedVariable = u"playersAccepted"; + std::u16string PlayersReadyVariable = u"playersReady"; + std::u16string BaseMobSetIndexVariable = u"baseMobSetNum"; + std::u16string RandMobSetIndexVariable = u"randMobSetNum"; + std::u16string AcceptedDelayStartedVariable = u"AcceptedDelayStarted"; + std::u16string NumberOfPlayersVariable = u"NumberOfPlayers"; + std::u16string FirstTimeDoneVariable = u"firstTimeDone"; + std::u16string MissionTypeVariable = u"missionType"; + std::u16string StartWaveMessageVariable = u"Start_Wave_Message"; + std::u16string ExitWavesVariable = u"Exit_waves"; + std::u16string UpdateDefaultStartTimerVariable = u"Update_Default_Start_Timer"; + std::u16string UpdateTimerVariable = u"Update_Timer"; + std::u16string IsCooldownVariable = u"isCoolDown"; + std::u16string SpawnMobVariable = u"Spawn_Mob"; - // Timer names - std::string SpawnTickTimer = "SpawnTick"; - std::string AllAcceptedDelayTimer = "AllAcceptedDelay"; - std::string AcceptedDelayTimer = "AcceptedDelay"; - std::string StartDelayTimer = "StartDelay"; - std::string ClockTickTimer = "ClockTick"; - std::string CoolDownStartTimer = "CoolDownStart"; - std::string CoolDownStopTimer = "CoolDownStop"; - std::string PlaySpawnSoundTimer = "PlaySpawnSound"; + // Timer names + std::string SpawnTickTimer = "SpawnTick"; + std::string AllAcceptedDelayTimer = "AllAcceptedDelay"; + std::string AcceptedDelayTimer = "AcceptedDelay"; + std::string StartDelayTimer = "StartDelay"; + std::string ClockTickTimer = "ClockTick"; + std::string CoolDownStartTimer = "CoolDownStart"; + std::string CoolDownStopTimer = "CoolDownStop"; + std::string PlaySpawnSoundTimer = "PlaySpawnSound"; - std::string spawnSoundGUID = "{ca36045d-89df-4e96-a317-1e152d226b69}"; + std::string spawnSoundGUID = "{ca36045d-89df-4e96-a317-1e152d226b69}"; private: - void SetGameVariables(Entity* self); - static void ResetStats(LWOOBJID player); - void GameOver(Entity* self); + void SetGameVariables(Entity* self); + static void ResetStats(LWOOBJID player); + void GameOver(Entity* self); - void StartWaves(Entity* self); + void StartWaves(Entity* self); static void ActivateSpawnerNetwork(SpawnerNetworkCollection& spawnerNetworkCollection); - void SpawnerReset(SpawnerNetworkCollection& spawnerNetworkCollection, bool hardReset = true); - void SpawnerUpdate(Entity* self, SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t amount = 0); - void SpawnMobs(Entity* self); - static SpawnerNetwork GetRandomSpawner(SpawnerNetworkCollection& spawnerNetworkCollection); - std::vector<uint32_t> GetRandomMobSet(SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t setNumber); + void SpawnerReset(SpawnerNetworkCollection& spawnerNetworkCollection, bool hardReset = true); + void SpawnerUpdate(Entity* self, SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t amount = 0); + void SpawnMobs(Entity* self); + static SpawnerNetwork GetRandomSpawner(SpawnerNetworkCollection& spawnerNetworkCollection); + std::vector<uint32_t> GetRandomMobSet(SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t setNumber); - static void SpawnNow(Spawner* spawner, uint32_t amount); + static void SpawnNow(Spawner* spawner, uint32_t amount); - bool CheckAllPlayersDead(); - void SetPlayerSpawnPoints(); + bool CheckAllPlayersDead(); + void SetPlayerSpawnPoints(); void UpdateMobLots(SpawnerNetworkCollection& spawnerNetworkCollection); void PlayerConfirmed(Entity* self); void PlayerAccepted(Entity* self, LWOOBJID playerID); - Constants constants {}; - MobSets mobSets {}; - SpawnerNetworks spawnerNetworks {}; - std::map<uint32_t, uint32_t> missionsToUpdate {}; + Constants constants{}; + MobSets mobSets{}; + SpawnerNetworks spawnerNetworks{}; + std::map<uint32_t, uint32_t> missionsToUpdate{}; }; diff --git a/dScripts/BaseWavesGenericEnemy.cpp b/dScripts/BaseWavesGenericEnemy.cpp index 7158accb..3270e2d8 100644 --- a/dScripts/BaseWavesGenericEnemy.cpp +++ b/dScripts/BaseWavesGenericEnemy.cpp @@ -1,13 +1,13 @@ #include "BaseWavesGenericEnemy.h" #include "dZoneManager.h" -void BaseWavesGenericEnemy::OnStartup(Entity *self) { - self->SetNetworkVar<uint32_t>(u"points", GetPoints()); +void BaseWavesGenericEnemy::OnStartup(Entity* self) { + self->SetNetworkVar<uint32_t>(u"points", GetPoints()); } -void BaseWavesGenericEnemy::OnDie(Entity *self, Entity *killer) { - auto* zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); - if (zoneControlObject != nullptr) { - zoneControlObject->OnFireEventServerSide(killer, "Survival_Update", GetPoints()); - } +void BaseWavesGenericEnemy::OnDie(Entity* self, Entity* killer) { + auto* zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); + if (zoneControlObject != nullptr) { + zoneControlObject->OnFireEventServerSide(killer, "Survival_Update", GetPoints()); + } } diff --git a/dScripts/BaseWavesGenericEnemy.h b/dScripts/BaseWavesGenericEnemy.h index 718f36e1..3c808b4e 100644 --- a/dScripts/BaseWavesGenericEnemy.h +++ b/dScripts/BaseWavesGenericEnemy.h @@ -3,8 +3,8 @@ class BaseWavesGenericEnemy : public CppScripts::Script { public: - void OnStartup(Entity *self) override; - void OnDie(Entity *self, Entity *killer) override; + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; protected: - virtual uint32_t GetPoints() { return 0; }; + virtual uint32_t GetPoints() { return 0; }; }; diff --git a/dScripts/BaseWavesServer.cpp b/dScripts/BaseWavesServer.cpp index 2c8a2edd..00340bd0 100644 --- a/dScripts/BaseWavesServer.cpp +++ b/dScripts/BaseWavesServer.cpp @@ -4,587 +4,588 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include "Character.h" // Done -void BaseWavesServer::SetGameVariables(Entity *self) { - this->constants = std::move(GetConstants()); - this->waves = std::move(GetWaves()); - this->missions = std::move(GetWaveMissions()); - this->spawners = std::move(GetSpawnerNames()); +void BaseWavesServer::SetGameVariables(Entity* self) { + this->constants = std::move(GetConstants()); + this->waves = std::move(GetWaves()); + this->missions = std::move(GetWaveMissions()); + this->spawners = std::move(GetSpawnerNames()); } // Done void BaseWavesServer::BasePlayerLoaded(Entity* self, Entity* player) { - GameMessages::SendPlayerSetCameraCyclingMode(player->GetObjectID(), player->GetSystemAddress()); - GameMessages::SendPlayerAllowedRespawn(player->GetObjectID(), true, player->GetSystemAddress()); + GameMessages::SendPlayerSetCameraCyclingMode(player->GetObjectID(), player->GetSystemAddress()); + GameMessages::SendPlayerAllowedRespawn(player->GetObjectID(), true, player->GetSystemAddress()); - state.waitingPlayers.push_back(player->GetObjectID()); - state.players.push_back(player->GetObjectID()); + state.waitingPlayers.push_back(player->GetObjectID()); + state.players.push_back(player->GetObjectID()); - self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1); - self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); + self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1); + self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress()); - // Notify the players of all other players - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - auto counter = 1; - for (const auto& playerID : state.players) { - self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); - counter++; - } + // Notify the players of all other players + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + auto counter = 1; + for (const auto& playerID : state.players) { + self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID)); + counter++; + } - if (!this->constants.introCelebration.empty()) { - self->SetNetworkVar<std::string>(WatchingIntroVariable, this->constants.introCelebration + "_" - + std::to_string(player->GetObjectID())); - } else { - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); - } - } + if (!this->constants.introCelebration.empty()) { + self->SetNetworkVar<std::string>(WatchingIntroVariable, this->constants.introCelebration + "_" + + std::to_string(player->GetObjectID())); + } else { + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); + } + } - SetPlayerSpawnPoints(); + SetPlayerSpawnPoints(); - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - PlayerConfirmed(self); - } else { - UpdatePlayer(self, player->GetObjectID()); - GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50); - ResetStats(player->GetObjectID()); - } + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + PlayerConfirmed(self); + } else { + UpdatePlayer(self, player->GetObjectID()); + GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50); + ResetStats(player->GetObjectID()); + } } // Done void BaseWavesServer::BaseStartup(Entity* self) { - self->SetVar<uint32_t>(PlayersAcceptedVariable, 0); - self->SetVar<bool>(PlayersReadyVariable, false); + self->SetVar<uint32_t>(PlayersAcceptedVariable, 0); + self->SetVar<bool>(PlayersReadyVariable, false); } // Done void BaseWavesServer::BasePlayerExit(Entity* self, Entity* player) { - auto waitingPlayerToErase = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); - if (waitingPlayerToErase != state.waitingPlayers.end()) state.waitingPlayers.erase(waitingPlayerToErase); + auto waitingPlayerToErase = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); + if (waitingPlayerToErase != state.waitingPlayers.end()) state.waitingPlayers.erase(waitingPlayerToErase); - auto playerToErase = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); - if (playerToErase != state.players.end()) state.players.erase(playerToErase); + auto playerToErase = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); + if (playerToErase != state.players.end()) state.players.erase(playerToErase); - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - PlayerConfirmed(self); + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + PlayerConfirmed(self); - if (state.players.empty()) - return; + if (state.players.empty()) + return; - if (state.waitingPlayers.empty()) { - ActivityTimerStopAllTimers(self); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay); - } else if (state.players.size() > state.waitingPlayers.size()) { - if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { - self->SetVar<bool>(AcceptedDelayStartedVariable, true); - ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay); - } - } - } else { - UpdatePlayer(self, player->GetObjectID(), true); - if (CheckAllPlayersDead()) { - GameOver(self); - } - } + if (state.waitingPlayers.empty()) { + ActivityTimerStopAllTimers(self); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay); + } else if (state.players.size() > state.waitingPlayers.size()) { + if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { + self->SetVar<bool>(AcceptedDelayStartedVariable, true); + ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay); + } + } + } else { + UpdatePlayer(self, player->GetObjectID(), true); + if (CheckAllPlayersDead()) { + GameOver(self); + } + } - SetActivityValue(self, player->GetObjectID(), 1, 0); - SetActivityValue(self, player->GetObjectID(), 2, 0); + SetActivityValue(self, player->GetObjectID(), 1, 0); + SetActivityValue(self, player->GetObjectID(), 2, 0); - self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, - std::min((uint32_t) 0, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1)); + self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, + std::min((uint32_t)0, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1)); } // Done void BaseWavesServer::BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "start") { - StartWaves(self); - } else if (args == "Survival_Update") { - const auto senderID = sender != nullptr ? sender->GetObjectID() : LWOOBJID_EMPTY; - if (UpdateSpawnedEnemies(self, senderID, param1)) { - const auto currentTime = GetActivityValue(self, senderID, 1); - const auto currentWave = GetActivityValue(self, senderID, 2); + int32_t param3) { + if (args == "start") { + StartWaves(self); + } else if (args == "Survival_Update") { + const auto senderID = sender != nullptr ? sender->GetObjectID() : LWOOBJID_EMPTY; + if (UpdateSpawnedEnemies(self, senderID, param1)) { + const auto currentTime = GetActivityValue(self, senderID, 1); + const auto currentWave = GetActivityValue(self, senderID, 2); - for (const auto& mission : this->missions) { - if (currentWave == mission.wave && currentTime <= mission.time) { - UpdateMissionForAllPlayers(self, mission.missionID); - } - } - } - } + for (const auto& mission : this->missions) { + if (currentWave == mission.wave && currentTime <= mission.time) { + UpdateMissionForAllPlayers(self, mission.missionID); + } + } + } + } } // Done void BaseWavesServer::BasePlayerDied(Entity* self, Entity* player) { - const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); - const auto finalTime = GetActivityValue(self, player->GetObjectID(), 1); - const auto finalWave = GetActivityValue(self, player->GetObjectID(), 2); + const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); + const auto finalTime = GetActivityValue(self, player->GetObjectID(), 1); + const auto finalWave = GetActivityValue(self, player->GetObjectID(), 2); - auto paramString = CheckAllPlayersDead() ? "true" : "false"; + auto paramString = CheckAllPlayersDead() ? "true" : "false"; - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, finalWave, - player->GetObjectID(), paramString, player->GetSystemAddress()); + GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, finalWave, + player->GetObjectID(), paramString, player->GetSystemAddress()); - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { - player->Resurrect(); - return; - } + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) { + player->Resurrect(); + return; + } - GameOver(self); + GameOver(self); } // Done -void BaseWavesServer::BasePlayerResurrected(Entity *self, Entity *player) { - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Res", 0, 0, - player->GetObjectID(), "", player->GetSystemAddress()); +void BaseWavesServer::BasePlayerResurrected(Entity* self, Entity* player) { + GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Res", 0, 0, + player->GetObjectID(), "", player->GetSystemAddress()); - if (self->GetNetworkVar<bool>(WavesStartedVariable)) - return; + if (self->GetNetworkVar<bool>(WavesStartedVariable)) + return; - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); - SetPlayerSpawnPoints(player->GetObjectID()); + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); + SetPlayerSpawnPoints(player->GetObjectID()); } // Done void BaseWavesServer::BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button, - const std::u16string &identifier, const std::u16string &userData) { - if (identifier == u"RePlay") { - PlayerAccepted(self, sender->GetObjectID()); - PlayerConfirmed(self); - } else if (identifier == u"Exit_Question" && button == 1) { - ResetStats(sender->GetObjectID()); - self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID())); + const std::u16string& identifier, const std::u16string& userData) { + if (identifier == u"RePlay") { + PlayerAccepted(self, sender->GetObjectID()); + PlayerConfirmed(self); + } else if (identifier == u"Exit_Question" && button == 1) { + ResetStats(sender->GetObjectID()); + self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID())); - if (sender->IsPlayer()) { - auto* character = sender->GetCharacter(); - if (character != nullptr) { - auto* player = dynamic_cast<Player*>(sender); - player->SendToZone(character->GetLastNonInstanceZoneID()); - } - } - } + if (sender->IsPlayer()) { + auto* character = sender->GetCharacter(); + if (character != nullptr) { + auto* player = dynamic_cast<Player*>(sender); + player->SendToZone(character->GetLastNonInstanceZoneID()); + } + } + } } // Done -void BaseWavesServer::OnActivityTimerUpdate(Entity *self, const std::string &name, float_t remainingTime, float_t elapsedTime) { - if (name == AcceptedDelayTimer) { - self->SetNetworkVar<uint32_t>(UpdateDefaultStartTimerVariable, remainingTime); - } else if (name == ClockTickTimer) { - self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime); - } else if (name == NextWaveTickTimer || name == TimedWaveTimer || name == GameOverWinTimer) { - self->SetNetworkVar<uint32_t>(UpdateCooldownVariable, remainingTime); - } +void BaseWavesServer::OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) { + if (name == AcceptedDelayTimer) { + self->SetNetworkVar<uint32_t>(UpdateDefaultStartTimerVariable, remainingTime); + } else if (name == ClockTickTimer) { + self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime); + } else if (name == NextWaveTickTimer || name == TimedWaveTimer || name == GameOverWinTimer) { + self->SetNetworkVar<uint32_t>(UpdateCooldownVariable, remainingTime); + } } // Done -void BaseWavesServer::OnActivityTimerDone(Entity *self, const std::string &name) { - if (name == AcceptedDelayTimer) { - self->SetNetworkVar<uint32_t>(UpdateDefaultStartTimerVariable, 0); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1); - } else if (name == AllAcceptedDelayTimer) { - self->SetNetworkVar<bool>(ClearScoreboardVariable, true); - ActivityTimerStart(self, StartDelayTimer, 4, 4); - StartWaves(self); - } else if (name == StartDelayTimer) { - ActivityTimerStart(self, ClockTickTimer, 1); - SpawnWave(self); - ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); - } else if (name == PlaySpawnSoundTimer) { - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); - } - } - } else if (name == NextWaveTickTimer) { - self->SetNetworkVar<bool>(StartCooldownVariable, false); - SpawnWave(self); - } else if (name == WaveCompleteDelayTimer) { - self->SetNetworkVar<uint32_t>(StartCooldownVariable, constants.waveTime); - ActivityTimerStart(self, NextWaveTickTimer, 1, constants.waveTime); - } else if (name == TimedWaveTimer) { - ActivityTimerStart(self, WaveCompleteDelayTimer, constants.waveCompleteDelay, constants.waveCompleteDelay); +void BaseWavesServer::OnActivityTimerDone(Entity* self, const std::string& name) { + if (name == AcceptedDelayTimer) { + self->SetNetworkVar<uint32_t>(UpdateDefaultStartTimerVariable, 0); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1); + } else if (name == AllAcceptedDelayTimer) { + self->SetNetworkVar<bool>(ClearScoreboardVariable, true); + ActivityTimerStart(self, StartDelayTimer, 4, 4); + StartWaves(self); + } else if (name == StartDelayTimer) { + ActivityTimerStart(self, ClockTickTimer, 1); + SpawnWave(self); + ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3); + } else if (name == PlaySpawnSoundTimer) { + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); + } + } + } else if (name == NextWaveTickTimer) { + self->SetNetworkVar<bool>(StartCooldownVariable, false); + SpawnWave(self); + } else if (name == WaveCompleteDelayTimer) { + self->SetNetworkVar<uint32_t>(StartCooldownVariable, constants.waveTime); + ActivityTimerStart(self, NextWaveTickTimer, 1, constants.waveTime); + } else if (name == TimedWaveTimer) { + ActivityTimerStart(self, WaveCompleteDelayTimer, constants.waveCompleteDelay, constants.waveCompleteDelay); - const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); - const auto currentWave = state.waveNumber; + const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); + const auto currentWave = state.waveNumber; - self->SetNetworkVar<uint32_t>(WaveCompleteVariable, { currentWave, (uint32_t) currentTime }); - } else if (name == GameOverWinTimer) { - GameOver(self, true); - } else if (name == CinematicDoneTimer) { - for (auto* boss : EntityManager::Instance()->GetEntitiesInGroup("boss")) { - boss->OnFireEventServerSide(self, "startAI"); - } - } + self->SetNetworkVar<uint32_t>(WaveCompleteVariable, { currentWave, (uint32_t)currentTime }); + } else if (name == GameOverWinTimer) { + GameOver(self, true); + } else if (name == CinematicDoneTimer) { + for (auto* boss : EntityManager::Instance()->GetEntitiesInGroup("boss")) { + boss->OnFireEventServerSide(self, "startAI"); + } + } } // Done void BaseWavesServer::ResetStats(LWOOBJID playerID) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { - // Boost all the player stats when loading in - auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); - destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); - destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination()); - } - } + // Boost all the player stats when loading in + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); + destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); + destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination()); + } + } } // Done void BaseWavesServer::PlayerConfirmed(Entity* self) { - std::vector<LWOOBJID> confirmedPlayers {}; + std::vector<LWOOBJID> confirmedPlayers{}; - for (const auto& playerID : state.players) { - auto pass = false; - for (const auto& waitingPlayerID : state.waitingPlayers) { - if (waitingPlayerID == playerID) - pass = true; - } + for (const auto& playerID : state.players) { + auto pass = false; + for (const auto& waitingPlayerID : state.waitingPlayers) { + if (waitingPlayerID == playerID) + pass = true; + } - if (!pass) - confirmedPlayers.push_back(playerID); - } + if (!pass) + confirmedPlayers.push_back(playerID); + } - auto playerIndex = 1; - for (const auto& playerID : confirmedPlayers) { - self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID)); - playerIndex++; - } + auto playerIndex = 1; + for (const auto& playerID : confirmedPlayers) { + self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID)); + playerIndex++; + } } // Done -void BaseWavesServer::PlayerAccepted(Entity *self, LWOOBJID playerID) { - state.waitingPlayers.erase(std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID)); - if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) { - ActivityTimerStopAllTimers(self); - ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay); - } else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { - self->SetVar<bool>(AcceptedDelayStartedVariable, true); - ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay); - } +void BaseWavesServer::PlayerAccepted(Entity* self, LWOOBJID playerID) { + state.waitingPlayers.erase(std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID)); + if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) { + ActivityTimerStopAllTimers(self); + ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay); + } else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) { + self->SetVar<bool>(AcceptedDelayStartedVariable, true); + ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay); + } } // Done -void BaseWavesServer::StartWaves(Entity *self) { - GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); +void BaseWavesServer::StartWaves(Entity* self) { + GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - self->SetNetworkVar<std::string>(WatchingIntroVariable, ""); - self->SetVar<bool>(PlayersReadyVariable, true); - self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0); - self->SetVar<uint32_t>(RandMobSetIndexVariable, 0); - self->SetVar<bool>(AcceptedDelayStartedVariable, false); + self->SetNetworkVar<std::string>(WatchingIntroVariable, ""); + self->SetVar<bool>(PlayersReadyVariable, true); + self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0); + self->SetVar<uint32_t>(RandMobSetIndexVariable, 0); + self->SetVar<bool>(AcceptedDelayStartedVariable, false); - state.waitingPlayers.clear(); + state.waitingPlayers.clear(); - for (const auto& playerID : state.players) { - const auto player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - state.waitingPlayers.push_back(playerID); + for (const auto& playerID : state.players) { + const auto player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + state.waitingPlayers.push_back(playerID); - UpdatePlayer(self, playerID); - GetLeaderboardData(self, playerID, GetActivityID(self), 1); - ResetStats(playerID); + UpdatePlayer(self, playerID); + GetLeaderboardData(self, playerID, GetActivityID(self), 1); + ResetStats(playerID); - if (!self->GetVar<bool>(FirstTimeDoneVariable)) { - TakeActivityCost(self, playerID); - } - } - } + if (!self->GetVar<bool>(FirstTimeDoneVariable)) { + TakeActivityCost(self, playerID); + } + } + } - self->SetVar<bool>(FirstTimeDoneVariable, true); - self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team"); - self->SetNetworkVar<bool>(WavesStartedVariable, true); - self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!"); + self->SetVar<bool>(FirstTimeDoneVariable, true); + self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team"); + self->SetNetworkVar<bool>(WavesStartedVariable, true); + self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!"); } // Done bool BaseWavesServer::CheckAllPlayersDead() { - auto deadPlayers = 0; + auto deadPlayers = 0; - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr || player->GetIsDead()) { - deadPlayers++; - } - } + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr || player->GetIsDead()) { + deadPlayers++; + } + } - return deadPlayers >= state.players.size(); + return deadPlayers >= state.players.size(); } // Done void BaseWavesServer::SetPlayerSpawnPoints(const LWOOBJID& specificPlayerID) { - auto spawnerIndex = 1; - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr && (specificPlayerID == LWOOBJID_EMPTY || playerID == specificPlayerID)) { - auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); - if (!possibleSpawners.empty()) { - auto* spawner = possibleSpawners.at(0); - GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); - } - } + auto spawnerIndex = 1; + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr && (specificPlayerID == LWOOBJID_EMPTY || playerID == specificPlayerID)) { + auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); + if (!possibleSpawners.empty()) { + auto* spawner = possibleSpawners.at(0); + GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); + } + } - spawnerIndex++; - } + spawnerIndex++; + } } // Done -void BaseWavesServer::GameOver(Entity *self, bool won) { - if (!CheckAllPlayersDead() && !won) - return; +void BaseWavesServer::GameOver(Entity* self, bool won) { + if (!CheckAllPlayersDead() && !won) + return; - ActivityTimerStopAllTimers(self); + ActivityTimerStopAllTimers(self); - // Reset all the spawners - state.waveNumber = 0; - state.totalSpawned = 0; - state.currentSpawned = 0; + // Reset all the spawners + state.waveNumber = 0; + state.totalSpawned = 0; + state.currentSpawned = 0; - self->SetNetworkVar<bool>(WavesStartedVariable, false); - self->SetNetworkVar<uint32_t>(StartCooldownVariable, 0); - SetPlayerSpawnPoints(); - ClearSpawners(); + self->SetNetworkVar<bool>(WavesStartedVariable, false); + self->SetNetworkVar<uint32_t>(StartCooldownVariable, 0); + SetPlayerSpawnPoints(); + ClearSpawners(); - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - continue; + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + continue; - const auto score = GetActivityValue(self, playerID, 0); - const auto time = GetActivityValue(self, playerID, 1); - const auto wave = GetActivityValue(self, playerID, 2); + const auto score = GetActivityValue(self, playerID, 0); + const auto time = GetActivityValue(self, playerID, 1); + const auto wave = GetActivityValue(self, playerID, 2); - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, - playerID, std::to_string(wave), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, + playerID, std::to_string(wave), UNASSIGNED_SYSTEM_ADDRESS); - if (won) { - SetPlayerSpawnPoints(); - self->SetNetworkVar<bool>(ShowScoreboardVariable, true); - } else { - player->Resurrect(); - } + if (won) { + SetPlayerSpawnPoints(); + self->SetNetworkVar<bool>(ShowScoreboardVariable, true); + } else { + player->Resurrect(); + } - // Update all mission progression - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, time, self->GetObjectID(), self->GetVar<std::string>(MissionTypeVariable)); - } + // Update all mission progression + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(), self->GetVar<std::string>(MissionTypeVariable)); + } - StopActivity(self, playerID, wave, time, score); - } + StopActivity(self, playerID, wave, time, score); + } } // Done -void BaseWavesServer::GameWon(Entity *self) { - ActivityTimerStopAllTimers(self); +void BaseWavesServer::GameWon(Entity* self) { + ActivityTimerStopAllTimers(self); - const auto winDelay = waves.back().winDelay; - ActivityTimerStart(self, GameOverWinTimer, 1, winDelay); - self->SetNetworkVar<uint32_t>(StartTimedWaveVariable, { winDelay, state.waveNumber }); + const auto winDelay = waves.back().winDelay; + ActivityTimerStart(self, GameOverWinTimer, 1, winDelay); + self->SetNetworkVar<uint32_t>(StartTimedWaveVariable, { winDelay, state.waveNumber }); } // Done void BaseWavesServer::SpawnNow(const std::string& spawnerName, uint32_t amount, LOT spawnLot) { - const auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - for (auto* spawner : spawners) { - if (spawnLot != LOT_NULL) { - spawner->SetSpawnLot(spawnLot); - } + const auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); + for (auto* spawner : spawners) { + if (spawnLot != LOT_NULL) { + spawner->SetSpawnLot(spawnLot); + } - spawner->m_Info.amountMaintained = amount; - spawner->m_Info.maxToSpawn = amount; + spawner->m_Info.amountMaintained = amount; + spawner->m_Info.maxToSpawn = amount; - spawner->Reset(); - spawner->Activate(); - } + spawner->Reset(); + spawner->Activate(); + } } // Done -void BaseWavesServer::SpawnWave(Entity *self) { - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) - return; +void BaseWavesServer::SpawnWave(Entity* self) { + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) + return; - // If there's no wave left - if (state.waveNumber >= waves.size()) { - GameOver(self); - return; - } + // If there's no wave left + if (state.waveNumber >= waves.size()) { + GameOver(self); + return; + } - const auto wave = waves.at(state.waveNumber); + const auto wave = waves.at(state.waveNumber); - // Handles meta info to the client about the current round - if (wave.winDelay != (uint32_t) -1) { - self->SetNetworkVar<bool>(WonWaveVariable, true); + // Handles meta info to the client about the current round + if (wave.winDelay != (uint32_t)-1) { + self->SetNetworkVar<bool>(WonWaveVariable, true); - // Close the game if we don't expect a notification from an other entity to end it - if (!wave.notifyWin) { - GameWon(self); - } + // Close the game if we don't expect a notification from an other entity to end it + if (!wave.notifyWin) { + GameWon(self); + } - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - player->Resurrect(); - } - } - } else { - if (wave.timeLimit != (uint32_t) -1) { - ActivityTimerStart(self, TimedWaveTimer, 1.0f, wave.timeLimit); - self->SetNetworkVar<uint32_t>(StartTimedWaveVariable, { wave.timeLimit, state.waveNumber + 1 } ); - } else { - self->SetNetworkVar<uint32_t>(NewWaveVariable, state.waveNumber + 1); - } - } + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player && player->GetIsDead()) { + player->Resurrect(); + } + } + } else { + if (wave.timeLimit != (uint32_t)-1) { + ActivityTimerStart(self, TimedWaveTimer, 1.0f, wave.timeLimit); + self->SetNetworkVar<uint32_t>(StartTimedWaveVariable, { wave.timeLimit, state.waveNumber + 1 }); + } else { + self->SetNetworkVar<uint32_t>(NewWaveVariable, state.waveNumber + 1); + } + } - // NOTE: The script does some stuff with events here, although BONS does not have those + // NOTE: The script does some stuff with events here, although BONS does not have those - // Optional cinematics to play - if (!wave.cinematic.empty()) { - ActivityTimerStart(self, CinematicDoneTimer, wave.cinematicLength, wave.cinematicLength); - self->SetNetworkVar<std::string>(StartCinematicVariable, wave.cinematic); - } + // Optional cinematics to play + if (!wave.cinematic.empty()) { + ActivityTimerStart(self, CinematicDoneTimer, wave.cinematicLength, wave.cinematicLength); + self->SetNetworkVar<std::string>(StartCinematicVariable, wave.cinematic); + } - // Spawn the enemies - state.currentSpawned = 0; + // Spawn the enemies + state.currentSpawned = 0; - for (const auto& mobDefinition : wave.waveMobs) { - SpawnNow(mobDefinition.spawnerName, mobDefinition.amountToSpawn, mobDefinition.lot); - state.currentSpawned += mobDefinition.amountToSpawn; - } + for (const auto& mobDefinition : wave.waveMobs) { + SpawnNow(mobDefinition.spawnerName, mobDefinition.amountToSpawn, mobDefinition.lot); + state.currentSpawned += mobDefinition.amountToSpawn; + } - state.waveNumber++; - state.totalSpawned += state.currentSpawned; - self->SetNetworkVar<uint32_t>(NumRemainingVariable, state.currentSpawned); + state.waveNumber++; + state.totalSpawned += state.currentSpawned; + self->SetNetworkVar<uint32_t>(NumRemainingVariable, state.currentSpawned); } // Done bool BaseWavesServer::UpdateSpawnedEnemies(Entity* self, LWOOBJID enemyID, uint32_t score) { - if (!self->GetNetworkVar<bool>(WavesStartedVariable)) - return false; + if (!self->GetNetworkVar<bool>(WavesStartedVariable)) + return false; - state.currentSpawned--; + state.currentSpawned--; - auto* enemy = EntityManager::Instance()->GetEntity(enemyID); - if (enemy != nullptr && enemy->IsPlayer() && IsPlayerInActivity(self, enemyID)) { - SetActivityValue(self, enemyID, 0, GetActivityValue(self, enemyID, 0) + score); - } + auto* enemy = EntityManager::Instance()->GetEntity(enemyID); + if (enemy != nullptr && enemy->IsPlayer() && IsPlayerInActivity(self, enemyID)) { + SetActivityValue(self, enemyID, 0, GetActivityValue(self, enemyID, 0) + score); + } - if (state.currentSpawned <= 0) { - const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); - const auto completedWave = state.waveNumber - 1; + if (state.currentSpawned <= 0) { + const auto currentTime = ActivityTimerGetCurrentTime(self, ClockTickTimer); + const auto completedWave = state.waveNumber - 1; - // When the last enemy is smashed (e.g. in last wave - 1) - if (state.waveNumber >= waves.size() - 1) { + // When the last enemy is smashed (e.g. in last wave - 1) + if (state.waveNumber >= waves.size() - 1) { - // If there's no more follow up waves, (e.g in last wave), end the game. Generally called by some other script - if (state.waveNumber >= waves.size()) { - GameWon(self); - return false; - } + // If there's no more follow up waves, (e.g in last wave), end the game. Generally called by some other script + if (state.waveNumber >= waves.size()) { + GameWon(self); + return false; + } - ActivityTimerStopAllTimers(self); - self->SetNetworkVar<float_t>(UpdateTimerVariable, currentTime); - } + ActivityTimerStopAllTimers(self); + self->SetNetworkVar<float_t>(UpdateTimerVariable, currentTime); + } - ActivityTimerStart(self, WaveCompleteDelayTimer, constants.waveCompleteDelay, constants.waveCompleteDelay); + ActivityTimerStart(self, WaveCompleteDelayTimer, constants.waveCompleteDelay, constants.waveCompleteDelay); - const auto waveMission = waves.at(completedWave).missions; - const auto soloWaveMissions = waves.at(completedWave).soloMissions; + const auto waveMission = waves.at(completedWave).missions; + const auto soloWaveMissions = waves.at(completedWave).soloMissions; - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr && !player->GetIsDead()) { - SetActivityValue(self, playerID, 1, currentTime); - SetActivityValue(self, playerID, 2, state.waveNumber); + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr && !player->GetIsDead()) { + SetActivityValue(self, playerID, 1, currentTime); + SetActivityValue(self, playerID, 2, state.waveNumber); - // Update player missions - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - for (const auto& missionID : waveMission) { - // Get the mission state - auto missionState = missionComponent->GetMissionState(missionID); - // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { - missionComponent->AcceptMission(missionID); - missionState = missionComponent->GetMissionState(missionID); - } + // Update player missions + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + for (const auto& missionID : waveMission) { + // Get the mission state + auto missionState = missionComponent->GetMissionState(missionID); + // For some reason these achievements are not accepted by default, so we accept them here if they arent already. + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { + missionComponent->AcceptMission(missionID); + missionState = missionComponent->GetMissionState(missionID); + } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { - auto mission = missionComponent->GetMission(missionID); - if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - } - } - // Progress solo missions - if (state.players.size() == 1) { - for (const auto& missionID : soloWaveMissions) { - // Get the mission state - auto missionState = missionComponent->GetMissionState(missionID); - // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { - missionComponent->AcceptMission(missionID); - missionState = missionComponent->GetMissionState(missionID); - } + if (missionState != eMissionState::COMPLETE) { + auto mission = missionComponent->GetMission(missionID); + if (mission != nullptr) { + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + } + } + // Progress solo missions + if (state.players.size() == 1) { + for (const auto& missionID : soloWaveMissions) { + // Get the mission state + auto missionState = missionComponent->GetMissionState(missionID); + // For some reason these achievements are not accepted by default, so we accept them here if they arent already. + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { + missionComponent->AcceptMission(missionID); + missionState = missionComponent->GetMissionState(missionID); + } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { - auto mission = missionComponent->GetMission(missionID); - if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - } - } - } - } - } - } + if (missionState != eMissionState::COMPLETE) { + auto mission = missionComponent->GetMission(missionID); + if (mission != nullptr) { + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + } + } + } + } + } + } - // Might seem odd to send the next wave but the client isn't 0-indexed so it thinks it completed the correct wave - self->SetNetworkVar<uint32_t>(WaveCompleteVariable, { state.waveNumber, (uint32_t) currentTime }); - return true; - } + // Might seem odd to send the next wave but the client isn't 0-indexed so it thinks it completed the correct wave + self->SetNetworkVar<uint32_t>(WaveCompleteVariable, { state.waveNumber, (uint32_t)currentTime }); + return true; + } - self->SetNetworkVar<uint32_t>(NumRemainingVariable, state.currentSpawned); - return false; + self->SetNetworkVar<uint32_t>(NumRemainingVariable, state.currentSpawned); + return false; } // Done void BaseWavesServer::UpdateMissionForAllPlayers(Entity* self, uint32_t missionID) { - for (const auto& playerID : state.players) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) return; - // Get the mission state - auto missionState = missionComponent->GetMissionState(missionID); - // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { - missionComponent->AcceptMission(missionID); - missionState = missionComponent->GetMissionState(missionID); - } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { - auto mission = missionComponent->GetMission(missionID); - if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - } - } - } + for (const auto& playerID : state.players) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player != nullptr) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) return; + // Get the mission state + auto missionState = missionComponent->GetMissionState(missionID); + // For some reason these achievements are not accepted by default, so we accept them here if they arent already. + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { + missionComponent->AcceptMission(missionID); + missionState = missionComponent->GetMissionState(missionID); + } + if (missionState != eMissionState::COMPLETE) { + auto mission = missionComponent->GetMission(missionID); + if (mission != nullptr) { + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + } + } + } } void BaseWavesServer::ClearSpawners() { - for (const auto& spawnerName : spawners) { - const auto spawnerObjects = dZoneManager::Instance()->GetSpawnersByName(spawnerName); + for (const auto& spawnerName : spawners) { + const auto spawnerObjects = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - for (auto* spawnerObject : spawnerObjects) { - spawnerObject->Reset(); - spawnerObject->Deactivate(); - } - } + for (auto* spawnerObject : spawnerObjects) { + spawnerObject->Reset(); + spawnerObject->Deactivate(); + } + } } diff --git a/dScripts/BaseWavesServer.h b/dScripts/BaseWavesServer.h index 3dc90da8..67eaf39d 100644 --- a/dScripts/BaseWavesServer.h +++ b/dScripts/BaseWavesServer.h @@ -5,151 +5,154 @@ * State for each active game */ struct WavesGameState { - std::vector<LWOOBJID> players {}; - std::vector<LWOOBJID> waitingPlayers {}; - uint32_t totalSpawned = 0; - uint32_t currentSpawned = 0; - uint32_t waveNumber = 0; - std::string introCelebration; + std::vector<LWOOBJID> players{}; + std::vector<LWOOBJID> waitingPlayers{}; + uint32_t totalSpawned = 0; + uint32_t currentSpawned = 0; + uint32_t waveNumber = 0; + std::string introCelebration; }; struct MobDefinition { - LOT lot; - uint32_t amountToSpawn; - std::string spawnerName; + LOT lot; + uint32_t amountToSpawn; + std::string spawnerName; }; struct WaveMission { - uint32_t time; - uint32_t wave; - uint32_t missionID; + uint32_t time; + uint32_t wave; + uint32_t missionID; }; struct Wave { - std::vector<MobDefinition> waveMobs {}; - std::vector<uint32_t> soloMissions {}; - std::vector<uint32_t> missions {}; - std::string cinematic; - float_t cinematicLength; - uint32_t timeLimit = UINT32_MAX; - bool notifyWin = false; - uint32_t winDelay = UINT32_MAX; + std::vector<MobDefinition> waveMobs{}; + std::vector<uint32_t> soloMissions{}; + std::vector<uint32_t> missions{}; + std::string cinematic; + float_t cinematicLength; + uint32_t timeLimit = UINT32_MAX; + bool notifyWin = false; + uint32_t winDelay = UINT32_MAX; }; /** * WaveConstants that have to be set for each game */ struct WaveConstants { - uint32_t acceptedDelay = 0; - uint32_t startDelay = 0; - uint32_t waveTime = 0; - uint32_t waveCompleteDelay = 0; - std::string eventGroup; - std::string introCelebration; + uint32_t acceptedDelay = 0; + uint32_t startDelay = 0; + uint32_t waveTime = 0; + uint32_t waveCompleteDelay = 0; + std::string eventGroup; + std::string introCelebration; }; class BaseWavesServer : public ActivityManager { public: - void OnStartup(Entity* self) override { SetGameVariables(self); BaseStartup(self); }; - void OnPlayerLoaded(Entity* self, Entity* player) override { BasePlayerLoaded(self, player); }; - void OnPlayerExit(Entity* self, Entity* player) override { BasePlayerExit(self, player); }; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override { BaseFireEvent(self, sender, args, param1, param2, param3); }; - void OnPlayerDied(Entity* self, Entity* player) override { BasePlayerDied(self, player); }; - void OnPlayerResurrected(Entity* self, Entity* player) override { BasePlayerResurrected(self, player); }; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, - const std::u16string& userData) override - { BaseMessageBoxResponse(self, sender, button, identifier, userData); }; + void OnStartup(Entity* self) override { SetGameVariables(self); BaseStartup(self); }; + void OnPlayerLoaded(Entity* self, Entity* player) override { BasePlayerLoaded(self, player); }; + void OnPlayerExit(Entity* self, Entity* player) override { BasePlayerExit(self, player); }; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override { + BaseFireEvent(self, sender, args, param1, param2, param3); + }; + void OnPlayerDied(Entity* self, Entity* player) override { BasePlayerDied(self, player); }; + void OnPlayerResurrected(Entity* self, Entity* player) override { BasePlayerResurrected(self, player); }; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, + const std::u16string& userData) override { + BaseMessageBoxResponse(self, sender, button, identifier, userData); + }; - void BasePlayerLoaded(Entity* self, Entity* player); - void BaseStartup(Entity* self); - void BasePlayerExit(Entity* self, Entity* player); - void BaseFireEvent(Entity *self, Entity *sender, const std::string& args, int32_t param1, int32_t param2, - int32_t param3); - void BasePlayerDied(Entity* self, Entity* player); - void BasePlayerResurrected(Entity* self, Entity* player); - void BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); + void BasePlayerLoaded(Entity* self, Entity* player); + void BaseStartup(Entity* self); + void BasePlayerExit(Entity* self, Entity* player); + void BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2, + int32_t param3); + void BasePlayerDied(Entity* self, Entity* player); + void BasePlayerResurrected(Entity* self, Entity* player); + void BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); - void OnActivityTimerDone(Entity *self, const std::string &name) override; - void OnActivityTimerUpdate(Entity *self, const std::string &name, float_t remainingTime, float_t elapsedTime) override; + void OnActivityTimerDone(Entity* self, const std::string& name) override; + void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) override; protected: - virtual WaveConstants GetConstants() { return WaveConstants(); }; - virtual std::vector<Wave> GetWaves() { return {}; }; - virtual std::vector<WaveMission> GetWaveMissions() { return {}; }; - virtual std::vector<std::string> GetSpawnerNames() { return {}; } - WavesGameState state {}; + virtual WaveConstants GetConstants() { return WaveConstants(); }; + virtual std::vector<Wave> GetWaves() { return {}; }; + virtual std::vector<WaveMission> GetWaveMissions() { return {}; }; + virtual std::vector<std::string> GetSpawnerNames() { return {}; } + WavesGameState state{}; - // Mob set default names - std::string BaseMobSet = "baseMobSet"; - std::string RandMobSet = "randMobSet"; + // Mob set default names + std::string BaseMobSet = "baseMobSet"; + std::string RandMobSet = "randMobSet"; - // Variable names - std::u16string WavesStartedVariable = u"wavesStarted"; - std::u16string ShowScoreboardVariable = u"Show_ScoreBoard"; - std::u16string WatchingIntroVariable = u"WatchingIntro"; - std::u16string ClearScoreboardVariable = u"Clear_Scoreboard"; - std::u16string DefinePlayerToUIVariable = u"Define_Player_To_UI"; - std::u16string UpdateScoreboardPlayersVariable = u"Update_ScoreBoard_Players."; - std::u16string PlayerConfirmVariable = u"PlayerConfirm_ScoreBoard."; - std::u16string PlayersAcceptedVariable = u"playersAccepted"; - std::u16string PlayersReadyVariable = u"playersReady"; - std::u16string BaseMobSetIndexVariable = u"baseMobSetNum"; - std::u16string RandMobSetIndexVariable = u"randMobSetNum"; - std::u16string AcceptedDelayStartedVariable = u"AcceptedDelayStarted"; - std::u16string NumberOfPlayersVariable = u"NumberOfPlayers"; - std::u16string FirstTimeDoneVariable = u"firstTimeDone"; - std::u16string MissionTypeVariable = u"missionType"; - std::u16string StartWaveMessageVariable = u"Start_Wave_Message"; - std::u16string ExitWavesVariable = u"Exit_waves"; - std::u16string UpdateDefaultStartTimerVariable = u"Update_Default_Start_Timer"; - std::u16string UpdateTimerVariable = u"Update_Timer"; - std::u16string UpdateCooldownVariable = u"Update_Cool_Down"; - std::u16string IsCooldownVariable = u"isCoolDown"; - std::u16string SpawnMobVariable = u"Spawn_Mob"; - std::u16string WonWaveVariable = u"Won_Wave"; - std::u16string WaveCompleteVariable = u"Wave_Complete"; - std::u16string StartTimedWaveVariable = u"Start_Timed_Wave"; - std::u16string NewWaveVariable = u"New_Wave"; - std::u16string StartCinematicVariable = u"startCinematic"; - std::u16string NumRemainingVariable = u"numRemaining"; - std::u16string StartCooldownVariable = u"Start_Cool_Down"; + // Variable names + std::u16string WavesStartedVariable = u"wavesStarted"; + std::u16string ShowScoreboardVariable = u"Show_ScoreBoard"; + std::u16string WatchingIntroVariable = u"WatchingIntro"; + std::u16string ClearScoreboardVariable = u"Clear_Scoreboard"; + std::u16string DefinePlayerToUIVariable = u"Define_Player_To_UI"; + std::u16string UpdateScoreboardPlayersVariable = u"Update_ScoreBoard_Players."; + std::u16string PlayerConfirmVariable = u"PlayerConfirm_ScoreBoard."; + std::u16string PlayersAcceptedVariable = u"playersAccepted"; + std::u16string PlayersReadyVariable = u"playersReady"; + std::u16string BaseMobSetIndexVariable = u"baseMobSetNum"; + std::u16string RandMobSetIndexVariable = u"randMobSetNum"; + std::u16string AcceptedDelayStartedVariable = u"AcceptedDelayStarted"; + std::u16string NumberOfPlayersVariable = u"NumberOfPlayers"; + std::u16string FirstTimeDoneVariable = u"firstTimeDone"; + std::u16string MissionTypeVariable = u"missionType"; + std::u16string StartWaveMessageVariable = u"Start_Wave_Message"; + std::u16string ExitWavesVariable = u"Exit_waves"; + std::u16string UpdateDefaultStartTimerVariable = u"Update_Default_Start_Timer"; + std::u16string UpdateTimerVariable = u"Update_Timer"; + std::u16string UpdateCooldownVariable = u"Update_Cool_Down"; + std::u16string IsCooldownVariable = u"isCoolDown"; + std::u16string SpawnMobVariable = u"Spawn_Mob"; + std::u16string WonWaveVariable = u"Won_Wave"; + std::u16string WaveCompleteVariable = u"Wave_Complete"; + std::u16string StartTimedWaveVariable = u"Start_Timed_Wave"; + std::u16string NewWaveVariable = u"New_Wave"; + std::u16string StartCinematicVariable = u"startCinematic"; + std::u16string NumRemainingVariable = u"numRemaining"; + std::u16string StartCooldownVariable = u"Start_Cool_Down"; - // Timer names - std::string SpawnTickTimer = "SpawnTick"; - std::string AllAcceptedDelayTimer = "AllAcceptedDelay"; - std::string AcceptedDelayTimer = "AcceptedDelay"; - std::string StartDelayTimer = "StartDelay"; - std::string ClockTickTimer = "ClockTick"; - std::string CoolDownStartTimer = "CoolDownStart"; - std::string CoolDownStopTimer = "CoolDownStop"; - std::string PlaySpawnSoundTimer = "PlaySpawnSound"; - std::string NextWaveTickTimer = "NextWaveTick"; - std::string WaveCompleteDelayTimer = "WaveCompleteDelay"; - std::string TimedWaveTimer = "TimedWave"; - std::string GameOverWinTimer = "GameOverWin"; - std::string CinematicDoneTimer = "CinematicDone"; + // Timer names + std::string SpawnTickTimer = "SpawnTick"; + std::string AllAcceptedDelayTimer = "AllAcceptedDelay"; + std::string AcceptedDelayTimer = "AcceptedDelay"; + std::string StartDelayTimer = "StartDelay"; + std::string ClockTickTimer = "ClockTick"; + std::string CoolDownStartTimer = "CoolDownStart"; + std::string CoolDownStopTimer = "CoolDownStop"; + std::string PlaySpawnSoundTimer = "PlaySpawnSound"; + std::string NextWaveTickTimer = "NextWaveTick"; + std::string WaveCompleteDelayTimer = "WaveCompleteDelay"; + std::string TimedWaveTimer = "TimedWave"; + std::string GameOverWinTimer = "GameOverWin"; + std::string CinematicDoneTimer = "CinematicDone"; - std::string spawnSoundGUID = "{ca36045d-89df-4e96-a317-1e152d226b69}"; + std::string spawnSoundGUID = "{ca36045d-89df-4e96-a317-1e152d226b69}"; private: - void SetGameVariables(Entity* self); - static void ResetStats(LWOOBJID player); - void GameOver(Entity* self, bool won = false); - void GameWon(Entity* self); - void UpdateMissionForAllPlayers(Entity* self, uint32_t missionID); + void SetGameVariables(Entity* self); + static void ResetStats(LWOOBJID player); + void GameOver(Entity* self, bool won = false); + void GameWon(Entity* self); + void UpdateMissionForAllPlayers(Entity* self, uint32_t missionID); - void StartWaves(Entity* self); - void SpawnWave(Entity* self); - static void SpawnNow(const std::string& spawnerName, uint32_t amount, LOT spawnLot); - bool UpdateSpawnedEnemies(Entity* self, LWOOBJID enemyID, uint32_t score); + void StartWaves(Entity* self); + void SpawnWave(Entity* self); + static void SpawnNow(const std::string& spawnerName, uint32_t amount, LOT spawnLot); + bool UpdateSpawnedEnemies(Entity* self, LWOOBJID enemyID, uint32_t score); - bool CheckAllPlayersDead(); - void SetPlayerSpawnPoints(const LWOOBJID& specificPlayerID = LWOOBJID_EMPTY); - void PlayerConfirmed(Entity* self); - void PlayerAccepted(Entity* self, LWOOBJID playerID); - void ClearSpawners(); + bool CheckAllPlayersDead(); + void SetPlayerSpawnPoints(const LWOOBJID& specificPlayerID = LWOOBJID_EMPTY); + void PlayerConfirmed(Entity* self); + void PlayerAccepted(Entity* self, LWOOBJID playerID); + void ClearSpawners(); - WaveConstants constants {}; - std::vector<Wave> waves {}; - std::vector<WaveMission> missions {}; - std::vector<std::string> spawners {}; + WaveConstants constants{}; + std::vector<Wave> waves{}; + std::vector<WaveMission> missions{}; + std::vector<std::string> spawners{}; }; diff --git a/dScripts/BootyDigServer.cpp b/dScripts/BootyDigServer.cpp deleted file mode 100644 index 50d873e0..00000000 --- a/dScripts/BootyDigServer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "BootyDigServer.h" -#include "EntityManager.h" -#include "RenderComponent.h" -#include "MissionComponent.h" -#include "MissionTaskType.h" - -void BootyDigServer::OnStartup(Entity *self) { - auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); - if (zoneControlObject != nullptr) { - zoneControlObject->OnFireEventServerSide(self, "CheckForPropertyOwner"); - } -} - -void BootyDigServer::OnPlayerLoaded(Entity *self, Entity *player) { - auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); - if (zoneControlObject != nullptr) { - zoneControlObject->OnFireEventServerSide(self, "CheckForPropertyOwner"); - } -} - -void -BootyDigServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - - auto propertyOwner = self->GetNetworkVar<std::string>(u"PropertyOwnerID"); - auto* player = self->GetParentEntity(); - if (player == nullptr) - return; - - if (args == "ChestReady" && (propertyOwner == std::to_string(LWOOBJID_EMPTY) || player->GetVar<bool>(u"bootyDug"))) { - self->Smash(self->GetObjectID(), SILENT); - } else if (args == "ChestOpened") { - // Make sure players only dig up one booty per instance - player->SetVar<bool>(u"bootyDug", true); - - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - auto* mission = missionComponent->GetMission(1881); - if (mission != nullptr && (mission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE || mission->GetMissionState() == MissionState::MISSION_STATE_COMPLETE_ACTIVE)) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) - renderComponent->PlayEffect(7730, u"cast", "bootyshine"); - - LootGenerator::Instance().DropLoot(player, self, 231, 75, 75); - } - } - } else if (args == "ChestDead") { - self->Smash(player->GetObjectID(), SILENT); - } -} diff --git a/dScripts/BootyDigServer.h b/dScripts/BootyDigServer.h deleted file mode 100644 index dde41e29..00000000 --- a/dScripts/BootyDigServer.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class BootyDigServer : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnPlayerLoaded(Entity *self, Entity *player) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; -}; diff --git a/dScripts/BuccaneerValiantShip.cpp b/dScripts/BuccaneerValiantShip.cpp deleted file mode 100644 index 710a0d1a..00000000 --- a/dScripts/BuccaneerValiantShip.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "BuccaneerValiantShip.h" -#include "SkillComponent.h" - -void BuccaneerValiantShip::OnStartup(Entity* self) { - self->AddCallbackTimer(1.0F, [self]() { - auto* skillComponent = self->GetComponent<SkillComponent>(); - auto* owner = self->GetOwner(); - - if (skillComponent != nullptr && owner != nullptr) { - skillComponent->CalculateBehavior(982, 20577, LWOOBJID_EMPTY, true, false, owner->GetObjectID()); - - // Kill self if missed - self->AddCallbackTimer(1.1F, [self]() { - self->Kill(); - }); - } - }); -} diff --git a/dScripts/BurningTile.cpp b/dScripts/BurningTile.cpp deleted file mode 100644 index b9a05391..00000000 --- a/dScripts/BurningTile.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "BurningTile.h" -#include "SkillComponent.h" - -void BurningTile::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - if (args == "PlayerEntered") - { - auto* skillComponent = sender->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(726, 11723, sender->GetObjectID(), true); - } -} diff --git a/dScripts/BurningTile.h b/dScripts/BurningTile.h deleted file mode 100644 index 5f43895e..00000000 --- a/dScripts/BurningTile.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class BurningTile : public CppScripts::Script -{ -public: - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; -}; \ No newline at end of file diff --git a/dScripts/CMakeLists.txt b/dScripts/CMakeLists.txt new file mode 100644 index 00000000..ac600dbc --- /dev/null +++ b/dScripts/CMakeLists.txt @@ -0,0 +1,54 @@ +set(DSCRIPTS_SOURCES + "ActivityManager.cpp" + "BaseConsoleTeleportServer.cpp" + "BasePropertyServer.cpp" + "BaseRandomServer.cpp" + "BaseSurvivalServer.cpp" + "BaseWavesGenericEnemy.cpp" + "BaseWavesServer.cpp" + "ChooseYourDestinationNsToNt.cpp" + "CppScripts.cpp" + "Darkitect.cpp" + "NPCAddRemoveItem.cpp" + "NtFactionSpyServer.cpp" + "ScriptComponent.cpp" + "ScriptedPowerupSpawner.cpp" + "SpawnPetBaseServer.cpp") + +add_subdirectory(02_server) + +foreach(file ${DSCRIPTS_SOURCES_02_SERVER}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "02_server/${file}") +endforeach() + +add_subdirectory(ai) + +foreach(file ${DSCRIPTS_SOURCES_AI}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "ai/${file}") +endforeach() + +add_subdirectory(client) + +foreach(file ${DSCRIPTS_SOURCES_CLIENT}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "client/${file}") +endforeach() + +add_subdirectory(EquipmentScripts) + +foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentScripts/${file}") +endforeach() + +add_subdirectory(EquipmentTriggers) + +foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentTriggers/${file}") +endforeach() + +add_subdirectory(zone) + +foreach(file ${DSCRIPTS_SOURCES_ZONE}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "zone/${file}") +endforeach() + +set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} PARENT_SCOPE) diff --git a/dScripts/CatapultBaseServer.h b/dScripts/CatapultBaseServer.h deleted file mode 100644 index a174fcaf..00000000 --- a/dScripts/CatapultBaseServer.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class CatapultBaseServer : public CppScripts::Script { -public: - void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; - - void OnTimerDone(Entity* self, std::string timerName) override; -}; diff --git a/dScripts/CatapultBouncerServer.cpp b/dScripts/CatapultBouncerServer.cpp deleted file mode 100644 index 098f38ac..00000000 --- a/dScripts/CatapultBouncerServer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "CatapultBouncerServer.h" -#include "GameMessages.h" -#include "EntityManager.h" - -void CatapultBouncerServer::OnRebuildComplete(Entity* self, Entity* target) -{ - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"Built", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - - self->SetNetworkVar<bool>(u"Built", true); - - const auto base = EntityManager::Instance()->GetEntitiesInGroup(self->GetVarAsString(u"BaseGroup")); - - for (auto* obj : base) - { - obj->NotifyObject(self, "BouncerBuilt"); - } -} diff --git a/dScripts/CauldronOfLife.cpp b/dScripts/CauldronOfLife.cpp deleted file mode 100644 index 13e07775..00000000 --- a/dScripts/CauldronOfLife.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "CauldronOfLife.h" - -void CauldronOfLife::OnStartup(Entity *self) { - self->SetVar<uint32_t>(u"numCycles", 10); - self->SetVar<float_t>(u"secPerCycle", 20.0f); - self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); - self->SetVar<float_t>(u"deathDelay", 20.0f); - self->SetVar<uint32_t>(u"numberOfPowerups", 3); - self->SetVar<LOT>(u"lootLOT", 177); - - // Initiate the actual script - OnTemplateStartup(self); -} diff --git a/dScripts/CavePrisonCage.cpp b/dScripts/CavePrisonCage.cpp deleted file mode 100644 index 5fe47f2d..00000000 --- a/dScripts/CavePrisonCage.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include "CavePrisonCage.h" -#include "EntityManager.h" -#include "RebuildComponent.h" -#include "GameMessages.h" -#include "Character.h" -#include "dZoneManager.h" - -void CavePrisonCage::OnStartup(Entity *self) -{ - const auto& myNum = self->GetVar<std::u16string>(u"myNumber"); - - if (myNum.empty()) - { - return; - } - - auto* spawner = dZoneManager::Instance()->GetSpawnersByName("PrisonCounterweight_0" + GeneralUtils::UTF16ToWTF8(myNum))[0]; - - self->SetVar<Spawner*>(u"CWSpawner", spawner); - - Setup(self, spawner); -} - -void CavePrisonCage::Setup(Entity *self, Spawner* spawner) -{ - SpawnCounterweight(self, spawner); - - NiPoint3 mypos = self->GetPosition(); - NiQuaternion myrot = self->GetRotation(); - - mypos.y += 1.5; - mypos.z -= 0.5; - - EntityInfo info {}; - info.lot = m_Villagers[self->GetVarAs<int32_t>(u"myNumber") - 1]; - info.pos = mypos; - info.rot = myrot; - info.spawnerID = self->GetObjectID(); - - // Spawn the villager inside the jail - auto* entity = EntityManager::Instance()->CreateEntity(info); - - // Save the villeger ID - self->SetVar<LWOOBJID>(u"villager", entity->GetObjectID()); - - // Construct the entity - EntityManager::Instance()->ConstructEntity(entity); -} - -void CavePrisonCage::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state != eRebuildState::REBUILD_RESETTING) - { - return; - } - - auto* spawner = self->GetVar<Spawner*>(u"CWSpawner"); - - if (spawner == nullptr) - { - return; - } - - spawner->Reset(); - - SpawnCounterweight(self, spawner); -} - -void CavePrisonCage::SpawnCounterweight(Entity* self, Spawner* spawner) -{ - spawner->Reset(); - - auto* counterweight = spawner->Spawn(); - - self->SetVar<LWOOBJID>(u"Counterweight", counterweight->GetObjectID()); - - auto* rebuildComponent = counterweight->GetComponent<RebuildComponent>(); - - if (rebuildComponent != nullptr) - { - rebuildComponent->AddRebuildStateCallback([this, self] (eRebuildState state) { - OnRebuildNotifyState(self, state); - }); - - rebuildComponent->AddRebuildCompleteCallback([this, self] (Entity* user) { - // The counterweight is a simple mover, which is not implemented, so we'll just set it's position - auto* counterweight = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Counterweight")); - - if (counterweight == nullptr) - { - return; - } - - // Move the counterweight down 2 units - counterweight->SetPosition(counterweight->GetPosition() + NiPoint3(0, -2, 0)); - - // Serialize the counterweight - EntityManager::Instance()->SerializeEntity(counterweight); - - // notifyPlatformAtLastWaypoint - - // Save the userID as Builder - self->SetVar<LWOOBJID>(u"Builder", user->GetObjectID()); - - // Get the button and make sure it still exists - auto* button = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Button")); - - if (button == nullptr) - { - return; - } - - // Play the 'down' animation on the button - GameMessages::SendPlayAnimation(button, u"down"); - - // Setup a timer named 'buttonGoingDown' to be triggered in 5 seconds - self->AddTimer("buttonGoingDown", 5.0f); - }); - } - - if (self->GetVar<LWOOBJID>(u"Button")) - { - return; - } - - GetButton(self); -} - -void CavePrisonCage::GetButton(Entity* self) -{ - const auto buttons = EntityManager::Instance()->GetEntitiesInGroup("PrisonButton_0" + std::to_string(self->GetVarAs<int32_t>(u"myNumber"))); - - if (buttons.size() == 0) - { - // Try again in 0.5 seconds - self->AddCallbackTimer(0.5, [this, self] () { - GetButton(self); - }); - - return; - } - - auto* button = buttons[0]; - - self->SetVar<LWOOBJID>(u"Button", button->GetObjectID()); -} - -void CavePrisonCage::OnTimerDone(Entity* self, std::string timerName) -{ - // the anim of the button down is over - if (timerName == "buttonGoingDown") - { - // Play the 'up' animation - GameMessages::SendPlayAnimation(self, u"up"); - - // Setup a timer named 'CageOpen' to be triggered in 1 second - self->AddTimer("CageOpen", 1.0f); - } - else if (timerName == "CageOpen") - { - // play the idle open anim - GameMessages::SendPlayAnimation(self, u"idle-up"); - - // Get the villeger - auto* villager = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"villager")); - - if (villager == nullptr) - { - return; - } - - GameMessages::SendNotifyClientObject(villager->GetObjectID(), u"TimeToChat", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - - // Get the builder and make sure it still exists - auto* builder = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Builder")); - - if (builder == nullptr) - { - return; - } - - const auto flagNum = 2020 + self->GetVarAs<int32_t>(u"myNumber"); - - // Set the flag on the builder character - builder->GetCharacter()->SetPlayerFlag(flagNum, true); - - // Setup a timer named 'VillagerEscape' to be triggered in 5 seconds - self->AddTimer("VillagerEscape", 5.0f); - } - else if (timerName == "VillagerEscape") - { - // Get the villeger and make sure it still exists - auto* villager = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"villager")); - - if (villager == nullptr) - { - return; - } - - // Kill the villager - villager->Kill(); - - // Setup a timer named 'SmashCounterweight' to be triggered in 2 seconds - self->AddTimer("SmashCounterweight", 2.0f); - } - else if (timerName == "SmashCounterweight") - { - // Get the counterweight and make sure it still exists - auto* counterweight = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Counterweight")); - - if (counterweight == nullptr) - { - return; - } - - // Smash the counterweight - counterweight->Smash(); - - // Get the button and make sure it still exists - auto* button = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"Button")); - - if (button == nullptr) - { - return; - } - - // Play the 'up' animation on the button - GameMessages::SendPlayAnimation(button, u"up"); - - // Setup a timer named 'CageClosed' to be triggered in 1 second - self->AddTimer("CageClosed", 1.0f); - } - else if (timerName == "CageClosed") - { - // play the idle closed anim - GameMessages::SendPlayAnimation(self, u"idle"); - - // Setup a timer named 'ResetPrison' to be triggered in 10 seconds - self->AddTimer("ResetPrison", 10.0f); - } - else if (timerName == "ResetPrison") - { - Setup(self, self->GetVar<Spawner*>(u"CWSpawner")); - } -} diff --git a/dScripts/CavePrisonCage.h b/dScripts/CavePrisonCage.h deleted file mode 100644 index 5ae357d5..00000000 --- a/dScripts/CavePrisonCage.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class CavePrisonCage : public CppScripts::Script { -public: - void OnStartup(Entity *self) override; - void Setup(Entity *self, Spawner* spawner); - void OnRebuildNotifyState(Entity* self, eRebuildState state) override; - void SpawnCounterweight(Entity* self, Spawner* spawner); - void GetButton(Entity* self); - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - std::vector<LOT> m_Villagers = { 15851, 15866, 15922, 15924, 15927, 15929 }; - std::vector<int32_t> m_Missions = { 1801, 2039 }; -}; diff --git a/dScripts/ChooseYourDestinationNsToNt.cpp b/dScripts/ChooseYourDestinationNsToNt.cpp index 823d7c85..f9ca0a79 100644 --- a/dScripts/ChooseYourDestinationNsToNt.cpp +++ b/dScripts/ChooseYourDestinationNsToNt.cpp @@ -1,78 +1,65 @@ #include "ChooseYourDestinationNsToNt.h" #include "Character.h" #include "GameMessages.h" +#include "eTerminateType.h" -bool ChooseYourDestinationNsToNt::CheckChoice(Entity* self, Entity* player) -{ - const auto choiceZoneID = self->GetVar<int32_t>(u"choiceZone"); - const auto newZoneID = self->GetVar<int32_t>(u"currentZone"); +bool ChooseYourDestinationNsToNt::CheckChoice(Entity* self, Entity* player) { + const auto choiceZoneID = self->GetVar<int32_t>(u"choiceZone"); + const auto newZoneID = self->GetVar<int32_t>(u"currentZone"); - if (newZoneID == choiceZoneID) - { - auto* character = player->GetCharacter(); + if (newZoneID == choiceZoneID) { + auto* character = player->GetCharacter(); - if (character == nullptr) - { - return false; - } + if (character == nullptr) { + return false; + } - if (character->HasBeenToWorld(1900)) - { - return true; - } + if (character->HasBeenToWorld(1900)) { + return true; + } - self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(1200)); - self->SetVar<std::u16string>(u"teleportString", u"UI_TRAVEL_TO_NS"); + self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(1200)); + self->SetVar<std::u16string>(u"teleportString", u"UI_TRAVEL_TO_NS"); - return false; - } + return false; + } - return false; + return false; } -void ChooseYourDestinationNsToNt::SetDestination(Entity* self, Entity* player) -{ - const auto currentMap = self->GetVar<int32_t>(u"currentZone"); - auto newMap = self->GetVar<int32_t>(u"choiceZone"); +void ChooseYourDestinationNsToNt::SetDestination(Entity* self, Entity* player) { + const auto currentMap = self->GetVar<int32_t>(u"currentZone"); + auto newMap = self->GetVar<int32_t>(u"choiceZone"); - if (currentMap == newMap) - { - newMap = 1200; - } + if (currentMap == newMap) { + newMap = 1200; + } - self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(newMap)); + self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(newMap)); } -void ChooseYourDestinationNsToNt::BaseChoiceBoxRespond(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - if (button != -1) - { - const auto newMapStr = GeneralUtils::UTF16ToWTF8(buttonIdentifier).substr(7, -1); +void ChooseYourDestinationNsToNt::BaseChoiceBoxRespond(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { + if (button != -1) { + const auto newMapStr = GeneralUtils::UTF16ToWTF8(buttonIdentifier).substr(7, -1); - int32_t newMap = 0; - if (!GeneralUtils::TryParse(newMapStr, newMap)) - { - return; - } + int32_t newMap = 0; + if (!GeneralUtils::TryParse(newMapStr, newMap)) { + return; + } - std::u16string strText = u""; + std::u16string strText = u""; - if (newMap == 1200) - { - strText = u"UI_TRAVEL_TO_NS"; - } - else - { - strText = u"UI_TRAVEL_TO_NEXUS_TOWER"; - } + if (newMap == 1200) { + strText = u"UI_TRAVEL_TO_NS"; + } else { + strText = u"UI_TRAVEL_TO_NEXUS_TOWER"; + } - self->SetVar(u"teleportString", strText); - self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(newMap)); + self->SetVar(u"teleportString", strText); + self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(newMap)); - GameMessages::SendDisplayMessageBox(sender->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, strText, u"", sender->GetSystemAddress()); - } - else - { - GameMessages::SendTerminateInteraction(sender->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); - } + GameMessages::SendDisplayMessageBox(sender->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, strText, u"", sender->GetSystemAddress()); + } else { + GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + } } diff --git a/dScripts/ChooseYourDestinationNsToNt.h b/dScripts/ChooseYourDestinationNsToNt.h index cbf3709e..9ce9988a 100644 --- a/dScripts/ChooseYourDestinationNsToNt.h +++ b/dScripts/ChooseYourDestinationNsToNt.h @@ -3,7 +3,7 @@ class ChooseYourDestinationNsToNt { public: - bool CheckChoice(Entity* self, Entity* player); - void SetDestination(Entity* self, Entity* player); - void BaseChoiceBoxRespond(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier); + bool CheckChoice(Entity* self, Entity* player); + void SetDestination(Entity* self, Entity* player); + void BaseChoiceBoxRespond(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier); }; diff --git a/dScripts/ClRing.cpp b/dScripts/ClRing.cpp deleted file mode 100644 index 5de3e683..00000000 --- a/dScripts/ClRing.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ClRing.h" - -void ClRing::OnCollisionPhantom(Entity* self, Entity* target) -{ - self->Smash(target->GetObjectID()); -} diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 420394bb..5459fd37 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -61,6 +61,8 @@ #include "VeMissionConsole.h" #include "VeEpsilonServer.h" #include "AgSurvivalBuffStation.h" +#include "QbSpawner.h" +#include "AgQbWall.h" // NS Scripts #include "NsModularBuild.h" @@ -116,6 +118,10 @@ #include "BaseEnemyApe.h" #include "GfApeSmashingQB.h" #include "ZoneGfProperty.h" +#include "GfArchway.h" +#include "GfMaelstromGeyser.h" +#include "PirateRep.h" +#include "GfParrotCrash.h" // SG Scripts #include "SGCannon.h" @@ -140,19 +146,20 @@ #include "FvConsoleLeftQuickbuild.h" #include "FvConsoleRightQuickbuild.h" #include "FvFacilityBrick.h" +#include "FvFacilityPipes.h" #include "ImgBrickConsoleQB.h" #include "ActParadoxPipeFix.h" #include "FvNinjaGuard.h" #include "FvPassThroughWall.h" #include "FvBounceOverWall.h" #include "FvFong.h" +#include "FvMaelstromGeyser.h" // FB Scripts #include "AgJetEffectServer.h" #include "AgSalutingNpcs.h" #include "BossSpiderQueenEnemyServer.h" #include "RockHydrantSmashable.h" -#include "SpecialImaginePowerupSpawner.h" // Misc Scripts #include "ExplodingAsset.h" @@ -201,6 +208,7 @@ #include "ForceVolumeServer.h" #include "NtXRayServer.h" #include "NtSleepingGuard.h" +#include "NtImagimeterVisibility.h" // DLU Scripts #include "DLUVanityNPC.h" @@ -269,6 +277,10 @@ #include "ImaginationBackpackHealServer.h" #include "LegoDieRoll.h" #include "BuccaneerValiantShip.h" +#include "GemPack.h" +#include "ShardArmor.h" +#include "TeslaPack.h" +#include "StunImmunity.h" // Survival scripts #include "AgSurvivalStromling.h" @@ -279,6 +291,27 @@ #include "RockHydrantBroken.h" #include "WhFans.h" +// WBL scripts +#include "WblGenericZone.h" + +// Alpha Scripts +#include "TriggerGas.h" +#include "ActNinjaSensei.h" + +// pickups +#include "SpecialCoinSpawner.h" +#include "SpecialPowerupSpawner.h" +#include "SpecialSpeedBuffSpawner.h" + +// Wild Scripts +#include "WildAndScared.h" +#include "WildGfGlowbug.h" +#include "WildAmbientCrab.h" +#include "WildPants.h" +#include "WildNinjaStudent.h" +#include "WildNinjaSensei.h" +#include "WildNinjaBricks.h" + //Big bad global bc this is a namespace and not a class: InvalidScript* invalidToReturn = new InvalidScript(); std::map<std::string, CppScripts::Script*> m_Scripts; @@ -355,8 +388,6 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new RemoveRentalGear(); else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_NJ_ASSISTANT_SERVER.lua") script = new NpcNjAssistantServer(); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER.lua") - script = new SpecialImaginePowerupSpawner(); else if (scriptName == "scripts\\ai\\AG\\L_AG_SALUTING_NPCS.lua") script = new AgSalutingNpcs(); else if (scriptName == "scripts\\ai\\AG\\L_AG_JET_EFFECT_SERVER.lua") @@ -377,38 +408,38 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new NpcAgCourseStarter(); else if (scriptName == "scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_GOAL.lua") script = new AgMonumentRaceGoal(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_CANCEL.lua") - script = new AgMonumentRaceCancel(); - else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_ZONE_AG_SPIDER_QUEEN.lua") - script = (ZoneAgProperty*)new ZoneAgSpiderQueen(); - else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_SPIDER_BOSS_TREASURE_CHEST_SERVER.lua") - script = new SpiderBossTreasureChestServer(); + else if (scriptName == "scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_CANCEL.lua") + script = new AgMonumentRaceCancel(); + else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_ZONE_AG_SPIDER_QUEEN.lua") + script = (ZoneAgProperty*)new ZoneAgSpiderQueen(); + else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_SPIDER_BOSS_TREASURE_CHEST_SERVER.lua") + script = new SpiderBossTreasureChestServer(); else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_COWBOY_SERVER.lua") script = new NpcCowboyServer(); else if (scriptName == "scripts\\02_server\\Map\\Property\\AG_Med\\L_ZONE_AG_MED_PROPERTY.lua") - script = new ZoneAgMedProperty(); + script = new ZoneAgMedProperty(); else if (scriptName == "scripts\\ai\\AG\\L_AG_STROMBIE_PROPERTY.lua") - script = new AgStromlingProperty(); + script = new AgStromlingProperty(); else if (scriptName == "scripts\\ai\\AG\\L_AG_DARKLING_MECH.lua") - script = new BaseEnemyMech(); + script = new BaseEnemyMech(); else if (scriptName == "scripts\\ai\\AG\\L_AG_DARK_SPIDERLING.lua") - script = new AgDarkSpiderling(); + script = new AgDarkSpiderling(); else if (scriptName == "scripts\\ai\\PROPERTY\\L_PROP_GUARDS.lua") - script = new AgPropguards(); + script = new AgPropguards(); else if (scriptName == "scripts\\ai\\PROPERTY\\L_PROPERTY_FX_DAMAGE.lua") - script = new PropertyFXDamage(); + script = new PropertyFXDamage(); else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_PIRATE_SERVER.lua") - script = new NpcPirateServer(); + script = new NpcPirateServer(); else if (scriptName == "scripts\\ai\\AG\\L_AG_PICNIC_BLANKET.lua") - script = new AgPicnicBlanket(); + script = new AgPicnicBlanket(); else if (scriptName == "scripts\\02_server\\Map\\Property\\L_PROPERTY_BANK_INTERACT_SERVER.lua") - script = new PropertyBankInteract(); - else if (scriptName == "scripts\\02_server\\Enemy\\VE\\L_VE_MECH.lua") - script = new VeMech(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_MISSION_CONSOLE_SERVER.lua") - script = new VeMissionConsole(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_EPSILON_SERVER.lua") - script = new VeEpsilonServer(); + script = new PropertyBankInteract(); + else if (scriptName == "scripts\\02_server\\Enemy\\VE\\L_VE_MECH.lua") + script = new VeMech(); + else if (scriptName == "scripts\\02_server\\Map\\VE\\L_MISSION_CONSOLE_SERVER.lua") + script = new VeMissionConsole(); + else if (scriptName == "scripts\\02_server\\Map\\VE\\L_EPSILON_SERVER.lua") + script = new VeEpsilonServer(); // Win32 thinks this if chain is too long, let's cut it up and serve it as a three course meal //NS: if (scriptName == "scripts\\ai\\NS\\L_NS_MODULAR_BUILD.lua") @@ -418,47 +449,51 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\ai\\NS\\L_NS_QB_IMAGINATION_STATUE.lua") script = new NsQbImaginationStatue(); else if (scriptName == "scripts\\02_server\\Map\\NS\\CONCERT_CHOICEBUILD_MANAGER_SERVER.lua") - script = new NsConcertChoiceBuildManager(); + script = new NsConcertChoiceBuildManager(); else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_CHOICEBUILD.lua") - script = new NsConcertChoiceBuild(); + script = new NsConcertChoiceBuild(); else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_QUICKBUILD.lua") - script = new NsConcertQuickBuild(); + script = new NsConcertQuickBuild(); else if (scriptName == "scripts\\ai\\AG\\L_AG_STAGE_PLATFORMS.lua") - script = new AgStagePlatforms(); + script = new AgStagePlatforms(); else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_INSTRUMENT_QB.lua") - script = new NsConcertInstrument(); + script = new NsConcertInstrument(); else if (scriptName == "scripts\\ai\\NS\\L_NS_JONNY_FLAG_MISSION_SERVER.lua") - script = new NsJohnnyMissionServer(); + script = new NsJohnnyMissionServer(); else if (scriptName == "scripts\\02_server\\Objects\\L_STINKY_FISH_TARGET.lua") - script = new StinkyFishTarget(); + script = new StinkyFishTarget(); else if (scriptName == "scripts\\zone\\PROPERTY\\NS\\L_ZONE_NS_PROPERTY.lua") - script = new ZoneNsProperty(); + script = new ZoneNsProperty(); else if (scriptName == "scripts\\02_server\\Map\\Property\\NS_Med\\L_ZONE_NS_MED_PROPERTY.lua") - script = new ZoneNsMedProperty(); + script = new ZoneNsMedProperty(); else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_TOKEN_CONSOLE_SERVER.lua") script = new NsTokenConsoleServer(); else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_LUP_TELEPORT.lua") script = new NsLupTeleport(); else if (scriptName == "scripts\\02_server\\Map\\NS\\Waves\\L_ZONE_NS_WAVES.lua") - script = new ZoneNsWaves(); + script = new ZoneNsWaves(); else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HAMMERLING_ENEMY_SERVER.lua") - script = new WaveBossHammerling(); + script = new WaveBossHammerling(); else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_APE_ENEMY_SERVER.lua") - script = (BaseEnemyApe*) new WaveBossApe(); + script = (BaseEnemyApe*) new WaveBossApe(); else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_DARK_SPIDERLING_ENEMY_SERVER.lua") - script = new WaveBossSpiderling(); + script = new WaveBossSpiderling(); else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HORESEMEN_ENEMY_SERVER.lua") - script = new WaveBossHorsemen(); + script = new WaveBossHorsemen(); else if (scriptName == "scripts\\02_server\\Minigame\\General\\L_MINIGAME_TREASURE_CHEST_SERVER.lua") - script = new MinigameTreasureChestServer(); + script = new MinigameTreasureChestServer(); else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_LEGO_CLUB_DOOR.lua") - script = new NsLegoClubDoor(); + script = new NsLegoClubDoor(); else if (scriptName == "scripts/ai/NS/L_CL_RING.lua") - script = new ClRing(); + script = new ClRing(); else if (scriptName == "scripts\\ai\\WILD\\L_WILD_AMBIENTS.lua") - script = new WildAmbients(); + script = new WildAmbients(); else if (scriptName == "scripts\\ai\\NS\\NS_PP_01\\L_NS_PP_01_TELEPORT.lua") script = new PropertyDeathPlane(); + else if (scriptName == "scripts\\02_server\\Map\\General\\L_QB_SPAWNER.lua") + script = new QbSpawner(); + else if (scriptName == "scripts\\ai\\AG\\L_AG_QB_Wall.lua") + script = new AgQbWall(); //GF: else if (scriptName == "scripts\\02_server\\Map\\GF\\L_GF_TORCH.lua") @@ -484,7 +519,7 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Map\\General\\L_QB_ENEMY_STUNNER.lua") script = new QbEnemyStunner(); else if (scriptName == "scripts\\ai\\GF\\L_GF_PET_DIG_BUILD.lua") - script = new PetDigBuild(); // Technically also used once in AG + script = new PetDigBuild(); // Technically also used once in AG else if (scriptName == "scripts\\02_server\\Map\\GF\\L_SPAWN_LION_SERVER.lua") script = new SpawnLionServer(); else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_APE.lua") @@ -492,13 +527,21 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_GF_APE_SMASHING_QB.lua") script = new GfApeSmashingQB(); else if (scriptName == "scripts\\zone\\PROPERTY\\GF\\L_ZONE_GF_PROPERTY.lua") - script = new ZoneGfProperty(); + script = new ZoneGfProperty(); + else if (scriptName == "scripts\\ai\\GF\\L_GF_ARCHWAY.lua") + script = new GfArchway(); + else if (scriptName == "scripts\\ai\\GF\\L_GF_MAELSTROM_GEYSER.lua") + script = new GfMaelstromGeyser(); + else if (scriptName == "scripts\\ai\\GF\\L_PIRATE_REP.lua") + script = new PirateRep(); + else if (scriptName == "scripts\\ai\\GF\\L_GF_PARROT_CRASH.lua") + script = new GfParrotCrash(); // SG else if (scriptName == "scripts\\ai\\MINIGAME\\SG_GF\\SERVER\\SG_CANNON.lua") - script = new SGCannon(); + script = new SGCannon(); else if (scriptName == "scripts\\ai\\MINIGAME\\SG_GF\\L_ZONE_SG_SERVER.lua") - script = new ZoneSGServer(); + script = new ZoneSGServer(); //PR: else if (scriptName == "scripts\\client\\ai\\PR\\L_PR_WHISTLE.lua") @@ -511,16 +554,16 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new HydrantBroken(); else if (scriptName == "scripts\\02_server\\Map\\General\\PET_DIG_SERVER.lua" || scriptName == "scripts\\02_server\\Map\\AM\\L_SKELETON_DRAGON_PET_DIG_SERVER.lua") script = new PetDigServer(); - else if (scriptName == "scripts\\client\\ai\\PR\\L_CRAB_SERVER.lua") - script = new CrabServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_DIG_SERVER.lua") - script = new PetFromDigServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_OBJECT_SERVER.lua") - script = new PetFromObjectServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_DAMAGING_PET.lua") - script = new DamagingPets(); - else if (scriptName == "scripts\\02_server\\Map\\PR\\L_SPAWN_GRYPHON_SERVER.lua") - script = new SpawnGryphonServer(); + else if (scriptName == "scripts\\client\\ai\\PR\\L_CRAB_SERVER.lua") + script = new CrabServer(); + else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_DIG_SERVER.lua") + script = new PetFromDigServer(); + else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_OBJECT_SERVER.lua") + script = new PetFromObjectServer(); + else if (scriptName == "scripts\\02_server\\Pets\\L_DAMAGING_PET.lua") + script = new DamagingPets(); + else if (scriptName == "scripts\\02_server\\Map\\PR\\L_SPAWN_GRYPHON_SERVER.lua") + script = new SpawnGryphonServer(); //FV Scripts: else if (scriptName == "scripts\\02_server\\Map\\FV\\L_ACT_CANDLE.lua") @@ -544,13 +587,13 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\ai\\GENERAL\\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua") script = new InstanceExitTransferPlayerToLastNonInstance(); else if (scriptName == "scripts\\ai\\FV\\L_NPC_FREE_GF_NINJAS.lua") - script = new FvFreeGfNinjas(); + script = new FvFreeGfNinjas(); else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SPAWNER_SERVER.lua") - script = new FvPandaSpawnerServer(); + script = new FvPandaSpawnerServer(); else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SERVER.lua") - script = new FvPandaServer(); - else if (scriptName == "scripts\\zone\\PROPERTY\\FV\\L_ZONE_FV_PROPERTY.lua") - script = new ZoneFvProperty(); + script = new FvPandaServer(); + else if (scriptName == "scripts\\zone\\PROPERTY\\FV\\L_ZONE_FV_PROPERTY.lua") + script = new ZoneFvProperty(); else if (scriptName == "scripts\\ai\\FV\\L_FV_BRICK_PUZZLE_SERVER.lua") script = new FvBrickPuzzleServer(); else if (scriptName == "scripts\\ai\\FV\\L_FV_CONSOLE_LEFT_QUICKBUILD.lua") @@ -559,6 +602,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new FvConsoleRightQuickbuild(); else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_BRICK.lua") script = new FvFacilityBrick(); + else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_PIPES.lua") + script = new FvFacilityPipes(); else if (scriptName == "scripts\\02_server\\Map\\FV\\L_IMG_BRICK_CONSOLE_QB.lua") script = new ImgBrickConsoleQB(); else if (scriptName == "scripts\\ai\\FV\\L_ACT_PARADOX_PIPE_FIX.lua") @@ -571,6 +616,9 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new FvBounceOverWall(); else if (scriptName == "scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua") script = new FvFong(); + else if (scriptName == "scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua") { + script = new FvMaelstromGeyser(); + } //Misc: if (scriptName == "scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua") @@ -579,16 +627,16 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new WishingWellServer(); else if (scriptName == "scripts\\ai\\ACT\\L_ACT_PLAYER_DEATH_TRIGGER.lua") script = new ActPlayerDeathTrigger(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_GROWING_FLOWER_SERVER.lua") - script = new GrowingFlower(); + else if (scriptName == "scripts\\02_server\\Map\\General\\L_GROWING_FLOWER_SERVER.lua") + script = new GrowingFlower(); else if (scriptName == "scripts\\02_server\\Map\\General\\L_TOKEN_CONSOLE_SERVER.lua") script = new TokenConsoleServer(); - else if (scriptName == "scripts\\ai\\ACT\\FootRace\\L_ACT_BASE_FOOT_RACE.lua") - script = new BaseFootRaceManager(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_PROP_PLATFORM.lua") - script = new PropertyPlatform(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_VE_BRICKSAMPLE_SERVER.lua") - return new VeBricksampleServer(); + else if (scriptName == "scripts\\ai\\ACT\\FootRace\\L_ACT_BASE_FOOT_RACE.lua") + script = new BaseFootRaceManager(); + else if (scriptName == "scripts\\02_server\\Map\\General\\L_PROP_PLATFORM.lua") + script = new PropertyPlatform(); + else if (scriptName == "scripts\\02_server\\Map\\VE\\L_VE_BRICKSAMPLE_SERVER.lua") + return new VeBricksampleServer(); else if (scriptName == "scripts\\02_server\\Map\\General\\L_MAIL_BOX_SERVER.lua") script = new MailBoxServer(); else if (scriptName == "scripts\\ai\\ACT\\L_ACT_MINE.lua") @@ -604,9 +652,9 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Map\\FV\\Racing\\RACE_MAELSTROM_GEISER.lua") script = new RaceMaelstromGeiser(); else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_SMASH_EGG_IMAGINE_SERVER.lua") - script = new FvRaceSmashEggImagineServer(); + script = new FvRaceSmashEggImagineServer(); else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\RACE_SMASH_SERVER.lua") - script = new RaceSmashServer(); + script = new RaceSmashServer(); //NT: else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_SENTINELWALKWAY_SERVER.lua") @@ -642,25 +690,28 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_CONSOLE_TELEPORT_SERVER.lua") script = new NtConsoleTeleportServer(); else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_STEGO_SERVER.lua") - script = new SpawnStegoServer(); + script = new SpawnStegoServer(); else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_SABERCAT_SERVER.lua") - script = new SpawnSaberCatServer(); + script = new SpawnSaberCatServer(); else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_SHRAKE_SERVER.lua") - script = new SpawnShrakeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_DUKE_SERVER.lua") - script = new NtDukeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_HAEL_SERVER.lua") - script = new NtHaelServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_OVERBUILD_SERVER.lua") - script = new NtOverbuildServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VANDA_SERVER.lua") - script = new NtVandaServer(); + script = new SpawnShrakeServer(); + else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_DUKE_SERVER.lua") + script = new NtDukeServer(); + else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_HAEL_SERVER.lua") + script = new NtHaelServer(); + else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_OVERBUILD_SERVER.lua") + script = new NtOverbuildServer(); + else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VANDA_SERVER.lua") + script = new NtVandaServer(); else if (scriptName == "scripts\\02_server\\Map\\General\\L_FORCE_VOLUME_SERVER.lua") script = new ForceVolumeServer(); else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_XRAY_SERVER.lua") script = new NtXRayServer(); else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_SLEEPING_GUARD.lua") script = new NtSleepingGuard(); + else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_IMAGIMETER_VISIBILITY_SERVER.lua") { + script = new NTImagimeterVisibility(); + } //AM: else if (scriptName == "scripts\\02_server\\Map\\AM\\L_AM_CONSOLE_TELEPORT_SERVER.lua") @@ -706,33 +757,33 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua") script = new BaseEnemyApe(); else if (scriptName == "scripts\\02_server\\Map\\AM\\L_BLUE_X.lua") - script = new AmBlueX(); + script = new AmBlueX(); else if (scriptName == "scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua") script = new AmTeapotServer(); // Ninjago else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_GARMADON_CELEBRATION_SERVER.lua") - script = new NjGarmadonCelebration(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_WU_NPC.lua") - script = new NjWuNPC(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_SCROLL_CHEST_SERVER.lua") - script = new NjScrollChestServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_COLE_NPC.lua") - script = new NjColeNPC(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_JAY_MISSION_ITEMS.lua") - script = (NjNPCMissionSpinjitzuServer*) new NjJayMissionItems(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_NPC_MISSION_SPINJITZU_SERVER.lua") - script = new NjNPCMissionSpinjitzuServer(); + script = new NjGarmadonCelebration(); + else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_WU_NPC.lua") + script = new NjWuNPC(); + else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_SCROLL_CHEST_SERVER.lua") + script = new NjScrollChestServer(); + else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_COLE_NPC.lua") + script = new NjColeNPC(); + else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_JAY_MISSION_ITEMS.lua") + script = (NjNPCMissionSpinjitzuServer*) new NjJayMissionItems(); + else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_NPC_MISSION_SPINJITZU_SERVER.lua") + script = new NjNPCMissionSpinjitzuServer(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_ENEMY_SKELETON_SPAWNER.lua") script = new EnemySkeletonSpawner(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_NJ_RAIL_SWITCH.lua") - script = new NjRailSwitch(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_ACTIVATORS_SERVER.lua") - script = new NjRailActivatorsServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_POST_SERVER.lua") - script = new NjRailPostServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_ICE_RAIL_ACTIVATOR_SERVER.lua") - script = new NjIceRailActivator(); + else if (scriptName == "scripts\\02_server\\Map\\General\\L_NJ_RAIL_SWITCH.lua") + script = new NjRailSwitch(); + else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_ACTIVATORS_SERVER.lua") + script = new NjRailActivatorsServer(); + else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_POST_SERVER.lua") + script = new NjRailPostServer(); + else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_ICE_RAIL_ACTIVATOR_SERVER.lua") + script = new NjIceRailActivator(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_FALLING_TILE.lua") script = new FallingTile(); else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF_STUN_IMMUNITY.lua") @@ -746,7 +797,7 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CAVE_PRISON_CAGE.lua") script = new CavePrisonCage(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\boss_instance\\L_MONASTERY_BOSS_INSTANCE_SERVER.lua") - script = new NjMonastryBossInstance(); + script = new NjMonastryBossInstance(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CATAPULT_BOUNCER_SERVER.lua") script = new CatapultBouncerServer(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CATAPULT_BASE_SERVER.lua") @@ -762,13 +813,13 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_BURNING_TILE.lua") script = new BurningTile(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_SPAWN_EARTH_PET_SERVER.lua") - script = new NjEarthDragonPetServer(); + script = new NjEarthDragonPetServer(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_EARTH_PET_SERVER.lua") - script = new NjEarthPetServer(); + script = new NjEarthPetServer(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_DRAGON_EMBLEM_CHEST_SERVER.lua") - script = new NjDragonEmblemChestServer(); + script = new NjDragonEmblemChestServer(); else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_NYA_MISSION_ITEMS.lua") - script = new NjNyaMissionitems(); + script = new NjNyaMissionitems(); //DLU: else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityNPC.lua") @@ -776,52 +827,115 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr // Survival minigame else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua") - script = new AgSurvivalStromling(); + script = new AgSurvivalStromling(); else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARKLING_MECH.lua") - script = new AgSurvivalMech(); + script = new AgSurvivalMech(); else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARK_SPIDERLING.lua") - script = new AgSurvivalSpiderling(); + script = new AgSurvivalSpiderling(); // Scripted equipment else if (scriptName == "scripts\\EquipmentScripts\\Sunflower.lua") - script = new Sunflower(); + script = new Sunflower(); else if (scriptName == "scripts/EquipmentScripts/AnvilOfArmor.lua") - script = new AnvilOfArmor(); + script = new AnvilOfArmor(); else if (scriptName == "scripts/EquipmentScripts/FountainOfImagination.lua") - script = new FountainOfImagination(); + script = new FountainOfImagination(); else if (scriptName == "scripts/EquipmentScripts/CauldronOfLife.lua") - script = new CauldronOfLife(); + script = new CauldronOfLife(); else if (scriptName == "scripts\\02_server\\Equipment\\L_BOOTYDIG_SERVER.lua") - script = new BootyDigServer(); + script = new BootyDigServer(); else if (scriptName == "scripts\\EquipmentScripts\\PersonalFortress.lua") script = new PersonalFortress(); else if (scriptName == "scripts\\02_server\\Map\\General\\L_PROPERTY_DEVICE.lua") - script = new PropertyDevice(); + script = new PropertyDevice(); else if (scriptName == "scripts\\02_server\\Map\\General\\L_IMAG_BACKPACK_HEALS_SERVER.lua") - script = new ImaginationBackpackHealServer(); + script = new ImaginationBackpackHealServer(); else if (scriptName == "scripts\\ai\\GENERAL\\L_LEGO_DIE_ROLL.lua") script = new LegoDieRoll(); - else if (scriptName == "scripts\\EquipmentScripts\\BuccaneerValiantShip.lua") - script = new BuccaneerValiantShip(); + else if (scriptName == "scripts\\EquipmentScripts\\BuccaneerValiantShip.lua") + script = new BuccaneerValiantShip(); else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") - script = new FireFirstSkillonStartup(); + script = new FireFirstSkillonStartup(); + else if (scriptName == "scripts\\equipmenttriggers\\gempack.lua") + script = new GemPack(); + else if (scriptName == "scripts\\equipmenttriggers\\shardarmor.lua") + script = new ShardArmor(); + else if (scriptName == "scripts\\equipmenttriggers\\coilbackpack.lua") + script = new TeslaPack(); + else if (scriptName == "scripts\\EquipmentScripts\\stunImmunity.lua") + script = new StunImmunity(); + // FB else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") script = new RockHydrantBroken(); else if (scriptName == "scripts\\ai\\NS\\L_NS_WH_FANS.lua") script = new WhFans(); - //Ignore these scripts: - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") - script = invalidToReturn; - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") - script = invalidToReturn; - else if (script == invalidToReturn) { - if (scriptName.length() > 0) - Game::logger->LogDebug("CppScripts", "Attempted to load CppScript for '" + scriptName + "', but returned InvalidScript.\n"); - // information not really needed for sys admins but is for developers + // WBL + else if (scriptName == "scripts\\zone\\LUPs\\WBL_generic_zone.lua") + script = new WblGenericZone(); - script = invalidToReturn; + // Alpha + if (scriptName == "scripts\\ai\\FV\\L_TRIGGER_GAS.lua") + script = new TriggerGas(); + else if (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_SENSEI.lua") + script = new ActNinjaSensei(); + + // pickups + if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(1); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_GOLD-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(10000); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_SILVER-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(100); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_BRONZE-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(10); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_GOLD-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(100000); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_SILVER-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(1000); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_BRONZE-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(25); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_GOLD-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(250000); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_SILVER-COIN-SPAWNER.lua") + script = new SpecialCoinSpawner(2500); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER.lua") + script = new SpecialPowerupSpawner(13); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER-2PT.lua") + script = new SpecialPowerupSpawner(129); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_LIFE-POWERUP-SPAWNER.lua") + script = new SpecialPowerupSpawner(5); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_ARMOR-POWERUP-SPAWNER.lua") + script = new SpecialPowerupSpawner(747); + else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_SPEED_BUFF_SPAWNER.lua") + script = new SpecialSpeedBuffSpawner(); + + // Wild + if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_RAT.lua" || scriptName == "scripts\\ai\\WILD\\L_WILD_GF_SNAIL.lua") + script = new WildAndScared(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_GLOWBUG.lua") + script = new WildGfGlowbug(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_AMBIENT_CRAB.lua") + script = new WildAmbientCrab(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_PANTS.lua") + script = new WildPants(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_BRICKS.lua") + script = new WildNinjaBricks(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_STUDENT.lua") + script = new WildNinjaStudent(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_SENSEI.lua") + script = new WildNinjaSensei(); + + // handle invalid script reporting if the path is greater than zero and it's not an ignored script + // information not really needed for sys admins but is for developers + else if (script == invalidToReturn) { + if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") || + (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") || + (scriptName =="scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") || + (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") || + (scriptName == "scripts\\empty.lua") + )) Game::logger->LogDebug("CppScripts", "LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); } m_Scripts[scriptName] = script; diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index bf30017c..4bf3720f 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -1,25 +1,28 @@ #pragma once -#include "dCommonVars.h" -#include "MissionState.h" + +#include <cstdint> #include <string> #include <vector> class User; class Entity; class NiPoint3; +enum class eMissionState : int32_t; +enum class ePetTamingNotifyType : uint32_t; +enum class eRebuildState : uint32_t; namespace CppScripts { /** * Base class for all scripts. Includes virtual methods to be overridden to handle LUA equivelent events. - * + * * All methods pass 'self' as the first parameter, this is the associated parent entity for the event. * There will only ever be one instance of each script. - * + * * Do not use class members as entity specific variables unless you're sure there will only event be one instance of this script. * Do use class members as script wide variables, variables all entities which this script will access. - * + * * Use self->GetVar<type_t>(u"variable_name") and self->SetVar<type_t>(u"variable_name", value) to manage variables. - * + * * Designed to yield as close to a 1:1 mapping as possible with LUA. * There will be events which are not implemented or inheritetly LUA features not easily translated to C++. * Most of the time these can be worked around or ignored. @@ -31,79 +34,86 @@ namespace CppScripts { /** * Invoked one frame after the script is loaded. - * + * * Equivalent to 'function onStartup(self)' */ virtual void OnStartup(Entity* self) {}; /** * Invoked upon an entity entering the phantom collider on self. - * + * * Equivalent to 'function onCollisionPhantom(self, msg)' */ virtual void OnCollisionPhantom(Entity* self, Entity* target) {}; + /** + * Invoked upon an entity leaving the phantom collider on self. + * + * Equivalent to 'function onOffCollisionPhantom(self, msg)' + */ + virtual void OnOffCollisionPhantom(Entity* self, Entity* target) {}; + /** * Invoked when a player accepted a mission. - * + * * Equivalent to 'function onMissionDialogueOK(self, msg)' */ - virtual void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) {}; + virtual void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {}; /** * Invoked when the client or the server invoked an event server-side. - * + * * Equivalent to 'function onFireEventServerSide(self, msg)' */ - virtual void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {}; + virtual void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {}; /** * Invoked upon sending a object notification. - * + * * Equivalent to 'function onNotifyObject(self, msg)' */ - virtual void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) {}; - + virtual void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) {}; + /** * Invoked upon a player exiting the modular build minigame. - * + * * Equivalent to 'function onModularBuildExit(self, msg)' */ virtual void OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) {}; - + /** * Invoked when a player has loaded into the zone. - * + * * Equivalent to 'function onPlayerLoaded(self, msg)' */ virtual void OnPlayerLoaded(Entity* self, Entity* player) {}; /** * Invoked when a player has died. - * + * * Equivalent to 'function onPlayerDied(self, msg)' */ virtual void OnPlayerDied(Entity* self, Entity* player) {}; /** * Invoked when a player has resurrected. - * + * * Equivalent to 'function onPlayerResurrected(self, msg)' */ virtual void OnPlayerResurrected(Entity* self, Entity* player) {}; /** * Invoked when a player has left the zone. - * + * * Equivalent to 'function onPlayerExit(self, msg)' */ virtual void OnPlayerExit(Entity* self, Entity* player) {}; /** * Invoked when a player has interacted with the proximity collider on self. - * + * * Equivalent to 'function onProximityUpdate(self, msg)' - * + * * @param name The name of the proximity collider recviving an interaction. * @param status "ENTER" if a player has entered the proximity collider; "LEAVE" if a player has left the proximity collider */ @@ -111,182 +121,189 @@ namespace CppScripts { /** * Invoked when a timer on self has expired. - * + * * Equivalent to 'function onTimerDone(self, msg)' */ virtual void OnTimerDone(Entity* self, std::string timerName) {}; /** * Invoked when a player interactions with self. - * + * * Equivalent to 'function onUse(self, msg)' */ virtual void OnUse(Entity* self, Entity* user) {}; /** * Invoked when self has died. - * + * * Equivalent to 'function onDie(self, msg)' */ virtual void OnDie(Entity* self, Entity* killer) {}; /** * Invoked when self has received a hit. - * + * * Equivalent to 'function onHit(self, msg)' */ virtual void OnHit(Entity* self, Entity* attacker) {}; /** * Invoked when self has received an emote from a player. - * + * * Equivalent to 'function onEmoteReceived(self, msg)' */ virtual void OnEmoteReceived(Entity* self, int32_t emote, Entity* target) {}; /** * Invoked when a player has started building this quickbuild. - * + * * Equivalent to 'function onRebuildStart(self, msg)' */ virtual void OnRebuildStart(Entity* self, Entity* target) {}; - + /** * Invoked when this quickbuild has changed state. - * + * * Equivalent to 'function onRebuildNotifyState(self, msg)' */ virtual void OnRebuildNotifyState(Entity* self, eRebuildState state) {}; /** * Invoked when this quickbuild has been completed. - * + * * Equivalent to 'function onRebuildComplete(self, msg)' */ virtual void OnRebuildComplete(Entity* self, Entity* target) {}; /** * Invoked when self has received either a hit or heal. - * + * * Equivalent to 'function onHitOrHealResult(self, msg)' */ virtual void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; - + + /** + * Invoked when self has received either a hit or heal. Only used for scripts subscribed to an entity. + * + * Equivalent to 'function notifyHitOrHealResult(self, msg)' + */ + virtual void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; + /** * Invoked when a player has responsed to a mission. - * + * * Equivalent to 'function onRespondToMission(self, msg)' */ virtual void OnRespondToMission(Entity* self, int missionID, Entity* player, int reward) {}; - + /** * Invoked once per frame. - * + * * No LUA eqivalent. */ virtual void OnUpdate(Entity* self) {}; - + /** * Invoked when this property has been rented. - * + * * Equivalent to 'function onZonePropertyRented(self, msg)' */ virtual void OnZonePropertyRented(Entity* self, Entity* renter) {}; - + /** * Invoked when a player has begun to edit this property. - * + * * Equivalent to 'function onZonePropertyEditBegin(self, msg)' */ virtual void OnZonePropertyEditBegin(Entity* self) {}; /** * Invoked when a player has concluded editing this property. - * + * * Equivalent to 'function onZonePropertyEditEnd(self, msg)' */ virtual void OnZonePropertyEditEnd(Entity* self) {}; /** * Invoked when a player has equipped a model while editing this property. - * + * * Equivalent to 'function onZonePropertyModelEquipped(self, msg)' */ virtual void OnZonePropertyModelEquipped(Entity* self) {}; /** * Invoked when a player has placed a model while editing this property. - * + * * Equivalent to 'function onZonePropertyModelPlaced(self, msg)' */ virtual void OnZonePropertyModelPlaced(Entity* self, Entity* player) {}; /** * Invoked when a player has picked up a model while editing this property. - * + * * Equivalent to 'function onZonePropertyModelPickedUp(self, msg)' */ virtual void OnZonePropertyModelPickedUp(Entity* self, Entity* player) {}; /** * Invoked when a player removed a model while editing this property. - * + * * Equivalent to 'function onZonePropertyModelRemoved(self, msg)' */ virtual void OnZonePropertyModelRemoved(Entity* self, Entity* player) {}; /** * Invoked when a player removed a model while holding it when editing this property. - * + * * Equivalent to 'function onZonePropertyModelRemoved(self, msg)' */ virtual void OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) {}; - + /** * Invoked when a player rotated a model while editing this property. - * + * * Equivalent to 'function onZonePropertyModelRotated(self, msg)' */ virtual void OnZonePropertyModelRotated(Entity* self, Entity* player) {}; /** * Invoked when the pet taming minigame encounted an event. - * + * * Equivalent to 'function onNotifyPetTamingMinigame(self, msg)' */ - virtual void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) {}; - + virtual void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) {}; + /** * Invoked when a player responded to a message box. - * + * * Equivalent to 'function onMessageBoxResponse(self, msg)' */ virtual void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) {}; - + /** * Invoked when a player responded to a choice box. - * + * * Equivalent to 'function onChoiceBoxResponse(self, msg)' */ virtual void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) {}; - + /** * Invoked when self arrived at a moving platform waypoint. - * + * * Equivalent to 'function onWaypointReached(self, msg)' */ virtual void OnWaypointReached(Entity* self, uint32_t waypointIndex) {}; - + /** * Invoked when a player fired a skill event on self. - * + * * Equivalent to 'function onSkillEventFired(self, msg)' */ virtual void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) {}; - + /** * Invoked when self casted a skill. - * + * * Equivalent to 'function onSkillCast(self, msg)' */ virtual void OnSkillCast(Entity* self, uint32_t skillID) {}; @@ -309,13 +326,31 @@ namespace CppScripts { * @param value2 some other value to represent the change * @param stringValue some string value to represent the change */ - virtual void OnActivityStateChangeRequest(Entity* self, const LWOOBJID senderID, const int32_t value1, - const int32_t value2, const std::u16string& stringValue) {}; + virtual void OnActivityStateChangeRequest(Entity* self, const LWOOBJID senderID, const int32_t value1, + const int32_t value2, const std::u16string& stringValue) { + }; virtual void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, - float_t pathTime, float_t totalTime, int32_t waypoint) {}; + float_t pathTime, float_t totalTime, int32_t waypoint) { + }; + + /** + * Used by items to tell their owner that they were equipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {}; + + /** + * Used by items to tell their owner that they were unequipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) {}; }; Script* GetScript(Entity* parent, const std::string& scriptName); std::vector<Script*> GetEntityScripts(Entity* entity); -}; \ No newline at end of file +}; diff --git a/dScripts/CrabServer.cpp b/dScripts/CrabServer.cpp deleted file mode 100644 index 7cab7fb5..00000000 --- a/dScripts/CrabServer.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "CrabServer.h" -#include "PetComponent.h" - -void CrabServer::OnStartup(Entity* self) { - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - return; - - // Triggers the local crab script for taming etc. - auto tamer = self->GetVar<LWOOBJID>(u"tamer"); - // Client compares this with player:GetID() which is a string, so we'll have to give it a string - self->SetNetworkVar(u"crabtamer", std::to_string(tamer)); - - // Kill if the player decides that the crab is not worthy - self->AddTimer("killself", 45.0f); -} - -void CrabServer::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "killself") { - - // Don't accidentally kill a pet that is already owned - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - return; - - self->Smash(self->GetObjectID(), SILENT); - } -} - -void CrabServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) { - if (type == NOTIFY_TYPE_BEGIN) { - self->CancelTimer("killself"); - } else if (type == NOTIFY_TYPE_QUIT || type == NOTIFY_TYPE_FAILED) { - self->Smash(self->GetObjectID(), SILENT); - } else if (type == NOTIFY_TYPE_SUCCESS) { - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr) - return; - // TODO: Remove custom group? - // Command the pet to the player as it may otherwise go to its spawn point which is non existant - // petComponent->Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 6, 202, true); - } -} diff --git a/dScripts/CrabServer.h b/dScripts/CrabServer.h deleted file mode 100644 index b773ed75..00000000 --- a/dScripts/CrabServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class CrabServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) override; -}; diff --git a/dScripts/DLUVanityNPC.cpp b/dScripts/DLUVanityNPC.cpp deleted file mode 100644 index c219a5f9..00000000 --- a/dScripts/DLUVanityNPC.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "DLUVanityNPC.h" -#include "GameMessages.h" -#include "dServer.h" -#include "VanityUtilities.h" - -void DLUVanityNPC::OnStartup(Entity* self) -{ - m_NPC = VanityUtilities::GetNPC("averysumner - Destroyer of Worlds"); - - if (m_NPC == nullptr) { - return; - } - - if (self->GetVar<bool>(u"teleport")) { - self->AddTimer("setupTeleport", 15.0f); - } -} - -void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "setupTeleport") { - GameMessages::SendPlayAnimation(self, u"interact"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); - - self->AddTimer("teleport", 2.0f); - self->AddTimer("stopFX", 2.0f); - } else if (timerName == "stopFX") { - GameMessages::SendStopFXEffect(self, true, "teleportBeam"); - GameMessages::SendStopFXEffect(self, true, "teleportRings"); - } else if (timerName == "teleport") { - std::vector<VanityNPCLocation>& locations = m_NPC->m_Locations[Game::server->GetZoneID()]; - -selectLocation: - VanityNPCLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)]; - - if (self->GetPosition() == newLocation.m_Position) { - goto selectLocation; // cry about it - } - - self->SetPosition(newLocation.m_Position); - self->SetRotation(newLocation.m_Rotation); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); - self->AddTimer("stopFX", 2.0f); - self->AddTimer("setupTeleport", 15.0f); - } -} diff --git a/dScripts/DLUVanityNPC.h b/dScripts/DLUVanityNPC.h deleted file mode 100644 index 4eba3554..00000000 --- a/dScripts/DLUVanityNPC.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class VanityNPC; -class DLUVanityNPC : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - VanityNPC* m_NPC; -}; diff --git a/dScripts/DamagingPets.cpp b/dScripts/DamagingPets.cpp deleted file mode 100644 index f82bc83e..00000000 --- a/dScripts/DamagingPets.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "DamagingPets.h" -#include "PetComponent.h" -#include "DestroyableComponent.h" -#include "BaseCombatAIComponent.h" -#include "RenderComponent.h" - -void DamagingPets::OnStartup(Entity *self) { - - // Make the pet hostile or non-hostile based on whether or not it is tamed - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { - self->AddTimer("GoEvil", 0.5f); - } -} - -void DamagingPets::OnPlayerLoaded(Entity *self, Entity *player) { - - // Makes it so that new players also see the effect - self->AddCallbackTimer(2.5f, [self]() { - if (self != nullptr) { - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr && petComponent->GetOwner() == nullptr && self->GetVar<bool>(u"IsEvil")) { - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - auto counter = 1; - for (const auto petEffect : GetPetInfo(self).effect) { - renderComponent->PlayEffect(petEffect, u"create", "FXname" + std::to_string(counter)); - counter++; - } - } - } - } - }); -} - -void DamagingPets::OnNotifyPetTamingMinigame(Entity *self, Entity *tamer, eNotifyType type) { - switch (type) { - case NOTIFY_TYPE_SUCCESS: - case NOTIFY_TYPE_BEGIN: - self->CancelAllTimers(); - ClearEffects(self); - break; - case NOTIFY_TYPE_FAILED: - case NOTIFY_TYPE_QUIT: - { - self->SetNetworkVar<bool>(u"bIAmTamable", false); - self->AddTimer("GoEvil", 1.0f); - break; - } - default: - break; - } -} - -void DamagingPets::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - const auto infoForPet = GetPetInfo(self); - if (infoForPet.skill == message) { - - // Only make pets tamable that aren't tamed yet - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr && petComponent->GetOwner() == nullptr && self->GetVar<bool>(u"IsEvil")) { - ClearEffects(self); - self->AddTimer("GoEvil", 30.0f); - self->SetNetworkVar<bool>(u"bIAmTamable", true); - } - } -} - -void DamagingPets::OnTimerDone(Entity *self, std::string message) { - if (message == "GoEvil") { - MakeUntamable(self); - } -} - -void DamagingPets::MakeUntamable(Entity *self) { - auto* petComponent = self->GetComponent<PetComponent>(); - - // If the pet is currently not being tamed, make it hostile - if (petComponent != nullptr && petComponent->GetStatus() != 5) { - self->SetNetworkVar<bool>(u"bIAmTamable", false); - self->SetVar<bool>(u"IsEvil", true); - petComponent->SetStatus(1); - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(false); - } - - // Special faction that can attack the player but the player can't attack - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetFaction(114); - destroyableComponent->SetHealth(5); - } - - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - auto counter = 1; - for (const auto petEffect : GetPetInfo(self).effect) { - renderComponent->PlayEffect(petEffect, u"create", "FXname" + std::to_string(counter)); - counter++; - } - } - } -} - -void DamagingPets::ClearEffects(Entity *self) { - self->SetVar<bool>(u"IsEvil", false); - - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr) { - petComponent->SetStatus(67108866); - } - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(true); - } - - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetFaction(99); - } - - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - auto counter = 1; - for (const auto petEffect : GetPetInfo(self).effect) { - renderComponent->StopEffect("FXname" + std::to_string(counter)); - counter++; - } - } -} - -PetInfo DamagingPets::GetPetInfo(Entity *self) { - const auto infoForPet = petInfo.find(self->GetLOT()); - return infoForPet != petInfo.end() ? infoForPet->second : petInfo.begin()->second; -} - -// Does not compile on Win32 with name specifiers -const std::map<LOT, PetInfo> DamagingPets::petInfo = { - { 5639, { /*.effect =*/ { 3170, 4058 }, /*.skill =*/ "waterspray"}}, // Red dragon - { 5641, { /*.effect =*/ { 3170, 4058 }, /*.skill =*/ "waterspray"}}, // Green dragon - { 3261, { /*.effect =*/ { 1490 }, /*.skill =*/ "waterspray"}}, // Skunk -}; diff --git a/dScripts/DamagingPets.h b/dScripts/DamagingPets.h deleted file mode 100644 index 04c4e6bf..00000000 --- a/dScripts/DamagingPets.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "CppScripts.h" - -/** - * Information about pets regarding which effect to play when a skill is cast - */ -struct PetInfo { - const std::vector<uint32_t> effect; - const std::string skill; -}; - -class DamagingPets : public CppScripts::Script { -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string message) override; - void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) override; - void OnSkillEventFired(Entity* self, Entity* target, const std::string& message) override; - void OnPlayerLoaded(Entity* self, Entity* player) override; -private: - static void MakeUntamable(Entity* self); - static PetInfo GetPetInfo(Entity* self); - static void ClearEffects(Entity* self); - static const std::map<LOT, PetInfo> petInfo; -}; diff --git a/dScripts/Darkitect.cpp b/dScripts/Darkitect.cpp index c4e1e45d..b4364332 100644 --- a/dScripts/Darkitect.cpp +++ b/dScripts/Darkitect.cpp @@ -4,9 +4,9 @@ #include "EntityManager.h" #include "GameMessages.h" #include "Character.h" +#include "eMissionState.h" -void Darkitect::Reveal(Entity* self, Entity* player) -{ +void Darkitect::Reveal(Entity* self, Entity* player) { const auto playerID = player->GetObjectID(); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"reveal", 0, 0, playerID, "", player->GetSystemAddress()); @@ -25,11 +25,11 @@ void Darkitect::Reveal(Entity* self, Entity* player) destroyableComponent->SetHealth(1); destroyableComponent->SetImagination(0); - if (missionComponent->GetMissionState(1295) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(1295) == eMissionState::ACTIVE) { character->SetPlayerFlag(1911, true); } EntityManager::Instance()->SerializeEntity(player); } - }); + }); } diff --git a/dScripts/EnemyNjBuff.cpp b/dScripts/EnemyNjBuff.cpp deleted file mode 100644 index 8dd19cce..00000000 --- a/dScripts/EnemyNjBuff.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "EnemyNjBuff.h" -#include "SkillComponent.h" - -void EnemyNjBuff::OnStartup(Entity* self) -{ - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(1127, 24812, self->GetObjectID(), true); -} diff --git a/dScripts/EnemyRoninSpawner.cpp b/dScripts/EnemyRoninSpawner.cpp deleted file mode 100644 index 25288968..00000000 --- a/dScripts/EnemyRoninSpawner.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "EnemyRoninSpawner.h" -#include "SkillComponent.h" -#include "RenderComponent.h" -#include "EntityManager.h" - -void EnemyRoninSpawner::OnStartup(Entity* self) -{ - self->SetProximityRadius(15, "ronin"); -} - -void EnemyRoninSpawner::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "hatchTime") - { - auto* renderComponent = self->GetComponent<RenderComponent>(); - - if (renderComponent != nullptr) - { - renderComponent->PlayEffect(644, u"create", "BurstFX1"); - } - - EntityInfo info {}; - info.lot = 7815; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.spawnerID = self->GetObjectID(); - - auto* spawnedEntity = EntityManager::Instance()->CreateEntity(info); - - if (spawnedEntity == nullptr) - { - return; - } - - EntityManager::Instance()->ConstructEntity(spawnedEntity); - - spawnedEntity->AddCallbackTimer(60, [spawnedEntity]() { - spawnedEntity->Smash(spawnedEntity->GetObjectID()); - }); - - self->Smash(self->GetObjectID()); - } -} - -void EnemyRoninSpawner::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (entering->IsPlayer() && name == "ronin" && status == "ENTER" && !self->GetVar<bool>(u"hatching")) - { - StartHatching(self); - - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(305, 3568, LWOOBJID_EMPTY); - } - } -} - -void EnemyRoninSpawner::OnHit(Entity* self, Entity* attacker) -{ - if (!self->GetVar<bool>(u"hatching")) - { - StartHatching(self); - } -} - -void EnemyRoninSpawner::StartHatching(Entity* self) -{ - self->SetVar(u"hatching", true); - - auto* renderComponent = self->GetComponent<RenderComponent>(); - - if (renderComponent != nullptr) - { - renderComponent->PlayEffect(2260, u"rebuild_medium", "WakeUpFX1"); - } - - self->AddTimer("hatchTime", 2); -} diff --git a/dScripts/EnemySkeletonSpawner.cpp b/dScripts/EnemySkeletonSpawner.cpp deleted file mode 100644 index f8c89ec6..00000000 --- a/dScripts/EnemySkeletonSpawner.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "EnemySkeletonSpawner.h" -#include "SkillComponent.h" -#include "RenderComponent.h" -#include "EntityManager.h" - -void EnemySkeletonSpawner::OnStartup(Entity* self) -{ - self->SetProximityRadius(15, "ronin"); - - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(1127, 24812, LWOOBJID_EMPTY, true); - } -} - -void EnemySkeletonSpawner::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "hatchTime") - { - auto* renderComponent = self->GetComponent<RenderComponent>(); - - if (renderComponent != nullptr) - { - renderComponent->PlayEffect(644, u"create", "BurstFX1"); - } - - EntityInfo info {}; - info.lot = 14024; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.spawnerID = self->GetObjectID(); - - auto* spawnedEntity = EntityManager::Instance()->CreateEntity(info); - - if (spawnedEntity == nullptr) - { - return; - } - - EntityManager::Instance()->ConstructEntity(spawnedEntity); - - spawnedEntity->AddCallbackTimer(60, [spawnedEntity]() { - spawnedEntity->Smash(spawnedEntity->GetObjectID()); - }); - - self->Smash(self->GetObjectID()); - } -} - -void EnemySkeletonSpawner::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (entering->IsPlayer() && name == "ronin" && status == "ENTER" && !self->GetVar<bool>(u"hatching")) - { - StartHatching(self); - - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(305, 3568, LWOOBJID_EMPTY); - } - } -} - -void EnemySkeletonSpawner::OnHit(Entity* self, Entity* attacker) -{ - if (!self->GetVar<bool>(u"hatching")) - { - StartHatching(self); - } -} - -void EnemySkeletonSpawner::StartHatching(Entity* self) -{ - self->SetVar(u"hatching", true); - - auto* renderComponent = self->GetComponent<RenderComponent>(); - - if (renderComponent != nullptr) - { - renderComponent->PlayEffect(9017, u"cast", "WakeUpFX1"); - renderComponent->PlayEffect(9018, u"burst", "WakeUpFX1"); - } - - self->AddTimer("hatchTime", 2); -} diff --git a/dScripts/EquipmentScripts/AnvilOfArmor.cpp b/dScripts/EquipmentScripts/AnvilOfArmor.cpp new file mode 100644 index 00000000..3704cb00 --- /dev/null +++ b/dScripts/EquipmentScripts/AnvilOfArmor.cpp @@ -0,0 +1,13 @@ +#include "AnvilOfArmor.h" + +void AnvilOfArmor::OnStartup(Entity* self) { + self->SetVar<uint32_t>(u"numCycles", 8); + self->SetVar<float_t>(u"secPerCycle", 25.0f); + self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); + self->SetVar<float_t>(u"deathDelay", 25.0f); + self->SetVar<uint32_t>(u"numberOfPowerups", 4); + self->SetVar<LOT>(u"lootLOT", 6431); + + // Initiate the actual script + OnTemplateStartup(self); +} diff --git a/dScripts/AnvilOfArmor.h b/dScripts/EquipmentScripts/AnvilOfArmor.h similarity index 71% rename from dScripts/AnvilOfArmor.h rename to dScripts/EquipmentScripts/AnvilOfArmor.h index 64c95216..2ff568aa 100644 --- a/dScripts/AnvilOfArmor.h +++ b/dScripts/EquipmentScripts/AnvilOfArmor.h @@ -2,5 +2,5 @@ #include "ScriptedPowerupSpawner.h" class AnvilOfArmor : public ScriptedPowerupSpawner { - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/EquipmentScripts/BuccaneerValiantShip.cpp b/dScripts/EquipmentScripts/BuccaneerValiantShip.cpp new file mode 100644 index 00000000..3db214b5 --- /dev/null +++ b/dScripts/EquipmentScripts/BuccaneerValiantShip.cpp @@ -0,0 +1,18 @@ +#include "BuccaneerValiantShip.h" +#include "SkillComponent.h" + +void BuccaneerValiantShip::OnStartup(Entity* self) { + self->AddCallbackTimer(1.0F, [self]() { + auto* skillComponent = self->GetComponent<SkillComponent>(); + auto* owner = self->GetOwner(); + + if (skillComponent != nullptr && owner != nullptr) { + skillComponent->CalculateBehavior(982, 20577, LWOOBJID_EMPTY, true, false, owner->GetObjectID()); + + // Kill self if missed + self->AddCallbackTimer(1.1F, [self]() { + self->Kill(); + }); + } + }); +} diff --git a/dScripts/BuccaneerValiantShip.h b/dScripts/EquipmentScripts/BuccaneerValiantShip.h similarity index 69% rename from dScripts/BuccaneerValiantShip.h rename to dScripts/EquipmentScripts/BuccaneerValiantShip.h index f501d1b9..8ed3f7ad 100644 --- a/dScripts/BuccaneerValiantShip.h +++ b/dScripts/EquipmentScripts/BuccaneerValiantShip.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class BuccaneerValiantShip : public CppScripts::Script { - void OnStartup(Entity *self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/EquipmentScripts/CMakeLists.txt b/dScripts/EquipmentScripts/CMakeLists.txt new file mode 100644 index 00000000..696be03d --- /dev/null +++ b/dScripts/EquipmentScripts/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS + "Sunflower.cpp" + "AnvilOfArmor.cpp" + "FountainOfImagination.cpp" + "CauldronOfLife.cpp" + "PersonalFortress.cpp" + "BuccaneerValiantShip.cpp" + "FireFirstSkillonStartup.cpp" + "StunImmunity.cpp" + PARENT_SCOPE) diff --git a/dScripts/EquipmentScripts/CauldronOfLife.cpp b/dScripts/EquipmentScripts/CauldronOfLife.cpp new file mode 100644 index 00000000..3ddb5c61 --- /dev/null +++ b/dScripts/EquipmentScripts/CauldronOfLife.cpp @@ -0,0 +1,13 @@ +#include "CauldronOfLife.h" + +void CauldronOfLife::OnStartup(Entity* self) { + self->SetVar<uint32_t>(u"numCycles", 10); + self->SetVar<float_t>(u"secPerCycle", 20.0f); + self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); + self->SetVar<float_t>(u"deathDelay", 20.0f); + self->SetVar<uint32_t>(u"numberOfPowerups", 3); + self->SetVar<LOT>(u"lootLOT", 177); + + // Initiate the actual script + OnTemplateStartup(self); +} diff --git a/dScripts/CauldronOfLife.h b/dScripts/EquipmentScripts/CauldronOfLife.h similarity index 71% rename from dScripts/CauldronOfLife.h rename to dScripts/EquipmentScripts/CauldronOfLife.h index 3a5892c6..f7b492b5 100644 --- a/dScripts/CauldronOfLife.h +++ b/dScripts/EquipmentScripts/CauldronOfLife.h @@ -2,5 +2,5 @@ #include "ScriptedPowerupSpawner.h" class CauldronOfLife : public ScriptedPowerupSpawner { - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp new file mode 100644 index 00000000..389f3621 --- /dev/null +++ b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp @@ -0,0 +1,26 @@ +#include "FireFirstSkillonStartup.h" +#include "Entity.h" +#include "SkillComponent.h" +#include "CDClientDatabase.h" +#include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDClientManager.h" + +void FireFirstSkillonStartup::OnStartup(Entity* self) { + auto skillComponent = self->GetComponent<SkillComponent>(); + if (!skillComponent) return; + + // Get the skill IDs of this object. + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>(); + std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); + + // For each skill, cast it with the associated behavior ID. + for (auto skill : skills) { + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>(); + CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); + + // Should parent entity be null, make the originator self. + const auto target = self->GetParentEntity() ? self->GetParentEntity()->GetObjectID() : self->GetObjectID(); + skillComponent->CalculateBehavior(skill.skillID, behaviorData.behaviorID, LWOOBJID_EMPTY, false, false, target); + } +} diff --git a/dScripts/FireFirstSkillonStartup.h b/dScripts/EquipmentScripts/FireFirstSkillonStartup.h similarity index 79% rename from dScripts/FireFirstSkillonStartup.h rename to dScripts/EquipmentScripts/FireFirstSkillonStartup.h index ad182e70..6b10f362 100644 --- a/dScripts/FireFirstSkillonStartup.h +++ b/dScripts/EquipmentScripts/FireFirstSkillonStartup.h @@ -5,8 +5,8 @@ #include "CppScripts.h" class FireFirstSkillonStartup : public CppScripts::Script { - public: - void OnStartup(Entity* self) override; +public: + void OnStartup(Entity* self) override; }; #endif //!__FIREFIRSTSKILLONSTARTUP__H__ diff --git a/dScripts/EquipmentScripts/FountainOfImagination.cpp b/dScripts/EquipmentScripts/FountainOfImagination.cpp new file mode 100644 index 00000000..6560e1cf --- /dev/null +++ b/dScripts/EquipmentScripts/FountainOfImagination.cpp @@ -0,0 +1,15 @@ +#include "FountainOfImagination.h" +#include "dCommonVars.h" +#include "Entity.h" + +void FountainOfImagination::OnStartup(Entity* self) { + self->SetVar<uint32_t>(u"numCycles", 6); + self->SetVar<float_t>(u"secPerCycle", 30.0f); + self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); + self->SetVar<float_t>(u"deathDelay", 30.0f); + self->SetVar<uint32_t>(u"numberOfPowerups", 5); + self->SetVar<LOT>(u"lootLOT", 935); + + // Initiate the actual script + OnTemplateStartup(self); +} diff --git a/dScripts/FountainOfImagination.h b/dScripts/EquipmentScripts/FountainOfImagination.h similarity index 72% rename from dScripts/FountainOfImagination.h rename to dScripts/EquipmentScripts/FountainOfImagination.h index 6ad0becd..e477a026 100644 --- a/dScripts/FountainOfImagination.h +++ b/dScripts/EquipmentScripts/FountainOfImagination.h @@ -2,5 +2,5 @@ #include "ScriptedPowerupSpawner.h" class FountainOfImagination : public ScriptedPowerupSpawner { - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/EquipmentScripts/PersonalFortress.cpp b/dScripts/EquipmentScripts/PersonalFortress.cpp new file mode 100644 index 00000000..f1fe73ee --- /dev/null +++ b/dScripts/EquipmentScripts/PersonalFortress.cpp @@ -0,0 +1,58 @@ +#include "PersonalFortress.h" +#include "GameMessages.h" +#include "SkillComponent.h" +#include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" +#include "EntityManager.h" +#include "eStateChangeType.h" + +void PersonalFortress::OnStartup(Entity* self) { + auto* owner = self->GetOwner(); + self->AddTimer("FireSkill", 1.5); + + auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + true, true, true, true, true, false, true, false, false + ); + + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true, true, true + ); + + EntityManager::Instance()->SerializeEntity(owner); +} + +void PersonalFortress::OnDie(Entity* self, Entity* killer) { + auto* owner = self->GetOwner(); + auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + true, true, true, true, true, false, true, false, false + ); + + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true, true, true + ); + + EntityManager::Instance()->SerializeEntity(owner); +} + +void PersonalFortress::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "FireSkill") { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent) skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); + } +} diff --git a/dScripts/PersonalFortress.h b/dScripts/EquipmentScripts/PersonalFortress.h similarity index 53% rename from dScripts/PersonalFortress.h rename to dScripts/EquipmentScripts/PersonalFortress.h index 5cae24ba..4d69ba1d 100644 --- a/dScripts/PersonalFortress.h +++ b/dScripts/EquipmentScripts/PersonalFortress.h @@ -6,7 +6,7 @@ class PersonalFortress : public CppScripts::Script public: void OnStartup(Entity* self) override; - void OnDie(Entity* self, Entity* killer) override; + void OnDie(Entity* self, Entity* killer) override; - void OnTimerDone(Entity* self, std::string timerName) override; + void OnTimerDone(Entity* self, std::string timerName) override; }; diff --git a/dScripts/EquipmentScripts/StunImmunity.cpp b/dScripts/EquipmentScripts/StunImmunity.cpp new file mode 100644 index 00000000..0ec956f0 --- /dev/null +++ b/dScripts/EquipmentScripts/StunImmunity.cpp @@ -0,0 +1,20 @@ +#include "StunImmunity.h" +#include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" +#include "eStateChangeType.h" + +void StunImmunity::OnStartup(Entity* self) { + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, false, false, true, true, false, false, false, false, true + ); + } + + auto* controllablePhysicsComponent = self->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, self->GetObjectID(), true + ); + } +} diff --git a/dScripts/EquipmentScripts/StunImmunity.h b/dScripts/EquipmentScripts/StunImmunity.h new file mode 100644 index 00000000..0faaf061 --- /dev/null +++ b/dScripts/EquipmentScripts/StunImmunity.h @@ -0,0 +1,6 @@ +#pragma once +#include "CppScripts.h" + +class StunImmunity : public CppScripts::Script { + void OnStartup(Entity* self) override; +}; diff --git a/dScripts/EquipmentScripts/Sunflower.cpp b/dScripts/EquipmentScripts/Sunflower.cpp new file mode 100644 index 00000000..11923e23 --- /dev/null +++ b/dScripts/EquipmentScripts/Sunflower.cpp @@ -0,0 +1,14 @@ +#include "Sunflower.h" +#include "Entity.h" + +void Sunflower::OnStartup(Entity* self) { + self->SetVar<uint32_t>(u"numCycles", 6); + self->SetVar<float_t>(u"secPerCycle", 5.0f); + self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); + self->SetVar<float_t>(u"deathDelay", 30.0f); + self->SetVar<uint32_t>(u"numberOfPowerups", 4); + self->SetVar<LOT>(u"lootLOT", 11910); + + // Initiate the actual script + OnTemplateStartup(self); +} diff --git a/dScripts/Sunflower.h b/dScripts/EquipmentScripts/Sunflower.h similarity index 70% rename from dScripts/Sunflower.h rename to dScripts/EquipmentScripts/Sunflower.h index f779d31c..560332c2 100644 --- a/dScripts/Sunflower.h +++ b/dScripts/EquipmentScripts/Sunflower.h @@ -2,5 +2,5 @@ #include "ScriptedPowerupSpawner.h" class Sunflower : public ScriptedPowerupSpawner { - void OnStartup(Entity* self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/EquipmentTriggers/CMakeLists.txt b/dScripts/EquipmentTriggers/CMakeLists.txt new file mode 100644 index 00000000..416ef553 --- /dev/null +++ b/dScripts/EquipmentTriggers/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS + "CoilBackpackBase.cpp" + PARENT_SCOPE) diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.cpp b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp new file mode 100644 index 00000000..4e323a08 --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp @@ -0,0 +1,25 @@ +#include "CoilBackpackBase.h" + +#include "Entity.h" +#include "SkillComponent.h" + +void CoilBackpackBase::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Subscribe(itemObjId, this, "HitOrHealResult"); + itemOwner->SetVar<uint8_t>(u"coilCount", 0); +} + +void CoilBackpackBase::NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + if (damage > 0) { + self->SetVar<uint8_t>(u"coilCount", self->GetVar<uint8_t>(u"coilCount") + 1); + if (self->GetVar<uint8_t>(u"coilCount") > 4) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (!skillComponent) return; + skillComponent->CastSkill(m_SkillId); + self->SetVar<uint8_t>(u"coilCount", 0); + } + } +} + +void CoilBackpackBase::OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Unsubscribe(itemObjId, "HitOrHealResult"); +} diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.h b/dScripts/EquipmentTriggers/CoilBackpackBase.h new file mode 100644 index 00000000..2d641346 --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.h @@ -0,0 +1,19 @@ +#ifndef __GemPackBase__H__ +#define __GemPackBase__H__ + +#include "CppScripts.h" + +class CoilBackpackBase: public CppScripts::Script { +public: + CoilBackpackBase(uint32_t skillId) { + m_SkillId = skillId; + }; + + void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override; + void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) override; +private: + uint32_t m_SkillId = 0; +}; + +#endif //!__GemPackBase__H__ diff --git a/dScripts/EquipmentTriggers/GemPack.h b/dScripts/EquipmentTriggers/GemPack.h new file mode 100644 index 00000000..d71181ab --- /dev/null +++ b/dScripts/EquipmentTriggers/GemPack.h @@ -0,0 +1,13 @@ +#ifndef __GEMPACK__H__ +#define __GEMPACK__H__ + +#include "CoilBackpackBase.h" + +class GemPack : public CoilBackpackBase { +public: + GemPack() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1488; +}; + +#endif //!__GEMPACK__H__ diff --git a/dScripts/EquipmentTriggers/ShardArmor.h b/dScripts/EquipmentTriggers/ShardArmor.h new file mode 100644 index 00000000..5486db54 --- /dev/null +++ b/dScripts/EquipmentTriggers/ShardArmor.h @@ -0,0 +1,13 @@ +#ifndef __SHARDARMOR__H__ +#define __SHARDARMOR__H__ + +#include "CoilBackpackBase.h" + +class ShardArmor : public CoilBackpackBase { +public: + ShardArmor() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1249; +}; + +#endif //!__SHARDARMOR__H__ diff --git a/dScripts/EquipmentTriggers/TeslaPack.h b/dScripts/EquipmentTriggers/TeslaPack.h new file mode 100644 index 00000000..3ba09f5c --- /dev/null +++ b/dScripts/EquipmentTriggers/TeslaPack.h @@ -0,0 +1,13 @@ +#ifndef __TESLAPACK__H__ +#define __TESLAPACK__H__ + +#include "CoilBackpackBase.h" + +class TeslaPack : public CoilBackpackBase { +public: + TeslaPack() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1001; +}; + +#endif //!__TESLAPACK__H__ diff --git a/dScripts/FallingTile.cpp b/dScripts/FallingTile.cpp deleted file mode 100644 index 2dd8c7bc..00000000 --- a/dScripts/FallingTile.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "FallingTile.h" -#include "MovingPlatformComponent.h" -#include "GameMessages.h" - -void FallingTile::OnStartup(Entity* self) -{ - auto* movingPlatfromComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatfromComponent == nullptr) - { - return; - } - - movingPlatfromComponent->SetSerialized(true); -} - -void FallingTile::OnCollisionPhantom(Entity* self, Entity* target) -{ - if (self->GetVar<bool>(u"AboutToFall")) - { - return; - } - - self->AddTimer("flipTime", 0.75f); - - self->SetVar<bool>(u"AboutToFall", true); - - self->SetNetworkVar<float>(u"startEffect", 2); -} - -void FallingTile::OnWaypointReached(Entity* self, uint32_t waypointIndex) -{ - if (waypointIndex == 1) - { - } - else if (waypointIndex == 0) - { - } -} - -void FallingTile::OnTimerDone(Entity* self, std::string timerName) -{ - auto* movingPlatfromComponent = self->GetComponent<MovingPlatformComponent>(); - - if (movingPlatfromComponent == nullptr) - { - return; - } - - if (timerName == "flipTime") - { - self->AddTimer("flipBack", 2.0f); - - self->SetNetworkVar<float>(u"stopEffect", 3); - - movingPlatfromComponent->GotoWaypoint(1); - - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"down", "down"); - } - else if (timerName == "flipBack") - { - self->SetVar<bool>(u"AboutToFall", false); - - movingPlatfromComponent->GotoWaypoint(0); - - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"up", "up"); - } -} diff --git a/dScripts/FallingTile.h b/dScripts/FallingTile.h deleted file mode 100644 index 073fc403..00000000 --- a/dScripts/FallingTile.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FallingTile : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnCollisionPhantom(Entity* self, Entity* target) override; - void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; - void OnTimerDone(Entity* self, std::string timerName) override; -}; \ No newline at end of file diff --git a/dScripts/FireFirstSkillonStartup.cpp b/dScripts/FireFirstSkillonStartup.cpp deleted file mode 100644 index da1b420e..00000000 --- a/dScripts/FireFirstSkillonStartup.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "FireFirstSkillonStartup.h" -#include "Entity.h" -#include "SkillComponent.h" -#include "CDClientDatabase.h" -#include "CDObjectSkillsTable.h" - -void FireFirstSkillonStartup::OnStartup(Entity* self) { - auto skillComponent = self->GetComponent<SkillComponent>(); - if (!skillComponent) return; - - // Get the skill IDs of this object. - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills"); - std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); - - // For each skill, cast it with the associated behavior ID. - for (auto skill : skills) { - CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior"); - CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); - - // Should parent entity be null, make the originator self. - const auto target = self->GetParentEntity() ? self->GetParentEntity()->GetObjectID() : self->GetObjectID(); - skillComponent->CalculateBehavior(skill.skillID, behaviorData.behaviorID, LWOOBJID_EMPTY, false, false, target); - } -} \ No newline at end of file diff --git a/dScripts/FlameJetServer.cpp b/dScripts/FlameJetServer.cpp deleted file mode 100644 index 0e6d91cc..00000000 --- a/dScripts/FlameJetServer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "FlameJetServer.h" -#include "SkillComponent.h" -#include "GameMessages.h" - -void FlameJetServer::OnStartup(Entity* self) -{ - if (self->GetVar<bool>(u"NotActive")) - { - return; - } - - self->SetNetworkVar<bool>(u"FlameOn", true); -} - -void FlameJetServer::OnCollisionPhantom(Entity* self, Entity* target) -{ - if (!target->IsPlayer()) - { - return; - } - - if (!self->GetNetworkVar<bool>(u"FlameOn")) - { - return; - } - - auto* skillComponent = target->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(726, 11723, target->GetObjectID(), true); - - auto dir = target->GetRotation().GetForwardVector(); - - dir.y = 25; - dir.x = -dir.x * 15; - dir.z = -dir.z * 15; - - GameMessages::SendKnockback(target->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 1000, dir); -} - -void FlameJetServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - Game::logger->Log("FlameJetServer::OnFireEventServerSide", "Event: %s\n", args.c_str()); - - if (args == "OnActivated") - { - self->SetNetworkVar<bool>(u"FlameOn", false); - } - else if (args == "OnDectivated") - { - self->SetNetworkVar<bool>(u"FlameOn", true); - } -} diff --git a/dScripts/FlameJetServer.h b/dScripts/FlameJetServer.h deleted file mode 100644 index 4f815d63..00000000 --- a/dScripts/FlameJetServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FlameJetServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnCollisionPhantom(Entity* self, Entity* target) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; -}; \ No newline at end of file diff --git a/dScripts/ForceVolumeServer.cpp b/dScripts/ForceVolumeServer.cpp deleted file mode 100644 index e9320527..00000000 --- a/dScripts/ForceVolumeServer.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "ForceVolumeServer.h" -#include "PhantomPhysicsComponent.h" -#include "EntityManager.h" - -void ForceVolumeServer::OnStartup(Entity* self) -{ - auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); - - if (phantomPhysicsComponent == nullptr) return; - - const auto forceAmount = self->GetVar<float>(u"ForceAmt"); - const auto forceX = self->GetVar<float>(u"ForceX"); - const auto forceY = self->GetVar<float>(u"ForceY"); - const auto forceZ = self->GetVar<float>(u"ForceZ"); - - phantomPhysicsComponent->SetEffectType(0); // PUSH - phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount); - phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ }); - phantomPhysicsComponent->SetPhysicsEffectActive(true); - - EntityManager::Instance()->SerializeEntity(self); -} diff --git a/dScripts/FountainOfImagination.cpp b/dScripts/FountainOfImagination.cpp deleted file mode 100644 index 43351e18..00000000 --- a/dScripts/FountainOfImagination.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "FountainOfImagination.h" -#include "dCommonVars.h" -#include "Entity.h" - -void FountainOfImagination::OnStartup(Entity *self) { - self->SetVar<uint32_t>(u"numCycles", 6); - self->SetVar<float_t>(u"secPerCycle", 30.0f); - self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); - self->SetVar<float_t>(u"deathDelay", 30.0f); - self->SetVar<uint32_t>(u"numberOfPowerups", 5); - self->SetVar<LOT>(u"lootLOT", 935); - - // Initiate the actual script - OnTemplateStartup(self); -} diff --git a/dScripts/FvBounceOverWall.cpp b/dScripts/FvBounceOverWall.cpp deleted file mode 100644 index 1c85ffbd..00000000 --- a/dScripts/FvBounceOverWall.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "FvBounceOverWall.h" -#include "MissionComponent.h" - -void FvBounceOverWall::OnCollisionPhantom(Entity* self, Entity* target) { - auto missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) return; - - // We force progress here to the Gate Crasher mission due to an overlap in LOTs with the 'Shark Bite' missions. - missionComponent->ForceProgress(GateCrasherMissionId, GateCrasherMissionUid, 1); -} \ No newline at end of file diff --git a/dScripts/FvBounceOverWall.h b/dScripts/FvBounceOverWall.h deleted file mode 100644 index 875122c9..00000000 --- a/dScripts/FvBounceOverWall.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvBounceOverWall : public CppScripts::Script -{ - /** - * @brief When a collision has been made with self this method is called. - * - * @param self The Entity that called this function. - * @param target The target Entity of self. - */ - void OnCollisionPhantom(Entity* self, Entity* target) override; -private: - /** - * MissionId for the Gate Crasher mission. - */ - int32_t GateCrasherMissionId = 849; - /** - * MissionUid for the Gate Crasher mission. - */ - int32_t GateCrasherMissionUid = 1241; -}; \ No newline at end of file diff --git a/dScripts/FvBrickPuzzleServer.cpp b/dScripts/FvBrickPuzzleServer.cpp deleted file mode 100644 index df6cc395..00000000 --- a/dScripts/FvBrickPuzzleServer.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "FvBrickPuzzleServer.h" -#include "GeneralUtils.h" -#include "dZoneManager.h" -#include "Spawner.h" -#include "RebuildComponent.h" - -void FvBrickPuzzleServer::OnStartup(Entity* self) -{ - const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); - - int32_t pipeNum = 0; - if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) - { - return; - } - - if (pipeNum != 1) - { - self->AddTimer("reset", 30); - } -} - -void FvBrickPuzzleServer::OnDie(Entity* self, Entity* killer) -{ - const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); - - int32_t pipeNum = 0; - if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) - { - return; - } - - const auto pipeGroup = myGroup.substr(0, 10); - - const auto nextPipeNum = pipeNum + 1; - - const auto samePipeSpawners = dZoneManager::Instance()->GetSpawnersByName(myGroup); - - if (!samePipeSpawners.empty()) - { - samePipeSpawners[0]->SoftReset(); - - samePipeSpawners[0]->Deactivate(); - } - - if (killer != nullptr && killer->IsPlayer()) - { - const auto nextPipe = pipeGroup + std::to_string(nextPipeNum); - - const auto nextPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); - - if (!nextPipeSpawners.empty()) - { - nextPipeSpawners[0]->Activate(); - } - } - else - { - const auto nextPipe = pipeGroup + "1"; - - const auto firstPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); - - if (!firstPipeSpawners.empty()) - { - firstPipeSpawners[0]->Activate(); - } - } - -} - -void FvBrickPuzzleServer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "reset") - { - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent != nullptr && rebuildComponent->GetState() == REBUILD_OPEN) - { - self->Smash(self->GetObjectID(), SILENT); - } - } -} diff --git a/dScripts/FvConsoleLeftQuickbuild.cpp b/dScripts/FvConsoleLeftQuickbuild.cpp deleted file mode 100644 index ef281f15..00000000 --- a/dScripts/FvConsoleLeftQuickbuild.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "FvConsoleLeftQuickbuild.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void FvConsoleLeftQuickbuild::OnStartup(Entity* self) -{ - self->SetVar(u"IAmBuilt", false); - self->SetVar(u"AmActive", false); -} - -void FvConsoleLeftQuickbuild::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == REBUILD_COMPLETED) - { - self->SetVar(u"IAmBuilt", true); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleLeftUp"); - } - } - else if (state == REBUILD_RESETTING) - { - self->SetVar(u"IAmBuilt", false); - self->SetVar(u"AmActive", false); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleLeftDown"); - } - } -} - -void FvConsoleLeftQuickbuild::OnUse(Entity* self, Entity* user) -{ - if (self->GetVar<bool>(u"AmActive")) - { - return; - } - - if (self->GetVar<bool>(u"IAmBuilt")) - { - self->SetVar(u"AmActive", true); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleLeftActive"); - } - } - - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} diff --git a/dScripts/FvConsoleRightQuickbuild.cpp b/dScripts/FvConsoleRightQuickbuild.cpp deleted file mode 100644 index 0bf9849a..00000000 --- a/dScripts/FvConsoleRightQuickbuild.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "FvConsoleRightQuickbuild.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void FvConsoleRightQuickbuild::OnStartup(Entity* self) -{ - self->SetVar(u"IAmBuilt", false); - self->SetVar(u"AmActive", false); -} - -void FvConsoleRightQuickbuild::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == REBUILD_COMPLETED) - { - self->SetVar(u"IAmBuilt", true); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleRightUp"); - } - } - else if (state == REBUILD_RESETTING) - { - self->SetVar(u"IAmBuilt", false); - self->SetVar(u"AmActive", false); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleRightDown"); - } - } -} - -void FvConsoleRightQuickbuild::OnUse(Entity* self, Entity* user) -{ - if (self->GetVar<bool>(u"AmActive")) - { - return; - } - - if (self->GetVar<bool>(u"IAmBuilt")) - { - self->SetVar(u"AmActive", true); - - const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); - - if (!objects.empty()) - { - objects[0]->NotifyObject(self, "ConsoleRightActive"); - } - } - - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} diff --git a/dScripts/FvDragonSmashingGolemQb.cpp b/dScripts/FvDragonSmashingGolemQb.cpp deleted file mode 100644 index 6a88d9a0..00000000 --- a/dScripts/FvDragonSmashingGolemQb.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "FvDragonSmashingGolemQb.h" -#include "GameMessages.h" -#include "EntityManager.h" - -void FvDragonSmashingGolemQb::OnStartup(Entity* self) -{ - self->AddTimer("GolemBreakTimer", 10.5f); -} - -void FvDragonSmashingGolemQb::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "GolemBreakTimer") - { - self->Smash(); - } -} - -void FvDragonSmashingGolemQb::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == eRebuildState::REBUILD_COMPLETED) - { - GameMessages::SendPlayAnimation(self, u"dragonsmash"); - - const auto dragonId = self->GetVar<LWOOBJID>(u"Dragon"); - - auto* dragon = EntityManager::Instance()->GetEntity(dragonId); - - if (dragon != nullptr) - { - dragon->OnFireEventServerSide(self, "rebuildDone"); - } - - self->CancelTimer("GolemBreakTimer"); - self->AddTimer("GolemBreakTimer", 10.5f); - } -} diff --git a/dScripts/FvDragonSmashingGolemQb.h b/dScripts/FvDragonSmashingGolemQb.h deleted file mode 100644 index 3cbe9a40..00000000 --- a/dScripts/FvDragonSmashingGolemQb.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvDragonSmashingGolemQb : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnRebuildNotifyState(Entity* self, eRebuildState state) override; -}; diff --git a/dScripts/FvFacilityBrick.cpp b/dScripts/FvFacilityBrick.cpp deleted file mode 100644 index fce9e630..00000000 --- a/dScripts/FvFacilityBrick.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "FvFacilityBrick.h" -#include "GameMessages.h" -#include "dZoneManager.h" -#include "EntityManager.h" - -void FvFacilityBrick::OnStartup(Entity* self) -{ - self->SetVar(u"ConsoleLEFTActive", false); - self->SetVar(u"ConsoleRIGHTtActive", false); -} - -void FvFacilityBrick::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) -{ - auto* brickSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationBrick")[0]; - auto* bugSpawner = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug")[0]; - auto* canisterSpawner = dZoneManager::Instance()->GetSpawnersByName("BrickCanister")[0]; - - if (name == "ConsoleLeftUp") - { - GameMessages::SendStopFXEffect(self, true, "LeftPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2775, u"create", "LeftPipeEnergy"); - } - else if (name == "ConsoleLeftDown") - { - self->SetVar(u"ConsoleLEFTActive", false); - - GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); - GameMessages::SendStopFXEffect(self, true, "LeftPipeOn"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); - } - else if (name == "ConsoleLeftActive") - { - self->SetVar(u"ConsoleLEFTActive", true); - - GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2776, u"create", "LeftPipeOn"); - } - - else if (name == "ConsoleRightUp") - { - GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2778, u"create", "RightPipeEnergy"); - } - else if (name == "ConsoleRightDown") - { - self->SetVar(u"ConsoleRIGHTActive", false); - - GameMessages::SendStopFXEffect(self, true, "RightPipeEnergy"); - GameMessages::SendStopFXEffect(self, true, "RightPipeOn"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); - } - else if (name == "ConsoleRightActive") - { - self->SetVar(u"ConsoleRIGHTActive", true); - - GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2779, u"create", "RightPipeEnergy"); - } - - if (self->GetVar<bool>(u"ConsoleLEFTActive") && self->GetVar<bool>(u"ConsoleRIGHTActive")) - { - auto* object = EntityManager::Instance()->GetEntitiesInGroup("Brick")[0]; - - if (object != nullptr) - { - GameMessages::SendPlayFXEffect(object->GetObjectID(), 122, u"create", "bluebrick"); - GameMessages::SendPlayFXEffect(object->GetObjectID(), 1034, u"cast", "imaginationexplosion"); - } - - object = EntityManager::Instance()->GetEntitiesInGroup("Canister")[0]; - - if (object != nullptr) - { - object->Smash(self->GetObjectID(), SILENT); - } - - canisterSpawner->Reset(); - canisterSpawner->Deactivate(); - } - else if (self->GetVar<bool>(u"ConsoleLEFTActive") || self->GetVar<bool>(u"ConsoleRIGHTActive")) - { - brickSpawner->Activate(); - - auto* object = EntityManager::Instance()->GetEntitiesInGroup("Brick")[0]; - - if (object != nullptr) - { - GameMessages::SendStopFXEffect(object, true, "bluebrick"); - } - - bugSpawner->Reset(); - bugSpawner->Deactivate(); - - canisterSpawner->Reset(); - canisterSpawner->Activate(); - } - else - { - brickSpawner->Reset(); - brickSpawner->Deactivate(); - - bugSpawner->Reset(); - bugSpawner->Activate(); - } -} - -void FvFacilityBrick::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) -{ - if (args != "PlayFX") - { - return; - } - - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2750, u"create", "imagination_canister"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2751, u"create", "canister_light_filler"); -} diff --git a/dScripts/FvFacilityBrick.h b/dScripts/FvFacilityBrick.h deleted file mode 100644 index 794dd5b6..00000000 --- a/dScripts/FvFacilityBrick.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvFacilityBrick : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; \ No newline at end of file diff --git a/dScripts/FvFlyingCreviceDragon.cpp b/dScripts/FvFlyingCreviceDragon.cpp deleted file mode 100644 index 4255daf5..00000000 --- a/dScripts/FvFlyingCreviceDragon.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "FvFlyingCreviceDragon.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "SkillComponent.h" -#include "GeneralUtils.h" - -void FvFlyingCreviceDragon::OnStartup(Entity* self) -{ - self->AddTimer("waypoint", 5); -} - -void FvFlyingCreviceDragon::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "waypoint") - { - auto point = self->GetVar<int32_t>(u"waypoint"); - - if (point >= 20) - { - point = 0; - } - - self->SetVar<int32_t>(u"waypoint", point + 1); - - self->AddTimer("waypoint", 5); - - OnArrived(self); - - return; - } - - std::string groupName = ""; - - if (timerName == "platform1attack") - { - groupName = "dragonFireballs1"; - } - else if (timerName == "platform3attack") - { - groupName = "dragonFireballs3"; - } - - const auto& group = EntityManager::Instance()->GetEntitiesInGroup(groupName); - - if (group.empty()) - { - return; - } - - auto* skillComponent = group[0]->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY, true); - } - - auto minionCount = 1; - for (size_t i = 1; i < group.size(); i++) - { - if (minionCount == 4) - { - return; - } - - if (/*GeneralUtils::GenerateRandomNumber<int32_t>(1, 5) > 3*/ true) - { - skillComponent = group[i]->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY); - - ++minionCount; - } - } - } -} - -void FvFlyingCreviceDragon::OnArrived(Entity* self) -{ - auto point = self->GetVar<int32_t>(u"waypoint"); - - if (point == 4) - { - GameMessages::SendPlayAnimation(self, u"attack1", 2); - self->AddTimer("platform1attack", 1.75f); - } - else if (point == 12) - { - GameMessages::SendPlayAnimation(self, u"attack2", 2); - - const auto& group2 = EntityManager::Instance()->GetEntitiesInGroup("dragonFireballs2"); - - if (group2.empty()) - { - return; - } - - auto* skillComponent = group2[0]->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY); - } - - auto minionCount = 1; - for (size_t i = 1; i < group2.size(); i++) - { - if (minionCount == 4) - { - return; - } - - if (GeneralUtils::GenerateRandomNumber<int32_t>(1, 5) > 3) - { - skillComponent = group2[i]->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY, true); - - ++minionCount; - } - } - } - } - else if (point == 16) - { - GameMessages::SendPlayAnimation(self, u"attack3", 2); - self->AddTimer("platform3attack", 0.5f); - } -} diff --git a/dScripts/FvFlyingCreviceDragon.h b/dScripts/FvFlyingCreviceDragon.h deleted file mode 100644 index 657f4eed..00000000 --- a/dScripts/FvFlyingCreviceDragon.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvFlyingCreviceDragon : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnArrived(Entity* self); -}; diff --git a/dScripts/FvFong.h b/dScripts/FvFong.h deleted file mode 100644 index fc47b484..00000000 --- a/dScripts/FvFong.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvFong : public CppScripts::Script -{ - public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; -}; diff --git a/dScripts/FvFreeGfNinjas.cpp b/dScripts/FvFreeGfNinjas.cpp deleted file mode 100644 index 8022b32f..00000000 --- a/dScripts/FvFreeGfNinjas.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "FvFreeGfNinjas.h" -#include "Character.h" -#include "MissionComponent.h" - -void FvFreeGfNinjas::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - if (missionID == 705 && missionState == MissionState::MISSION_STATE_AVAILABLE) { - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; - - missionComponent->AcceptMission(701); - missionComponent->AcceptMission(702); - missionComponent->AcceptMission(703); - missionComponent->AcceptMission(704); - - auto* character = target->GetCharacter(); - if (character != nullptr) - character->SetPlayerFlag(68, true); - } else if (missionID == 786) { - auto* character = target->GetCharacter(); - if (character != nullptr) - character->SetPlayerFlag(81, true); - } -} - -void FvFreeGfNinjas::OnUse(Entity* self, Entity* user) -{ - // To allow player who already have the mission to progress. - auto* missionComponent = user->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; - - if (missionComponent->GetMissionState(705) == MissionState::MISSION_STATE_ACTIVE) { - auto* character = user->GetCharacter(); - if (character != nullptr) - character->SetPlayerFlag(68, true); - - missionComponent->AcceptMission(701, true); - missionComponent->AcceptMission(702, true); - missionComponent->AcceptMission(703, true); - missionComponent->AcceptMission(704, true); - } -} diff --git a/dScripts/FvFreeGfNinjas.h b/dScripts/FvFreeGfNinjas.h deleted file mode 100644 index cdff0d2d..00000000 --- a/dScripts/FvFreeGfNinjas.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvFreeGfNinjas : public CppScripts::Script { -public: - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - void OnUse(Entity* self, Entity* user) override; -}; diff --git a/dScripts/FvHorsemenTrigger.cpp b/dScripts/FvHorsemenTrigger.cpp deleted file mode 100644 index 541c11e0..00000000 --- a/dScripts/FvHorsemenTrigger.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "FvHorsemenTrigger.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void FvHorsemenTrigger::OnStartup(Entity* self) -{ - self->SetProximityRadius(40, "horsemenTrigger"); - - self->SetVar<std::vector<LWOOBJID>>(u"players", {}); -} - -void FvHorsemenTrigger::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (name != "horsemenTrigger" || !entering->IsPlayer()) - { - return; - } - - auto players = self->GetVar<std::vector<LWOOBJID>>(u"players"); - - const auto& iter = std::find(players.begin(), players.end(), entering->GetObjectID()); - - if (status == "ENTER" && iter == players.end()) - { - players.push_back(entering->GetObjectID()); - } - else if (status == "LEAVE" && iter != players.end()) - { - players.erase(iter); - } - - self->SetVar<std::vector<LWOOBJID>>(u"players", players); -} - -void -FvHorsemenTrigger::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) -{ - auto players = self->GetVar<std::vector<LWOOBJID>>(u"players"); - - if (args == "HorsemenDeath") - { - for (const auto& playerId : self->GetVar<std::vector<LWOOBJID>>(u"players")) - { - auto* player = EntityManager::Instance()->GetEntity(playerId); - - if (player == nullptr) - { - continue; - } - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - continue; - } - - for (const auto missionId : m_Missions) - { - missionComponent->ForceProgressTaskType(missionId, 1, 1); - } - } - } -} diff --git a/dScripts/FvHorsemenTrigger.h b/dScripts/FvHorsemenTrigger.h deleted file mode 100644 index 9ec47084..00000000 --- a/dScripts/FvHorsemenTrigger.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "RenderComponent.h" - -class FvHorsemenTrigger : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; - -private: - std::vector<int32_t> m_Missions = {854, 738, 1432, 1530, 1567, 1604}; -}; diff --git a/dScripts/FvMaelstromCavalry.cpp b/dScripts/FvMaelstromCavalry.cpp deleted file mode 100644 index b4a32991..00000000 --- a/dScripts/FvMaelstromCavalry.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "FvMaelstromCavalry.h" -#include "EntityManager.h" - -void FvMaelstromCavalry::OnStartup(Entity* self) -{ - for (const auto& group : self->GetGroups()) - { - const auto& objects = EntityManager::Instance()->GetEntitiesInGroup(group); - - for (auto* obj : objects) - { - if (obj->GetLOT() != 8551) continue; - - obj->OnFireEventServerSide(self, "ISpawned"); - } - } -} - -void FvMaelstromCavalry::OnDie(Entity* self, Entity* killer) -{ - if (killer == nullptr) - { - return; - } - - if (killer->GetLOT() != 8665) - { - return; - } - - const auto& triggers = EntityManager::Instance()->GetEntitiesInGroup("HorsemenTrigger"); - - for (auto* trigger : triggers) - { - trigger->OnFireEventServerSide(self, "HorsemenDeath"); - } -} diff --git a/dScripts/FvMaelstromDragon.cpp b/dScripts/FvMaelstromDragon.cpp deleted file mode 100644 index afdfa4ae..00000000 --- a/dScripts/FvMaelstromDragon.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "FvMaelstromDragon.h" -#include "EntityManager.h" -#include "SkillComponent.h" -#include "BaseCombatAIComponent.h" -#include "DestroyableComponent.h" - -void FvMaelstromDragon::OnStartup(Entity* self) -{ - self->SetVar<int32_t>(u"weakspot", 0); - - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - - if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->SetStunImmune(true); - } -} - -void FvMaelstromDragon::OnDie(Entity* self, Entity* killer) -{ - if (self->GetVar<bool>(u"bDied")) - { - return; - } - - self->SetVar<bool>(u"bDied", true); - - auto position = self->GetPosition(); - auto rotation = self->GetRotation(); - - auto chestObject = 11229; - - EntityInfo info {}; - info.lot = chestObject; - info.pos = position; - info.rot = rotation; - info.spawnerID = self->GetObjectID(); - - auto* chest = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(chest); - - auto golemId = self->GetVar<LWOOBJID>(u"Golem"); - - auto* golem = EntityManager::Instance()->GetEntity(golemId); - - if (golem != nullptr) - { - golem->Smash(self->GetObjectID()); - } -} - -void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) -{ - GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); - - if (true) - { - auto weakpoint = self->GetVar<int32_t>(u"weakspot"); - - if (weakpoint == 1) - { - self->Smash(attacker->GetObjectID()); - } - } - - auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) - { - Game::logger->Log("FvMaelstromDragon", "Hit %i\n", destroyableComponent->GetArmor()); - - if (destroyableComponent->GetArmor() > 0) return; - - auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); - - if (weakpoint == 0) - { - Game::logger->Log("FvMaelstromDragon", "Activating weakpoint\n"); - - self->AddTimer("ReviveTimer", 12); - - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->SetDisabled(true); - baseCombatAIComponent->SetStunned(true); - } - - if (skillComponent != nullptr) - { - skillComponent->Interrupt(); - } - - self->SetVar<int32_t>(u"weakpoint", 2); - - GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); - - self->AddTimer("timeToStunLoop", 1); - - auto position = self->GetPosition(); - auto forward = self->GetRotation().GetForwardVector(); - auto backwards = forward * -1; - - forward.x *= 10; - forward.z *= 10; - - auto rotation = self->GetRotation(); - - auto objectPosition = NiPoint3(); - - objectPosition.y = position.y; - objectPosition.x = position.x - (backwards.x * 8); - objectPosition.z = position.z - (backwards.z * 8); - - auto golem = self->GetVar<int32_t>(u"DragonSmashingGolem"); - - EntityInfo info {}; - info.lot = golem != 0 ? golem : 8340; - info.pos = objectPosition; - info.rot = rotation; - info.spawnerID = self->GetObjectID(); - info.settings = { - new LDFData<std::string>(u"rebuild_activators", - std::to_string(objectPosition.x + forward.x) + "\x1f" + - std::to_string(objectPosition.y) + "\x1f" + - std::to_string(objectPosition.z + forward.z) - ), - new LDFData<int32_t>(u"respawn", 100000), - new LDFData<float>(u"rebuild_reset_time", 15), - new LDFData<bool>(u"no_timed_spawn", true), - new LDFData<LWOOBJID>(u"Dragon", self->GetObjectID()) - }; - - auto* golemObject = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(golemObject); - } - } -} - -void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "ReviveHeldTimer") - { - self->AddTimer("backToAttack", 2.5); - } - else if (timerName == "ExposeWeakSpotTimer") - { - self->SetVar<int32_t>(u"weakspot", 1); - } - else if (timerName == "timeToStunLoop") - { - GameMessages::SendPlayAnimation(self, u"stunloop", 1.8f); - } - else if (timerName == "ReviveTimer") - { - GameMessages::SendPlayAnimation(self, u"stunend", 2.0f); - self->AddTimer("backToAttack", 1); - } - else if (timerName == "backToAttack") - { - auto* baseCombatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->SetDisabled(false); - baseCombatAIComponent->SetStunned(false); - } - - if (skillComponent != nullptr) - { - skillComponent->Interrupt(); - } - - self->SetVar<int32_t>(u"weakspot", -1); - - GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); - } -} - -void -FvMaelstromDragon::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) -{ - if (args != "rebuildDone") return; - - self->AddTimer("ExposeWeakSpotTimer", 3.8f); - - self->CancelTimer("ReviveTimer"); - - self->AddTimer("ReviveHeldTimer", 10.5f); - - self->SetVar<LWOOBJID>(u"Golem", sender->GetObjectID()); - - GameMessages::SendPlayAnimation(self, u"quickbuildhold", 1.9f); -} diff --git a/dScripts/FvMaelstromDragon.h b/dScripts/FvMaelstromDragon.h deleted file mode 100644 index 52af80c4..00000000 --- a/dScripts/FvMaelstromDragon.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvMaelstromDragon : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnDie(Entity* self, Entity* killer) override; - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/FvPandaServer.cpp b/dScripts/FvPandaServer.cpp deleted file mode 100644 index ea814936..00000000 --- a/dScripts/FvPandaServer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "FvPandaServer.h" -#include "PetComponent.h" -#include "Character.h" - -void FvPandaServer::OnStartup(Entity *self) { - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { - self->SetNetworkVar<std::string>(u"pandatamer", std::to_string(self->GetVar<LWOOBJID>(u"tamer"))); - self->AddTimer("killSelf", 45); - } -} - -void FvPandaServer::OnNotifyPetTamingMinigame(Entity *self, Entity *tamer, eNotifyType type) { - if (type == NOTIFY_TYPE_BEGIN) { - self->CancelAllTimers(); - } else if (type == NOTIFY_TYPE_QUIT || type == NOTIFY_TYPE_FAILED) { - self->Smash(); - } else if (type == NOTIFY_TYPE_SUCCESS) { - // TODO: Remove from groups - - auto* character = tamer->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(82, true); - } - } -} - -void FvPandaServer::OnTimerDone(Entity *self, std::string timerName) { - if (timerName == "killSelf") { - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { - self->Smash(self->GetObjectID(), SILENT); - } - } -} diff --git a/dScripts/FvPandaServer.h b/dScripts/FvPandaServer.h deleted file mode 100644 index 377371c1..00000000 --- a/dScripts/FvPandaServer.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvPandaServer : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnNotifyPetTamingMinigame(Entity *self, Entity *tamer, eNotifyType type) override; - void OnTimerDone(Entity *self, std::string timerName) override; -}; diff --git a/dScripts/FvPandaSpawnerServer.cpp b/dScripts/FvPandaSpawnerServer.cpp deleted file mode 100644 index 97738271..00000000 --- a/dScripts/FvPandaSpawnerServer.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "FvPandaSpawnerServer.h" -#include "Character.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "ScriptedActivityComponent.h" - -void FvPandaSpawnerServer::OnCollisionPhantom(Entity *self, Entity *target) { - auto* character = target->GetCharacter(); - if (character != nullptr && character->GetPlayerFlag(81)) { - - auto raceObjects = EntityManager::Instance()->GetEntitiesInGroup("PandaRaceObject"); - if (raceObjects.empty()) - return; - - // Check if the player is currently in a footrace - auto* scriptedActivityComponent = raceObjects.at(0)->GetComponent<ScriptedActivityComponent>(); - if (scriptedActivityComponent == nullptr || !scriptedActivityComponent->IsPlayedBy(target)) - return; - - // If the player already spawned a panda - auto playerPandas = EntityManager::Instance()->GetEntitiesInGroup("panda" + std::to_string(target->GetObjectID())); - if (!playerPandas.empty()) { - GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"playerPanda", - target->GetObjectID(), 0, 0, target->GetObjectID()); - return; - } - - // If there's already too many spawned pandas - auto pandas = EntityManager::Instance()->GetEntitiesInGroup("pandas"); - if (pandas.size() > 4) { - GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"tooManyPandas", - target->GetObjectID(), 0, 0, target->GetObjectID()); - return; - } - - EntityInfo info {}; - info.spawnerID = target->GetObjectID(); - info.pos = self->GetPosition(); - info.lot = 5643; - info.settings = { - new LDFData<LWOOBJID>(u"tamer", target->GetObjectID()), - new LDFData<std::u16string>(u"groupID", u"panda" + (GeneralUtils::to_u16string(target->GetObjectID())) + u";pandas") - }; - - auto* panda = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(panda); - } -} diff --git a/dScripts/FvPassThroughWall.cpp b/dScripts/FvPassThroughWall.cpp deleted file mode 100644 index e894f923..00000000 --- a/dScripts/FvPassThroughWall.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "FvPassThroughWall.h" -#include "InventoryComponent.h" -#include "MissionComponent.h" - -void FvPassThroughWall::OnCollisionPhantom(Entity* self, Entity* target) { - auto missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) return; - - //Because at the moment we do not have an ItemComponent component, we check to make sure a Maelstrom-Infused hood is equipped. There are only three in the game right now. - auto inventoryComponent = target->GetComponent<InventoryComponent>(); - // If no inventory component is found then abort. - if (inventoryComponent == nullptr) return; - // If no Maelstrom hoods are equipped then abort. - if (!inventoryComponent->IsEquipped(WhiteMaelstromHood) && !inventoryComponent->IsEquipped(BlackMaelstromHood) && !inventoryComponent->IsEquipped(RedMaelstromHood)) return; - - // Progress mission Friend of the Ninja since all prerequisites are met. - missionComponent->ForceProgress(friendOfTheNinjaMissionId, friendOfTheNinjaMissionUid, 1); -} \ No newline at end of file diff --git a/dScripts/FvPassThroughWall.h b/dScripts/FvPassThroughWall.h deleted file mode 100644 index 4dacc74e..00000000 --- a/dScripts/FvPassThroughWall.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class FvPassThroughWall : public CppScripts::Script -{ - /** - * @brief This method is called when there is a collision with self from target. - * - * @param self The Entity that called this method. - * @param target The Entity that self is targetting. - */ - void OnCollisionPhantom(Entity* self, Entity* target) override; -private: - /** - * Mission ID for Friend of the Ninjas. - */ - int32_t friendOfTheNinjaMissionId = 848; - /** - * Mission UID for Friend of the Ninjas. - */ - int32_t friendOfTheNinjaMissionUid = 1221; - /** - * Item LOT for Maelstrom-Infused White Ninja Hood - */ - int32_t WhiteMaelstromHood = 2641; - /** - * Item LOT for Maelstrom-Infused Black Ninja Hood - */ - int32_t BlackMaelstromHood = 2642; - /** - * Item LOT for Red Ninja Hood - Maelstrom Infused - */ - int32_t RedMaelstromHood = 1889; -}; \ No newline at end of file diff --git a/dScripts/FvRaceSmashEggImagineServer.cpp b/dScripts/FvRaceSmashEggImagineServer.cpp deleted file mode 100644 index 696504e2..00000000 --- a/dScripts/FvRaceSmashEggImagineServer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "FvRaceSmashEggImagineServer.h" -#include "CharacterComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "PossessableComponent.h" -#include "RacingTaskParam.h" -#include "MissionComponent.h" - -void FvRaceSmashEggImagineServer::OnDie(Entity *self, Entity *killer) { - if (killer != nullptr) { - auto* destroyableComponent = killer->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetImagination(destroyableComponent->GetImagination() + 10); - EntityManager::Instance()->SerializeEntity(killer); - } - - // get possessor to progress statistics and tasks. - auto* possessableComponent = killer->GetComponent<PossessableComponent>(); - if (possessableComponent != nullptr) { - - auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (possessor != nullptr) { - - auto* missionComponent = possessor->GetComponent<MissionComponent>(); - auto* characterComponent = possessor->GetComponent<CharacterComponent>(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(ImaginationPowerUpsCollected); - characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); - } - if (missionComponent == nullptr) return; - // Dragon eggs have their own smash server so we handle mission progression for them here. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASH_SPECIFIC_SMASHABLE); - } - } - - } -} diff --git a/dScripts/GfApeSmashingQB.cpp b/dScripts/GfApeSmashingQB.cpp deleted file mode 100644 index 973cb728..00000000 --- a/dScripts/GfApeSmashingQB.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "GfApeSmashingQB.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void GfApeSmashingQB::OnStartup(Entity *self) { - self->SetNetworkVar<LWOOBJID>(u"lootTagOwner", self->GetVar<LWOOBJID>(u"lootTagOwner")); -} - -void GfApeSmashingQB::OnTimerDone(Entity *self, std::string timerName) { - if (timerName == "anchorBreakTime") { - self->Smash(); - } -} - -void GfApeSmashingQB::OnRebuildComplete(Entity *self, Entity *target) { - auto* ape = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"ape")); - if (ape != nullptr) { - ape->OnFireEventServerSide(target, "rebuildDone"); - GameMessages::SendPlayAnimation(self, u"smash", 1.7f); - self->AddTimer("anchorBreakTime", 1.0f); - } -} diff --git a/dScripts/GfApeSmashingQB.h b/dScripts/GfApeSmashingQB.h deleted file mode 100644 index 825fe916..00000000 --- a/dScripts/GfApeSmashingQB.h +++ /dev/null @@ -1,8 +0,0 @@ -# pragma once -#include "CppScripts.h" - -class GfApeSmashingQB : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnTimerDone(Entity *self, std::string timerName) override; - void OnRebuildComplete(Entity *self, Entity *target) override; -}; diff --git a/dScripts/GfCaptainsCannon.cpp b/dScripts/GfCaptainsCannon.cpp deleted file mode 100644 index ee973a13..00000000 --- a/dScripts/GfCaptainsCannon.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "GfCaptainsCannon.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void GfCaptainsCannon::OnUse(Entity* self, Entity* user) -{ - if (self->GetVar<bool>(u"bIsInUse")) - { - return; - } - - self->SetVar<LWOOBJID>(u"userID", user->GetObjectID()); - - self->SetVar<bool>(u"bIsInUse", true); - self->SetNetworkVar<bool>(u"bIsInUse", true); - - GameMessages::SendSetStunned(user->GetObjectID(), PUSH, user->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true, true - ); - - auto position = self->GetPosition(); - auto forward = self->GetRotation().GetForwardVector(); - - position.x += forward.x * -3; - position.z += forward.z * -3; - - auto rotation = self->GetRotation(); - - GameMessages::SendTeleport(user->GetObjectID(), position, rotation, user->GetSystemAddress()); - - GameMessages::SendPlayAnimation(user, u"cannon-strike-no-equip"); - - GameMessages::SendPlayFXEffect(user->GetObjectID(), 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); - - self->AddTimer("FireCannon", 1.667f); -} - -void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) -{ - const auto playerId = self->GetVar<LWOOBJID>(u"userID"); - - auto* player = EntityManager::Instance()->GetEntity(playerId); - - if (player == nullptr) - { - self->SetVar<bool>(u"bIsInUse", false); - self->SetNetworkVar<bool>(u"bIsInUse", false); - - return; - } - - if (timerName == "FireCannon") - { - float cinematicTime = 6.3f; - - GameMessages::SendPlayCinematic(playerId, u"Cannon_Cam", player->GetSystemAddress()); - - self->AddTimer("cinematicTimer", cinematicTime); - - const auto sharkObjects = EntityManager::Instance()->GetEntitiesInGroup("SharkCannon"); - - for (auto* shark : sharkObjects) - { - if (shark->GetLOT() != m_SharkItemID) continue; - - GameMessages::SendPlayAnimation(shark, u"cannon"); - } - - GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}"); - } - else if (timerName == "cinematicTimer") - { - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true, true - ); - - self->SetVar<bool>(u"bIsInUse", false); - self->SetNetworkVar<bool>(u"bIsInUse", false); - - GameMessages::SendStopFXEffect(player, true, "hook"); - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->ForceProgress(601, 910, 1); - } - - GameMessages::SendTerminateInteraction(playerId, FROM_INTERACTION, self->GetObjectID()); - } -} diff --git a/dScripts/GfCaptainsCannon.h b/dScripts/GfCaptainsCannon.h deleted file mode 100644 index 44dd791c..00000000 --- a/dScripts/GfCaptainsCannon.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class GfCaptainsCannon : public CppScripts::Script -{ -public: - void OnUse(Entity* self, Entity* user) override; - void OnTimerDone(Entity* self, std::string timerName) override; -private: - int32_t m_SharkItemID = 7343; -}; diff --git a/dScripts/GfJailWalls.cpp b/dScripts/GfJailWalls.cpp deleted file mode 100644 index da547d0b..00000000 --- a/dScripts/GfJailWalls.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "GfJailWalls.h" -#include "dZoneManager.h" -#include "GeneralUtils.h" - -void GfJailWalls::OnRebuildComplete(Entity* self, Entity* target) -{ - const auto wall = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Wall")); - - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("Jail0" + wall)) - { - spawner->Deactivate(); - } - - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("JailCaptain0" + wall)) - { - spawner->Deactivate(); - } -} - -void GfJailWalls::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state != eRebuildState::REBUILD_RESETTING) return; - - const auto wall = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Wall")); - - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("Jail0" + wall)) - { - spawner->Activate(); - } - - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("JailCaptain0" + wall)) - { - spawner->Activate(); - } -} diff --git a/dScripts/GfJailWalls.h b/dScripts/GfJailWalls.h deleted file mode 100644 index 8f3ad54b..00000000 --- a/dScripts/GfJailWalls.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class GfJailWalls final : public CppScripts::Script -{ -public: - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnRebuildNotifyState(Entity* self, eRebuildState state) override; -}; diff --git a/dScripts/GfJailkeepMission.cpp b/dScripts/GfJailkeepMission.cpp deleted file mode 100644 index bf3b25f8..00000000 --- a/dScripts/GfJailkeepMission.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "GfJailkeepMission.h" -#include "MissionComponent.h" -#include "Character.h" - -void GfJailkeepMission::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; - - if (missionID == 385 && missionState == MissionState::MISSION_STATE_AVAILABLE) { - missionComponent->AcceptMission(386, true); - missionComponent->AcceptMission(387, true); - missionComponent->AcceptMission(388, true); - missionComponent->AcceptMission(390, true); - } else if (missionID == 385 && missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { - auto* character = target->GetCharacter(); - if (character != nullptr && character->GetPlayerFlag(68)) { - missionComponent->AcceptMission(701); - missionComponent->AcceptMission(702); - missionComponent->AcceptMission(703); - missionComponent->AcceptMission(704); - } - } -} - -void GfJailkeepMission::OnUse(Entity* self, Entity* user) -{ - auto* missionComponent = user->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; - - if (missionComponent->GetMissionState(385) == MissionState::MISSION_STATE_ACTIVE) { - missionComponent->AcceptMission(386, true); - missionComponent->AcceptMission(387, true); - missionComponent->AcceptMission(388, true); - missionComponent->AcceptMission(390, true); - } -} - diff --git a/dScripts/GfJailkeepMission.h b/dScripts/GfJailkeepMission.h deleted file mode 100644 index 6c1b2a3e..00000000 --- a/dScripts/GfJailkeepMission.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class GfJailkeepMission final : public CppScripts::Script -{ -public: - void OnUse(Entity* self, Entity* user) override; - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; -}; diff --git a/dScripts/GrowingFlower.cpp b/dScripts/GrowingFlower.cpp deleted file mode 100644 index 1acb2455..00000000 --- a/dScripts/GrowingFlower.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "GrowingFlower.h" -#include "MissionComponent.h" - -void GrowingFlower::OnSkillEventFired(Entity *self, Entity *target, const std::string &message) { - if (!self->GetVar<bool>(u"blooming") && (message == "waterspray" || message == "shovelgrow")) { - self->SetVar<bool>(u"blooming", true); - self->SetNetworkVar(u"blooming", true); - self->AddTimer("FlowerDie", GrowingFlower::aliveTime); - - const auto mission1 = self->GetVar<int32_t>(u"missionID"); - const auto mission2 = self->GetVar<int32_t>(u"missionID2"); - - LootGenerator::Instance().DropActivityLoot(target, self, self->GetLOT(), 0); - - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - for (const auto mission : achievementIDs) - missionComponent->ForceProgressTaskType(mission, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); - - if (mission1 && missionComponent->GetMissionState(mission1) == MissionState::MISSION_STATE_ACTIVE) - missionComponent->ForceProgressTaskType(mission1, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); - - if (mission2 && missionComponent->GetMissionState(mission2) == MissionState::MISSION_STATE_ACTIVE) - missionComponent->ForceProgressTaskType(mission2, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); - } - } -} - -void GrowingFlower::OnTimerDone(Entity *self, std::string message) { - if (message == "FlowerDie") { - self->Smash(); - } -} - -const std::vector<uint32_t> GrowingFlower::achievementIDs = { 143, 152, 153, 1409, 1507, 1544, 1581, 1845 }; diff --git a/dScripts/GrowingFlower.h b/dScripts/GrowingFlower.h deleted file mode 100644 index 92fc0035..00000000 --- a/dScripts/GrowingFlower.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class GrowingFlower : public CppScripts::Script { -public: - void OnSkillEventFired(Entity* self, Entity* target, const std::string& message) override; - void OnTimerDone(Entity* self, std::string message) override; -private: - static const std::vector<uint32_t> achievementIDs; - constexpr static const float aliveTime = 16.0f; -}; \ No newline at end of file diff --git a/dScripts/HydrantBroken.cpp b/dScripts/HydrantBroken.cpp deleted file mode 100644 index 2b620a21..00000000 --- a/dScripts/HydrantBroken.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "HydrantBroken.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void HydrantBroken::OnStartup(Entity* self) -{ - self->AddTimer("playEffect", 1); - - const auto hydrant = "hydrant" + self->GetVar<std::string>(u"hydrant"); - - const auto bouncers = EntityManager::Instance()->GetEntitiesInGroup(hydrant); - - for (auto* bouncer : bouncers) - { - self->SetVar<LWOOBJID>(u"bouncer", bouncer->GetObjectID()); - - GameMessages::SendBouncerActiveStatus(bouncer->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision", UNASSIGNED_SYSTEM_ADDRESS); - } - - self->AddTimer("KillBroken", 25); -} - -void HydrantBroken::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "KillBroken") - { - auto* bouncer = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"bouncer")); - - if (bouncer != nullptr) - { - GameMessages::SendBouncerActiveStatus(bouncer->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision", UNASSIGNED_SYSTEM_ADDRESS); - } - - self->Kill(); - } - else if (timerName == "playEffect") - { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 384, u"water", "water", LWOOBJID_EMPTY, 1, 1, true); - } -} diff --git a/dScripts/HydrantSmashable.cpp b/dScripts/HydrantSmashable.cpp deleted file mode 100644 index 5cdf84c9..00000000 --- a/dScripts/HydrantSmashable.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "HydrantSmashable.h" -#include "EntityManager.h" -#include "GeneralUtils.h" - -void HydrantSmashable::OnDie(Entity* self, Entity* killer) -{ - const auto hydrantName = self->GetVar<std::u16string>(u"hydrant"); - - LDFBaseData* data = new LDFData<std::string>(u"hydrant", GeneralUtils::UTF16ToWTF8(hydrantName)); - - EntityInfo info {}; - info.lot = HYDRANT_BROKEN; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.settings = {data}; - info.spawnerID = self->GetSpawnerID(); - - auto* hydrant = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(hydrant); -} diff --git a/dScripts/ImaginationBackpackHealServer.cpp b/dScripts/ImaginationBackpackHealServer.cpp deleted file mode 100644 index 1d7da2c5..00000000 --- a/dScripts/ImaginationBackpackHealServer.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "ImaginationBackpackHealServer.h" -#include "GameMessages.h" -#include "MissionComponent.h" - -void ImaginationBackpackHealServer::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - if (message == "CastImaginationBackpack") { - auto healMission = self->GetVar<int32_t>(u"FXOffMis"); - if (healMission == 0) - healMission = self->GetVar<int32_t>(u"FXOnMis"); - if (healMission == 0) - return; - - auto* missionComponent = caster->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == MissionState::MISSION_STATE_ACTIVE) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0, - caster->GetObjectID(), "", caster->GetSystemAddress()); - } - } -} diff --git a/dScripts/ImaginationShrineServer.cpp b/dScripts/ImaginationShrineServer.cpp deleted file mode 100644 index 54c02614..00000000 --- a/dScripts/ImaginationShrineServer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "ImaginationShrineServer.h" -#include "RebuildComponent.h" - -void ImaginationShrineServer::OnUse(Entity* self, Entity* user) -{ - // If the rebuild component is complete, use the shrine - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent == nullptr) - { - return; - } - - if (rebuildComponent->GetState() == REBUILD_COMPLETED) - { - // Use the shrine - BaseUse(self, user); - } -} diff --git a/dScripts/ImgBrickConsoleQB.cpp b/dScripts/ImgBrickConsoleQB.cpp deleted file mode 100644 index 0dfb6288..00000000 --- a/dScripts/ImgBrickConsoleQB.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "ImgBrickConsoleQB.h" -#include "RebuildComponent.h" -#include "dZoneManager.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "MissionComponent.h" -#include "InventoryComponent.h" - -int32_t ImgBrickConsoleQB::ResetBricks = 30; -int32_t ImgBrickConsoleQB::ResetConsole = 60; -int32_t ImgBrickConsoleQB::ResetInteract = 45; - -void ImgBrickConsoleQB::OnStartup(Entity* self) -{ - self->SetNetworkVar(u"used", false); - - self->AddTimer("reset", ResetBricks); -} - -void ImgBrickConsoleQB::OnUse(Entity* self, Entity* user) -{ - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent->GetState() == REBUILD_COMPLETED) - { - if (!self->GetNetworkVar<bool>(u"used")) - { - const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); - - auto bothBuilt = false; - - for (auto* console : consoles) - { - auto* consoleRebuildComponent = console->GetComponent<RebuildComponent>(); - - if (consoleRebuildComponent->GetState() != REBUILD_COMPLETED) - { - continue; - } - - console->CancelAllTimers(); - - if (console->GetNetworkVar<bool>(u"used")) - { - bothBuilt = true; - } - } - - if (bothBuilt) - { - SmashCanister(self); - } - else - { - SpawnBrick(self); - } - - self->AddTimer("Die", ResetInteract); - - auto onFX = 0; - - const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); - - if (location == "Left") - { - onFX = 2776; - } - else - { - onFX = 2779; - } - - const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); - - if (!facility.empty()) - { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), onFX, u"create", location + "PipeOn"); - } - } - - auto* player = user; - - auto* missionComponent = player->GetComponent<MissionComponent>(); - auto* inventoryComponent = player->GetComponent<InventoryComponent>(); - - if (missionComponent != nullptr && inventoryComponent != nullptr) - { - if (missionComponent->GetMissionState(1302) == MissionState::MISSION_STATE_ACTIVE) - { - inventoryComponent->RemoveItem(13074, 1); - - missionComponent->ForceProgressTaskType(1302, 1, 1); - } - - if (missionComponent->GetMissionState(1926) == MissionState::MISSION_STATE_ACTIVE) - { - inventoryComponent->RemoveItem(14472, 1); - - missionComponent->ForceProgressTaskType(1926, 1, 1); - } - } - - self->SetNetworkVar(u"used", true); - - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); - } -} - -void ImgBrickConsoleQB::SpawnBrick(Entity* self) -{ - const auto netDevil = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug"); - if (!netDevil.empty()) - { - netDevil[0]->Reset(); - netDevil[0]->Deactivate(); - } - - const auto brick = dZoneManager::Instance()->GetSpawnersByName("Imagination"); - if (!brick.empty()) - { - brick[0]->Activate(); - } -} - -void ImgBrickConsoleQB::SmashCanister(Entity* self) -{ - const auto brick = EntityManager::Instance()->GetEntitiesInGroup("Imagination"); - if (!brick.empty()) - { - GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 122, u"create", "bluebrick"); - GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 1034, u"cast", "imaginationexplosion"); - } - - const auto canisters = EntityManager::Instance()->GetEntitiesInGroup("Canister"); - for (auto* canister : canisters) - { - canister->Smash(canister->GetObjectID(), VIOLENT); - } - - const auto canister = dZoneManager::Instance()->GetSpawnersByName("BrickCanister"); - if (!canister.empty()) - { - canister[0]->Reset(); - canister[0]->Deactivate(); - } -} - -void ImgBrickConsoleQB::OnRebuildComplete(Entity* self, Entity* target) -{ - auto energyFX = 0; - - const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); - - if (location == "Left") - { - energyFX = 2775; - } - else - { - energyFX = 2778; - } - - const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); - - if (!facility.empty()) - { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOff"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), energyFX, u"create", location + "PipeEnergy"); - } - - const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); - - for (auto* console : consoles) - { - auto* consoleRebuildComponent = console->GetComponent<RebuildComponent>(); - - if (consoleRebuildComponent->GetState() != REBUILD_COMPLETED) - { - continue; - } - - console->CancelAllTimers(); - } - - self->AddTimer("Die", ResetConsole); -} - -void ImgBrickConsoleQB::OnDie(Entity* self, Entity* killer) -{ - if (self->GetVar<bool>(u"Died")) - { - return; - } - - self->CancelAllTimers(); - - self->SetVar(u"Died", true); - - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent->GetState() == REBUILD_COMPLETED) - { - auto offFX = 0; - - const auto location = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"console")); - - if (location == "Left") - { - offFX = 2774; - } - else - { - offFX = 2777; - } - - const auto& facility = EntityManager::Instance()->GetEntitiesInGroup("FacilityPipes"); - - if (!facility.empty()) - { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOn"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), offFX, u"create", location + "PipeOff"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), 2750, u"create", location + "imagination_canister"); - } - } - - const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); - - const auto pipeGroup = myGroup.substr(0, 10); - - const auto firstPipe = pipeGroup + "1"; - - const auto samePipeSpawner = dZoneManager::Instance()->GetSpawnersByName(myGroup); - if (!samePipeSpawner.empty()) - { - samePipeSpawner[0]->Reset(); - samePipeSpawner[0]->Deactivate(); - } - - const auto firstPipeSpawner = dZoneManager::Instance()->GetSpawnersByName(firstPipe); - if (!firstPipeSpawner.empty()) - { - firstPipeSpawner[0]->Activate(); - } - - const auto netdevil = dZoneManager::Instance()->GetSpawnersByName("Imagination"); - if (!netdevil.empty()) - { - netdevil[0]->Reset(); - netdevil[0]->Deactivate(); - } - - const auto brick = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug"); - if (!brick.empty()) - { - brick[0]->Activate(); - } - - const auto canister = dZoneManager::Instance()->GetSpawnersByName("BrickCanister"); - if (!canister.empty()) - { - canister[0]->Activate(); - } - - self->SetNetworkVar(u"used", false); -} - -void ImgBrickConsoleQB::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "reset") - { - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent->GetState() == REBUILD_OPEN) - { - self->Smash(self->GetObjectID(), SILENT); - } - } - else if (timerName == "Die") - { - const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); - - for (auto* console : consoles) - { - console->Smash(console->GetObjectID(), VIOLENT); - } - } -} diff --git a/dScripts/ImgBrickConsoleQB.h b/dScripts/ImgBrickConsoleQB.h deleted file mode 100644 index f51f8e6c..00000000 --- a/dScripts/ImgBrickConsoleQB.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class ImgBrickConsoleQB : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void SpawnBrick(Entity* self); - void SmashCanister(Entity* self); - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnDie(Entity* self, Entity* killer) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -public: - static int32_t ResetBricks; - static int32_t ResetConsole; - static int32_t ResetInteract; -}; \ No newline at end of file diff --git a/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp b/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp deleted file mode 100644 index 307c6c73..00000000 --- a/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "InstanceExitTransferPlayerToLastNonInstance.h" -#include "GameMessages.h" -#include "Player.h" -#include "Character.h" -#include "dServer.h" - -void InstanceExitTransferPlayerToLastNonInstance::OnUse(Entity* self, Entity* user) -{ - auto transferText = self->GetVar<std::u16string>(u"transferText"); - if (transferText.empty()) - transferText = u"DRAGON_EXIT_QUESTION"; - - GameMessages::SendDisplayMessageBox( - user->GetObjectID(), - true, - self->GetObjectID(), - u"Instance_Exit", - 1, - transferText, - u"", - user->GetSystemAddress() - ); -} - -void InstanceExitTransferPlayerToLastNonInstance::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - auto* player = dynamic_cast<Player*>(sender); - if (player == nullptr) - return; - - auto* character = sender->GetCharacter(); - if (character != nullptr) { - if (identifier == u"Instance_Exit" && button == 1) { - auto lastInstance = character->GetLastNonInstanceZoneID(); - - // Sanity check - if (lastInstance == 0) { - switch (Game::server->GetZoneID()) - { - case 2001: - lastInstance = 2000; - break; - case 1402: - lastInstance = 1400; - break; - default: - lastInstance = 1100; - break; - } - } - - player->SendToZone(lastInstance); - } - } - - GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); -} - - diff --git a/dScripts/LegoDieRoll.cpp b/dScripts/LegoDieRoll.cpp deleted file mode 100644 index 386313be..00000000 --- a/dScripts/LegoDieRoll.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "LegoDieRoll.h" -#include "Entity.h" -#include "GameMessages.h" -#include "MissionComponent.h" - -void LegoDieRoll::OnStartup(Entity* self) { - self->AddTimer("DoneRolling", 10.0f); - self->AddTimer("ThrowDice", LegoDieRoll::animTime); -} - -void LegoDieRoll::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "DoneRolling") { - self->Smash(self->GetObjectID(), SILENT); - } - else if (timerName == "ThrowDice") { - int dieRoll = GeneralUtils::GenerateRandomNumber<int>(1, 6); - - switch (dieRoll) - { - case 1: - GameMessages::SendPlayAnimation(self, u"roll-die-1"); - break; - case 2: - GameMessages::SendPlayAnimation(self, u"roll-die-2"); - break; - case 3: - GameMessages::SendPlayAnimation(self, u"roll-die-3"); - break; - case 4: - GameMessages::SendPlayAnimation(self, u"roll-die-4"); - break; - case 5: - GameMessages::SendPlayAnimation(self, u"roll-die-5"); - break; - case 6: - { - GameMessages::SendPlayAnimation(self, u"roll-die-6"); - // tracking the It's Truly Random Achievement - auto* owner = self->GetOwner(); - auto* missionComponent = owner->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) { - const auto rollMissionState = missionComponent->GetMissionState(756); - if (rollMissionState == MissionState::MISSION_STATE_ACTIVE) { - missionComponent->ForceProgress(756, 1103, 1); - } - } - break; - } - default: - break; - } - } -} \ No newline at end of file diff --git a/dScripts/Lieutenant.cpp b/dScripts/Lieutenant.cpp deleted file mode 100644 index 91ffce63..00000000 --- a/dScripts/Lieutenant.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Lieutenant.h" -#include "SkillComponent.h" -#include "dZoneManager.h" - -void Lieutenant::OnStartup(Entity* self) -{ - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(1127, 24812, self->GetObjectID(), true); -} - -void Lieutenant::OnDie(Entity* self, Entity* killer) -{ - const auto myLOT = self->GetLOT(); - - std::string spawnerName; - - switch (myLOT) - { - case 16047: - spawnerName = "EarthShrine_ERail"; - break; - case 16050: - spawnerName = "IceShrine_QBBouncer"; - break; - case 16049: - spawnerName = "LightningShrine_LRail"; - break; - default: - return; - } - - const auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - - if (spawners.empty()) - { - return; - } - - for (auto* spawner : spawners) - { - spawner->Reset(); - spawner->Activate(); - } -} diff --git a/dScripts/MailBoxServer.cpp b/dScripts/MailBoxServer.cpp deleted file mode 100644 index 3e4e9687..00000000 --- a/dScripts/MailBoxServer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "MailBoxServer.h" -#include "AMFFormat.h" -#include "GameMessages.h" - -void MailBoxServer::OnUse(Entity* self, Entity* user) { - AMFStringValue* value = new AMFStringValue(); - value->SetStringValue("Mail"); - AMFArrayValue args; - args.InsertValue("state", value); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); - delete value; -} \ No newline at end of file diff --git a/dScripts/MailBoxServer.h b/dScripts/MailBoxServer.h deleted file mode 100644 index 9cd93e24..00000000 --- a/dScripts/MailBoxServer.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "CppScripts.h" - -class MailBoxServer : public CppScripts::Script { -public: - /** - * When a mailbox is interacted with, this method updates the player game state - * to be in a mailbox. - * - * @param self The object that owns this script. - * @param user The user that interacted with this Entity. - */ - void OnUse(Entity* self, Entity* user) override; -}; \ No newline at end of file diff --git a/dScripts/MastTeleport.cpp b/dScripts/MastTeleport.cpp deleted file mode 100644 index 94d5f552..00000000 --- a/dScripts/MastTeleport.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "MastTeleport.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "Preconditions.h" - -#ifdef _WIN32 -#define _USE_MATH_DEFINES -#include <math.h> -#endif - -void MastTeleport::OnStartup(Entity* self) -{ - self->SetNetworkVar<std::string>(u"hookPreconditions", "154;44", UNASSIGNED_SYSTEM_ADDRESS); -} - -void MastTeleport::OnRebuildComplete(Entity* self, Entity* target) -{ - if (Preconditions::Check(target, 154) && Preconditions::Check(target, 44)) - { - self->SetVar<LWOOBJID>(u"userID", target->GetObjectID()); - - GameMessages::SendSetStunned(target->GetObjectID(), PUSH, target->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true - ); - - self->AddTimer("Start", 3); - } -} - -void MastTeleport::OnTimerDone(Entity* self, std::string timerName) -{ - const auto playerId = self->GetVar<LWOOBJID>(u"userID"); - - auto* player = EntityManager::Instance()->GetEntity(playerId); - - if (player == nullptr) return; - - if (timerName == "Start") - { - auto position = self->GetPosition(); - auto rotation = self->GetRotation(); - - GameMessages::SendTeleport(playerId, position, rotation, player->GetSystemAddress(), true); - - // Hacky fix for odd rotations - if (self->GetVar<std::u16string>(u"MastName") != u"Jail") - { - GameMessages::SendOrientToAngle(playerId, true, (M_PI / 180) * 140.0f, player->GetSystemAddress()); - } - else - { - GameMessages::SendOrientToAngle(playerId, true, (M_PI / 180) * 100.0f, player->GetSystemAddress()); - } - - const auto cinematic = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Cinematic")); - const auto leanIn = self->GetVar<float>(u"LeanIn"); - - if (!cinematic.empty()) - { - GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(), - true, true, false, false, 0, false, leanIn - ); - } - - GameMessages::SendPlayFXEffect(playerId, 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); - - GameMessages::SendPlayAnimation(player, u"crow-swing-no-equip"); - - GameMessages::SendPlayAnimation(self, u"swing"); - - self->AddTimer("PlayerAnimDone", 6.25f); - } - else if (timerName == "PlayerAnimDone") - { - GameMessages::SendStopFXEffect(player, true, "hook"); - - auto forward = self->GetRotation().GetForwardVector(); - - const auto degrees = -25.0f; - - const auto rads = degrees * (static_cast<float>(M_PI) / 180.0f); - - const Vector3 newPlayerRot = {0, rads, 0}; - - auto position = self->GetPosition(); - - position.x += (forward.x * 20.5f); - position.y += 12; - position.z += (forward.z * 20.5f); - - GameMessages::SendOrientToAngle(playerId, true, rads, player->GetSystemAddress()); - - GameMessages::SendTeleport(playerId, position, NiQuaternion::IDENTITY, player->GetSystemAddress()); - - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true - ); - } -} diff --git a/dScripts/MinigameTreasureChestServer.cpp b/dScripts/MinigameTreasureChestServer.cpp deleted file mode 100644 index fc3f14c0..00000000 --- a/dScripts/MinigameTreasureChestServer.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "MinigameTreasureChestServer.h" -#include "ScriptedActivityComponent.h" -#include "TeamManager.h" -#include "EntityManager.h" -#include "dZoneManager.h" - -void MinigameTreasureChestServer::OnUse(Entity *self, Entity *user) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac == nullptr) - return; - - if (self->GetVar<bool>(u"used")) - return; - self->SetVar<bool>(u"used", true); - - if (!IsPlayerInActivity(self, user->GetObjectID())) - UpdatePlayer(self, user->GetObjectID()); - - auto* team = TeamManager::Instance()->GetTeam(user->GetObjectID()); - uint32_t activityRating = 0; - if (team != nullptr) { - for (const auto& teamMemberID : team->members) { - auto* teamMember = EntityManager::Instance()->GetEntity(teamMemberID); - if (teamMember != nullptr) { - activityRating = CalculateActivityRating(self, teamMemberID); - - if (self->GetLOT() == frakjawChestId) activityRating = team->members.size(); - - LootGenerator::Instance().DropActivityLoot(teamMember, self, sac->GetActivityID(), activityRating); - } - } - } else { - activityRating = CalculateActivityRating(self, user->GetObjectID()); - - if (self->GetLOT() == frakjawChestId) activityRating = 1; - - LootGenerator::Instance().DropActivityLoot(user, self, sac->GetActivityID(), activityRating); - } - - sac->PlayerRemove(user->GetObjectID()); - - auto* zoneControl = dZoneManager::Instance()->GetZoneControlObject(); - if (zoneControl != nullptr) { - zoneControl->OnFireEventServerSide(self, "Survival_Update", 0); - } - - self->Smash(self->GetObjectID()); -} - -uint32_t MinigameTreasureChestServer::CalculateActivityRating(Entity *self, LWOOBJID playerID) { - auto* team = TeamManager::Instance()->GetTeam(playerID); - return team != nullptr ? team->members.size() * 100 : ActivityManager::CalculateActivityRating(self, playerID) * 100; -} - -void MinigameTreasureChestServer::OnStartup(Entity *self) { - - // BONS treasure chest thinks it's on FV, causing it to start a lobby - if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1204) { - auto* sac = self->GetComponent<ScriptedActivityComponent>(); - if (sac != nullptr) { - sac->SetInstanceMapID(1204); - } - } -} diff --git a/dScripts/MinigameTreasureChestServer.h b/dScripts/MinigameTreasureChestServer.h deleted file mode 100644 index c718f016..00000000 --- a/dScripts/MinigameTreasureChestServer.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "ActivityManager.h" - -class MinigameTreasureChestServer : public ActivityManager { -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - uint32_t CalculateActivityRating(Entity *self, LWOOBJID playerID) override; -private: - const uint32_t frakjawChestId = 16486; -}; diff --git a/dScripts/MonCoreNookDoors.cpp b/dScripts/MonCoreNookDoors.cpp deleted file mode 100644 index c3fcf9be..00000000 --- a/dScripts/MonCoreNookDoors.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "MonCoreNookDoors.h" -#include "dZoneManager.h" - -void MonCoreNookDoors::OnStartup(Entity* self) -{ - SpawnDoor(self); -} - -void MonCoreNookDoors::SpawnDoor(Entity* self) -{ - const auto doorNum = self->GetVarAsString(u"number"); - - if (doorNum.empty()) - { - return; - } - - const auto spawners = dZoneManager::Instance()->GetSpawnersByName("MonCoreNookDoor0" + doorNum); - - if (spawners.empty()) - { - return; - } - - auto* spawner = spawners[0]; - - spawner->Reset(); - spawner->Activate(); -} - -void MonCoreNookDoors::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - if (args == "DoorSmashed") - { - self->AddTimer("RespawnDoor", 30); - } -} - -void MonCoreNookDoors::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "RespawnDoor") - { - SpawnDoor(self); - } -} diff --git a/dScripts/MonCoreNookDoors.h b/dScripts/MonCoreNookDoors.h deleted file mode 100644 index a7ad7906..00000000 --- a/dScripts/MonCoreNookDoors.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class MonCoreNookDoors : public CppScripts::Script { -public: - void OnStartup(Entity* self) override; - - void SpawnDoor(Entity* self); - - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - - void OnTimerDone(Entity* self, std::string timerName) override; -}; - diff --git a/dScripts/NPCAddRemoveItem.cpp b/dScripts/NPCAddRemoveItem.cpp index 58c46ac0..13677072 100644 --- a/dScripts/NPCAddRemoveItem.cpp +++ b/dScripts/NPCAddRemoveItem.cpp @@ -1,30 +1,31 @@ #include "NPCAddRemoveItem.h" #include "InventoryComponent.h" +#include "eMissionState.h" -void NPCAddRemoveItem::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - auto* inventory = target->GetComponent<InventoryComponent>(); - if (inventory == nullptr) - return; +void NPCAddRemoveItem::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* inventory = target->GetComponent<InventoryComponent>(); + if (inventory == nullptr) + return; - for (const auto& missionSetting : m_MissionItemSettings) { - if (missionSetting.first == missionID) { - for (const auto& itemSetting : missionSetting.second) { - for (const auto& lot : itemSetting.items) { - if (itemSetting.add && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE)) { - inventory->AddItem(lot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (itemSetting.remove && (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE)) { - inventory->RemoveItem(lot, 1); - } - } - } - } - } + for (const auto& missionSetting : m_MissionItemSettings) { + if (missionSetting.first == missionID) { + for (const auto& itemSetting : missionSetting.second) { + for (const auto& lot : itemSetting.items) { + if (itemSetting.add && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE)) { + inventory->AddItem(lot, 1, eLootSourceType::NONE); + } else if (itemSetting.remove && (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE)) { + inventory->RemoveItem(lot, 1); + } + } + } + } + } } std::map<uint32_t, std::vector<ItemSetting>> NPCAddRemoveItem::GetSettings() { - return std::map<uint32_t, std::vector<ItemSetting>>(); + return std::map<uint32_t, std::vector<ItemSetting>>(); } -void NPCAddRemoveItem::OnStartup(Entity *self) { - m_MissionItemSettings = GetSettings(); +void NPCAddRemoveItem::OnStartup(Entity* self) { + m_MissionItemSettings = GetSettings(); } diff --git a/dScripts/NPCAddRemoveItem.h b/dScripts/NPCAddRemoveItem.h index 1b4aba13..73a7f2c9 100644 --- a/dScripts/NPCAddRemoveItem.h +++ b/dScripts/NPCAddRemoveItem.h @@ -2,9 +2,9 @@ #include "CppScripts.h" struct ItemSetting { - std::vector<LOT> items; // The items to add/remove - bool add; // Add items on mission accept - bool remove; // Remove items on mission complete + std::vector<LOT> items; // The items to add/remove + bool add; // Add items on mission accept + bool remove; // Remove items on mission complete }; /** @@ -12,9 +12,9 @@ struct ItemSetting { */ class NPCAddRemoveItem : public CppScripts::Script { protected: - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - virtual std::map<uint32_t, std::vector<ItemSetting>> GetSettings(); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + virtual std::map<uint32_t, std::vector<ItemSetting>> GetSettings(); private: - void OnStartup(Entity *self) override; - std::map<uint32_t, std::vector<ItemSetting>> m_MissionItemSettings; + void OnStartup(Entity* self) override; + std::map<uint32_t, std::vector<ItemSetting>> m_MissionItemSettings; }; diff --git a/dScripts/NjColeNPC.cpp b/dScripts/NjColeNPC.cpp deleted file mode 100644 index 1b889445..00000000 --- a/dScripts/NjColeNPC.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "NjColeNPC.h" -#include "MissionComponent.h" -#include "InventoryComponent.h" - -void NjColeNPC::OnEmoteReceived(Entity* self, int32_t emote, Entity* target) -{ - if (emote != 393) - { - return; - } - - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - - if (inventoryComponent == nullptr) - { - return; - } - - if (!inventoryComponent->IsEquipped(14499) && !inventoryComponent->IsEquipped(16644)) - { - return; - } - - auto* missionComponent = target->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - return; - } - - missionComponent->ForceProgressTaskType(1818, 1, 1); -} - -void NjColeNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); - - if (missionID == 1818 && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) - { - auto* missionComponent = target->GetComponent<MissionComponent>(); - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - - if (missionComponent == nullptr || inventoryComponent == nullptr) - { - return; - } - - if (inventoryComponent->GetLotCount(14499) > 0) - { - inventoryComponent->RemoveItem(14499, 1); - } - else - { - return; - } - - inventoryComponent->AddItem(16644, 1, eLootSourceType::LOOT_SOURCE_NONE); - } -} diff --git a/dScripts/NjColeNPC.h b/dScripts/NjColeNPC.h deleted file mode 100644 index c6421a66..00000000 --- a/dScripts/NjColeNPC.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "NjNPCMissionSpinjitzuServer.h" - -class NjColeNPC : public NjNPCMissionSpinjitzuServer { - void OnEmoteReceived(Entity* self, int32_t emote, Entity* target) override; - - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; -}; diff --git a/dScripts/NjDragonEmblemChestServer.cpp b/dScripts/NjDragonEmblemChestServer.cpp deleted file mode 100644 index ea699c55..00000000 --- a/dScripts/NjDragonEmblemChestServer.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "NjDragonEmblemChestServer.h" -#include "Character.h" -#include "DestroyableComponent.h" - -void NjDragonEmblemChestServer::OnUse(Entity *self, Entity *user) { - auto* character = user->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(NJ_WU_SHOW_DAILY_CHEST, false); - } - - auto* destroyable = self->GetComponent<DestroyableComponent>(); - if (destroyable != nullptr) { - LootGenerator::Instance().DropLoot(user, self, destroyable->GetLootMatrixID(), 0, 0); - } -} diff --git a/dScripts/NjEarthDragonPetServer.cpp b/dScripts/NjEarthDragonPetServer.cpp deleted file mode 100644 index 2b91f33c..00000000 --- a/dScripts/NjEarthDragonPetServer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "NjEarthDragonPetServer.h" -#include "Entity.h" - -void NjEarthDragonPetServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 16210); - self->SetVar<std::string>(u"petType", "earthpet"); - self->SetVar<uint32_t>(u"maxPets", 3); - self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); - self->SetVar<std::u16string>(u"spawnCinematic", u"EarthPetSpawn"); -} diff --git a/dScripts/NjEarthPetServer.cpp b/dScripts/NjEarthPetServer.cpp deleted file mode 100644 index 12036355..00000000 --- a/dScripts/NjEarthPetServer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "NjEarthPetServer.h" -#include "PetComponent.h" - -void NjEarthPetServer::OnStartup(Entity *self) { - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwnerId() != LWOOBJID_EMPTY) - return; - - // Removes the chocolate bars - petComponent->SetPreconditions(const_cast<std::string &>(m_Precondition)); - PetFromObjectServer::OnStartup(self); -} diff --git a/dScripts/NjGarmadonCelebration.cpp b/dScripts/NjGarmadonCelebration.cpp deleted file mode 100644 index ab71e092..00000000 --- a/dScripts/NjGarmadonCelebration.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "NjGarmadonCelebration.h" -#include "Character.h" -#include "GameMessages.h" - -void NjGarmadonCelebration::OnCollisionPhantom(Entity *self, Entity *target) { - auto* character = target->GetCharacter(); - - if (character == nullptr) { - return; - } - - if (!character->GetPlayerFlag(ePlayerFlags::NJ_GARMADON_CINEMATIC_SEEN)) { - character->SetPlayerFlag(ePlayerFlags::NJ_GARMADON_CINEMATIC_SEEN, true); - - GameMessages::SendStartCelebrationEffect(target, target->GetSystemAddress(), GarmadonCelebrationID); - } -} diff --git a/dScripts/NjGarmadonCelebration.h b/dScripts/NjGarmadonCelebration.h deleted file mode 100644 index 858ecfce..00000000 --- a/dScripts/NjGarmadonCelebration.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NjGarmadonCelebration : public CppScripts::Script { - void OnCollisionPhantom(Entity *self, Entity *target) override; -private: - const int32_t GarmadonCelebrationID = 23; -}; diff --git a/dScripts/NjIceRailActivator.cpp b/dScripts/NjIceRailActivator.cpp deleted file mode 100644 index dbf0acd6..00000000 --- a/dScripts/NjIceRailActivator.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "NjIceRailActivator.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void NjIceRailActivator::OnPlayerRailArrived(Entity *self, Entity *sender, const std::u16string &pathName, - int32_t waypoint) { - const auto breakPoint = self->GetVar<int32_t>(BreakpointVariable); - if (breakPoint == waypoint) { - const auto& blockGroup = self->GetVar<std::u16string>(BlockGroupVariable); - - for (auto* block : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(blockGroup))) { - GameMessages::SendPlayAnimation(block, u"explode"); - - const auto blockID = block->GetObjectID(); - - self->AddCallbackTimer(1.0f, [self, blockID]() { - auto* block = EntityManager::Instance()->GetEntity(blockID); - - if (block != nullptr) { - block->Kill(self); - } - }); - } - } -} diff --git a/dScripts/NjIceRailActivator.h b/dScripts/NjIceRailActivator.h deleted file mode 100644 index dd56be62..00000000 --- a/dScripts/NjIceRailActivator.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "NjRailActivatorsServer.h" - -class NjIceRailActivator : public NjRailActivatorsServer{ - void OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName, int32_t waypoint) override; -private: - std::u16string BreakpointVariable = u"BreakPoint"; - std::u16string BlockGroupVariable = u"BlockGroup"; - std::u16string IceBlockVariable = u"IceBlock"; -}; diff --git a/dScripts/NjJayMissionItems.cpp b/dScripts/NjJayMissionItems.cpp deleted file mode 100644 index c4b037bb..00000000 --- a/dScripts/NjJayMissionItems.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "NjJayMissionItems.h" - -void NjJayMissionItems::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); - NPCAddRemoveItem::OnMissionDialogueOK(self, target, missionID, missionState); -} - -std::map<uint32_t, std::vector<ItemSetting>> NjJayMissionItems::GetSettings() { - return { - {1789, {{{14474},false, true}}}, - {1927, {{{14493},false, true}}} - }; -} diff --git a/dScripts/NjMonastryBossInstance.cpp b/dScripts/NjMonastryBossInstance.cpp deleted file mode 100644 index cd34ea2c..00000000 --- a/dScripts/NjMonastryBossInstance.cpp +++ /dev/null @@ -1,523 +0,0 @@ -#include "NjMonastryBossInstance.h" -#include "RebuildComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "dZoneManager.h" -#include "GameMessages.h" -#include "BaseCombatAIComponent.h" -#include "BuffComponent.h" -#include "SkillComponent.h" -#include "TeamManager.h" -#include <algorithm> - -// // // // // // // -// Event handling // -// // // // // // // - -void NjMonastryBossInstance::OnStartup(Entity *self) { - auto spawnerNames = std::vector<std::string> { LedgeFrakjawSpawner, LowerFrakjawSpawner, BaseEnemiesSpawner + std::to_string(1), - BaseEnemiesSpawner + std::to_string(2), BaseEnemiesSpawner + std::to_string(3), - BaseEnemiesSpawner + std::to_string(4), CounterweightSpawner }; - - // Add a notification request for all the spawned entities, corresponds to notifySpawnedObjectLoaded - for (const auto& spawnerName : spawnerNames) { - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - spawner->AddEntitySpawnedCallback([self, this](Entity* entity) { - const auto lot = entity->GetLOT(); - switch (lot) { - case LedgedFrakjawLOT: - NjMonastryBossInstance::HandleLedgedFrakjawSpawned(self, entity); - return; - case CounterWeightLOT: - NjMonastryBossInstance::HandleCounterWeightSpawned(self, entity); - return; - case LowerFrakjawLOT: - NjMonastryBossInstance::HandleLowerFrakjawSpawned(self, entity); - return; - default: - NjMonastryBossInstance::HandleWaveEnemySpawned(self, entity); - return; - } - }); - } - } -} - -void NjMonastryBossInstance::OnPlayerLoaded(Entity *self, Entity *player) { - ActivityTimerStop(self, WaitingForPlayersTimer); - - // Join the player in the activity - UpdatePlayer(self, player->GetObjectID()); - - // Buff the player - auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->SetHealth((int32_t) destroyableComponent->GetMaxHealth()); - destroyableComponent->SetArmor((int32_t) destroyableComponent->GetMaxArmor()); - destroyableComponent->SetImagination((int32_t) destroyableComponent->GetMaxImagination()); - } - - // Add player ID to instance - auto totalPlayersLoaded = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable); - totalPlayersLoaded.push_back(player->GetObjectID()); - - // Properly position the player - self->SetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable, totalPlayersLoaded); - // This was always spawning all players at position one before and other values cause players to be invisible. - TeleportPlayer(player, 1); - - // Large teams face a tougher challenge - if (totalPlayersLoaded.size() >= 3) - self->SetVar<bool>(LargeTeamVariable, true); - - // Start the game if all players in the team have loaded - auto* team = TeamManager::Instance()->GetTeam(player->GetObjectID()); - if (team == nullptr || totalPlayersLoaded.size() == team->members.size()) { - StartFight(self); - return; - } - - self->AddCallbackTimer(0.0f, [self, player]() { - if (player != nullptr) { - // If we don't have enough players yet, wait for the others to load and notify the client to play a cool cinematic - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLoaded", 0, 0, - player->GetObjectID(), "", player->GetSystemAddress()); - } - }); - - ActivityTimerStart(self, WaitingForPlayersTimer, 45.0f, 45.0f); -} - -void NjMonastryBossInstance::OnPlayerExit(Entity *self, Entity *player) { - UpdatePlayer(self, player->GetObjectID(), true); - // Fetch the total players loaded from the vars - auto totalPlayersLoaded = self->GetVar<std::vector<LWOOBJID> >(TotalPlayersLoadedVariable); - - // Find the player to remove - auto playerToRemove = std::find(totalPlayersLoaded.begin(), totalPlayersLoaded.end(), player->GetObjectID()); - - // If we found the player remove them from out list of players - if (playerToRemove != totalPlayersLoaded.end()) { - totalPlayersLoaded.erase(playerToRemove); - } else { - Game::logger->Log("NjMonastryBossInstance", "Failed to remove player at exit.\n"); - } - - // Set the players loaded var back - self->SetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable, totalPlayersLoaded); - - // Since this is an exit method, check if enough players have left. If enough have left - // resize the instance to account for such. - if (totalPlayersLoaded.size() <= 2) self->SetVar<bool>(LargeTeamVariable, false); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); -} - -void NjMonastryBossInstance::OnActivityTimerDone(Entity *self, const std::string &name) { - auto split = GeneralUtils::SplitString(name, TimerSplitChar); - auto timerName = split[0]; - auto objectID = split.size() > 1 ? (LWOOBJID) std::stoull(split[1]) : LWOOBJID_EMPTY; - - if (timerName == WaitingForPlayersTimer) { - StartFight(self); - } else if (timerName == SpawnNextWaveTimer) { - auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); - if (frakjaw != nullptr) { - SummonWave(self, frakjaw); - } - } else if (timerName == SpawnWaveTimer) { - auto wave = self->GetVar<uint32_t>(WaveNumberVariable); - self->SetVar<uint32_t>(WaveNumberVariable, wave + 1); - self->SetVar<uint32_t>(TotalAliveInWaveVariable, 0); - - if (wave < m_Waves.size()) { - auto waves = m_Waves.at(wave); - auto counter = 0; - - for (const auto& waveEnemy : waves) { - const auto numberToSpawn = self->GetVar<bool>(LargeTeamVariable) - ? waveEnemy.largeNumber : waveEnemy.smallNumber; - - auto spawnIndex = counter % 4 + 1; - SpawnOnNetwork(self, waveEnemy.lot, numberToSpawn, BaseEnemiesSpawner + std::to_string(spawnIndex)); - counter++; - } - } - } else if (timerName + TimerSplitChar == UnstunTimer) { - auto* entity = EntityManager::Instance()->GetEntity(objectID); - if (entity != nullptr) { - auto* combatAI = entity->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetDisabled(false); - } - } - } else if (timerName == SpawnCounterWeightTimer) { - auto spawners = dZoneManager::Instance()->GetSpawnersByName(CounterweightSpawner); - if (!spawners.empty()) { - // Spawn the counter weight at a specific waypoint, there's one for each round - auto* spawner = spawners.front(); - - spawner->Spawn({ - spawner->m_Info.nodes.at((self->GetVar<uint32_t>(WaveNumberVariable) - 1) % 3) - }, true); - } - } else if (timerName == LowerFrakjawCamTimer) { - // Destroy the frakjaw on the ledge - auto* ledgeFrakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); - if (ledgeFrakjaw != nullptr) { - ledgeFrakjaw->Kill(); - } - - ActivityTimerStart(self, SpawnLowerFrakjawTimer, 1.0f, 1.0f); - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BottomFrakSpawn, UNASSIGNED_SYSTEM_ADDRESS); - } else if (timerName == SpawnLowerFrakjawTimer) { - auto spawners = dZoneManager::Instance()->GetSpawnersByName(LowerFrakjawSpawner); - if (!spawners.empty()) { - auto* spawner = spawners.front(); - spawner->Activate(); - } - } else if (timerName == SpawnRailTimer) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, FireRailSpawn, UNASSIGNED_SYSTEM_ADDRESS); - - auto spawners = dZoneManager::Instance()->GetSpawnersByName(FireRailSpawner); - if (!spawners.empty()) { - auto* spawner = spawners.front(); - spawner->Activate(); - } - } else if (timerName + TimerSplitChar == FrakjawSpawnInTimer) { - auto* lowerFrakjaw = EntityManager::Instance()->GetEntity(objectID); - if (lowerFrakjaw != nullptr) { - LowerFrakjawSummon(self, lowerFrakjaw); - } - } else if (timerName == WaveOverTimer) { - WaveOver(self); - } else if (timerName == FightOverTimer) { - FightOver(self); - } -} - -// // // // // // // // -// Custom functions // -// // // // // // // // - -void NjMonastryBossInstance::StartFight(Entity *self) { - if (self->GetVar<bool>(FightStartedVariable)) - return; - - self->SetVar<bool>(FightStartedVariable, true); - - // Activate the frakjaw spawner - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(LedgeFrakjawSpawner)) { - spawner->Activate(); - } -} - -void NjMonastryBossInstance::HandleLedgedFrakjawSpawned(Entity *self, Entity *ledgedFrakjaw) { - self->SetVar<LWOOBJID>(LedgeFrakjawVariable, ledgedFrakjaw->GetObjectID()); - SummonWave(self, ledgedFrakjaw); -} - -void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity *self, Entity *counterWeight) { - auto* rebuildComponent = counterWeight->GetComponent<RebuildComponent>(); - if (rebuildComponent != nullptr) { - rebuildComponent->AddRebuildStateCallback([this, self, counterWeight](eRebuildState state) { - - switch (state) { - case REBUILD_BUILDING: - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, - 0, 0, counterWeight->GetObjectID(), - BaseCounterweightQB + std::to_string(self->GetVar<uint32_t>(WaveNumberVariable)), - UNASSIGNED_SYSTEM_ADDRESS); - return; - case REBUILD_INCOMPLETE: - GameMessages::SendNotifyClientObject(self->GetObjectID(), EndCinematicNotification, - 0, 0, LWOOBJID_EMPTY,"", - UNASSIGNED_SYSTEM_ADDRESS); - return; - case REBUILD_RESETTING: - ActivityTimerStart(self, SpawnCounterWeightTimer, 0.0f, 0.0f); - return; - case REBUILD_COMPLETED: { - // TODO: Move the platform? - - // The counterweight is actually a moving platform and we should listen to the last waypoint event here - // 0.5f is a rough estimate of that path, though, and results in less needed logic - self->AddCallbackTimer(0.5f, [this, self, counterWeight]() { - if (counterWeight != nullptr) { - counterWeight->Kill(); - } - - auto* frakjaw = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(LedgeFrakjawVariable)); - if (frakjaw == nullptr) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, - 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - return; - } - - auto* skillComponent = frakjaw->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->CalculateBehavior(1635, 39097, frakjaw->GetObjectID(), true, false); - } - - GameMessages::SendPlayAnimation(frakjaw, StunnedAnimation); - GameMessages::SendPlayNDAudioEmitter(frakjaw, UNASSIGNED_SYSTEM_ADDRESS, CounterSmashAudio); - - // Before wave 4 we should lower frakjaw from the ledge - if (self->GetVar<uint32_t>(WaveNumberVariable) == 3) { - LowerFrakjaw(self, frakjaw); - return; - } - - ActivityTimerStart(self, SpawnNextWaveTimer, 2.0f, 2.0f); - }); - } - default: - return; - } - }); - } -} - -void NjMonastryBossInstance::HandleLowerFrakjawSpawned(Entity *self, Entity *lowerFrakjaw) { - GameMessages::SendPlayAnimation(lowerFrakjaw, TeleportInAnimation); - self->SetVar<LWOOBJID>(LowerFrakjawVariable, lowerFrakjaw->GetObjectID()); - - auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetDisabled(true); - } - - auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>(); - if (destroyableComponent != nullptr) { - destroyableComponent->AddOnHitCallback([this, self, lowerFrakjaw](Entity* attacker) { - NjMonastryBossInstance::HandleLowerFrakjawHit(self, lowerFrakjaw, attacker); - }); - } - - lowerFrakjaw->AddDieCallback([this, self, lowerFrakjaw]() { - NjMonastryBossInstance::HandleLowerFrakjawDied(self, lowerFrakjaw); - }); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - - if (self->GetVar<bool>(LargeTeamVariable)) { - // Double frakjaws health for large teams - if (destroyableComponent != nullptr) { - const auto doubleHealth = destroyableComponent->GetHealth() * 2; - destroyableComponent->SetHealth(doubleHealth); - destroyableComponent->SetMaxHealth((float_t) doubleHealth); - } - - ActivityTimerStart(self, FrakjawSpawnInTimer + std::to_string(lowerFrakjaw->GetObjectID()), - 2.0f, 2.0f); - ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), - 7.0f, 7.0f); - } else { - ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), - 5.0f, 5.0f); - } -} - -void NjMonastryBossInstance::HandleLowerFrakjawHit(Entity *self, Entity *lowerFrakjaw, Entity *attacker) { - auto* destroyableComponent = lowerFrakjaw->GetComponent<DestroyableComponent>(); - if (destroyableComponent == nullptr) - return; - - // Progress the fight to the last wave if frakjaw has less than 50% of his health left - if (destroyableComponent->GetHealth() <= (uint32_t) destroyableComponent->GetMaxHealth() / 2 && !self->GetVar<bool>(OnLastWaveVarbiale)) { - self->SetVar<bool>(OnLastWaveVarbiale, true); - - // Stun frakjaw during the cinematic - auto* combatAI = lowerFrakjaw->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetDisabled(true); - } - ActivityTimerStart(self, UnstunTimer + std::to_string(lowerFrakjaw->GetObjectID()), 5.0f, 5.0f); - - const auto trashMobsAlive = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); - std::vector<LWOOBJID> newTrashMobs = {}; - - for (const auto& trashMobID : trashMobsAlive) { - auto* trashMob = EntityManager::Instance()->GetEntity(trashMobID); - if (trashMob != nullptr) { - newTrashMobs.push_back(trashMobID); - - // Stun all the enemies until the cinematic is over - auto* trashMobCombatAI = trashMob->GetComponent<BaseCombatAIComponent>(); - if (trashMobCombatAI != nullptr) { - trashMobCombatAI->SetDisabled(true); - } - ActivityTimerStart(self, UnstunTimer + std::to_string(trashMobID), 5.0f, 5.0f); - } - } - - self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, newTrashMobs); - - LowerFrakjawSummon(self, lowerFrakjaw); - RemovePoison(self); - } -} - -void NjMonastryBossInstance::HandleLowerFrakjawDied(Entity *self, Entity *lowerFrakjaw) { - ActivityTimerStart(self, FightOverTimer, 2.0f, 2.0f); -} - -void NjMonastryBossInstance::HandleWaveEnemySpawned(Entity *self, Entity *waveEnemy) { - waveEnemy->AddDieCallback([this, self, waveEnemy]() { - NjMonastryBossInstance::HandleWaveEnemyDied(self, waveEnemy); - }); - - auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); - waveEnemies.push_back(waveEnemy->GetObjectID()); - self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies); - - auto* combatAI = waveEnemy->GetComponent<BaseCombatAIComponent>(); - if (combatAI != nullptr) { - combatAI->SetDisabled(true); - ActivityTimerStart(self, UnstunTimer + std::to_string(waveEnemy->GetObjectID()), 3.0f, 3.0f); - } -} - -void NjMonastryBossInstance::HandleWaveEnemyDied(Entity *self, Entity* waveEnemy) { - auto waveEnemies = self->GetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable); - waveEnemies.erase(std::remove(waveEnemies.begin(), waveEnemies.end(), waveEnemy->GetObjectID()), waveEnemies.end()); - self->SetVar<std::vector<LWOOBJID>>(TrashMobsAliveVariable, waveEnemies); - - if (waveEnemies.empty()) { - ActivityTimerStart(self, WaveOverTimer, 2.0f, 2.0f); - } -} - -void NjMonastryBossInstance::TeleportPlayer(Entity *player, uint32_t position) { - for (const auto* spawnPoint : EntityManager::Instance()->GetEntitiesInGroup("SpawnPoint" + std::to_string(position))) { - GameMessages::SendTeleport(player->GetObjectID(), spawnPoint->GetPosition(), spawnPoint->GetRotation(), - player->GetSystemAddress(), true); - } -} - -void NjMonastryBossInstance::SummonWave(Entity* self, Entity* frakjaw) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, - LedgeFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendPlayAnimation(frakjaw, SummonAnimation); - - // Stop the music for the first, fourth and fifth wave - const auto wave = self->GetVar<uint32_t>(WaveNumberVariable); - if (wave >= 1 || wave < (m_Waves.size() - 1)) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave - 1), - UNASSIGNED_SYSTEM_ADDRESS); - } - - // After frakjaw moves down the music stays the same - if (wave < (m_Waves.size() - 1)) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), StartMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave), - UNASSIGNED_SYSTEM_ADDRESS); - } - - ActivityTimerStart(self, SpawnWaveTimer, 4.0f, 4.0f); -} - -void NjMonastryBossInstance::LowerFrakjawSummon(Entity *self, Entity *frakjaw) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BottomFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); - ActivityTimerStart(self, SpawnWaveTimer, 2.0f, 2.0f); - GameMessages::SendPlayAnimation(frakjaw, SummonAnimation); -} - -void NjMonastryBossInstance::RemovePoison(Entity *self) { - const auto& totalPlayer = self->GetVar<std::vector<LWOOBJID>>(TotalPlayersLoadedVariable); - for (const auto& playerID : totalPlayer) { - - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { - - auto* buffComponent = player->GetComponent<BuffComponent>(); - if (buffComponent != nullptr) { - buffComponent->RemoveBuff(PoisonBuff); - } - } - } -} - -void NjMonastryBossInstance::LowerFrakjaw(Entity *self, Entity* frakjaw) { - GameMessages::SendPlayAnimation(frakjaw, TeleportOutAnimation); - ActivityTimerStart(self, LowerFrakjawCamTimer, 2.0f, 2.0f); - - GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 3), UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StartMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), UNASSIGNED_SYSTEM_ADDRESS); -} - -void NjMonastryBossInstance::SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName) { - auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); - if (spawners.empty() || numberToSpawn <= 0) - return; - - auto* spawner = spawners.front(); - - // Spawn the lot N times - spawner->SetSpawnLot(toSpawn); - for (auto i = 0; i < numberToSpawn; i++) - spawner->Spawn({ spawner->m_Info.nodes.at(i % spawner->m_Info.nodes.size()) }, true); -} - -void NjMonastryBossInstance::WaveOver(Entity *self) { - auto wave = self->GetVar<uint32_t>(WaveNumberVariable); - if (wave >= m_Waves.size() - 1) - return; - - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BaseCounterweightSpawn + std::to_string(wave), - UNASSIGNED_SYSTEM_ADDRESS); - ActivityTimerStart(self, SpawnCounterWeightTimer, 1.5f, 1.5f); - RemovePoison(self); -} - -void NjMonastryBossInstance::FightOver(Entity *self) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"GroundFrakjawDead", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - - // Remove all the enemies from the battlefield - for (auto i = 1; i < 5; i++) { - auto spawners = dZoneManager::Instance()->GetSpawnersByName(BaseEnemiesSpawner + std::to_string(i)); - if (!spawners.empty()) { - auto* spawner = spawners.front(); - spawner->Deactivate(); - spawner->Reset(); - } - } - - RemovePoison(self); - ActivityTimerStart(self, SpawnRailTimer, 1.5f, 1.5f); - - // Set the music to play the victory music - GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(self->GetObjectID(), FlashMusicNotification, 0, 0, - LWOOBJID_EMPTY, "Monastery_Frakjaw_Battle_Win", UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, TreasureChestSpawning, UNASSIGNED_SYSTEM_ADDRESS); - - auto treasureChests = EntityManager::Instance()->GetEntitiesInGroup(ChestSpawnpointGroup); - for (auto* treasureChest : treasureChests) { - auto info = EntityInfo {}; - - info.lot = ChestLOT; - info.pos = treasureChest->GetPosition(); - info.rot = treasureChest->GetRotation(); - info.spawnerID = self->GetObjectID(); - info.settings = { - new LDFData<LWOOBJID>(u"parent_tag", self->GetObjectID()) - }; - - // Finally spawn a treasure chest at the correct spawn point - auto* chestObject = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(chestObject); - } -} diff --git a/dScripts/NjMonastryBossInstance.h b/dScripts/NjMonastryBossInstance.h deleted file mode 100644 index 6153d84f..00000000 --- a/dScripts/NjMonastryBossInstance.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once -#include "ActivityManager.h" - -enum FrakjawEnemies { - BoneWolf = 16191, - BlackSmith = 14007, - Marksman = 14008, - Commando = 14009, - MadScientist = 16511 -}; - -enum FrakjawLots : LOT { - ChestLOT = 16486, - LedgedFrakjawLOT = 16289, - LowerFrakjawLOT = 16048, - CounterWeightLOT = 16141 -}; - -struct FrakjawWaveEnemy { - LOT lot; - uint32_t largeNumber; - uint32_t smallNumber; -}; - -class NjMonastryBossInstance : public ActivityManager { -public: - void OnStartup(Entity* self) override; - void OnPlayerLoaded(Entity* self, Entity* player) override; - void OnPlayerExit(Entity* self, Entity* player) override; - void OnActivityTimerDone(Entity *self, const std::string &name) override; -private: - void StartFight(Entity* self); - void WaveOver(Entity* self); - void FightOver(Entity* self); - void SummonWave(Entity* self, Entity* frakjaw); - void LowerFrakjaw(Entity* self, Entity* frakjaw); - void LowerFrakjawSummon(Entity* self, Entity* frakjaw); - void RemovePoison(Entity* self); - static void SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName); - static void TeleportPlayer(Entity* player, uint32_t position); - - // Event handlers for anything spawned by the main spawner - void HandleLedgedFrakjawSpawned(Entity* self, Entity* ledgedFrakjaw); - void HandleCounterWeightSpawned(Entity* self, Entity* counterWeight); - void HandleLowerFrakjawSpawned(Entity* self, Entity* lowerFrakjaw); - void HandleWaveEnemySpawned(Entity* self, Entity* waveEnemy); - void HandleWaveEnemyDied(Entity* self, Entity* waveEnemy); - void HandleLowerFrakjawHit(Entity* self, Entity* lowerFrakjaw, Entity* attacker); - void HandleLowerFrakjawDied(Entity* self, Entity* lowerFrakjaw); - - const std::vector<std::vector<FrakjawWaveEnemy>> m_Waves = { - // Wave 1 - { - { FrakjawEnemies::Marksman, 2, 1}, - { FrakjawEnemies::BlackSmith, 4, 3}, - { FrakjawEnemies::Commando, 2, 1}, - { FrakjawEnemies::MadScientist, 1, 0}, - }, - - // Wave 2 - { - { FrakjawEnemies::BoneWolf, 1, 0}, - { FrakjawEnemies::BlackSmith, 2, 2}, - { FrakjawEnemies::Marksman, 2, 1}, - { FrakjawEnemies::MadScientist, 1, 1}, - }, - - // Wave 3 - { - { FrakjawEnemies::BoneWolf, 2, 1}, - { FrakjawEnemies::Marksman, 2, 1}, - { FrakjawEnemies::Commando, 2, 2}, - { FrakjawEnemies::MadScientist, 1, 0}, - }, - - // Wave 4 - { - { FrakjawEnemies::BlackSmith, 2, 2}, - { FrakjawEnemies::BoneWolf, 1, 1}, - { FrakjawEnemies::Commando, 3, 1}, - { FrakjawEnemies::Marksman, 2, 0}, - }, - - // Wave 5 - { - { FrakjawEnemies::MadScientist, 1, 0}, - { FrakjawEnemies::BoneWolf, 2, 0}, - { FrakjawEnemies::Commando, 3, 0}, - { FrakjawEnemies::Marksman, 2, 0}, - } - }; - - const int32_t PoisonBuff = 60; - - // Variables - const std::u16string TotalPlayersLoadedVariable = u"TotalPlayersLoaded"; - const std::u16string LargeTeamVariable = u"LargeTeam"; - const std::u16string FightStartedVariable = u"FightStarted"; - const std::u16string LedgeFrakjawVariable = u"LedgeFrakjaw"; - const std::u16string LowerFrakjawVariable = u"LowerFrakjaw"; - const std::u16string WaveNumberVariable = u"WaveNumber"; - const std::u16string OnLastWaveVarbiale = u"OnLastWave"; - const std::u16string TrashMobsAliveVariable = u"TrashMobsAlive"; - const std::u16string TotalAliveInWaveVariable = u"TotalAliveInWave"; - - // Timers - const char TimerSplitChar = '+'; - const std::string WaitingForPlayersTimer = "WaitingForPlayers"; - const std::string SpawnWaveTimer = "SpawnWave"; - const std::string SpawnNextWaveTimer = "SpawnNextWave"; - const std::string UnstunTimer = "Unstun+"; - const std::string FrakjawSpawnInTimer = "LowerFrakjawSpawnIn+"; - const std::string WaveOverTimer = "WaveOverTimer"; - const std::string FightOverTimer = "FightOver"; - const std::string LowerFrakjawCamTimer = "StartLowerFrakjawCam"; - const std::string SpawnCounterWeightTimer = "SpawnQB"; - const std::string SpawnRailTimer = "SpawnRailQB"; - const std::string SpawnLowerFrakjawTimer = "SpawnLowerFrakjaw"; - - // Groups - const std::string ChestSpawnpointGroup = "ChestSpawnPoint"; - - // Spawner network names - const std::string LedgeFrakjawSpawner = "LedgeFrakjaw"; - const std::string LowerFrakjawSpawner = "LowerFrakjaw"; - const std::string BaseEnemiesSpawner = "EnemySpawnPoints_"; - const std::string CounterweightSpawner = "Counterweights"; - const std::string FireRailSpawner = "FireRailActivatorQB"; - const std::string ExtraRocks = "ExtraRocks"; - - // Cinematics - const std::string LedgeFrakSummon = "FrakjawSummoning"; - const std::string BaseCounterweightQB = "CounterweightQB"; - const std::string BaseCounterweightSpawn = "CWQBSpawn"; - const std::string BottomFrakSummon = "BottomFrakjawSummoning"; - const std::string BottomFrakSpawn = "BottomFrakjawSpawning"; - const std::string TreasureChestSpawning = "TreasureChestSpawning"; - const std::string FireRailSpawn = "RailQBSpawn"; - - // Notifications - const std::u16string StopMusicNotification = u"StopMusic"; - const std::u16string StartMusicNotification = u"StartMusic"; - const std::u16string FlashMusicNotification = u"FlashMusic"; - const std::u16string PlayCinematicNotification = u"PlayCinematic"; - const std::u16string EndCinematicNotification = u"EndCinematic"; - - // Animations - const std::u16string SummonAnimation = u"summon"; - const std::u16string TeleportOutAnimation = u"teleport-out"; - const std::u16string TeleportInAnimation = u"teleport-in"; - const std::u16string StunnedAnimation = u"stunned"; - - // Audio cues - const std::string AudioWaveAudio = "Monastery_Frakjaw_Battle_"; - const std::string BattleOverAudio = "Monastery_Frakjaw_Battle_Win"; - const std::string CounterSmashAudio = "{d76d7b9d-9dc2-4e52-a315-69b25ef521ca}"; -}; diff --git a/dScripts/NjNPCMissionSpinjitzuServer.cpp b/dScripts/NjNPCMissionSpinjitzuServer.cpp deleted file mode 100644 index 74b01617..00000000 --- a/dScripts/NjNPCMissionSpinjitzuServer.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "NjNPCMissionSpinjitzuServer.h" -#include "Character.h" -#include "EntityManager.h" - -void NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, - MissionState missionState) { - - const auto& element = self->GetVar<std::u16string>(ElementVariable); - if (missionID == ElementMissions.at(element) && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { - - const auto targetID = target->GetObjectID(); - - // Wait for an animation to complete and flag that the player has learned spinjitzu - self->AddCallbackTimer(5.0f, [targetID, element]() { - auto* target = EntityManager::Instance()->GetEntity(targetID); - if (target != nullptr) { - auto* character = target->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(ElementFlags.at(element), true); - } - } - }); - } -} diff --git a/dScripts/NjNPCMissionSpinjitzuServer.h b/dScripts/NjNPCMissionSpinjitzuServer.h deleted file mode 100644 index 5b346ee7..00000000 --- a/dScripts/NjNPCMissionSpinjitzuServer.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include <map> - -static std::map<std::u16string, uint32_t> ElementFlags = { - {u"earth", ePlayerFlags::NJ_EARTH_SPINJITZU}, - {u"lightning", ePlayerFlags::NJ_LIGHTNING_SPINJITZU}, - {u"ice", ePlayerFlags::NJ_ICE_SPINJITZU}, - {u"fire", ePlayerFlags::NJ_FIRE_SPINJITZU} -}; - -static std::map<std::u16string, uint32_t> ElementMissions = { - {u"earth", 1796}, - {u"lightning", 1952}, - {u"ice", 1959}, - {u"fire", 1962}, -}; - -class NjNPCMissionSpinjitzuServer : public CppScripts::Script { -public: - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; -private: - const std::u16string ElementVariable = u"element"; -}; diff --git a/dScripts/NjRailActivatorsServer.cpp b/dScripts/NjRailActivatorsServer.cpp deleted file mode 100644 index 6c7e6ada..00000000 --- a/dScripts/NjRailActivatorsServer.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "NjRailActivatorsServer.h" -#include "RebuildComponent.h" -#include "Character.h" - -void NjRailActivatorsServer::OnUse(Entity *self, Entity *user) { - const auto flag = self->GetVar<int32_t>(u"RailFlagNum"); - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - // Only allow use if this is not a quick build or the quick build is built - if (rebuildComponent == nullptr || rebuildComponent->GetState() == REBUILD_COMPLETED) { - auto* character = user->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(flag, true); - } - } -} diff --git a/dScripts/NjRailPostServer.cpp b/dScripts/NjRailPostServer.cpp deleted file mode 100644 index 097006c7..00000000 --- a/dScripts/NjRailPostServer.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "NjRailPostServer.h" -#include "RebuildComponent.h" -#include "EntityManager.h" - -void NjRailPostServer::OnStartup(Entity *self) { - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - if (rebuildComponent != nullptr) { - self->SetNetworkVar<bool>(NetworkNotActiveVariable, true); - } -} - -void NjRailPostServer::OnNotifyObject(Entity *self, Entity *sender, const std::string &name, int32_t param1, - int32_t param2) { - if (name == "PostRebuilt") { - self->SetNetworkVar<bool>(NetworkNotActiveVariable, false); - } else if (name == "PostDied") { - self->SetNetworkVar<bool>(NetworkNotActiveVariable, true); - } -} - -void NjRailPostServer::OnRebuildNotifyState(Entity *self, eRebuildState state) { - if (state == REBUILD_COMPLETED) { - auto* relatedRail = GetRelatedRail(self); - if (relatedRail == nullptr) - return; - - relatedRail->NotifyObject(self, "PostRebuilt"); - - if (self->GetVar<bool>(NotActiveVariable)) - return; - - self->SetNetworkVar(NetworkNotActiveVariable, false); - } else if (state == REBUILD_RESETTING) { - auto* relatedRail = GetRelatedRail(self); - if (relatedRail == nullptr) - return; - - relatedRail->NotifyObject(self, "PostDied"); - } -} - -Entity *NjRailPostServer::GetRelatedRail(Entity* self) { - const auto& railGroup = self->GetVar<std::u16string>(RailGroupVariable); - if (!railGroup.empty()) { - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(railGroup))) { - return entity; - } - } - - return nullptr; -} diff --git a/dScripts/NjRailPostServer.h b/dScripts/NjRailPostServer.h deleted file mode 100644 index 65a95733..00000000 --- a/dScripts/NjRailPostServer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NjRailPostServer : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnNotifyObject(Entity *self, Entity *sender, const std::string &name, int32_t param1, int32_t param2) override; - void OnRebuildNotifyState(Entity *self, eRebuildState state) override; -private: - Entity* GetRelatedRail(Entity* self); - const std::u16string NetworkNotActiveVariable = u"NetworkNotActive"; - const std::u16string NotActiveVariable = u"NotActive"; - const std::u16string RailGroupVariable = u"RailGroup"; -}; diff --git a/dScripts/NjRailSwitch.cpp b/dScripts/NjRailSwitch.cpp deleted file mode 100644 index 70a52a0e..00000000 --- a/dScripts/NjRailSwitch.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "NjRailSwitch.h" -#include "GameMessages.h" - -void NjRailSwitch::OnUse(Entity *self, Entity *user) { -// const auto path = self->GetVar<std::u16string>(u"rail_path"); -// const auto pathStart = self->GetVar<uint32_t>(u"rail_path_start"); -// const auto pathGoForward = self->GetVar<bool>(u"rail_path_direction"); -// const auto cinematicName = self->GetVar<std::u16string>(u"cinematic"); -// -// GameMessages::SendSetRailMovement(self->GetObjectID(), pathGoForward, path, pathStart, user->GetSystemAddress()); -// GameMessages::SendPlayCinematic(self->GetObjectID(), cinematicName, user->GetSystemAddress()); -} diff --git a/dScripts/NjScrollChestServer.cpp b/dScripts/NjScrollChestServer.cpp deleted file mode 100644 index b72f93cf..00000000 --- a/dScripts/NjScrollChestServer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "NjScrollChestServer.h" -#include "InventoryComponent.h" - -void NjScrollChestServer::OnUse(Entity *self, Entity *user) { - const auto keyLOT = self->GetVar<LOT>(u"KeyNum"); - const auto rewardItemLOT = self->GetVar<LOT>(u"openItemID"); - - auto* playerInventory = user->GetComponent<InventoryComponent>(); - if (playerInventory != nullptr && playerInventory->GetLotCount(keyLOT) == 1) { - - // Check for the key and remove - playerInventory->RemoveItem(keyLOT, 1); - - // Reward the player with the item set - playerInventory->AddItem(rewardItemLOT, 1, eLootSourceType::LOOT_SOURCE_NONE); - } -} diff --git a/dScripts/NjWuNPC.cpp b/dScripts/NjWuNPC.cpp deleted file mode 100644 index 9c950e5c..00000000 --- a/dScripts/NjWuNPC.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "NjWuNPC.h" -#include "MissionComponent.h" -#include "Character.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void NjWuNPC::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - - // The Dragon statue daily mission - if (missionID == m_MainDragonMissionID) { - auto* character = target->GetCharacter(); - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (character == nullptr || missionComponent == nullptr) - return; - - switch(missionState) { - case MissionState::MISSION_STATE_AVAILABLE: - case MissionState::MISSION_STATE_COMPLETE_AVAILABLE: - { - // Reset the sub missions - for (const auto& subMissionID : m_SubDragonMissionIDs) { - missionComponent->RemoveMission(subMissionID); - missionComponent->AcceptMission(subMissionID); - } - - character->SetPlayerFlag(ePlayerFlags::NJ_WU_SHOW_DAILY_CHEST, false); - - // Hide the chest - for (auto* chest : EntityManager::Instance()->GetEntitiesInGroup(m_DragonChestGroup)) { - GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 0, -1, - target->GetObjectID(), "", target->GetSystemAddress()); - } - - return; - } - case MissionState::MISSION_STATE_READY_TO_COMPLETE: - case MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE: - { - character->SetPlayerFlag(NJ_WU_SHOW_DAILY_CHEST, true); - - // Show the chest - for (auto* chest : EntityManager::Instance()->GetEntitiesInGroup(m_DragonChestGroup)) { - GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 1, -1, - target->GetObjectID(), "", target->GetSystemAddress()); - } - - auto playerID = target->GetObjectID(); - self->AddCallbackTimer(5.0f, [this, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - return; - - // Stop the dragon effects - for (auto* dragon : EntityManager::Instance()->GetEntitiesInGroup(m_DragonStatueGroup)) { - GameMessages::SendStopFXEffect(dragon, true, "on"); - } - }); - } - default: - return; - } - } -} diff --git a/dScripts/NjWuNPC.h b/dScripts/NjWuNPC.h deleted file mode 100644 index 8ad6dbf3..00000000 --- a/dScripts/NjWuNPC.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "AmTemplateSkillVolume.h" - -class NjWuNPC : public AmTemplateSkillVolume { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - const uint32_t m_MainDragonMissionID = 2040; - const std::vector<uint32_t> m_SubDragonMissionIDs = {2064, 2065, 2066, 2067}; - - // Groups and variables - const std::string m_DragonChestGroup = "DragonEmblemChest"; - const std::string m_DragonStatueGroup = "Minidragons"; - const std::u16string m_ShowChestNotification = u"showChest"; -}; diff --git a/dScripts/NjhubLavaPlayerDeathTrigger.cpp b/dScripts/NjhubLavaPlayerDeathTrigger.cpp deleted file mode 100644 index af47f99b..00000000 --- a/dScripts/NjhubLavaPlayerDeathTrigger.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "NjhubLavaPlayerDeathTrigger.h" -#include "Entity.h" - -void NjhubLavaPlayerDeathTrigger::OnCollisionPhantom(Entity *self, Entity *target) -{ - if (!target->IsPlayer()) - return; - - target->Smash(self->GetObjectID(), VIOLENT, u"drown"); -} diff --git a/dScripts/NpcCowboyServer.cpp b/dScripts/NpcCowboyServer.cpp deleted file mode 100644 index f4986045..00000000 --- a/dScripts/NpcCowboyServer.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "NpcCowboyServer.h" -#include "MissionState.h" -#include "InventoryComponent.h" - -void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - if (missionID != 1880) - { - return; - } - - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - - if (inventoryComponent == nullptr) - { - return; - } - - if (missionState == MissionState::MISSION_STATE_COMPLETE_ACTIVE|| - missionState == MissionState::MISSION_STATE_ACTIVE || - missionState == MissionState::MISSION_STATE_AVAILABLE || - missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) - { - if (inventoryComponent->GetLotCount(14378) == 0) - { - inventoryComponent->AddItem(14378, 1, eLootSourceType::LOOT_SOURCE_NONE); - } - } - else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) - { - inventoryComponent->RemoveItem(14378, 1); - } -} diff --git a/dScripts/NpcPirateServer.cpp b/dScripts/NpcPirateServer.cpp deleted file mode 100644 index 04c62b47..00000000 --- a/dScripts/NpcPirateServer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "NpcPirateServer.h" -#include "InventoryComponent.h" - -void NpcPirateServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - auto* inventory = target->GetComponent<InventoryComponent>(); - if (inventory != nullptr && missionID == 1881) { - auto* luckyShovel = inventory->FindItemByLot(14591); - - // Add or remove the lucky shovel based on whether the mission was completed or started - if ((missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) - && luckyShovel == nullptr) { - inventory->AddItem(14591, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { - inventory->RemoveItem(14591, 1); - } - } -} diff --git a/dScripts/NpcPirateServer.h b/dScripts/NpcPirateServer.h deleted file mode 100644 index 795356d6..00000000 --- a/dScripts/NpcPirateServer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NpcPirateServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; -}; diff --git a/dScripts/NpcWispServer.cpp b/dScripts/NpcWispServer.cpp deleted file mode 100644 index 0f573d65..00000000 --- a/dScripts/NpcWispServer.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "NpcWispServer.h" -#include "InventoryComponent.h" -#include "EntityManager.h" -#include "Entity.h" -#include "GameMessages.h" - -void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionID != 1849 && missionID != 1883) - return; - - auto* inventory = target->GetComponent<InventoryComponent>(); - if (inventory == nullptr) - return; - - LOT maelstromVacuumLot = 14592; - auto* maelstromVacuum = inventory->FindItemByLot(maelstromVacuumLot); - - // For the daily we add the maelstrom vacuum if the player doesn't have it yet - if (missionID == 1883 && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) - && maelstromVacuum == nullptr) { - inventory->AddItem(maelstromVacuumLot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { - inventory->RemoveItem(maelstromVacuumLot, 1); - } - - // Next up hide or show the samples based on the mission state - auto visible = 1; - if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { - visible = 0; - } - - auto groups = missionID == 1849 - ? std::vector<std::string> { "MaelstromSamples" } - : std::vector<std::string> { "MaelstromSamples", "MaelstromSamples2ndary1", "MaelstromSamples2ndary2"}; - - for (const auto& group : groups) { - auto samples = EntityManager::Instance()->GetEntitiesInGroup(group); - for (auto* sample : samples) { - GameMessages::SendNotifyClientObject(sample->GetObjectID(), u"SetVisibility", visible, 0, - target->GetObjectID(), "", target->GetSystemAddress()); - } - } -} diff --git a/dScripts/NsConcertChoiceBuild.cpp b/dScripts/NsConcertChoiceBuild.cpp deleted file mode 100644 index 8a93544c..00000000 --- a/dScripts/NsConcertChoiceBuild.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "NsConcertChoiceBuild.h" - -void NsConcertChoiceBuild::OnStartup(Entity *self) { -} diff --git a/dScripts/NsConcertChoiceBuildManager.cpp b/dScripts/NsConcertChoiceBuildManager.cpp deleted file mode 100644 index 8875beed..00000000 --- a/dScripts/NsConcertChoiceBuildManager.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "NsConcertChoiceBuildManager.h" -#include "EntityManager.h" - -const std::vector<Crate> NsConcertChoiceBuildManager::crates { - { "laser", 11203, 5.0, "Concert_Laser_QB_" }, - { "rocket", 11204, 3.0, "Concert_Rocket_QB_" }, - { "speaker", 11205, 5.0, "Concert_Speaker_QB_" }, - { "spotlight", 11206, 5.0, "Concert_Spotlight_QB_" } -}; - -void NsConcertChoiceBuildManager::OnStartup(Entity *self) { - NsConcertChoiceBuildManager::SpawnCrate(self); -} - -void NsConcertChoiceBuildManager::SpawnCrate(Entity *self) { - const auto spawnNumber = self->GetVar<uint32_t>(u"spawnNumber") % crates.size(); - const auto crate = crates[spawnNumber]; - - const auto groups = self->GetGroups(); - if (groups.empty()) - return; - - // Groups are of the form CB_1, CB_2, etc. - auto group = groups.at(0); - const auto splitGroup = GeneralUtils::SplitString(group, '_'); - if (splitGroup.size() < 2) - return; - const auto groupNumber = std::stoi(splitGroup.at(1)); - - EntityInfo info {}; - info.lot = crate.lot; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.spawnerID = self->GetObjectID(); - info.settings = { - new LDFData<bool>(u"startsQBActivator", true), - new LDFData<std::string>(u"grpNameQBShowBricks", crate.group + std::to_string(groupNumber)), - new LDFData<std::u16string>(u"groupID", GeneralUtils::ASCIIToUTF16("Crate_" + group)), - new LDFData<float>(u"crateTime", crate.time), - }; - - auto* spawnedCrate = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(spawnedCrate); - - spawnedCrate->AddDieCallback([self]() { - self->CancelAllTimers(); // Don't switch if the crate was smashed - self->SetVar<LWOOBJID>(u"currentCrate", LWOOBJID_EMPTY); - }); - - self->SetVar<uint32_t>(u"spawnNumber", spawnNumber + 1); - self->SetVar<float>(u"currentTimer", crate.time); - self->SetVar<LWOOBJID>(u"currentCrate", spawnedCrate->GetObjectID()); - - // Timer that rotates the crates - self->AddCallbackTimer(crate.time, [self]() { - auto crateID = self->GetVar<LWOOBJID>(u"currentCrate"); - if (crateID != LWOOBJID_EMPTY) { - EntityManager::Instance()->DestroyEntity(crateID); - self->SetVar<LWOOBJID>(u"currentCrate", LWOOBJID_EMPTY); - } - - SpawnCrate(self); - }); -} diff --git a/dScripts/NsConcertChoiceBuildManager.h b/dScripts/NsConcertChoiceBuildManager.h deleted file mode 100644 index 25c7690b..00000000 --- a/dScripts/NsConcertChoiceBuildManager.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "CppScripts.h" - -struct Crate { - std::string name; - LOT lot; - float time; - std::string group; -}; - -class NsConcertChoiceBuildManager : public CppScripts::Script { -public: - void OnStartup(Entity *self) override; - static void SpawnCrate(Entity* self); -private: - static const std::vector<Crate> crates; -}; diff --git a/dScripts/NsConcertInstrument.cpp b/dScripts/NsConcertInstrument.cpp deleted file mode 100644 index a449a6a4..00000000 --- a/dScripts/NsConcertInstrument.cpp +++ /dev/null @@ -1,362 +0,0 @@ -#include "NsConcertInstrument.h" -#include "GameMessages.h" -#include "Item.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "RebuildComponent.h" -#include "SoundTriggerComponent.h" -#include "MissionComponent.h" - -// Constants are at the bottom - -void NsConcertInstrument::OnStartup(Entity *self) { - self->SetVar<bool>(u"beingPlayed", false); - self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); - self->SetVar<LWOOBJID>(u"oldItemLeft", LWOOBJID_EMPTY); - self->SetVar<LWOOBJID>(u"oldItemRight", LWOOBJID_EMPTY); -} - -void NsConcertInstrument::OnRebuildNotifyState(Entity *self, eRebuildState state) { - if (state == REBUILD_RESETTING || state == REBUILD_OPEN) { - self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); - } -} - -void NsConcertInstrument::OnRebuildComplete(Entity *self, Entity *target) { - if (!target->GetIsDead()) { - self->SetVar<LWOOBJID>(u"activePlayer", target->GetObjectID()); - - self->AddCallbackTimer(0.2f, [self, target]() { - RepositionPlayer(self, target); - if (hideInstrumentOnPlay.at(GetInstrumentLot(self))) - self->SetNetworkVar<bool>(u"Hide", true); - }); - - self->AddCallbackTimer(0.1f, [self, target]() { - StartPlayingInstrument(self, target); - }); - } -} - -void NsConcertInstrument::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - if (args == "stopPlaying") { - const auto activePlayerID = self->GetVar<LWOOBJID>(u"activePlayer"); - if (activePlayerID == LWOOBJID_EMPTY) - return; - - const auto activePlayer = EntityManager::Instance()->GetEntity(activePlayerID); - if (activePlayer == nullptr) - return; - - StopPlayingInstrument(self, activePlayer); - } -} - -void NsConcertInstrument::OnTimerDone(Entity *self, std::string name) { - const auto activePlayerID = self->GetVar<LWOOBJID>(u"activePlayer"); - if (activePlayerID == LWOOBJID_EMPTY) - return; - - // If for some reason the player becomes null (for example an unexpected leave), we need to clean up - const auto activePlayer = EntityManager::Instance()->GetEntity(activePlayerID); - if (activePlayer == nullptr && name != "cleanupAfterStop") { - StopPlayingInstrument(self, nullptr); - return; - } - - if (activePlayer != nullptr && name == "checkPlayer" && self->GetVar<bool>(u"beingPlayed")) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"checkMovement", 0, 0, - activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - auto* stats = activePlayer->GetComponent<DestroyableComponent>(); - if (stats) { - if (stats->GetImagination() > 0) { - self->AddTimer("checkPlayer", updateFrequency); - } else { - StopPlayingInstrument(self, activePlayer); - } - } - } else if (activePlayer != nullptr && name == "deductImagination" && self->GetVar<bool>(u"beingPlayed")) { - auto* stats = activePlayer->GetComponent<DestroyableComponent>(); - if (stats) - stats->SetImagination(stats->GetImagination() - instrumentImaginationCost); - - self->AddTimer("deductImagination", instrumentCostFrequency); - } else if (name == "cleanupAfterStop") { - if (activePlayer != nullptr) { - UnEquipInstruments(self, activePlayer); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopPlaying", 0, 0, - activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - } - - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - if (rebuildComponent != nullptr) - rebuildComponent->ResetRebuild(false); - - self->Smash(self->GetObjectID(), VIOLENT); - self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); - } else if (activePlayer != nullptr && name == "achievement") { - auto* missionComponent = activePlayer->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->ForceProgress(302, 462, self->GetLOT()); - } - self->AddTimer("achievement2", 10.0f); - } else if (activePlayer != nullptr && name == "achievement2") { - auto* missionComponent = activePlayer->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->ForceProgress(602, achievementTaskID.at(GetInstrumentLot(self)), self->GetLOT()); - } - } -} - -void NsConcertInstrument::StartPlayingInstrument(Entity *self, Entity* player) { - const auto instrumentLot = GetInstrumentLot(self); - self->SetVar<bool>(u"beingPlayed", true); - - // Stuff to notify the player - EquipInstruments(self, player); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"startPlaying", 0, 0, - player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendPlayCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS); - self->AddCallbackTimer(1.0f, [player, instrumentLot]() { - GameMessages::SendPlayAnimation(player, animations.at(instrumentLot), 2.0f); - }); - - for (auto* soundBox : EntityManager::Instance()->GetEntitiesInGroup("Audio-Concert")) { - auto* soundTrigger = soundBox->GetComponent<SoundTriggerComponent>(); - if (soundTrigger != nullptr) { - soundTrigger->ActivateMusicCue(music.at(instrumentLot)); - } - } - - // Add timers for deducting imagination and checking if the instruments can still be played - self->AddTimer("checkPlayer", updateFrequency); - self->AddTimer("deductImagination", instrumentCostFrequency); - self->AddTimer("achievement", 20.0f); -} - -void NsConcertInstrument::StopPlayingInstrument(Entity *self, Entity* player) { - // No use in stopping twice - if (!self->GetVar<bool>(u"beingPlayed")) - return; - - const auto instrumentLot = GetInstrumentLot(self); - - // Player might be null if they left - if (player != nullptr) { - auto* missions = player->GetComponent<MissionComponent>(); - if (missions != nullptr && missions->GetMissionState(176) == MissionState::MISSION_STATE_ACTIVE) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - - GameMessages::SendEndCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS, 1.0f); - GameMessages::SendPlayAnimation(player, smashAnimations.at(instrumentLot), 2.0f); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopCheckingMovement", 0, 0, - player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - } - - self->SetVar<bool>(u"beingPlayed", false); - - for (auto* soundBox : EntityManager::Instance()->GetEntitiesInGroup("Audio-Concert")) { - auto* soundTrigger = soundBox->GetComponent<SoundTriggerComponent>(); - if (soundTrigger != nullptr) { - soundTrigger->DeactivateMusicCue(music.at(instrumentLot)); - } - } - - self->CancelAllTimers(); - self->AddTimer("cleanupAfterStop", instrumentSmashAnimationTime.at(instrumentLot)); -} - -void NsConcertInstrument::EquipInstruments(Entity *self, Entity *player) { - auto* inventory = player->GetComponent<InventoryComponent>(); - if (inventory != nullptr) { - auto equippedItems = inventory->GetEquippedItems(); - - // Un equip the current left item - const auto equippedLeftItem = equippedItems.find("special_l"); - if (equippedLeftItem != equippedItems.end()) { - auto* leftItem = inventory->FindItemById(equippedLeftItem->second.id); - if (leftItem != nullptr) { - leftItem->UnEquip(); - self->SetVar<LWOOBJID>(u"oldItemLeft", leftItem->GetId()); - } - } - - // Un equip the current right item - const auto equippedRightItem = equippedItems.find("special_r"); - if (equippedRightItem != equippedItems.end()) { - auto* rightItem = inventory->FindItemById(equippedRightItem->second.id); - if (rightItem != nullptr) { - rightItem->UnEquip(); - self->SetVar<LWOOBJID>(u"oldItemRight", rightItem->GetId()); - } - } - - // Equip the left hand instrument - const auto leftInstrumentLot = instrumentLotLeft.find(GetInstrumentLot(self))->second; - if (leftInstrumentLot != LOT_NULL) { - inventory->AddItem(leftInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false); - auto* leftInstrument = inventory->FindItemByLot(leftInstrumentLot, TEMP_ITEMS); - leftInstrument->Equip(); - } - - // Equip the right hand instrument - const auto rightInstrumentLot = instrumentLotRight.find(GetInstrumentLot(self))->second; - if (rightInstrumentLot != LOT_NULL) { - inventory->AddItem(rightInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false); - auto* rightInstrument = inventory->FindItemByLot(rightInstrumentLot, TEMP_ITEMS); - rightInstrument->Equip(); - } - } -} - -void NsConcertInstrument::UnEquipInstruments(Entity *self, Entity *player) { - auto* inventory = player->GetComponent<InventoryComponent>(); - if (inventory != nullptr) { - auto equippedItems = inventory->GetEquippedItems(); - - // Un equip the current left instrument - const auto equippedInstrumentLeft = equippedItems.find("special_l"); - if (equippedInstrumentLeft != equippedItems.end()) { - auto* leftItem = inventory->FindItemById(equippedInstrumentLeft->second.id); - if (leftItem != nullptr) { - leftItem->UnEquip(); - inventory->RemoveItem(leftItem->GetLot(), 1, TEMP_ITEMS); - } - } - - // Un equip the current right instrument - const auto equippedInstrumentRight = equippedItems.find("special_r"); - if (equippedInstrumentRight != equippedItems.end()) { - auto* rightItem = inventory->FindItemById(equippedInstrumentRight->second.id); - if (rightItem != nullptr) { - rightItem->UnEquip(); - inventory->RemoveItem(rightItem->GetLot(), 1, TEMP_ITEMS); - } - } - - // Equip the old left hand item - const auto leftItemID = self->GetVar<LWOOBJID>(u"oldItemLeft"); - if (leftItemID != LWOOBJID_EMPTY) { - auto* item = inventory->FindItemById(leftItemID); - if (item != nullptr) - item->Equip(); - self->SetVar<LWOOBJID>(u"oldItemLeft", LWOOBJID_EMPTY); - } - - // Equip the old right hand item - const auto rightItemID = self->GetVar<LWOOBJID>(u"oldItemRight"); - if (rightItemID != LWOOBJID_EMPTY) { - auto* item = inventory->FindItemById(rightItemID); - if (item != nullptr) - item->Equip(); - self->SetVar<LWOOBJID>(u"oldItemRight", LWOOBJID_EMPTY); - } - } -} - -void NsConcertInstrument::RepositionPlayer(Entity *self, Entity *player) { - auto position = self->GetPosition(); - auto rotation = self->GetRotation(); - position.SetY(0.0f); - - switch (GetInstrumentLot(self)) { - case Bass: - case Guitar: - position.SetX(position.GetX() + 5.0f); - break; - case Keyboard: - position.SetX(position.GetX() - 0.45f); - position.SetZ(position.GetZ() + 0.75f); - rotation = NiQuaternion::CreateFromAxisAngle(position, -0.8f); // Slight rotation to make the animation sensible - break; - case Drum: - position.SetZ(position.GetZ() - 0.5f); - break; - } - - GameMessages::SendTeleport(player->GetObjectID(), position, rotation, player->GetSystemAddress()); -} - -InstrumentLot NsConcertInstrument::GetInstrumentLot(Entity *self) { - return static_cast<const InstrumentLot>(self->GetLOT()); -} - -// Static stuff needed for script execution - -const std::map<InstrumentLot, std::u16string> NsConcertInstrument::animations { - { Guitar, u"guitar"}, - { Bass, u"bass"}, - { Keyboard, u"keyboard"}, - { Drum, u"drums"} -}; - -const std::map<InstrumentLot, std::u16string> NsConcertInstrument::smashAnimations { - {Guitar, u"guitar-smash"}, - {Bass, u"bass-smash"}, - {Keyboard, u"keyboard-smash"}, - {Drum, u"keyboard-smash"} -}; - -const std::map<InstrumentLot, float> NsConcertInstrument::instrumentSmashAnimationTime { - {Guitar, 2.167f}, - {Bass, 1.167f}, - {Keyboard, 1.0f}, - {Drum, 1.0f} -}; - -const std::map<InstrumentLot, std::string> NsConcertInstrument::music { - {Guitar, "Concert_Guitar"}, - {Bass, "Concert_Bass"}, - {Keyboard, "Concert_Keys"}, - {Drum, "Concert_Drums"}, -}; - -const std::map<InstrumentLot, std::u16string> NsConcertInstrument::cinematics { - {Guitar, u"Concert_Cam_G"}, - {Bass, u"Concert_Cam_B"}, - {Keyboard, u"Concert_Cam_K"}, - {Drum, u"Concert_Cam_D"}, -}; - -const std::map<InstrumentLot, LOT> NsConcertInstrument::instrumentLotLeft { - {Guitar, 4991}, - {Bass, 4992}, - {Keyboard, LOT_NULL}, - {Drum, 4995}, -}; - -const std::map<InstrumentLot, LOT> NsConcertInstrument::instrumentLotRight { - {Guitar, LOT_NULL}, - {Bass, LOT_NULL}, - {Keyboard, LOT_NULL}, - {Drum, 4996}, -}; - -const std::map<InstrumentLot, bool> NsConcertInstrument::hideInstrumentOnPlay { - {Guitar, true}, - {Bass, true}, - {Keyboard, false}, - {Drum, false}, -}; - -const std::map<InstrumentLot, float> NsConcertInstrument::instrumentEquipTime { - {Guitar, 1.033}, - {Bass, 0.75}, - {Keyboard, -1}, - {Drum, 0}, -}; - -const std::map<InstrumentLot, uint32_t> NsConcertInstrument::achievementTaskID { - {Guitar, 911}, - {Bass, 912}, - {Keyboard, 913}, - {Drum, 914}, -}; - -const uint32_t NsConcertInstrument::instrumentImaginationCost = 2; - -const float NsConcertInstrument::instrumentCostFrequency = 4.0f; - -const float NsConcertInstrument::updateFrequency = 1.0f; diff --git a/dScripts/NsConcertInstrument.h b/dScripts/NsConcertInstrument.h deleted file mode 100644 index bf59d886..00000000 --- a/dScripts/NsConcertInstrument.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once -#include "CppScripts.h" - -enum InstrumentLot { - Guitar = 4039, - Bass = 4040, - Keyboard = 4041, - Drum = 4042 -}; - -class NsConcertInstrument : public CppScripts::Script { -public: - void OnStartup(Entity* self) override; - void OnRebuildNotifyState(Entity* self, eRebuildState state) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string name) override; -private: - static void StartPlayingInstrument(Entity* self, Entity* player); - static void StopPlayingInstrument(Entity* self, Entity* player); - static void EquipInstruments(Entity* self, Entity* player); - static void UnEquipInstruments(Entity* self, Entity* player); - static void RepositionPlayer(Entity* self, Entity* player); - static InstrumentLot GetInstrumentLot(Entity* self); - - /** - * Animations played when using an instrument - */ - static const std::map<InstrumentLot, std::u16string> animations; - - /** - * Animation played when an instrument is smashed - */ - static const std::map<InstrumentLot, std::u16string> smashAnimations; - - /** - * Music to play while playing an instrument - */ - static const std::map<InstrumentLot, std::string> music; - - /** - * Cinematics to play while playing an instrument - */ - static const std::map<InstrumentLot, std::u16string> cinematics; - - /** - * Lot to equip in your left hand when playing an instrument - */ - static const std::map<InstrumentLot, LOT> instrumentLotLeft; - - /** - * Lot to play in your right hand when playing an instrument - */ - static const std::map<InstrumentLot, LOT> instrumentLotRight; - - /** - * Whether to hide the instrument or not when someone is playing it - */ - static const std::map<InstrumentLot, bool> hideInstrumentOnPlay; - - /** - * How long to wait before unequipping the instrument if the instrument was smashed - */ - static const std::map<InstrumentLot, float> instrumentEquipTime; - - /** - * How long the smash animation takes for each of the instruments - */ - static const std::map<InstrumentLot, float> instrumentSmashAnimationTime; - - /** - * Task ID of tasks of the Solo Artist 2 achievement - */ - static const std::map<InstrumentLot, uint32_t> achievementTaskID; - - /** - * How much imagination playing an instrument costs per interval - */ - static const uint32_t instrumentImaginationCost; - - /** - * The interval to deduct imagination at when playing an instrument - */ - static const float instrumentCostFrequency; - - /** - * The interval to check if the player still has enough imagination - */ - static const float updateFrequency; -}; \ No newline at end of file diff --git a/dScripts/NsConcertQuickBuild.cpp b/dScripts/NsConcertQuickBuild.cpp deleted file mode 100644 index ba7b4010..00000000 --- a/dScripts/NsConcertQuickBuild.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "NsConcertQuickBuild.h" -#include "EntityManager.h" -#include "NsConcertChoiceBuildManager.h" -#include "DestroyableComponent.h" -#include "GameMessages.h" -#include "MovingPlatformComponent.h" -#include "MissionComponent.h" - -const float NsConcertQuickBuild::resetTime = 40.0f; -const float NsConcertQuickBuild::resetBlinkTime = 6.0f; -const float NsConcertQuickBuild::resetStageTime = 66.5f; -const float NsConcertQuickBuild::resetActivatorTime = 30.0f; -const std::map<LOT, QuickBuildSet> NsConcertQuickBuild::quickBuildSets { - {5846, QuickBuildSet {"laser", {"discoball", "discofloor", "stagelights", "spotlight"}}}, - {5847, QuickBuildSet {"spotlight", {"spotlight", "stagelights"}}}, - {5848, QuickBuildSet {"rocket", {"flamethrower"}}}, - {5845, QuickBuildSet {"speaker", {"speaker", "speakerHill", "stagelights", "spotlight"}}} -}; - -const std::map<std::string, std::string> NsConcertQuickBuild::quickBuildFX { - {"discoball", "effectsDiscoball"}, - {"speaker", "effectsShell"}, - {"speakerHill", "effectsHill"}, - {"spotlight", "effectsHill"}, - {"discofloor", "effectsShell"}, - {"flamethrower", "effectsShell"}, - {"stagelights", "effectsShell"} -}; - -std::vector<LWOOBJID> NsConcertQuickBuild::finishedQuickBuilds = {}; - -void NsConcertQuickBuild::OnStartup(Entity *self) { - const auto groups = self->GetGroups(); - if (groups.empty()) - return; - - // Groups are of the form Concert_Laser_QB_1, Concert_Laser_QB_2, etc. - auto group = groups.at(0); - const auto splitGroup = GeneralUtils::SplitString(group, '_'); - if (splitGroup.size() < 4) - return; - - // Get the manager of the crate of this quick build - const auto groupNumber = std::stoi(splitGroup.at(3)); - const auto managerObjects = EntityManager::Instance()->GetEntitiesInGroup("CB_" + std::to_string(groupNumber)); - if (managerObjects.empty()) - return; - - auto* managerObject = managerObjects.at(0); - self->SetVar<LWOOBJID>(u"managerObject", managerObject->GetObjectID()); - self->SetVar<int32_t>(u"groupNumber", groupNumber); - - // Makes the quick build blink after a certain amount of time - self->AddCallbackTimer(GetBlinkTime(resetActivatorTime), [self]() { - self->SetNetworkVar<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); - }); - - // Destroys the quick build after a while if it wasn't built - self->AddCallbackTimer(resetActivatorTime, [self]() { - self->SetNetworkVar<float>(u"startEffect", -1.0f); - self->Smash(self->GetObjectID(), SILENT); - }); -} - -float NsConcertQuickBuild::GetBlinkTime(float time) { - return time <= NsConcertQuickBuild::resetBlinkTime ? 1.0f : time - NsConcertQuickBuild::resetBlinkTime; -} - -void NsConcertQuickBuild::OnDie(Entity *self, Entity *killer) { - auto* managerObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"managerObject")); - if (managerObject) { - managerObject->CancelAllTimers(); - managerObject->AddCallbackTimer(1.0f, [managerObject]() { - NsConcertChoiceBuildManager::SpawnCrate(managerObject); - }); - } - - auto position = std::find(finishedQuickBuilds.begin(), finishedQuickBuilds.end(), self->GetObjectID()); - if (position != finishedQuickBuilds.end()) - finishedQuickBuilds.erase(position); -} - -void NsConcertQuickBuild::OnRebuildComplete(Entity *self, Entity *target) { - const auto groupNumber = self->GetVar<int32_t>(u"groupNumber"); - finishedQuickBuilds.push_back(self->GetObjectID()); - self->SetNetworkVar<float>(u"startEffect", -1.0f); - - ProgressStageCraft(self, target); - - // Find all the quick build objects of the same lot - auto finishedQuickBuildObjects = std::vector<Entity*>(); - for (auto quickBuildID : finishedQuickBuilds) { - const auto quickBuildObject = EntityManager::Instance()->GetEntity(quickBuildID); - if (quickBuildObject && quickBuildObject->GetLOT() == self->GetLOT()) { - quickBuildObject->SetVar<LWOOBJID>(u"Player_" + (GeneralUtils::to_u16string(groupNumber)), target->GetObjectID()); - finishedQuickBuildObjects.push_back(quickBuildObject); - } - } - - // If all 4 sets were built, do cool stuff - if (finishedQuickBuildObjects.size() >= 4) { - - // Move all the platforms so the user can collect the imagination brick - const auto movingPlatforms = EntityManager::Instance()->GetEntitiesInGroup("ConcertPlatforms"); - for (auto* movingPlatform : movingPlatforms) { - auto* component = movingPlatform->GetComponent<MovingPlatformComponent>(); - if (component) { - component->WarpToWaypoint(component->GetLastWaypointIndex()); - - movingPlatform->AddCallbackTimer(resetStageTime, [movingPlatform, component]() { - component->WarpToWaypoint(0); - }); - } - } - - ProgressLicensedTechnician(self); - - // Reset all timers for the quickbuilds and make them indestructible - for (auto quickBuild : finishedQuickBuildObjects) { - quickBuild->SetNetworkVar<float>(u"startEffect", -1.0f); - quickBuild->CancelAllTimers(); - - // Indicate that the stage will reset - quickBuild->AddCallbackTimer(GetBlinkTime(resetStageTime), [quickBuild]() { - quickBuild->SetNetworkVar<float>(u"startEffect", GetBlinkTime(resetTime)); - }); - - // Reset the stage - quickBuild->AddCallbackTimer(resetStageTime, [quickBuild]() { - CancelEffects(quickBuild); - quickBuild->SetNetworkVar<float>(u"startEffect", -1); - quickBuild->Smash(); - }); - - auto* destroyableComponent = quickBuild->GetComponent<DestroyableComponent>(); - if (destroyableComponent) - destroyableComponent->SetFaction(-1); - } - - UpdateEffects(self); - return; - } - - // If not all 4 sets were built, reset the timers that were set on spawn - self->CancelAllTimers(); - - // Makes the quick build blink after a certain amount of time - self->AddCallbackTimer(GetBlinkTime(resetTime), [self]() { - self->SetNetworkVar<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); - }); - - // Destroys the quick build after a while if it wasn't built - self->AddCallbackTimer(resetTime, [self]() { - self->SetNetworkVar<float>(u"startEffect", -1.0f); - self->Smash(self->GetObjectID()); - }); -} - -void NsConcertQuickBuild::ProgressStageCraft(Entity *self, Entity* player) { - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent) { - - // Has to be forced as to not accidentally trigger the licensed technician achievement - switch(self->GetLOT()) { - case 5845: - missionComponent->ForceProgress(283, 432, 5845); - break; - case 5846: - missionComponent->ForceProgress(283, 433, 5846); - break; - case 5847: - missionComponent->ForceProgress(283, 434, 5847); - break; - case 5848: - missionComponent->ForceProgress(283, 435, 5848); - break; - default: - break; - } - } -} - -void NsConcertQuickBuild::ProgressLicensedTechnician(Entity *self) { - for (auto i = 1; i < 5; i++) { - const auto playerID = self->GetVar<LWOOBJID>(u"Player_" + (GeneralUtils::to_u16string(i))); - if (playerID != LWOOBJID_EMPTY) { - const auto player = EntityManager::Instance()->GetEntity(playerID); - if (player) { - auto playerMissionComponent = player->GetComponent<MissionComponent>(); - if (playerMissionComponent) - playerMissionComponent->ForceProgress(598, 903, self->GetLOT()); - } - } - } -} - -void NsConcertQuickBuild::UpdateEffects(Entity *self) { - CancelEffects(self); - - auto setIterator = quickBuildSets.find(self->GetLOT()); - if (setIterator == quickBuildSets.end()) - return; - - for (const auto& effectName : setIterator->second.effects) { - const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); - for (auto* effectObject : effectObjects) { - GameMessages::SendPlayFXEffect(effectObject, 0, GeneralUtils::ASCIIToUTF16(effectName), - effectName + "Effect", LWOOBJID_EMPTY, 1, 1, true); - } - } -} - -void NsConcertQuickBuild::CancelEffects(Entity *self) { - auto setIterator = quickBuildSets.find(self->GetLOT()); - if (setIterator == quickBuildSets.end()) - return; - - for (const auto& effectName : setIterator->second.effects) { - const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); - for (auto* effectObject : effectObjects) { - GameMessages::SendStopFXEffect(effectObject, true, effectName + "Effect"); - } - } -} diff --git a/dScripts/NsConcertQuickBuild.h b/dScripts/NsConcertQuickBuild.h deleted file mode 100644 index b3f6d702..00000000 --- a/dScripts/NsConcertQuickBuild.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "CppScripts.h" - -struct QuickBuildSet { - std::string name; - std::vector<std::string> effects; -}; - -class NsConcertQuickBuild : public CppScripts::Script { -public: - void OnStartup(Entity* self) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnDie(Entity* self, Entity* killer) override; -private: - static std::vector<LWOOBJID> finishedQuickBuilds; - static const float resetBlinkTime; - static const float resetStageTime; - static const float resetActivatorTime; - static const float resetTime; - static const std::map<std::string, std::string> quickBuildFX; - static const std::map<LOT, QuickBuildSet> quickBuildSets; - static float GetBlinkTime(float time); - static void ProgressStageCraft(Entity* self, Entity* player); - static void ProgressLicensedTechnician(Entity* self); - static void UpdateEffects(Entity* self); - static void CancelEffects(Entity* self); -}; diff --git a/dScripts/NsJohnnyMissionServer.cpp b/dScripts/NsJohnnyMissionServer.cpp deleted file mode 100644 index 6fc73a82..00000000 --- a/dScripts/NsJohnnyMissionServer.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "NsJohnnyMissionServer.h" -#include "MissionComponent.h" - -void NsJohnnyMissionServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - if (missionID == 773 && missionState <= MissionState::MISSION_STATE_ACTIVE) { - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - missionComponent->AcceptMission(774); - missionComponent->AcceptMission(775); - missionComponent->AcceptMission(776); - missionComponent->AcceptMission(777); - } - } -} diff --git a/dScripts/NsJohnnyMissionServer.h b/dScripts/NsJohnnyMissionServer.h deleted file mode 100644 index 920231da..00000000 --- a/dScripts/NsJohnnyMissionServer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NsJohnnyMissionServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; -}; diff --git a/dScripts/NsLegoClubDoor.cpp b/dScripts/NsLegoClubDoor.cpp deleted file mode 100644 index 0b773b09..00000000 --- a/dScripts/NsLegoClubDoor.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "NsLegoClubDoor.h" -#include "dZoneManager.h" -#include "GameMessages.h" -#include "AMFFormat.h" - -void NsLegoClubDoor::OnStartup(Entity* self) -{ - self->SetVar(u"currentZone", (int32_t) dZoneManager::Instance()->GetZoneID().GetMapID()); - self->SetVar(u"choiceZone", m_ChoiceZoneID); - self->SetVar(u"teleportAnim", m_TeleportAnim); - self->SetVar(u"teleportString", m_TeleportString); - self->SetVar(u"spawnPoint", m_SpawnPoint); - - args = {}; - - /** - { {0,{ - {"image", "textures/ui/zone_thumnails/Nimbus_Station.dds"}, - {"caption", "%[UI_CHOICE_NS]"}, -- "%[LOC_STRING]" is the format for sending localization tokens to the choice box - {"identifier", "zoneID_1200"}, - {"tooltipText", "%[UI_CHOICE_NS_HOVER]"} - }}, - {1,{ - {"image", "textures/ui/zone_thumnails/Nexus_Tower.dds"}, - {"caption", "%[UI_CHOICE_NT]"}, - {"identifier", "zoneID_1900"}, - {"tooltipText", "%[UI_CHOICE_NT_HOVER]"} - } } } - */ - - AMFStringValue* callbackClient = new AMFStringValue(); - callbackClient->SetStringValue(std::to_string(self->GetObjectID())); - args.InsertValue("callbackClient", callbackClient); - - AMFStringValue* strIdentifier = new AMFStringValue(); - strIdentifier->SetStringValue("choiceDoor"); - args.InsertValue("strIdentifier", strIdentifier); - - AMFStringValue* title = new AMFStringValue(); - title->SetStringValue("%[UI_CHOICE_DESTINATION]"); - args.InsertValue("title", title); - - AMFArrayValue* choiceOptions = new AMFArrayValue(); - - { - AMFArrayValue* nsArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Nimbus_Station.dds"); - nsArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[UI_CHOICE_NS]"); - nsArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1200"); - nsArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[UI_CHOICE_NS_HOVER]"); - nsArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(nsArgs); - } - - { - AMFArrayValue* ntArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Nexus_Tower.dds"); - ntArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[UI_CHOICE_NT]"); - ntArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1900"); - ntArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[UI_CHOICE_NT_HOVER]"); - ntArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(ntArgs); - } - - options = choiceOptions; - - args.InsertValue("options", choiceOptions); -} - -void NsLegoClubDoor::OnUse(Entity* self, Entity* user) -{ - auto* player = user; - - if (CheckChoice(self, player)) - { - /** - { {"callbackClient", self}, - {"strIdentifier", "choiceDoor"}, - {"title", "%[UI_CHOICE_DESTINATION]"}, - {"options", choiceOptions} } - */ - AMFArrayValue* multiArgs = new AMFArrayValue(); - - AMFStringValue* callbackClient = new AMFStringValue(); - callbackClient->SetStringValue(std::to_string(self->GetObjectID())); - multiArgs->InsertValue("callbackClient", callbackClient); - - AMFStringValue* strIdentifier = new AMFStringValue(); - strIdentifier->SetStringValue("choiceDoor"); - multiArgs->InsertValue("strIdentifier", strIdentifier); - - AMFStringValue* title = new AMFStringValue(); - title->SetStringValue("%[UI_CHOICE_DESTINATION]"); - multiArgs->InsertValue("title", title); - - multiArgs->InsertValue("options", options); - - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs); - - delete multiArgs; - delete callbackClient; - delete strIdentifier; - delete title; - } - else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID) - { - /** - { {"state", "Lobby"}, - {"context", {{"user", msg.user}, {"callbackObj", self}, - {"HelpVisible", "show" }, {"type", "Lego_Club_Valid"}} }} - */ - AMFArrayValue* multiArgs = new AMFArrayValue(); - - AMFStringValue* state = new AMFStringValue(); - state->SetStringValue("Lobby"); - multiArgs->InsertValue("state", state); - - AMFArrayValue* context = new AMFArrayValue(); - - AMFStringValue* user = new AMFStringValue(); - user->SetStringValue(std::to_string(player->GetObjectID())); - context->InsertValue("user", user); - - AMFStringValue* callbackObj = new AMFStringValue(); - callbackObj->SetStringValue(std::to_string(self->GetObjectID())); - context->InsertValue("callbackObj", callbackObj); - - AMFStringValue* helpVisible = new AMFStringValue(); - helpVisible->SetStringValue("show"); - context->InsertValue("HelpVisible", helpVisible); - - AMFStringValue* type = new AMFStringValue(); - type->SetStringValue("Lego_Club_Valid"); - context->InsertValue("type", type); - - multiArgs->InsertValue("context", context); - - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "pushGameState", multiArgs); - - delete multiArgs; - delete state; - delete context; - delete user; - delete callbackObj; - delete helpVisible; - delete type; - } - else - { - BaseOnUse(self, player); - } -} - -void NsLegoClubDoor::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - std::u16string strIdentifier = identifier; - - if (strIdentifier == u"PlayButton" || strIdentifier == u"CloseButton") - { - strIdentifier = u"TransferBox"; - } - - BaseOnMessageBoxResponse(self, sender, button, strIdentifier, userData); -} - -void NsLegoClubDoor::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - BaseChoiceBoxRespond(self, sender, button, buttonIdentifier, identifier); -} - -void NsLegoClubDoor::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); -} - -void NsLegoClubDoor::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); -} diff --git a/dScripts/NsLegoClubDoor.h b/dScripts/NsLegoClubDoor.h deleted file mode 100644 index 7f17692d..00000000 --- a/dScripts/NsLegoClubDoor.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" -#include "BaseConsoleTeleportServer.h" - -class NsLegoClubDoor : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - -private: - int32_t m_ChoiceZoneID = 1700; - std::string m_SpawnPoint = "NS_LEGO_Club"; - std::u16string m_TeleportAnim = u"lup-teleport"; - std::u16string m_TeleportString = u"ROCKET_TOOLTIP_USE_THE_GATEWAY_TO_TRAVEL_TO_LUP_WORLD"; - AMFArrayValue args = {}; - AMFArrayValue* options = {}; -}; diff --git a/dScripts/NsLupTeleport.cpp b/dScripts/NsLupTeleport.cpp deleted file mode 100644 index 4c196d01..00000000 --- a/dScripts/NsLupTeleport.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "NsLupTeleport.h" -#include "dZoneManager.h" -#include "GameMessages.h" -#include "AMFFormat.h" - -void NsLupTeleport::OnStartup(Entity* self) -{ - self->SetVar(u"currentZone", (int32_t) dZoneManager::Instance()->GetZoneID().GetMapID()); - self->SetVar(u"choiceZone", m_ChoiceZoneID); - self->SetVar(u"teleportAnim", m_TeleportAnim); - self->SetVar(u"teleportString", m_TeleportString); - self->SetVar(u"spawnPoint", m_SpawnPoint); - - args = {}; - - AMFStringValue* callbackClient = new AMFStringValue(); - callbackClient->SetStringValue(std::to_string(self->GetObjectID())); - args.InsertValue("callbackClient", callbackClient); - - AMFStringValue* strIdentifier = new AMFStringValue(); - strIdentifier->SetStringValue("choiceDoor"); - args.InsertValue("strIdentifier", strIdentifier); - - AMFStringValue* title = new AMFStringValue(); - title->SetStringValue("%[UI_CHOICE_DESTINATION]"); - args.InsertValue("title", title); - - AMFArrayValue* choiceOptions = new AMFArrayValue(); - - { - AMFArrayValue* nsArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Nimbus_Station.dds"); - nsArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[UI_CHOICE_NS]"); - nsArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1200"); - nsArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[UI_CHOICE_NS_HOVER]"); - nsArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(nsArgs); - } - - { - AMFArrayValue* ntArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Nexus_Tower.dds"); - ntArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[UI_CHOICE_NT]"); - ntArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1900"); - ntArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[UI_CHOICE_NT_HOVER]"); - ntArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(ntArgs); - } - - args.InsertValue("options", choiceOptions); -} - -void NsLupTeleport::OnUse(Entity* self, Entity* user) -{ - auto* player = user; - - if (CheckChoice(self, player)) - { - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", &args); - } - else - { - BaseOnUse(self, player); - } -} - -void NsLupTeleport::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - BaseOnMessageBoxResponse(self, sender, button, identifier, userData); -} - -void NsLupTeleport::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - BaseChoiceBoxRespond(self, sender, button, buttonIdentifier, identifier); -} - -void NsLupTeleport::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); -} - -void NsLupTeleport::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); -} diff --git a/dScripts/NsLupTeleport.h b/dScripts/NsLupTeleport.h deleted file mode 100644 index 833f5f0a..00000000 --- a/dScripts/NsLupTeleport.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" -#include "BaseConsoleTeleportServer.h" - -class NsLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - -private: - int32_t m_ChoiceZoneID = 1600; - std::string m_SpawnPoint = "NS_LW"; - std::u16string m_TeleportAnim = u"lup-teleport"; - std::u16string m_TeleportString = u"UI_TRAVEL_TO_LUP_STATION"; - AMFArrayValue args = {}; -}; diff --git a/dScripts/NsQbImaginationStatue.cpp b/dScripts/NsQbImaginationStatue.cpp deleted file mode 100644 index 4404ba5f..00000000 --- a/dScripts/NsQbImaginationStatue.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "NsQbImaginationStatue.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void NsQbImaginationStatue::OnStartup(Entity* self) -{ - -} - -void NsQbImaginationStatue::OnRebuildComplete(Entity* self, Entity* target) -{ - if (target == nullptr) return; - - self->SetVar(u"Player", target->GetObjectID()); - - SpawnLoot(self); - - self->AddTimer("SpawnDelay", 1.5f); - - self->AddTimer("StopSpawner", 10.0f); -} - -void NsQbImaginationStatue::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "SpawnDelay") - { - SpawnLoot(self); - - self->AddTimer("SpawnDelay", 1.5f); - } - else if (timerName == "StopSpawner") - { - self->CancelAllTimers(); - } -} - -void NsQbImaginationStatue::SpawnLoot(Entity* self) -{ - const auto playerId = self->GetVar<LWOOBJID>(u"Player"); - - auto* player = EntityManager::Instance()->GetEntity(playerId); - - if (player == nullptr) return; - - GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); - GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); -} diff --git a/dScripts/NsQbImaginationStatue.h b/dScripts/NsQbImaginationStatue.h deleted file mode 100644 index 3d699ac9..00000000 --- a/dScripts/NsQbImaginationStatue.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NsQbImaginationStatue : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void SpawnLoot(Entity* self); -}; diff --git a/dScripts/NsTokenConsoleServer.cpp b/dScripts/NsTokenConsoleServer.cpp deleted file mode 100644 index 976b9bc8..00000000 --- a/dScripts/NsTokenConsoleServer.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "NsTokenConsoleServer.h" -#include "InventoryComponent.h" -#include "GameMessages.h" -#include "Character.h" -#include "MissionComponent.h" -#include "RebuildComponent.h" - -void NsTokenConsoleServer::OnStartup(Entity* self) -{ - -} - -void NsTokenConsoleServer::OnUse(Entity* self, Entity* user) -{ - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - - if (rebuildComponent == nullptr) - { - return; - } - - if (rebuildComponent->GetState() != REBUILD_COMPLETED) - { - return; - } - - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - auto* missionComponent = user->GetComponent<MissionComponent>(); - auto* character = user->GetCharacter(); - - if (inventoryComponent == nullptr || missionComponent == nullptr || character == nullptr) - { - return; - } - - if (inventoryComponent->GetLotCount(6194) < 25) - { - return; - } - - inventoryComponent->RemoveItem(6194, 25); - - const auto useSound = self->GetVar<std::string>(u"sound1"); - - if (!useSound.empty()) - { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, useSound); - } - - // Player must be in faction to interact with this entity. - LOT tokenLOT = 0; - - if (character->GetPlayerFlag(46)) - { - tokenLOT = 8321; - } - else if (character->GetPlayerFlag(47)) - { - tokenLOT = 8318; - } - else if (character->GetPlayerFlag(48)) - { - tokenLOT = 8320; - } - else if (character->GetPlayerFlag(49)) - { - tokenLOT = 8319; - } - - inventoryComponent->AddItem(tokenLOT, 5, eLootSourceType::LOOT_SOURCE_NONE); - - missionComponent->ForceProgressTaskType(863, 1, 1, false); - - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} diff --git a/dScripts/NtAssemblyTubeServer.cpp b/dScripts/NtAssemblyTubeServer.cpp deleted file mode 100644 index 935993f4..00000000 --- a/dScripts/NtAssemblyTubeServer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "NtAssemblyTubeServer.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void NtAssemblyTubeServer::OnStartup(Entity* self) -{ - self->SetProximityRadius(5, "teleport"); -} - -void NtAssemblyTubeServer::OnPlayerLoaded(Entity* self, Entity* player) -{ - -} - -void NtAssemblyTubeServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; - - auto* player = entering; - const auto playerID = player->GetObjectID(); - - RunAssemblyTube(self, player); - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } -} - -void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) -{ - const auto playerID = player->GetObjectID(); - - const auto iter = m_TeleportingPlayerTable.find(playerID); - if (iter == m_TeleportingPlayerTable.end()) m_TeleportingPlayerTable[playerID] = false; - const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; - - if (player->IsPlayer() && !bPlayerBeingTeleported) - { - auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); - - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); - - if (!teleCinematic.empty()) - { - const auto teleCinematicUname = teleCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, -1, false, true - ); - } - - GameMessages::SendPlayAnimation(player, u"tube-sucker", 4.0f); - - const auto animTime = 3; - - self->AddCallbackTimer(animTime, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - TeleportPlayer(self, player); - }); - } -} - -void NtAssemblyTubeServer::TeleportPlayer(Entity* self, Entity* player) -{ - auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); - auto* destination = self; - - if (!destinationGroup.empty()) - { - const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); - - if (!groupObjs.empty()) - { - destination = groupObjs[0]; - } - } - - const auto destPosition = destination->GetPosition(); - const auto destRotation = destination->GetRotation(); - - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); - - GameMessages::SendPlayAnimation(player, u"tube-resurrect", 4.0f); - - const auto animTime = 2; - - const auto playerID = player->GetObjectID(); - - self->AddCallbackTimer(animTime, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - UnlockPlayer(self, player); - }); - - const auto useSound = self->GetVar<std::string>(u"sound1"); - - if (!useSound.empty()) - { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); - } -} - -void NtAssemblyTubeServer::UnlockPlayer(Entity* self, Entity* player) -{ - const auto playerID = player->GetObjectID(); - - m_TeleportingPlayerTable[playerID] = false; - - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); -} diff --git a/dScripts/NtAssemblyTubeServer.h b/dScripts/NtAssemblyTubeServer.h deleted file mode 100644 index 116be068..00000000 --- a/dScripts/NtAssemblyTubeServer.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtAssemblyTubeServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnPlayerLoaded(Entity* self, Entity* player) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void RunAssemblyTube(Entity* self, Entity* player); - void TeleportPlayer(Entity* self, Entity* player); - void UnlockPlayer(Entity* self, Entity* player); - -private: - std::map<LWOOBJID, bool> m_TeleportingPlayerTable; -}; diff --git a/dScripts/NtBeamImaginationCollectors.cpp b/dScripts/NtBeamImaginationCollectors.cpp deleted file mode 100644 index ed756c02..00000000 --- a/dScripts/NtBeamImaginationCollectors.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "NtBeamImaginationCollectors.h" -#include "GeneralUtils.h" -#include "GameMessages.h" - -void NtBeamImaginationCollectors::OnStartup(Entity* self) -{ - self->AddTimer("PlayFX", GetRandomNum()); -} - -int32_t NtBeamImaginationCollectors::GetRandomNum() -{ - int32_t randNum = m_LastRandom; - - while (randNum == m_LastRandom) - { - randNum = GeneralUtils::GenerateRandomNumber<int32_t>(m_RandMin, m_RandMax); - } - - m_LastRandom = randNum; - - return randNum; -} - -void NtBeamImaginationCollectors::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName != "PlayFX") - { - return; - } - - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, m_FxName, "Beam"); - - self->AddTimer("PlayFX", GetRandomNum()); -} diff --git a/dScripts/NtBeamImaginationCollectors.h b/dScripts/NtBeamImaginationCollectors.h deleted file mode 100644 index d494d66c..00000000 --- a/dScripts/NtBeamImaginationCollectors.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtBeamImaginationCollectors : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - int32_t GetRandomNum(); - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - int32_t m_LastRandom = 0; - int32_t m_RandMin = 5; - int32_t m_RandMax = 15; - std::u16string m_FxName = u"beam_collect"; -}; diff --git a/dScripts/NtCombatChallengeDummy.cpp b/dScripts/NtCombatChallengeDummy.cpp deleted file mode 100644 index a391e00f..00000000 --- a/dScripts/NtCombatChallengeDummy.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "NtCombatChallengeDummy.h" -#include "EntityManager.h" - -void NtCombatChallengeDummy::OnDie(Entity* self, Entity* killer) -{ - const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); - - auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); - - if (challengeObject != nullptr) - { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) - { - script->OnDie(challengeObject, killer); - } - } -} - -void NtCombatChallengeDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) -{ - const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); - - auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); - - if (challengeObject != nullptr) - { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) - { - script->OnHitOrHealResult(challengeObject, attacker, damage); - } - } -} diff --git a/dScripts/NtCombatChallengeDummy.h b/dScripts/NtCombatChallengeDummy.h deleted file mode 100644 index d9ef8cbd..00000000 --- a/dScripts/NtCombatChallengeDummy.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtCombatChallengeDummy : public CppScripts::Script -{ -public: - void OnDie(Entity* self, Entity* killer) override; - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; -}; diff --git a/dScripts/NtCombatChallengeExplodingDummy.cpp b/dScripts/NtCombatChallengeExplodingDummy.cpp deleted file mode 100644 index 24494939..00000000 --- a/dScripts/NtCombatChallengeExplodingDummy.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "NtCombatChallengeExplodingDummy.h" -#include "EntityManager.h" -#include "SkillComponent.h" - -void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) -{ - const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); - - auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); - - if (challengeObject != nullptr) - { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) - { - script->OnDie(challengeObject, killer); - } - } -} - -void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { - const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); - - auto* challengeObject = EntityManager::Instance()->GetEntity(challengeObjectID); - - if (challengeObject != nullptr) - { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) - { - script->OnHitOrHealResult(challengeObject, attacker, damage); - } - } - auto skillComponent = self->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID()); - } - self->Kill(attacker); -} \ No newline at end of file diff --git a/dScripts/NtCombatChallengeExplodingDummy.h b/dScripts/NtCombatChallengeExplodingDummy.h deleted file mode 100644 index c1c5ef1c..00000000 --- a/dScripts/NtCombatChallengeExplodingDummy.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtCombatChallengeExplodingDummy : public CppScripts::Script -{ - void OnDie(Entity* self, Entity* killer) override; - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; -}; \ No newline at end of file diff --git a/dScripts/NtCombatChallengeServer.cpp b/dScripts/NtCombatChallengeServer.cpp deleted file mode 100644 index 4bf5dffc..00000000 --- a/dScripts/NtCombatChallengeServer.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include "NtCombatChallengeServer.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "InventoryComponent.h" -#include "MissionComponent.h" - -void NtCombatChallengeServer::OnUse(Entity* self, Entity* user) -{ - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Open", 0, 0, user->GetObjectID(), "", user->GetSystemAddress()); -} - -void NtCombatChallengeServer::OnDie(Entity* self, Entity* killer) -{ - if (killer != self && killer != nullptr) - { - SpawnTargetDummy(self); - } -} - - -void NtCombatChallengeServer::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) -{ - const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - auto totalDmg = self->GetVar<int32_t>(u"totalDmg"); - - totalDmg += damage; - - self->SetVar(u"totalDmg", totalDmg); - self->SetNetworkVar(u"totalDmg", totalDmg); - - GameMessages::SendPlayNDAudioEmitter(self, attacker->GetSystemAddress(), scoreSound); -} - - -void NtCombatChallengeServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) -{ - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 0, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); -} - - -void NtCombatChallengeServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - if (identifier == u"PlayButton" && button == 1) - { - self->SetNetworkVar(u"bInUse", true); - - self->SetVar(u"playerID", sender->GetObjectID()); - - auto* inventoryComponent = sender->GetComponent<InventoryComponent>(); - - if (inventoryComponent != nullptr) - { - inventoryComponent->RemoveItem(3039, 1); - } - - GameMessages::SendPlayNDAudioEmitter(self, sender->GetSystemAddress(), startSound); - - self->AddTimer("start_delay", 2.0f); - - GameMessages::SendShowActivityCountdown(self->GetObjectID(), false, false, u"", 0, sender->GetSystemAddress()); - - self->SetNetworkVar(u"toggle", true); - } - else if (identifier == u"CloseButton") - { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 1, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); - } -} - -void NtCombatChallengeServer::SpawnTargetDummy(Entity* self) -{ - const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - auto targetNumber = self->GetVar<int32_t>(u"TargetNumber"); - if (targetNumber == 0) targetNumber = 1; - - if (targetNumber > tTargets.size()) targetNumber = tTargets.size(); - - self->SetVar<int32_t>(u"TargetNumber", targetNumber + 1); - - const auto dummyLOT = tTargets[targetNumber - 1]; - - EntityInfo info {}; - info.lot = dummyLOT; - info.spawnerID = self->GetObjectID(); - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.settings = { new LDFData<std::string>(u"custom_script_server", "scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_DUMMY.lua") }; - - auto* dummy = EntityManager::Instance()->CreateEntity(info); - - dummy->SetVar(u"challengeObjectID", self->GetObjectID()); - - EntityManager::Instance()->ConstructEntity(dummy); - - self->SetVar(u"currentDummy", dummy->GetObjectID()); -} - -void NtCombatChallengeServer::SetAttackImmunity(LWOOBJID objID, bool bTurnOn) -{ - -} - -void NtCombatChallengeServer::OnChildLoaded(Entity* self, Entity* child) -{ - auto targetNumber = self->GetVar<int32_t>(u"TargetNumber"); - if (targetNumber == 0) targetNumber = 1; - self->SetVar(u"TargetNumber", targetNumber + 1); - - const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - child->SetRotation(NiQuaternion::LookAt(child->GetPosition(), player->GetPosition())); - - self->SetVar(u"currentTargetID", child->GetObjectID()); - - EntityManager::Instance()->SerializeEntity(child); - - child->GetGroups().push_back("targets_" + std::to_string(self->GetObjectID())); -} - -void NtCombatChallengeServer::ResetGame(Entity* self) -{ - const auto totalDmg = self->GetVar<int32_t>(u"totalDmg"); - const auto playerID = self->GetVar<LWOOBJID>(u"playerID"); - - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player != nullptr) - { - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - for (const auto& mission : tMissions) - { - if (totalDmg >= mission.damage) - { - missionComponent->ForceProgressTaskType(mission.mission, 1, 1); - } - } - } - } - - self->SetVar(u"TargetNumber", 1); - self->SetVar(u"playerID", LWOOBJID_EMPTY); - self->SetVar(u"totalDmg", 0); - self->SetNetworkVar(u"totalDmg", false); - self->SetNetworkVar(u"update_time", 0); - - const auto& targetObjs = EntityManager::Instance()->GetEntitiesInGroup("targets_" + std::to_string(self->GetObjectID())); - - for (auto* target : targetObjs) - { - target->Smash(self->GetObjectID()); - } - - const auto currentID = self->GetVar<LWOOBJID>(u"currentDummy"); - - auto* current = EntityManager::Instance()->GetEntity(currentID); - - if (current != nullptr) - { - current->Smash(self->GetObjectID()); - } -} - -void NtCombatChallengeServer::OnActivityTimerUpdate(Entity* self, float timeRemaining) -{ - self->SetNetworkVar(u"update_time", std::ceil(timeRemaining)); - - if (timeRemaining <= 3) - { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerLowSound); - } - else - { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerSound); - } -} - -void NtCombatChallengeServer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "start_delay") - { - self->SetVar(u"game_tick", gameTime); - - SpawnTargetDummy(self); - - self->AddTimer("game_tick", 1); - - self->SetNetworkVar(u"totalTime", gameTime); - } - else if (timerName == "game_tick") - { - auto gameTick = self->GetVar<float>(u"game_tick"); - - gameTick -= 1; - - self->SetVar(u"game_tick", gameTick); - - if (gameTick <= 0) - { - ResetGame(self); - - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, stopSound); - - self->AddTimer("reset_tick", 5); - } - else - { - self->AddTimer("game_tick", 1); - - OnActivityTimerUpdate(self, gameTick); - } - } - else if (timerName == "reset_tick") - { - self->SetNetworkVar(u"toggle", false); - self->SetNetworkVar(u"bInUse", false); - } -} diff --git a/dScripts/NtCombatChallengeServer.h b/dScripts/NtCombatChallengeServer.h deleted file mode 100644 index 6a193a11..00000000 --- a/dScripts/NtCombatChallengeServer.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtCombatChallengeServer : public CppScripts::Script -{ -public: - void OnUse(Entity* self, Entity* user) override; - void OnDie(Entity* self, Entity* killer) override; - void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void SpawnTargetDummy(Entity* self); - void SetAttackImmunity(LWOOBJID objID, bool bTurnOn); - void OnChildLoaded(Entity* self, Entity* child); - void ResetGame(Entity* self); - void OnActivityTimerUpdate(Entity* self, float timeRemaining); - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - float gameTime = 30.0f; - std::string startSound = "{a477f897-30da-4b15-8fce-895c6547adae}"; - std::string stopSound = "{a832b9c5-b000-4c97-820a-2a7d1e68dd9d}"; - std::string timerSound = "{79b38431-4fc7-403b-8ede-eaff700a7ab0}"; - std::string timerLowSound = "{0e1f1284-e1c4-42ed-8ef9-93e8756948f8}"; - std::string scoreSound = "{cfdade40-3d97-4cf5-b53c-862e0b84c1a1}"; - - std::vector<LOT> tTargets = { - 13556, 13556, 13764, 13764, 13765, 13765, - 13766, 13766, 13767, 13767, 13768, 13768, - 13830, 13769, 13769, 13770, 13830, 13770, - 13771, 13771, 13830, 13772 - }; - - struct MissionRequirements - { - int32_t mission; - int32_t damage; - }; - - std::vector<MissionRequirements> tMissions = { - {1010, 25}, - {1340, 100}, - {1341, 240}, - {1342, 290} - }; -}; diff --git a/dScripts/NtConsoleTeleportServer.cpp b/dScripts/NtConsoleTeleportServer.cpp deleted file mode 100644 index b03ae34e..00000000 --- a/dScripts/NtConsoleTeleportServer.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "NtConsoleTeleportServer.h" -#include "Entity.h" -#include "AMFFormat.h" - -void NtConsoleTeleportServer::OnStartup(Entity* self) -{ - self->SetVar(u"teleportAnim", m_TeleportAnim); - self->SetVar(u"teleportString", m_TeleportString); -} - -void NtConsoleTeleportServer::OnUse(Entity* self, Entity* user) -{ - BaseOnUse(self, user); -} - -void NtConsoleTeleportServer::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - BaseOnMessageBoxResponse(self, sender, button, identifier, userData); -} - -void NtConsoleTeleportServer::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - -} - -void NtConsoleTeleportServer::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); -} - -void NtConsoleTeleportServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); -} diff --git a/dScripts/NtConsoleTeleportServer.h b/dScripts/NtConsoleTeleportServer.h deleted file mode 100644 index 7bba7ee1..00000000 --- a/dScripts/NtConsoleTeleportServer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" -#include "BaseConsoleTeleportServer.h" - -class NtConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - -private: - int32_t m_ChoiceZoneID = 1800; - std::string m_SpawnPoint = "NS_LW"; - std::u16string m_TeleportAnim = u"lup-teleport"; - std::u16string m_TeleportString = u"UI_TRAVEL_TO_CRUX_PRIME"; -}; diff --git a/dScripts/NtDirtCloudServer.cpp b/dScripts/NtDirtCloudServer.cpp deleted file mode 100644 index 82572703..00000000 --- a/dScripts/NtDirtCloudServer.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "NtDirtCloudServer.h" -#include "MissionComponent.h" - -std::map<std::string, std::vector<int32_t>> NtDirtCloudServer::m_Missions = -{ - {"Dirt_Clouds_Sent", {1333,1253}}, - {"Dirt_Clouds_Assem", {1333,1276}}, - {"Dirt_Clouds_Para", {1333,1277}}, - {"Dirt_Clouds_Halls", {1333,1283}} -}; - -void NtDirtCloudServer::OnStartup(Entity* self) -{ - self->SetVar(u"CloudOn", true); -} - -void NtDirtCloudServer::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) -{ - if (message != "soapspray") - { - return; - } - - if (!self->GetVar<bool>(u"CloudOn")) - { - return; - } - - const auto mySpawner = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); - - if (m_Missions.count(mySpawner) == 0) - { - return; - } - - const auto& myMis = m_Missions[mySpawner]; - - auto* missionComponent = caster->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) - { - return; - } - - for (const auto missionID : myMis) - { - missionComponent->ForceProgressTaskType(missionID, 1, 1); - } - - self->SetVar(u"CloudOn", false); - - self->Smash(self->GetObjectID(), VIOLENT); -} diff --git a/dScripts/NtDirtCloudServer.h b/dScripts/NtDirtCloudServer.h deleted file mode 100644 index 0c9e50d1..00000000 --- a/dScripts/NtDirtCloudServer.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtDirtCloudServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; - -private: - static std::map<std::string, std::vector<int32_t>> m_Missions; -}; diff --git a/dScripts/NtDukeServer.cpp b/dScripts/NtDukeServer.cpp deleted file mode 100644 index df3f39d6..00000000 --- a/dScripts/NtDukeServer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "NtDukeServer.h" -#include "InventoryComponent.h" -#include "MissionComponent.h" - -void NtDukeServer::SetVariables(Entity *self) { - self->SetVar<float_t>(m_SpyProximityVariable, 35.0f); - - self->SetVar<SpyData>(m_SpyDataVariable, { - NT_FACTION_SPY_DUKE, 13548, 1319 - }); - - self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { - { "DUKE_NT_CONVO_1", 0 }, - { "DUKE_NT_CONVO_2", 0 }, - { "DUKE_NT_CONVO_3", 0 }, - }); - - // If there's an alternating conversation, indices should be provided using the conversationID variables - self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); -} - -void NtDukeServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - - // Handles adding and removing the sword for the Crux Prime Sword mission - auto* missionComponent = target->GetComponent<MissionComponent>(); - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - - if (missionComponent != nullptr && inventoryComponent != nullptr) { - auto state = missionComponent->GetMissionState(m_SwordMissionID); - auto lotCount = inventoryComponent->GetLotCount(m_SwordLot); - - if ((state == MissionState::MISSION_STATE_AVAILABLE || state == MissionState::MISSION_STATE_ACTIVE) && lotCount < 1) { - inventoryComponent->AddItem(m_SwordLot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (state == MissionState::MISSION_STATE_READY_TO_COMPLETE) { - inventoryComponent->RemoveItem(m_SwordLot, lotCount); - } - } -} diff --git a/dScripts/NtDukeServer.h b/dScripts/NtDukeServer.h deleted file mode 100644 index f56e9912..00000000 --- a/dScripts/NtDukeServer.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "NtFactionSpyServer.h" - -class NtDukeServer : public NtFactionSpyServer { - void SetVariables(Entity *self) override; - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; - const uint32_t m_SwordMissionID = 1448; - const LOT m_SwordLot = 13777; -}; diff --git a/dScripts/NtFactionSpyServer.cpp b/dScripts/NtFactionSpyServer.cpp index f1104e34..a1161880 100644 --- a/dScripts/NtFactionSpyServer.cpp +++ b/dScripts/NtFactionSpyServer.cpp @@ -4,97 +4,101 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" +#include "eCinematicEvent.h" +#include "ePlayerFlag.h" -void NtFactionSpyServer::OnStartup(Entity *self) { - SetVariables(self); +void NtFactionSpyServer::OnStartup(Entity* self) { + SetVariables(self); - // Set the proximity to sense later - auto* proximityMonitor = self->GetComponent<ProximityMonitorComponent>(); - if (proximityMonitor == nullptr) { - proximityMonitor = new ProximityMonitorComponent(self, -1, -1); - self->AddComponent(COMPONENT_TYPE_PROXIMITY_MONITOR, proximityMonitor); - } + // Set the proximity to sense later + auto* proximityMonitor = self->GetComponent<ProximityMonitorComponent>(); + if (proximityMonitor == nullptr) { + proximityMonitor = new ProximityMonitorComponent(self, -1, -1); + self->AddComponent(eReplicaComponentType::PROXIMITY_MONITOR, proximityMonitor); + } - proximityMonitor->SetProximityRadius(self->GetVar<float_t>(m_SpyProximityVariable), m_ProximityName); + proximityMonitor->SetProximityRadius(self->GetVar<float_t>(m_SpyProximityVariable), m_ProximityName); } void NtFactionSpyServer::SetVariables(Entity* self) { - self->SetVar<float_t>(m_SpyProximityVariable, 0.0f); - self->SetVar<SpyData>(m_SpyDataVariable, {}); - self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, {}); + self->SetVar<float_t>(m_SpyProximityVariable, 0.0f); + self->SetVar<SpyData>(m_SpyDataVariable, {}); + self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, {}); - // If there's an alternating conversation, indices should be provided using the conversationID variables - self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); + // If there's an alternating conversation, indices should be provided using the conversationID variables + self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); } -void NtFactionSpyServer::OnProximityUpdate(Entity *self, Entity *entering, std::string name, std::string status) { - if (name == m_ProximityName && status == "ENTER" && IsSpy(self, entering)) { - auto cinematic = self->GetVar<std::u16string>(m_SpyCinematicVariable); - if (!cinematic.empty()) { +void NtFactionSpyServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (name == m_ProximityName && status == "ENTER" && IsSpy(self, entering)) { + auto cinematic = self->GetVar<std::u16string>(m_SpyCinematicVariable); + if (!cinematic.empty()) { - // Save the root of this cinematic so we can identify updates later - auto cinematicSplit = GeneralUtils::SplitString(cinematic, u'_'); - if (!cinematicSplit.empty()) { - self->SetVar<std::u16string>(m_CinematicRootVariable, cinematicSplit.at(0)); - } + // Save the root of this cinematic so we can identify updates later + auto cinematicSplit = GeneralUtils::SplitString(cinematic, u'_'); + if (!cinematicSplit.empty()) { + self->SetVar<std::u16string>(m_CinematicRootVariable, cinematicSplit.at(0)); + } - GameMessages::SendPlayCinematic(entering->GetObjectID(), cinematic, entering->GetSystemAddress(), - true, true, true); - } - } + GameMessages::SendPlayCinematic(entering->GetObjectID(), cinematic, entering->GetSystemAddress(), + true, true, true); + } + } } -bool NtFactionSpyServer::IsSpy(Entity* self, Entity *possibleSpy) { - auto spyData = self->GetVar<SpyData>(m_SpyDataVariable); - if (!spyData.missionID || !spyData.flagID || !spyData.itemID) - return false; +bool NtFactionSpyServer::IsSpy(Entity* self, Entity* possibleSpy) { + auto spyData = self->GetVar<SpyData>(m_SpyDataVariable); + if (!spyData.missionID || !spyData.flagID || !spyData.itemID) + return false; - auto* missionComponent = possibleSpy->GetComponent<MissionComponent>(); - auto* inventoryComponent = possibleSpy->GetComponent<InventoryComponent>(); - auto* character = possibleSpy->GetCharacter(); + auto* missionComponent = possibleSpy->GetComponent<MissionComponent>(); + auto* inventoryComponent = possibleSpy->GetComponent<InventoryComponent>(); + auto* character = possibleSpy->GetCharacter(); - // A player is a spy if they have the spy mission, have the spy equipment equipped and don't have the spy flag set yet - return missionComponent != nullptr && missionComponent->GetMissionState(spyData.missionID) == MissionState::MISSION_STATE_ACTIVE - && inventoryComponent != nullptr && inventoryComponent->IsEquipped(spyData.itemID) - && character != nullptr && !character->GetPlayerFlag(spyData.flagID); + // A player is a spy if they have the spy mission, have the spy equipment equipped and don't have the spy flag set yet + return missionComponent != nullptr && missionComponent->GetMissionState(spyData.missionID) == eMissionState::ACTIVE + && inventoryComponent != nullptr && inventoryComponent->IsEquipped(spyData.itemID) + && character != nullptr && !character->GetPlayerFlag(spyData.flagID); } -void NtFactionSpyServer::OnCinematicUpdate(Entity *self, Entity *sender, eCinematicEvent event, - const std::u16string &pathName, float_t pathTime, float_t totalTime, - int32_t waypoint) { +void NtFactionSpyServer::OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, + const std::u16string& pathName, float_t pathTime, float_t totalTime, + int32_t waypoint) { - const auto& cinematicRoot = self->GetVar<std::u16string>(m_CinematicRootVariable); - auto pathNameCopy = std::u16string(pathName); // Mutable copy - auto pathSplit = GeneralUtils::SplitString(pathNameCopy, u'_'); + const auto& cinematicRoot = self->GetVar<std::u16string>(m_CinematicRootVariable); + auto pathNameCopy = std::u16string(pathName); // Mutable copy + auto pathSplit = GeneralUtils::SplitString(pathNameCopy, u'_'); - // Make sure we have a path of type <root>_<index> - if (pathSplit.size() >= 2) { - auto pathRoot = pathSplit.at(0); - auto pathIndex = std::stoi(GeneralUtils::UTF16ToWTF8(pathSplit.at(1))) - 1; - const auto& dialogueTable = self->GetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable); + // Make sure we have a path of type <root>_<index> + if (pathSplit.size() >= 2) { + auto pathRoot = pathSplit.at(0); + auto pathIndex = std::stoi(GeneralUtils::UTF16ToWTF8(pathSplit.at(1))) - 1; + const auto& dialogueTable = self->GetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable); - // Make sure we're listening to the root we're interested in - if (pathRoot == cinematicRoot) { - if (event == STARTED && pathIndex >= 0 && pathIndex < dialogueTable.size()) { + // Make sure we're listening to the root we're interested in + if (pathRoot == cinematicRoot) { + if (event == eCinematicEvent::STARTED && pathIndex >= 0 && pathIndex < dialogueTable.size()) { - // If the cinematic started, show part of the conversation - GameMessages::SendNotifyClientObject(self->GetObjectID(), m_SpyDialogueNotification, 0, - 0, ParamObjectForConversationID(self, dialogueTable.at(pathIndex).conversationID), - dialogueTable.at(pathIndex).token, sender->GetSystemAddress()); + // If the cinematic started, show part of the conversation + GameMessages::SendNotifyClientObject(self->GetObjectID(), m_SpyDialogueNotification, 0, + 0, ParamObjectForConversationID(self, dialogueTable.at(pathIndex).conversationID), + dialogueTable.at(pathIndex).token, sender->GetSystemAddress()); - } else if (event == ENDED && pathIndex >= dialogueTable.size() - 1) { - auto spyData = self->GetVar<SpyData>(m_SpyDataVariable); - auto* character = sender->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(spyData.flagID, true); - } - } - } - } + } else if (event == eCinematicEvent::ENDED && pathIndex >= dialogueTable.size() - 1) { + auto spyData = self->GetVar<SpyData>(m_SpyDataVariable); + auto* character = sender->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(spyData.flagID, true); + } + } + } + } } LWOOBJID NtFactionSpyServer::ParamObjectForConversationID(Entity* self, uint32_t conversationID) { - auto paramObjects = self->GetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable); - auto index = conversationID >= paramObjects.size() ? paramObjects.size() - 1 : conversationID; - return paramObjects.at(index); + auto paramObjects = self->GetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable); + auto index = conversationID >= paramObjects.size() ? paramObjects.size() - 1 : conversationID; + return paramObjects.at(index); } diff --git a/dScripts/NtFactionSpyServer.h b/dScripts/NtFactionSpyServer.h index ec8df1f4..4406859c 100644 --- a/dScripts/NtFactionSpyServer.h +++ b/dScripts/NtFactionSpyServer.h @@ -2,31 +2,31 @@ #include "CppScripts.h" struct SpyDialogue { - std::string token; - uint32_t conversationID; + std::string token; + uint32_t conversationID; }; struct SpyData { - uint32_t flagID; - LOT itemID; - uint32_t missionID; + int32_t flagID; + LOT itemID; + uint32_t missionID; }; class NtFactionSpyServer : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnProximityUpdate(Entity *self, Entity *entering, std::string name, std::string status) override; - void OnCinematicUpdate(Entity *self, Entity *sender, eCinematicEvent event, const std::u16string &pathName, float_t pathTime, float_t totalTime, int32_t waypoint) override; + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, float_t pathTime, float_t totalTime, int32_t waypoint) override; protected: - virtual void SetVariables(Entity* self); - bool IsSpy(Entity* self, Entity* possibleSpy); - LWOOBJID ParamObjectForConversationID(Entity* self, uint32_t conversationID); + virtual void SetVariables(Entity* self); + bool IsSpy(Entity* self, Entity* possibleSpy); + LWOOBJID ParamObjectForConversationID(Entity* self, uint32_t conversationID); - const std::string m_ProximityName = "SpyDistance"; - const std::u16string m_SpyDialogueNotification = u"displayDialogueLine"; - const std::u16string m_SpyCinematicVariable = u"SpyCinematic"; - const std::u16string m_SpyCinematicObjectsVariable = u"SpyCinematicObjects"; - const std::u16string m_CinematicRootVariable = u"CinematicRoot"; - const std::u16string m_SpyProximityVariable = u"Proximity"; - const std::u16string m_SpyDialogueTableVariable = u"SpyDialogueTable"; - const std::u16string m_SpyDataVariable = u"SpyData"; + const std::string m_ProximityName = "SpyDistance"; + const std::u16string m_SpyDialogueNotification = u"displayDialogueLine"; + const std::u16string m_SpyCinematicVariable = u"SpyCinematic"; + const std::u16string m_SpyCinematicObjectsVariable = u"SpyCinematicObjects"; + const std::u16string m_CinematicRootVariable = u"CinematicRoot"; + const std::u16string m_SpyProximityVariable = u"Proximity"; + const std::u16string m_SpyDialogueTableVariable = u"SpyDialogueTable"; + const std::u16string m_SpyDataVariable = u"SpyData"; }; diff --git a/dScripts/NtHaelServer.cpp b/dScripts/NtHaelServer.cpp deleted file mode 100644 index a4c16e1f..00000000 --- a/dScripts/NtHaelServer.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "NtHaelServer.h" -#include "Entity.h" - -void NtHaelServer::SetVariables(Entity *self) { - self->SetVar<float_t>(m_SpyProximityVariable, 25.0f); - - self->SetVar<SpyData>(m_SpyDataVariable, { - NT_FACTION_SPY_HAEL, 13892, 1321 - }); - - self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { - { "HAEL_NT_CONVO_1", 0 }, - { "HAEL_NT_CONVO_2", 0 }, - { "HAEL_NT_CONVO_3", 0 }, - { "HAEL_NT_CONVO_4", 0 }, - }); - - // If there's an alternating conversation, indices should be provided using the conversationID variables - self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); -} diff --git a/dScripts/NtImagBeamBuffer.cpp b/dScripts/NtImagBeamBuffer.cpp deleted file mode 100644 index 067a8d61..00000000 --- a/dScripts/NtImagBeamBuffer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "NtImagBeamBuffer.h" -#include "EntityManager.h" -#include "SkillComponent.h" - -void NtImagBeamBuffer::OnStartup(Entity* self) -{ - self->SetProximityRadius(100, "ImagZone"); - - self->AddTimer("BuffImag", 2.0f); -} - -void NtImagBeamBuffer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (name != "ImagZone" || !entering->IsPlayer()) - { - return; - } - - if (status == "ENTER") - { - const auto& iter = std::find(m_EntitiesInProximity.begin(), m_EntitiesInProximity.end(), entering->GetObjectID()); - - if (iter == m_EntitiesInProximity.end()) - { - m_EntitiesInProximity.push_back(entering->GetObjectID()); - } - } - else if (status == "LEAVE") - { - const auto& iter = std::find(m_EntitiesInProximity.begin(), m_EntitiesInProximity.end(), entering->GetObjectID()); - - if (iter != m_EntitiesInProximity.end()) - { - m_EntitiesInProximity.erase(iter); - } - } -} - -void NtImagBeamBuffer::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName != "BuffImag") - { - return; - } - - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - for (const auto entityID : m_EntitiesInProximity) - { - auto* entity = EntityManager::Instance()->GetEntity(entityID); - - if (entity == nullptr) - { - continue; - } - - skillComponent->CalculateBehavior(1311, 30235, entityID, true); - } - - self->AddTimer("BuffImag", 2.0f); -} diff --git a/dScripts/NtImagBeamBuffer.h b/dScripts/NtImagBeamBuffer.h deleted file mode 100644 index 4c6c7fc3..00000000 --- a/dScripts/NtImagBeamBuffer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtImagBeamBuffer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - std::vector<LWOOBJID> m_EntitiesInProximity = {}; -}; diff --git a/dScripts/NtOverbuildServer.cpp b/dScripts/NtOverbuildServer.cpp deleted file mode 100644 index 7bc62f50..00000000 --- a/dScripts/NtOverbuildServer.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "NtOverbuildServer.h" -#include "EntityManager.h" - -void NtOverbuildServer::SetVariables(Entity *self) { - self->SetVar<float_t>(m_SpyProximityVariable, 30.0f); - - self->SetVar<SpyData>(m_SpyDataVariable, { - NT_FACTION_SPY_OVERBUILD, 13891, 1320 - }); - - self->SetVar<std::vector<SpyDialogue>>(m_SpyDialogueTableVariable, { - { "OVERBUILD_NT_CONVO_1", 0 }, - { "OVERBUILD_NT_CONVO_2", 1 }, - { "OVERBUILD_NT_CONVO_3", 0 }, - { "OVERBUILD_NT_CONVO_4", 1 }, - { "OVERBUILD_NT_CONVO_5", 0 }, - { "OVERBUILD_NT_CONVO_6", 1 }, - { "OVERBUILD_NT_CONVO_7", 0 }, - }); - - // Find the second object Dr. Overbuild interacts with - LWOOBJID otherConvoObjectID = LWOOBJID_EMPTY; - for (auto* otherConvoObject : EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(m_OtherEntitiesGroupVariable)))) { - otherConvoObjectID = otherConvoObject->GetObjectID(); - break; - } - - // If there's an alternating conversation, indices should be provided using the conversationID variables - self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID(), otherConvoObjectID }); -} diff --git a/dScripts/NtOverbuildServer.h b/dScripts/NtOverbuildServer.h deleted file mode 100644 index 301dd4e3..00000000 --- a/dScripts/NtOverbuildServer.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "NtFactionSpyServer.h" - -class NtOverbuildServer : public NtFactionSpyServer { - void SetVariables(Entity *self) override; - const std::u16string m_OtherEntitiesGroupVariable = u"SpyConvo2Group"; -}; diff --git a/dScripts/NtParadoxTeleServer.cpp b/dScripts/NtParadoxTeleServer.cpp deleted file mode 100644 index 84222374..00000000 --- a/dScripts/NtParadoxTeleServer.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "NtParadoxTeleServer.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void NtParadoxTeleServer::OnStartup(Entity* self) -{ - self->SetProximityRadius(5, "teleport"); -} - -void NtParadoxTeleServer::OnPlayerLoaded(Entity* self, Entity* player) -{ - -} - -void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; - - auto* player = entering; - const auto playerID = player->GetObjectID(); - - const auto iter = m_TeleportingPlayerTable.find(playerID); - if (iter == m_TeleportingPlayerTable.end()) m_TeleportingPlayerTable[playerID] = false; - const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; - - if (player->IsPlayer() && !bPlayerBeingTeleported) - { - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); - - GameMessages::SendPlayAnimation(player, u"teledeath", 4.0f); - - const auto animTime = 2; - - self->AddCallbackTimer(animTime, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - TeleportPlayer(self, player); - }); - } - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } -} - -void NtParadoxTeleServer::TeleportPlayer(Entity* self, Entity* player) -{ - auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); - auto* destination = self; - - if (!destinationGroup.empty()) - { - const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); - - if (!groupObjs.empty()) - { - destination = groupObjs[0]; - } - } - - const auto destPosition = destination->GetPosition(); - const auto destRotation = destination->GetRotation(); - - auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); - - if (!teleCinematic.empty()) - { - const auto teleCinematicUname = teleCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); - } - - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); - - GameMessages::SendPlayAnimation(player, u"paradox-teleport-in", 4.0f); - - const auto animTime = 2; - - const auto playerID = player->GetObjectID(); - - self->AddCallbackTimer(animTime, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - UnlockPlayer(self, player); - }); - - const auto useSound = self->GetVar<std::string>(u"sound1"); - - if (!useSound.empty()) - { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); - } -} - -void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) -{ - const auto playerID = player->GetObjectID(); - - m_TeleportingPlayerTable[playerID] = false; - - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); - - auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); - - if (!teleCinematic.empty()) - { - const auto teleCinematicUname = teleCinematic; - GameMessages::SendEndCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); - } -} diff --git a/dScripts/NtParadoxTeleServer.h b/dScripts/NtParadoxTeleServer.h deleted file mode 100644 index 9f73bd85..00000000 --- a/dScripts/NtParadoxTeleServer.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtParadoxTeleServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnPlayerLoaded(Entity* self, Entity* player) override; - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - void TeleportPlayer(Entity* self, Entity* player); - void UnlockPlayer(Entity* self, Entity* player); - -private: - std::map<LWOOBJID, bool> m_TeleportingPlayerTable; -}; diff --git a/dScripts/NtSentinelWalkwayServer.cpp b/dScripts/NtSentinelWalkwayServer.cpp deleted file mode 100644 index 3d7c75a3..00000000 --- a/dScripts/NtSentinelWalkwayServer.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "NtSentinelWalkwayServer.h" -#include "PhantomPhysicsComponent.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void NtSentinelWalkwayServer::OnStartup(Entity* self) -{ - auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); - - if (phantomPhysicsComponent == nullptr) - { - return; - } - - auto force = self->GetVar<int32_t>(u"force"); - - if (force == 0) - { - force = 115; - } - - const auto forward = self->GetRotation().GetRightVector() * -1; - - phantomPhysicsComponent->SetEffectType(0); // PUSH - phantomPhysicsComponent->SetDirectionalMultiplier(force); - phantomPhysicsComponent->SetDirection(forward); - phantomPhysicsComponent->SetPhysicsEffectActive(true); - - EntityManager::Instance()->SerializeEntity(self); - - self->SetProximityRadius(3, "speedboost"); -} - -void NtSentinelWalkwayServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (name != "speedboost" || !entering->IsPlayer() || status != "ENTER") - { - return; - } - - auto* player = entering; - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } -} diff --git a/dScripts/NtVandaServer.cpp b/dScripts/NtVandaServer.cpp deleted file mode 100644 index 29750101..00000000 --- a/dScripts/NtVandaServer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "NtVandaServer.h" -#include "InventoryComponent.h" - -void NtVandaServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - - // Removes the alien parts after completing the mission - if (missionID == m_AlienPartMissionID && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { - auto* inventoryComponent = target->GetComponent<InventoryComponent>(); - for (const auto& alienPartLot : m_AlienPartLots) { - inventoryComponent->RemoveItem(alienPartLot, 1); - } - } -} diff --git a/dScripts/NtVandaServer.h b/dScripts/NtVandaServer.h deleted file mode 100644 index 84d494fc..00000000 --- a/dScripts/NtVandaServer.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtVandaServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - const uint32_t m_AlienPartMissionID = 1183; - const std::vector<LOT> m_AlienPartLots = { 12479, 12480, 12481 }; -}; diff --git a/dScripts/NtVentureCannonServer.cpp b/dScripts/NtVentureCannonServer.cpp deleted file mode 100644 index 66172733..00000000 --- a/dScripts/NtVentureCannonServer.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "NtVentureCannonServer.h" -#include "GameMessages.h" -#include "EntityManager.h" - -void NtVentureCannonServer::OnUse(Entity* self, Entity* user) -{ - auto* player = user; - const auto playerID = player->GetObjectID(); - - auto enterCinematic = self->GetVar<std::u16string>(u"EnterCinematic"); - - if (enterCinematic.empty()) - { - return; - } - - self->SetNetworkVar(u"bIsInUse", true); - - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); - - auto destPosition = self->GetPosition(); - - destPosition.y += 5 - 1.57f; - - auto destRotation = self->GetRotation(); - - GameMessages::SendTeleport(playerID, destPosition, destRotation, player->GetSystemAddress(), true); - - GameMessages::SendPlayAnimation(player, u"scale-down", 4.0f); - - const auto enterCinematicUname = enterCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), enterCinematicUname, player->GetSystemAddress()); - - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), "{e8bf79ce-7453-4a7d-b872-fee65e97ff15}"); - - self->AddCallbackTimer(3, [this, self]() { - self->SetNetworkVar(u"bIsInUse", false); - }); - - self->AddCallbackTimer(1.5f, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - EnterCannonEnded(self, player); - }); -} - -void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) -{ - const auto playerID = player->GetObjectID(); - - const auto& cannonEffectGroup = EntityManager::Instance()->GetEntitiesInGroup("cannonEffect"); - - if (!cannonEffectGroup.empty()) - { - auto* cannonEffect = cannonEffectGroup[0]; - - GameMessages::SendPlayFXEffect(cannonEffect, 6036, u"create", "cannon_blast", LWOOBJID_EMPTY, 1, 1, true); - - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(cannonEffect, u"camshake-bridge", cannonEffect->GetObjectID(), 100); - } - - FirePlayer(self, player); - - auto exitCinematic = self->GetVar<std::u16string>(u"ExitCinematic"); - - if (exitCinematic.empty()) - { - UnlockCannonPlayer(self, player); - - return; - } - - const auto exitCinematicUname = exitCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, 0, false, false - ); - - self->AddCallbackTimer(1.5f, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - ExitCannonEnded(self, player); - }); -} - -void NtVentureCannonServer::ExitCannonEnded(Entity* self, Entity* player) -{ - UnlockCannonPlayer(self, player); -} - -void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) -{ - GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true - ); - - self->SetNetworkVar(u"bIsInUse", false); - - GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} - -void NtVentureCannonServer::FirePlayer(Entity* self, Entity* player) -{ - auto destinationGroup = self->GetVar<std::u16string>(u"teleGroup"); - auto* destination = self; - - if (!destinationGroup.empty()) - { - const auto& groupObjs = EntityManager::Instance()->GetEntitiesInGroup(GeneralUtils::UTF16ToWTF8(destinationGroup)); - - if (!groupObjs.empty()) - { - destination = groupObjs[0]; - } - } - - const auto destPosition = destination->GetPosition(); - const auto destRotation = destination->GetRotation(); - - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); - - GameMessages::SendPlayAnimation(player, u"venture-cannon-out", 4.0f); -} diff --git a/dScripts/NtVentureCannonServer.h b/dScripts/NtVentureCannonServer.h deleted file mode 100644 index 5ad6a54e..00000000 --- a/dScripts/NtVentureCannonServer.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class NtVentureCannonServer : public CppScripts::Script -{ -public: - void OnUse(Entity* self, Entity* user) override; - void EnterCannonEnded(Entity* self, Entity* player); - void ExitCannonEnded(Entity* self, Entity* player); - void UnlockCannonPlayer(Entity* self, Entity* player); - void FirePlayer(Entity* self, Entity* player); -}; diff --git a/dScripts/NtVentureSpeedPadServer.cpp b/dScripts/NtVentureSpeedPadServer.cpp deleted file mode 100644 index 19a752d2..00000000 --- a/dScripts/NtVentureSpeedPadServer.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "NtVentureSpeedPadServer.h" -#include "SkillComponent.h" -#include "MissionComponent.h" - -void NtVentureSpeedPadServer::OnStartup(Entity* self) -{ - self->SetProximityRadius(3, "speedboost"); -} - - -void NtVentureSpeedPadServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (name != "speedboost" || !entering->IsPlayer() || status != "ENTER") - { - return; - } - - auto* player = entering; - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); - } - - auto* skillComponent = player->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(927, 18913, player->GetObjectID(), true); - } -} diff --git a/dScripts/NtXRayServer.cpp b/dScripts/NtXRayServer.cpp deleted file mode 100644 index b65cf65b..00000000 --- a/dScripts/NtXRayServer.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "NtXRayServer.h" -#include "SkillComponent.h" - -void NtXRayServer::OnCollisionPhantom(Entity* self, Entity* target) -{ - auto* skillComponent = target->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(1220, 27641, target->GetObjectID()); -} diff --git a/dScripts/PersonalFortress.cpp b/dScripts/PersonalFortress.cpp deleted file mode 100644 index 88ac9163..00000000 --- a/dScripts/PersonalFortress.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "PersonalFortress.h" -#include "GameMessages.h" -#include "SkillComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" - -void PersonalFortress::OnStartup(Entity* self) -{ - auto* owner = self->GetOwner(); - self->AddTimer("FireSkill", 1.5); - GameMessages::SendSetStunned(owner->GetObjectID(), PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true, true, true - ); - - auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) - { - destroyableComponent->PushImmunity(); - } - - EntityManager::Instance()->SerializeEntity(owner); -} - -void PersonalFortress::OnDie(Entity* self, Entity* killer) -{ - auto* owner = self->GetOwner(); - GameMessages::SendSetStunned(owner->GetObjectID(), POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true, true, true - ); - - auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) - { - destroyableComponent->PopImmunity(); - } - - EntityManager::Instance()->SerializeEntity(owner); -} - -void PersonalFortress::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "FireSkill") - { - auto* owner = self->GetOwner(); - - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); - } -} diff --git a/dScripts/PetDigBuild.cpp b/dScripts/PetDigBuild.cpp deleted file mode 100644 index 7ff88fff..00000000 --- a/dScripts/PetDigBuild.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "PetDigBuild.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { - auto flagNumber = self->GetVar<std::u16string>(u"flagNum"); - - EntityInfo info {}; - auto pos = self->GetPosition(); - pos.SetY(pos.GetY() + 0.5f); - info.pos = pos; - info.rot = self->GetRotation(); - info.spawnerID = self->GetSpawnerID(); - info.settings = { - new LDFData<LWOOBJID>(u"builder", target->GetObjectID()), - new LDFData<LWOOBJID>(u"X", self->GetObjectID()) - }; - - if (!flagNumber.empty()) { - info.lot = 7410; // Normal GF treasure - info.settings.push_back(new LDFData<std::u16string>(u"groupID", u"Flag" + flagNumber)); - } else { - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(746) == MissionState::MISSION_STATE_ACTIVE) { - info.lot = 9307; // Special Captain Jack treasure that drops a mission item - } else { - info.lot = 3495; // Normal AG treasure - } - } - - auto* treasure = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(treasure); - self->SetVar<LWOOBJID>(u"chestObj", treasure->GetObjectID()); -} - -void PetDigBuild::OnDie(Entity* self, Entity* killer) { - auto treasureID = self->GetVar<LWOOBJID>(u"chestObj"); - if (treasureID == LWOOBJID_EMPTY) - return; - - auto treasure = EntityManager::Instance()->GetEntity(treasureID); - if (treasure == nullptr) - return; - - // If the quick build expired and the treasure was not collected, hide the treasure - if (!treasure->GetIsDead()) { - treasure->Smash(self->GetObjectID(), SILENT); - } -} diff --git a/dScripts/PetDigBuild.h b/dScripts/PetDigBuild.h deleted file mode 100644 index c70d9e84..00000000 --- a/dScripts/PetDigBuild.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PetDigBuild : public CppScripts::Script -{ -public: - void OnRebuildComplete(Entity* self, Entity* target); - void OnDie(Entity* self, Entity* killer); -}; diff --git a/dScripts/PetDigServer.cpp b/dScripts/PetDigServer.cpp deleted file mode 100644 index dc7e85dd..00000000 --- a/dScripts/PetDigServer.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "dZoneManager.h" -#include "PetDigServer.h" -#include "MissionComponent.h" -#include "EntityManager.h" -#include "Character.h" -#include "PetComponent.h" - -std::vector<LWOOBJID> PetDigServer::treasures {}; - -const DigInfo PetDigServer::defaultDigInfo = DigInfo { 3495, -1, -1, false, false, false, false }; - -/** - * Summary of all the special treasure behaviors, indexed by their lot - */ -const std::map<LOT, DigInfo> PetDigServer::digInfoMap { - // Regular treasures - {3495, defaultDigInfo}, - - // Pet cove treasure - {7612, DigInfo { 7612, -1, -1, false, false, false, false }}, - - // Gnarled Forest flag treasure - {7410, DigInfo { 7410, -1, -1, false, true, false, false }}, - - // Gnarled Forest crab treasure - {9308, DigInfo { 9308, 7694, -1, false, false, false, false }}, - - // Avant Gardens mission treasure - {9307, DigInfo { 9307, -1, -1, false, true, false, true }}, - - // Avant Gardens bouncer treasure - {7559, DigInfo { 7559, -1, -1, false, false, true, false }}, - - // Crux Prime dragon treasure - {13098, DigInfo { 13098, 13067, 1298, false, false, false, false }}, - - // Bone treasure (can only be digged using the dragon) - {12192, DigInfo { 12192, -1, -1, true, false, false, false }}, -}; - -void PetDigServer::OnStartup(Entity* self) -{ - treasures.push_back(self->GetObjectID()); - const auto digInfoIterator = digInfoMap.find(self->GetLOT()); - const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo; - - // Reset any bouncers that might've been created by the previous dig - if (digInfo.bouncer) { - auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber")); - auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber); - auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber); - - for (auto* bouncerSpawner : bouncerSpawners) { - for (auto* bouncer : bouncerSpawner->m_Info.nodes) - bouncerSpawner->Deactivate(); - bouncerSpawner->Reset(); - } - - for (auto* switchSpawner : switchSpawners) { - switchSpawner->Deactivate(); - switchSpawner->Reset(); - } - } -} - -void PetDigServer::OnDie(Entity* self, Entity* killer) -{ - const auto iterator = std::find(treasures.begin(), treasures.end(), self->GetObjectID()); - if (iterator != treasures.end()) - { - treasures.erase(iterator); - } - - auto* owner = killer->GetOwner(); - const auto digInfoIterator = digInfoMap.find(self->GetLOT()); - const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo; - - if (digInfo.spawnLot >= 0) { - PetDigServer::SpawnPet(self, owner, digInfo); - } else if (digInfo.builderOnly) { - - // Some treasures may only be retrieved by the player that built the diggable - auto builder = self->GetVar<LWOOBJID>(u"builder"); // Set by the pet dig build script - if (builder != owner->GetObjectID()) - return; - } else if (digInfo.xBuild) { - PetDigServer::HandleXBuildDig(self, owner, killer); - return; - } else if (digInfo.bouncer) { - PetDigServer::HandleBouncerDig(self, owner); - } - - PetDigServer::ProgressPetDigMissions(owner, self); - - self->SetNetworkVar<bool>(u"treasure_dug", true); - // TODO: Reset other pets - - // Handles smashing leftovers (edge case for the AG X) - auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X")); - if (xObject != nullptr) { - xObject->Smash(xObject->GetObjectID(), VIOLENT); - } -} - -void PetDigServer::HandleXBuildDig(const Entity *self, Entity *owner, Entity* pet) { - auto playerID = self->GetVar<LWOOBJID>(u"builder"); - if (playerID == LWOOBJID_EMPTY || playerID != owner->GetObjectID()) - return; - - auto* playerEntity = EntityManager::Instance()->GetEntity(playerID); - if (!playerEntity || !playerEntity->GetParentUser() || !playerEntity->GetParentUser()->GetLastUsedChar()) - return; - - auto* player = playerEntity->GetCharacter(); - const auto groupID = self->GetVar<std::u16string>(u"groupID"); - auto playerFlag = 0; - - // The flag that the player dug up - if (groupID == u"Flag1") { - playerFlag = 61; - } else if (groupID == u"Flag2") { - playerFlag = 62; - } else if (groupID == u"Flag3") { - playerFlag = 63; - } - - // If the player doesn't have the flag yet - if (playerFlag != 0 && !player->GetPlayerFlag(playerFlag)) { - auto* petComponent = pet->GetComponent<PetComponent>(); - if (petComponent != nullptr) { - // TODO: Pet state = 9 ?? - } - - // Shows the flag object to the player - player->SetPlayerFlag(playerFlag, true); - } - - auto* xObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"X")); - if (xObject != nullptr) { - xObject->Smash(xObject->GetObjectID(), VIOLENT); - } -} - -void PetDigServer::HandleBouncerDig(const Entity *self, const Entity *owner) { - auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber")); - auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber); - auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber); - - for (auto* bouncerSpawner : bouncerSpawners) { - bouncerSpawner->Activate(); - } - - for (auto* switchSpawner : switchSpawners) { - switchSpawner->Activate(); - } -} - -/** - * Progresses the Can You Dig It mission and the Pet Excavator Achievement if the player has never completed it yet - * \param owner the owner that just made a pet dig something up - */ -void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* chest) { - auto* missionComponent = owner->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) - { - // Can You Dig It progress - const auto digMissionState = missionComponent->GetMissionState(843); - if (digMissionState == MissionState::MISSION_STATE_ACTIVE) - { - missionComponent->ForceProgress(843, 1216, 1); - } - - // Pet Excavator progress - const auto excavatorMissionState = missionComponent->GetMissionState(505); - if (excavatorMissionState == MissionState::MISSION_STATE_ACTIVE) - { - if (chest->HasVar(u"PetDig")) { - int32_t playerFlag = 1260 + chest->GetVarAs<int32_t>(u"PetDig"); - Character* player = owner->GetCharacter(); - - // check if player flag is set - if (!player->GetPlayerFlag(playerFlag)) { - missionComponent->ForceProgress(505, 767, 1); - player->SetPlayerFlag(playerFlag, 1); - } - } - } - } -} - -/** - * Some treasures spawn special pets, this handles that case - * \param owner the owner that just made a pet dig something up - * \param digInfo information regarding the treasure, will also contain info about the pet to spawn - */ -void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo digInfo) { - // Some treasures require a mission to be active - if (digInfo.requiredMission >= 0) { - auto* missionComponent = owner->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < MissionState::MISSION_STATE_ACTIVE) { - return; - } - } - - EntityInfo info {}; - info.lot = digInfo.spawnLot; - info.pos = self->GetPosition(); - info.rot = self->GetRotation(); - info.spawnerID = self->GetSpawnerID(); - info.settings = { - new LDFData<LWOOBJID>(u"tamer", owner->GetObjectID()), - new LDFData<std::string>(u"group", "pet" + std::to_string(owner->GetObjectID())), - new LDFData<std::string>(u"spawnAnim", "spawn-pet"), - new LDFData<float>(u"spawnTimer", 1.0) - }; - - auto* spawnedPet = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(spawnedPet); -} - -Entity* PetDigServer::GetClosestTresure(NiPoint3 position) -{ - float closestDistance = 0; - Entity* closest = nullptr; - - for (const auto tresureId : treasures) - { - auto* tresure = EntityManager::Instance()->GetEntity(tresureId); - - if (tresure == nullptr) continue; - - float distance = Vector3::DistanceSquared(tresure->GetPosition(), position); - - if (closest == nullptr || distance < closestDistance) - { - closestDistance = distance; - closest = tresure; - } - } - - return closest; -} diff --git a/dScripts/PetDigServer.h b/dScripts/PetDigServer.h deleted file mode 100644 index 968ca50d..00000000 --- a/dScripts/PetDigServer.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include "CppScripts.h" - -struct DigInfo { - LOT digLot; // The lot of the chest - LOT spawnLot; // Option lot of pet to spawn - int32_t requiredMission; // Optional mission required before pet can be spawned, if < 0 == don't use - bool specificPet; // This treasure requires a specific pet to be dug up - bool xBuild; // This treasure is retrieved from a buildable cross - bool bouncer; // This treasure spawns a bouncer - bool builderOnly; // Only the builder of this diggable may access the rewards, for example with crosses -}; - -class PetDigServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnDie(Entity* self, Entity* killer) override; - - static Entity* GetClosestTresure(NiPoint3 position); - -private: - static void ProgressPetDigMissions(const Entity* owner, const Entity* chest); - static void SpawnPet(Entity* self, const Entity* owner, DigInfo digInfo); - static void HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet); - static void HandleBouncerDig(const Entity* self, const Entity* owner); - static std::vector<LWOOBJID> treasures; - static const DigInfo defaultDigInfo; - static const std::map<LOT, DigInfo> digInfoMap; -}; diff --git a/dScripts/PetFromDigServer.cpp b/dScripts/PetFromDigServer.cpp deleted file mode 100644 index 235f6f8b..00000000 --- a/dScripts/PetFromDigServer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "PetFromDigServer.h" -#include "PetComponent.h" - -void PetFromDigServer::OnStartup(Entity* self) { - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - return; - - // Triggers the local dig pet script for taming etc. - auto tamer = self->GetVar<LWOOBJID>(u"tamer"); - - // Client compares this with player:GetID() which is a string, so we'll have to give it a string - self->SetNetworkVar(u"pettamer", std::to_string(tamer)); - - // Kill if the player decides that the dig pet is not worthy - self->AddTimer("killself", 45.0f); -} - -void PetFromDigServer::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "killself") { - - // Don't accidentally kill a pet that is already owned - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - return; - - self->Smash(self->GetObjectID(), SILENT); - } -} - -void PetFromDigServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) { - if (type == NOTIFY_TYPE_BEGIN) { - self->CancelTimer("killself"); - } else if (type == NOTIFY_TYPE_QUIT || type == NOTIFY_TYPE_FAILED) { - self->Smash(self->GetObjectID(), SILENT); - } else if (type == NOTIFY_TYPE_SUCCESS) { - auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr) - return; - // TODO: Remove custom group? - // Command the pet to the player as it may otherwise go to its spawn point which is non existant - // petComponent->Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 6, 202, true); - } -} diff --git a/dScripts/PetFromDigServer.h b/dScripts/PetFromDigServer.h deleted file mode 100644 index e4a69a71..00000000 --- a/dScripts/PetFromDigServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PetFromDigServer : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) override; -}; diff --git a/dScripts/PetFromObjectServer.cpp b/dScripts/PetFromObjectServer.cpp deleted file mode 100644 index 4658fcce..00000000 --- a/dScripts/PetFromObjectServer.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "PetFromObjectServer.h" -#include "PetComponent.h" - -void PetFromObjectServer::OnStartup(Entity *self) { - self->SetNetworkVar(u"pettamer", std::to_string(self->GetVar<LWOOBJID>(u"tamer"))); - self->AddTimer("killSelf", 45.0f); -} - -void PetFromObjectServer::OnTimerDone(Entity *self, std::string timerName) { - if (timerName == "killSelf") { - const auto* petComponent = self->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - return; - self->Smash(self->GetObjectID(), SILENT); - } -} - -void PetFromObjectServer::OnNotifyPetTamingMinigame(Entity *self, Entity *tamer, eNotifyType type) { - switch (type) { - case NOTIFY_TYPE_BEGIN: - self->CancelAllTimers(); - break; - case NOTIFY_TYPE_QUIT: - case NOTIFY_TYPE_FAILED: - self->Smash(self->GetObjectID(), SILENT); - break; - case NOTIFY_TYPE_SUCCESS: - // TODO: Remove from groups? - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UpdateSuccessPicking", 0, - 0, tamer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - default: - break; - } -} diff --git a/dScripts/PetFromObjectServer.h b/dScripts/PetFromObjectServer.h deleted file mode 100644 index 989df880..00000000 --- a/dScripts/PetFromObjectServer.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PetFromObjectServer : public CppScripts::Script { -public: - void OnStartup(Entity *self) override; - void OnTimerDone(Entity *self, std::string timerName) override; - void OnNotifyPetTamingMinigame(Entity *self, Entity *tamer, eNotifyType type) override; -}; diff --git a/dScripts/PrWhistle.cpp b/dScripts/PrWhistle.cpp deleted file mode 100644 index 4d4d0708..00000000 --- a/dScripts/PrWhistle.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "PrWhistle.h" -#include "Character.h" -#include "Entity.h" - -void PrWhistle::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) -{ - if (args == "unlockEmote") - { - auto* character = sender->GetCharacter(); - - if (character != nullptr) - { - character->UnlockEmote(115); - } - } -} diff --git a/dScripts/PrWhistle.h b/dScripts/PrWhistle.h deleted file mode 100644 index 58bc0a23..00000000 --- a/dScripts/PrWhistle.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PrWhistle : public CppScripts::Script -{ -public: - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; - diff --git a/dScripts/PropertyBankInteract.cpp b/dScripts/PropertyBankInteract.cpp deleted file mode 100644 index 974b33a6..00000000 --- a/dScripts/PropertyBankInteract.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "PropertyBankInteract.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void PropertyBankInteract::OnStartup(Entity *self) { - auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - if (zoneControl != nullptr) { - zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); - } -} - -void PropertyBankInteract::OnPlayerLoaded(Entity *self, Entity *player) { - auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - if (zoneControl != nullptr) { - zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); - } -} - -void PropertyBankInteract::OnUse(Entity *self, Entity *user) { - - AMFArrayValue args; - auto* value = new AMFStringValue(); - value->SetStringValue("bank"); - args.InsertValue("state", value); - - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args); - delete value; - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, - "", user->GetSystemAddress()); -} - -void PropertyBankInteract::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - if (args == "ToggleBank") { - AMFArrayValue amfArgs; - auto* amfFalse = new AMFFalseValue(); - amfArgs.InsertValue("visible", amfFalse); - - GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", &amfArgs); - - delete amfFalse; - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, - "", sender->GetSystemAddress()); - } -} diff --git a/dScripts/PropertyBankInteract.h b/dScripts/PropertyBankInteract.h deleted file mode 100644 index 54bc0484..00000000 --- a/dScripts/PropertyBankInteract.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PropertyBankInteract : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnPlayerLoaded(Entity *self, Entity *player) override; - void OnUse(Entity *self, Entity *user) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/PropertyDeathPlane.cpp b/dScripts/PropertyDeathPlane.cpp deleted file mode 100644 index 93981dac..00000000 --- a/dScripts/PropertyDeathPlane.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "PropertyDeathPlane.h" -#include "Entity.h" -#include "GameMessages.h" -#include "EntityManager.h" - -void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) -{ - const auto teleportGroup = EntityManager::Instance()->GetEntitiesInGroup("Teleport"); - - if (teleportGroup.size() == 0) - { - return; - } - - auto* teleport = teleportGroup[0]; - - GameMessages::SendTeleport(target->GetObjectID(), teleport->GetPosition(), teleport->GetRotation(), target->GetSystemAddress()); -} diff --git a/dScripts/PropertyDevice.cpp b/dScripts/PropertyDevice.cpp deleted file mode 100644 index ed0d7b81..00000000 --- a/dScripts/PropertyDevice.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "PropertyDevice.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "MissionComponent.h" - -void PropertyDevice::OnStartup(Entity *self) { - auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - if (zoneControl != nullptr) { - zoneControl->OnFireEventServerSide(self, "CheckForPropertyOwner"); - } -} - -void PropertyDevice::OnRebuildComplete(Entity *self, Entity *target) { - auto propertyOwnerID = self->GetNetworkVar<std::string>(m_PropertyOwnerVariable); - if (propertyOwnerID == std::to_string(LWOOBJID_EMPTY)) - return; - - auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr) { - if (missionComponent->GetMissionState(m_PropertyMissionID) == MissionState::MISSION_STATE_ACTIVE) { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 641, u"create", "callhome"); - missionComponent->ForceProgress(m_PropertyMissionID, 1793, self->GetLOT()); - } - } -} diff --git a/dScripts/PropertyDevice.h b/dScripts/PropertyDevice.h deleted file mode 100644 index 9c97df4d..00000000 --- a/dScripts/PropertyDevice.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PropertyDevice : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnRebuildComplete(Entity *self, Entity *target) override; - const std::u16string m_PropertyOwnerVariable = u"PropertyOwnerID"; - const uint32_t m_PropertyMissionID = 1291; -}; diff --git a/dScripts/PropertyFXDamage.cpp b/dScripts/PropertyFXDamage.cpp deleted file mode 100644 index 2c01ceb1..00000000 --- a/dScripts/PropertyFXDamage.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "PropertyFXDamage.h" -#include "DestroyableComponent.h" -#include "SkillComponent.h" - -void PropertyFXDamage::OnCollisionPhantom(Entity *self, Entity *target) { - if (target == nullptr) - return; - - auto* skills = self->GetComponent<SkillComponent>(); - auto* targetStats = target->GetComponent<DestroyableComponent>(); - - if (skills != nullptr && targetStats != nullptr) { - auto targetFactions = targetStats->GetFactionIDs(); - if (std::find(targetFactions.begin(), targetFactions.end(), 1) != targetFactions.end()) { - skills->CalculateBehavior(11386, 692, target->GetObjectID()); - } - } -} diff --git a/dScripts/PropertyPlatform.cpp b/dScripts/PropertyPlatform.cpp deleted file mode 100644 index 3b744663..00000000 --- a/dScripts/PropertyPlatform.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "PropertyPlatform.h" -#include "RebuildComponent.h" -#include "GameMessages.h" - -void PropertyPlatform::OnRebuildComplete(Entity *self, Entity *target) { -// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>(); -// if (movingPlatform != nullptr) { -// movingPlatform->StopPathing(); -// movingPlatform->SetNoAutoStart(true); -// } - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); -} - -void PropertyPlatform::OnUse(Entity *self, Entity *user) { - auto* rebuildComponent = self->GetComponent<RebuildComponent>(); - if (rebuildComponent != nullptr && rebuildComponent->GetState() == REBUILD_COMPLETED) { -// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>(); -// if (movingPlatform != nullptr) { -// movingPlatform->GotoWaypoint(1); -// } - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); - - self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() { - self->SetNetworkVar<float_t>(u"startEffect", dieDelay); - self->AddCallbackTimer(dieDelay, [self]() { - self->Smash(); - }); - }); - } -} diff --git a/dScripts/PropertyPlatform.h b/dScripts/PropertyPlatform.h deleted file mode 100644 index 9a2b3229..00000000 --- a/dScripts/PropertyPlatform.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class PropertyPlatform : public CppScripts::Script { -public: - void OnUse(Entity *self, Entity *user) override; - void OnRebuildComplete(Entity *self, Entity *target) override; -private: - float_t movementDelay = 10.0f; - float_t effectDelay = 5.0f; - float_t dieDelay = 5.0f; - uint32_t desiredWaypoint = 1; -}; diff --git a/dScripts/QbEnemyStunner.cpp b/dScripts/QbEnemyStunner.cpp deleted file mode 100644 index a3dfa94b..00000000 --- a/dScripts/QbEnemyStunner.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "QbEnemyStunner.h" -#include "SkillComponent.h" -#include "DestroyableComponent.h" - -void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) -{ - auto* destroyable = self->GetComponent<DestroyableComponent>(); - - if (destroyable != nullptr) - { - destroyable->SetFaction(115); - } - - auto skillComponent = self->GetComponent<SkillComponent>(); - if (!skillComponent) return; - - // Get the skill IDs of this object. - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills"); - auto skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); - std::map<uint32_t, uint32_t> skillBehaviorMap; - // For each skill, cast it with the associated behavior ID. - for (auto skill : skills) { - CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior"); - CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); - - skillBehaviorMap.insert(std::make_pair(skill.skillID, behaviorData.behaviorID)); - } - - // If there are no skills found, insert a default skill to use. - if (skillBehaviorMap.size() == 0) { - skillBehaviorMap.insert(std::make_pair(499U, 6095U)); - } - - // Start all skills associated with the object next tick - self->AddTimer("TickTime", 0); - - self->AddTimer("PlayEffect", 20); - - self->SetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap", skillBehaviorMap); -} - -void QbEnemyStunner::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "DieTime") - { - self->Smash(); - - self->CancelAllTimers(); - } - else if (timerName == "PlayEffect") - { - self->SetNetworkVar(u"startEffect", 5.0f, UNASSIGNED_SYSTEM_ADDRESS); - - self->AddTimer("DieTime", 5.0f); - } - else if (timerName == "TickTime") - { - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent != nullptr) - { - auto skillBehaviorMap = self->GetVar<std::map<uint32_t, uint32_t>>(u"skillBehaviorMap"); - if (skillBehaviorMap.size() == 0) { - // Should no skills have been found, default to the mermaid stunner - skillComponent->CalculateBehavior(499U, 6095U, LWOOBJID_EMPTY); - } else { - for (auto pair : skillBehaviorMap) { - skillComponent->CalculateBehavior(pair.first, pair.second, LWOOBJID_EMPTY); - } - } - } - self->AddTimer("TickTime", 1); - } -} diff --git a/dScripts/QbEnemyStunner.h b/dScripts/QbEnemyStunner.h deleted file mode 100644 index 18c52d4d..00000000 --- a/dScripts/QbEnemyStunner.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class QbEnemyStunner : public CppScripts::Script -{ -public: - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; -}; diff --git a/dScripts/RaceImagineCrateServer.cpp b/dScripts/RaceImagineCrateServer.cpp deleted file mode 100644 index 3729004a..00000000 --- a/dScripts/RaceImagineCrateServer.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "CharacterComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "PossessableComponent.h" -#include "RaceImagineCrateServer.h" -#include "RacingTaskParam.h" -#include "MissionComponent.h" -#include "SkillComponent.h" - -void RaceImagineCrateServer::OnDie(Entity* self, Entity* killer) -{ - if (self->GetVar<bool>(u"bIsDead")) - { - return; - } - - self->SetVar<bool>(u"bIsDead", true); - - if (killer == nullptr) - { - return; - } - - auto* skillComponent = killer->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - auto* destroyableComponent = killer->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) - { - destroyableComponent->SetImagination(60); - - EntityManager::Instance()->SerializeEntity(killer); - } - - // Find possessor of race car to progress missions and update stats. - auto* possessableComponent = killer->GetComponent<PossessableComponent>(); - if (possessableComponent != nullptr) { - - auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (possessor != nullptr) { - - auto* missionComponent = possessor->GetComponent<MissionComponent>(); - auto* characterComponent = possessor->GetComponent<CharacterComponent>(); - - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingImaginationCratesSmashed); - characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); - } - - // Progress racing smashable missions - if(missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); - } - } -} diff --git a/dScripts/RaceImagineCrateServer.h b/dScripts/RaceImagineCrateServer.h deleted file mode 100644 index 42f36b30..00000000 --- a/dScripts/RaceImagineCrateServer.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class RaceImagineCrateServer : public CppScripts::Script -{ -public: -/** - * @brief When a boost smashable has been smashed, this function is called - * - * @param self The Entity that called this function. - * @param killer The Entity that killed this Entity. - */ - void OnDie(Entity* self, Entity* killer) override; -}; diff --git a/dScripts/RaceImaginePowerup.cpp b/dScripts/RaceImaginePowerup.cpp deleted file mode 100644 index a940b88d..00000000 --- a/dScripts/RaceImaginePowerup.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "PossessorComponent.h" -#include "RaceImaginePowerup.h" -#include "RacingTaskParam.h" -#include "MissionComponent.h" - -void RaceImaginePowerup::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) -{ - if (sender->IsPlayer() && args == "powerup") - { - auto* possessorComponent = sender->GetComponent<PossessorComponent>(); - - if (possessorComponent == nullptr) - { - return; - } - - auto* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - - if (vehicle == nullptr) - { - return; - } - - auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>(); - - if (destroyableComponent == nullptr) - { - return; - } - - destroyableComponent->Imagine(10); - - auto* missionComponent = sender->GetComponent<MissionComponent>(); - - if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COLLECT_IMAGINATION); - } -} diff --git a/dScripts/RaceImaginePowerup.h b/dScripts/RaceImaginePowerup.h deleted file mode 100644 index c9d7be2d..00000000 --- a/dScripts/RaceImaginePowerup.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class RaceImaginePowerup : public CppScripts::Script -{ -public: - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/RaceMaelstromGeiser.cpp b/dScripts/RaceMaelstromGeiser.cpp deleted file mode 100644 index 88a45bbd..00000000 --- a/dScripts/RaceMaelstromGeiser.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "RaceMaelstromGeiser.h" -#include "GameMessages.h" -#include "PossessableComponent.h" -#include "PossessorComponent.h" -#include "EntityManager.h" -#include "RacingControlComponent.h" -#include "dZoneManager.h" - -void RaceMaelstromGeiser::OnStartup(Entity* self) -{ - self->SetVar(u"AmFiring", false); - - self->AddTimer("downTime", self->GetVar<int32_t>(u"startTime")); - - self->SetProximityRadius(15, "deathZone"); -} - -void RaceMaelstromGeiser::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ - if (!entering->IsPlayer() || name != "deathZone" || status != "ENTER") - { - return; - } - - if (!self->GetVar<bool>(u"AmFiring")) - { - return; - } - - auto* possessableComponent = entering->GetComponent<PossessableComponent>(); - - Entity* vehicle; - Entity* player; - - if (possessableComponent != nullptr) - { - player = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - - if (player == nullptr) - { - return; - } - - vehicle = entering; - } - else if (entering->IsPlayer()) - { - auto* possessorComponent = entering->GetComponent<PossessorComponent>(); - - if (possessorComponent == nullptr) - { - return; - } - - vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); - - if (vehicle == nullptr) - { - return; - } - - player = entering; - } - else - { - return; - } - - - GameMessages::SendDie(vehicle, self->GetObjectID(), LWOOBJID_EMPTY, true, VIOLENT, u"", 0, 0, 0, true, false, 0); - - auto* zoneController = dZoneManager::Instance()->GetZoneControlObject(); - - auto* racingControlComponent = zoneController->GetComponent<RacingControlComponent>(); - - if (racingControlComponent != nullptr) - { - racingControlComponent->OnRequestDie(player); - } -} - -void RaceMaelstromGeiser::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "downTime") - { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 4048, u"rebuild_medium", "geiser", LWOOBJID_EMPTY, 1, 1, true); - - self->AddTimer("buildUpTime", 1); - } - else if (timerName == "buildUpTime") - { - self->SetVar(u"AmFiring", true); - - self->AddTimer("killTime", 1.5f); - } - else if (timerName == "killTime") - { - GameMessages::SendStopFXEffect(self, true, "geiser"); - - self->SetVar(u"AmFiring", false); - - self->AddTimer("downTime", 3.0); - } -} diff --git a/dScripts/RaceSmashServer.cpp b/dScripts/RaceSmashServer.cpp deleted file mode 100644 index 8c8b3f79..00000000 --- a/dScripts/RaceSmashServer.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "CharacterComponent.h" -#include "EntityManager.h" -#include "PossessableComponent.h" -#include "RaceSmashServer.h" -#include "RacingTaskParam.h" -#include "MissionComponent.h" - -void RaceSmashServer::OnDie(Entity *self, Entity *killer) { - // Crate is smashed by the car - auto* possessableComponent = killer->GetComponent<PossessableComponent>(); - if (possessableComponent != nullptr) { - - auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); - if (possessor != nullptr) { - - auto* missionComponent = possessor->GetComponent<MissionComponent>(); - auto* characterComponent = possessor->GetComponent<CharacterComponent>(); - - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); - } - - // Progress racing smashable missions - if(missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); - // Progress missions that ask us to smash a specific smashable. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASH_SPECIFIC_SMASHABLE); - } - } -} diff --git a/dScripts/RaceSmashServer.h b/dScripts/RaceSmashServer.h deleted file mode 100644 index 7fa1441d..00000000 --- a/dScripts/RaceSmashServer.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class RaceSmashServer : public CppScripts::Script { - /** - * @brief When a smashable has been destroyed, this function is called. - * - * @param self The Entity that called this function. - * @param killer The Entity that killed this Entity. - */ - void OnDie(Entity *self, Entity *killer) override; -}; diff --git a/dScripts/RainOfArrows.cpp b/dScripts/RainOfArrows.cpp deleted file mode 100644 index d9a7ba42..00000000 --- a/dScripts/RainOfArrows.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "RainOfArrows.h" -#include "EntityManager.h" -#include "SkillComponent.h" -#include "GameMessages.h" - -void RainOfArrows::OnStartup(Entity* self) -{ - -} - -void RainOfArrows::OnRebuildComplete(Entity* self, Entity* target) -{ - auto myPos = self->GetPosition(); - auto myRot = self->GetRotation(); - - EntityInfo info; - info.lot = m_ArrowFXObject; - info.pos = myPos; - info.rot = myRot; - info.spawnerID = self->GetObjectID(); - - auto* entity = EntityManager::Instance()->CreateEntity(info); - - EntityManager::Instance()->ConstructEntity(entity); - - self->SetVar<LWOOBJID>(u"ChildFX", entity->GetObjectID()); - self->SetVar<LWOOBJID>(u"playerID", target->GetObjectID()); - - self->AddTimer("ArrowsIncoming", m_ArrowDelay); - self->AddTimer("PlayArrowSound", m_ArrowDelay - 4); -} - -void RainOfArrows::OnTimerDone(Entity* self, std::string timerName) -{ - auto* child = EntityManager::Instance()->GetEntity( - self->GetVar<LWOOBJID>(u"ChildFX") - ); - - auto* player = EntityManager::Instance()->GetEntity( - self->GetVar<LWOOBJID>(u"playerID") - ); - - if (timerName == "ArrowsIncoming") - { - if (child == nullptr) - { - return; - } - - auto* skillComponent = child->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) - { - return; - } - - skillComponent->CalculateBehavior( - m_ArrowSkill, - m_ArrowBehavior, - LWOOBJID_EMPTY, - true, - false, - player != nullptr ? player->GetObjectID() : LWOOBJID_EMPTY - ); - - self->AddTimer("FireSkill", 0.7f); - } - else if (timerName == "PlayArrowSound") - { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, m_ArrowsGUID); - } - else if (timerName == "FireSkill") - { - if (child != nullptr) - { - child->Smash(); - } - - self->Smash(player != nullptr ? player->GetObjectID() : LWOOBJID_EMPTY); - } -} diff --git a/dScripts/RainOfArrows.h b/dScripts/RainOfArrows.h deleted file mode 100644 index 5b997251..00000000 --- a/dScripts/RainOfArrows.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class RainOfArrows : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; - void OnRebuildComplete(Entity* self, Entity* target) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - LOT m_ArrowFXObject = 15850; - int32_t m_ArrowSkill = 1482; - int32_t m_ArrowBehavior = 36680; - int32_t m_ArrowDelay = 6; - std::string m_ArrowsGUID = "{532cba3c-54da-446c-986b-128af9647bdb}"; -}; \ No newline at end of file diff --git a/dScripts/RandomSpawnerFin.h b/dScripts/RandomSpawnerFin.h deleted file mode 100644 index 174b90f0..00000000 --- a/dScripts/RandomSpawnerFin.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseRandomServer.h" - -class RandomSpawnerFin : public CppScripts::Script, BaseRandomServer -{ - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - struct Mobs - { - static const LOT stromb = 11212; - static const LOT mech = 11213; - static const LOT spider = 11214; - static const LOT pirate = 11215; - static const LOT admiral = 11216; - static const LOT gorilla = 11217; - static const LOT ronin = 11218; - static const LOT horse = 11219; - static const LOT dragon = 112201; - }; - - Mobs mobs; -}; - diff --git a/dScripts/RandomSpawnerPit.h b/dScripts/RandomSpawnerPit.h deleted file mode 100644 index 8346ec37..00000000 --- a/dScripts/RandomSpawnerPit.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseRandomServer.h" - -class RandomSpawnerPit : public CppScripts::Script, BaseRandomServer -{ - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - struct Mobs - { - static const LOT stromb = 11212; - static const LOT mech = 11213; - static const LOT spider = 11214; - static const LOT pirate = 11215; - static const LOT admiral = 11216; - static const LOT gorilla = 11217; - static const LOT ronin = 11218; - static const LOT horse = 11219; - static const LOT dragon = 112200; - }; - - Mobs mobs; -}; - diff --git a/dScripts/RandomSpawnerStr.h b/dScripts/RandomSpawnerStr.h deleted file mode 100644 index a3ee920e..00000000 --- a/dScripts/RandomSpawnerStr.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseRandomServer.h" - -class RandomSpawnerStr : public CppScripts::Script, BaseRandomServer -{ - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - struct Mobs - { - static const LOT stromb = 11212; - static const LOT mech = 11213; - static const LOT spider = 11214; - static const LOT pirate = 11215; - static const LOT admiral = 11216; - static const LOT gorilla = 11217; - static const LOT ronin = 11218; - static const LOT horse = 11219; - static const LOT dragon = 112200; - }; - - Mobs mobs; -}; - diff --git a/dScripts/RandomSpawnerZip.h b/dScripts/RandomSpawnerZip.h deleted file mode 100644 index 6c0cf511..00000000 --- a/dScripts/RandomSpawnerZip.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseRandomServer.h" - -class RandomSpawnerZip : public CppScripts::Script, BaseRandomServer -{ - void OnStartup(Entity* self) override; - void OnTimerDone(Entity* self, std::string timerName) override; - -private: - struct Mobs - { - static const LOT stromb = 11212; - static const LOT mech = 11213; - static const LOT spider = 11214; - static const LOT pirate = 11215; - static const LOT admiral = 11216; - static const LOT gorilla = 11217; - static const LOT ronin = 11218; - static const LOT horse = 11219; - static const LOT dragon = 112200; - }; - - Mobs mobs; -}; - diff --git a/dScripts/SGCannon.cpp b/dScripts/SGCannon.cpp deleted file mode 100644 index b1f64b64..00000000 --- a/dScripts/SGCannon.cpp +++ /dev/null @@ -1,1090 +0,0 @@ -#include "SGCannon.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "dZoneManager.h" -#include "Player.h" -#include "Character.h" -#include "ShootingGalleryComponent.h" -#include "PossessorComponent.h" -#include "CharacterComponent.h" -#include "SimplePhysicsComponent.h" -#include "MovementAIComponent.h" -#include "../dWorldServer/ObjectIDManager.h" -#include "MissionComponent.h" - -void SGCannon::OnStartup(Entity *self) { - Game::logger->Log("SGCannon", "OnStartup\n"); - - m_Waves = GetWaves(); - constants = GetConstants(); - - ResetVars(self); - - self->SetVar<bool>(GameStartedVariable, false); - self->SetVar<Vector3>(InitialVelocityVariable, {}); - self->SetVar<uint32_t>(ImpactSkillVariale, constants.impactSkillID); - - auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); - if (shootingGalleryComponent != nullptr) { - shootingGalleryComponent->SetStaticParams({ - Vector3 { -327.8609924316406, 256.8999938964844, 1.6482199430465698 }, - Vector3 { -181.4320068359375, 212.39999389648438, 2.5182199478149414 } - }); - - shootingGalleryComponent->SetDynamicParams({ - Vector3 { 0.0, 4.3, 9.0 }, - Vector3 { }, - 129.0, - 800.0, - 30.0, - 0.0, - -1.0, - 58.6 - }); - } - - self->SetVar<uint32_t>(TimeLimitVariable, 30); - self->SetVar<std::vector<LOT>>(ValidActorsVariable, {3109, 3110, 3111, 3112, 3125, 3126}); - self->SetVar<std::vector<LOT>>(ValidEffectsVariable, {3122}); - self->SetVar<std::vector<uint32_t>>(StreakBonusVariable, {1, 2, 5, 10}); - self->SetVar<bool>(SuperChargeActiveVariable, false); - self->SetVar<uint32_t>(MatrixVariable, 1); - self->SetVar<bool>(InitVariable, true); - - auto* simplePhysicsComponent = self->GetComponent<SimplePhysicsComponent>(); - - if (simplePhysicsComponent != nullptr) { - simplePhysicsComponent->SetPhysicsMotionState(5); - } -} - -void SGCannon::OnPlayerLoaded(Entity *self, Entity *player) { - Game::logger->Log("SGCannon", "Player loaded\n"); - self->SetVar<LWOOBJID>(PlayerIDVariable, player->GetObjectID()); -} - -void SGCannon::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - Script::OnFireEventServerSide(self, sender, args, param1, param2, param3); -} - -void SGCannon::OnActivityStateChangeRequest(Entity *self, LWOOBJID senderID, int32_t value1, int32_t value2, - const std::u16string &stringValue) { - Game::logger->Log("SGCannon", "Got activity state change request: %s\n", GeneralUtils::UTF16ToWTF8(stringValue).c_str()); - if (stringValue == u"clientready") { - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - Game::logger->Log("SGCannon", "Player is ready\n"); - /*GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true);*/ - - Game::logger->Log("SGCannon", "Sending ActivityEnter\n"); - - GameMessages::SendActivityEnter(self->GetObjectID(), player->GetSystemAddress()); - - auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); - - if (shootingGalleryComponent != nullptr) { - shootingGalleryComponent->SetCurrentPlayerID(player->GetObjectID()); - - Game::logger->Log("SGCannon", "Setting player ID\n"); - - EntityManager::Instance()->SerializeEntity(self); - } - else { - Game::logger->Log("SGCannon", "Shooting gallery component is null\n"); - } - - auto* possessorComponent = player->GetComponent<PossessorComponent>(); - - /*if (possessorComponent != nullptr) { - possessorComponent->SetPossessable(self->GetObjectID()); - - EntityManager::Instance()->SerializeEntity(player); - }*/ - - auto* characterComponent = player->GetComponent<CharacterComponent>(); - - if (characterComponent != nullptr) { - characterComponent->SetIsRacing(true); - characterComponent->SetCurrentActivity(2); - auto possessor = player->GetComponent<PossessorComponent>(); - if(possessor) { - possessor->SetPossessable(self->GetObjectID()); - possessor->SetPossessableType(0); - } - - EntityManager::Instance()->SerializeEntity(player); - } - - self->SetNetworkVar<bool>(HideScoreBoardVariable, true); - self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); - self->SetNetworkVar<bool>(ShowLoadingUI, true); - - /* - GameMessages::SendTeleport( - player->GetObjectID(), - {-292.6415710449219, 230.20237731933594, -3.9090466499328613}, - {0.7067984342575073, -6.527870573336259e-05, 0.707414984703064, 0.00021762956748716533}, - player->GetSystemAddress(), true - ); - */ - - //GameMessages::SendRequestActivityEnter(self->GetObjectID(), player->GetSystemAddress(), false, player->GetObjectID()); - } - else { - Game::logger->Log("SGCannon", "Player not found\n"); - } - } - else if (value1 == 1200) { - StartGame(self); - } -} - -void SGCannon::OnMessageBoxResponse(Entity *self, Entity *sender, int32_t button, const std::u16string &identifier, - const std::u16string &userData) { - auto * player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - if (button == 1 && identifier == u"Shooting_Gallery_Stop") - { - UpdatePlayer(self, player->GetObjectID(), true); - RemovePlayer(player->GetObjectID()); - StopGame(self, true); - return; - } - - if (identifier == u"Scoreboardinfo") { - GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, - dZoneManager::Instance()->GetZoneControlObject()->GetObjectID(), - u"Shooting_Gallery_Retry?", 2, u"Retry?", - u"", player->GetSystemAddress()); - } else { - if ((button == 1 && (identifier == u"Shooting_Gallery_Retry" || identifier == u"RePlay")) - || identifier == u"SG1" || button == 0) { - - if (identifier == u"RePlay") { - static_cast<Player*>(player)->SendToZone(1300); - - return; - } - - self->SetNetworkVar<bool>(ClearVariable, true); - StartGame(self); - } else if (button == 1 && identifier == u"Shooting_Gallery_Exit") { - UpdatePlayer(self, player->GetObjectID(), true); - RemovePlayer(player->GetObjectID()); - } - } - } -} - -void SGCannon::OnActivityTimerDone(Entity *self, const std::string &name) { - if (name == SuperChargeTimer && !self->GetVar<bool>(SuperChargePausedVariable)) { - if (self->GetVar<bool>(WaveStatusVariable) || self->GetVar<uint32_t>(CurrentSuperChargedTimeVariable) < 1) { - self->SetNetworkVar<uint32_t>(ChargeCountingVariable, 99); - self->SetNetworkVar<uint32_t>(SuperChargeBarVariable, 0); - ToggleSuperCharge(self, false); - } - } else if (name == SpawnWaveTimer) { - if (self->GetVar<bool>(GameStartedVariable)) { - self->SetVar<bool>(WaveStatusVariable, true); - const auto wave = (int32_t) self->GetVar<uint32_t>(ThisWaveVariable); - - if (wave != 0 && self->GetVar<bool>(SuperChargePausedVariable)) { - StartChargedCannon(self, self->GetVar<uint32_t>(CurrentSuperChargedTimeVariable)); - self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, 0); - } - - TimerToggle(self, true); - - for (const auto& enemyToSpawn : m_Waves.at(self->GetVar<uint32_t>(ThisWaveVariable))) { - SpawnObject(self, enemyToSpawn, true); - } - - Game::logger->Log("SGCannon", "Current wave spawn: %i/%i\n", wave, m_Waves.size()); - - // All waves completed - const auto timeLimit = (float_t) self->GetVar<uint32_t>(TimeLimitVariable); - if (wave >= m_Waves.size()) { - ActivityTimerStart(self, GameOverTimer, timeLimit, timeLimit); - } else { - ActivityTimerStart(self, EndWaveTimer, timeLimit, timeLimit); - } - - const auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - GameMessages::SendPlayFXEffect(player->GetObjectID(), -1, u"SG-start", ""); - - GameMessages::SendStartActivityTime(self->GetObjectID(), timeLimit, player->GetSystemAddress()); - Game::logger->Log("SGCannon", "Sending ActivityPause false\n"); - - GameMessages::SendActivityPause(self->GetObjectID(), false, player->GetSystemAddress()); - } - } - } else if (name == EndWaveTimer) { - self->SetVar<bool>(WaveStatusVariable, false); - TimerToggle(self); - RecordPlayerScore(self); - - if (self->GetVar<uint32_t>(ThisWaveVariable) >= 2) { - GameMessages::SendActivityPause(self->GetObjectID(), true); - ActivityTimerStart(self, GameOverTimer, 0.1, 0.1); - return; - } - - self->SetVar<uint32_t>(ThisWaveVariable, self->GetVar<uint32_t>(ThisWaveVariable) + 1); - PlaySceneAnimation(self, u"wave" + GeneralUtils::to_u16string(self->GetVar<uint32_t>(ThisWaveVariable)), true, true, 1.7f); - self->SetNetworkVar<uint32_t>(WaveNumVariable, self->GetVar<uint32_t>(ThisWaveVariable) + 1); - self->SetNetworkVar<uint32_t>(WaveStrVariable, self->GetVar<uint32_t>(TimeLimitVariable)); - - Game::logger->Log("SGCannon", "Current wave: %i/%i\n", self->GetVar<uint32_t>(ThisWaveVariable), m_Waves.size()); - - if (self->GetVar<uint32_t>(ThisWaveVariable) >= m_Waves.size()) { - ActivityTimerStart(self, GameOverTimer, 0.1, 0.1); - } else { - ActivityTimerStart(self, SpawnWaveTimer, constants.inBetweenWavePause, constants.inBetweenWavePause); - } - - Game::logger->Log("SGCannon", "Sending ActivityPause true\n"); - - GameMessages::SendActivityPause(self->GetObjectID(), true); - if (self->GetVar<bool>(SuperChargeActiveVariable) && !self->GetVar<bool>(SuperChargePausedVariable)) { - PauseChargeCannon(self); - } - } else if (name == GameOverTimer) { - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - Game::logger->Log("SGCannon", "Sending ActivityPause true\n"); - - GameMessages::SendActivityPause(self->GetObjectID(), true, player->GetSystemAddress()); - - /*const auto leftoverCannonballs = EntityManager::Instance()->GetEntitiesInGroup("cannonball"); - if (leftoverCannonballs.empty()) { - RecordPlayerScore(self); - - } else { - ActivityTimerStart(self, EndGameBufferTimer, 1, leftoverCannonballs.size()); - }*/ - - ActivityTimerStart(self, EndGameBufferTimer, 1, 1); - - TimerToggle(self); - } - } else if (name.rfind(DoSpawnTimer, 0) == 0) { - if (self->GetVar<bool>(GameStartedVariable)) { - const auto spawnNumber = (uint32_t) std::stoi(name.substr(7)); - const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable); - const auto& toSpawn = activeSpawns.at(spawnNumber); - - const auto pathIndex = GeneralUtils::GenerateRandomNumber<float_t>(0, toSpawn.spawnPaths.size() - 1); - - const auto* path = dZoneManager::Instance()->GetZone()->GetPath( - toSpawn.spawnPaths.at(pathIndex) - ); - - auto info = EntityInfo {}; - info.lot = toSpawn.lot; - info.spawnerID = self->GetObjectID(); - info.pos = path->pathWaypoints.at(0).position; - - info.settings = { - new LDFData<SGEnemy>(u"SpawnData", toSpawn), - new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"), - new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"), - new LDFData<std::string>(u"attached_path", path->pathName), - new LDFData<uint32_t>(u"attached_path_start", 0), - new LDFData<std::u16string>(u"groupID", u"SGEnemy") - }; - - Game::logger->Log("SGCannon", "Spawning enemy %i on path %s\n", toSpawn.lot, path->pathName.c_str()); - - auto* enemy = EntityManager::Instance()->CreateEntity(info, nullptr, self); - EntityManager::Instance()->ConstructEntity(enemy); - - if (true) { - auto* movementAI = new MovementAIComponent(enemy, {}); - - enemy->AddComponent(COMPONENT_TYPE_MOVEMENT_AI, movementAI); - - movementAI->SetSpeed(toSpawn.initialSpeed); - movementAI->SetCurrentSpeed(toSpawn.initialSpeed); - movementAI->SetHaltDistance(0.0f); - - std::vector<NiPoint3> pathWaypoints; - - for (const auto& waypoint : path->pathWaypoints) { - pathWaypoints.push_back(waypoint.position); - } - - if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) { - std::reverse(pathWaypoints.begin(), pathWaypoints.end()); - } - - movementAI->SetPath(pathWaypoints); - - enemy->AddDieCallback([this, self, enemy, name] () { - RegisterHit(self, enemy, name); - }); - } - - // Save the enemy and tell it to start pathing - if (enemy != nullptr) { - const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).push_back(enemy->GetObjectID()); - GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS); - } - } - } else if (name == EndGameBufferTimer) { - RecordPlayerScore(self); - StopGame(self, false); - } -} - -void -SGCannon::OnActivityTimerUpdate(Entity *self, const std::string &name, float_t timeRemaining, float_t elapsedTime) { - ActivityManager::OnActivityTimerUpdate(self, name, timeRemaining, elapsedTime); -} - -void SGCannon::StartGame(Entity *self) { - self->SetNetworkVar<uint32_t>(TimeLimitVariable, self->GetVar<uint32_t>(TimeLimitVariable)); - self->SetNetworkVar<bool>(AudioStartIntroVariable, true); - self->SetVar<LOT>(CurrentRewardVariable, LOT_NULL); - - auto rewardObjects = EntityManager::Instance()->GetEntitiesInGroup(constants.rewardModelGroup); - for (auto* reward : rewardObjects) { - reward->OnFireEventServerSide(self, ModelToBuildEvent); - } - - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self)); - Game::logger->Log("SGCannon", "Sending ActivityStart\n"); - GameMessages::SendActivityStart(self->GetObjectID(), player->GetSystemAddress()); - - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"start", ""); - - self->SetNetworkVar<bool>(ClearVariable, true); - DoGameStartup(self); - - if (!self->GetVar<bool>(FirstTimeDoneVariable)) { - TakeActivityCost(self, player->GetObjectID()); - } - - self->SetVar<bool>(FirstTimeDoneVariable, true); - } - - SpawnNewModel(self); -} - -void SGCannon::DoGameStartup(Entity *self) { - ResetVars(self); - self->SetVar<bool>(GameStartedVariable, true); - self->SetNetworkVar<bool>(ClearVariable, true); - self->SetVar<uint32_t>(ThisWaveVariable, 0); - - if (constants.firstWaveStartTime < 1) { - constants.firstWaveStartTime = 1; - } - - ActivityTimerStart(self, SpawnWaveTimer, constants.firstWaveStartTime, - constants.firstWaveStartTime); -} - -void SGCannon::SpawnNewModel(Entity *self) { - - // Add a new reward to the existing rewards - const auto currentReward = self->GetVar<LOT>(CurrentRewardVariable); - if (currentReward != -1) { - auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable); - rewards.push_back(currentReward); - self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward); - } - - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - for (auto* rewardModel : EntityManager::Instance()->GetEntitiesInGroup(constants.rewardModelGroup)) { - uint32_t lootMatrix; - switch (self->GetVar<uint32_t>(MatrixVariable)) { - case 1: - lootMatrix = constants.scoreLootMatrix1; - break; - case 2: - lootMatrix = constants.scoreLootMatrix2; - break; - case 3: - lootMatrix = constants.scoreLootMatrix3; - break; - case 4: - lootMatrix = constants.scoreLootMatrix4; - break; - case 5: - lootMatrix = constants.scoreLootMatrix5; - break; - default: - lootMatrix = 0; - } - - if (lootMatrix != 0) { - std::unordered_map<LOT, int32_t> toDrop = {}; - toDrop = LootGenerator::Instance().RollLootMatrix(player, lootMatrix); - - for (auto drop : toDrop) { - rewardModel->OnFireEventServerSide(self, ModelToBuildEvent, drop.first); - self->SetVar<LOT>(CurrentRewardVariable, drop.first); - } - } - } - } -} - -void SGCannon::RemovePlayer(LWOOBJID playerID) { - auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player == nullptr) - return; - - auto* playerObject = dynamic_cast<Player*>(player); - if (playerObject == nullptr) - return; - - auto* character = playerObject->GetCharacter(); - if (character != nullptr) { - playerObject->SendToZone(character->GetLastNonInstanceZoneID()); - } -} - -void SGCannon::StartChargedCannon(Entity *self, uint32_t optionalTime) { - optionalTime = optionalTime == 0 ? constants.chargedTime : optionalTime; - self->SetVar<bool>(SuperChargePausedVariable, false); - ToggleSuperCharge(self, true); - ActivityTimerStart(self, SuperChargeTimer, 1, optionalTime); - - if (!self->GetVar<bool>(WaveStatusVariable)) { - PauseChargeCannon(self); - } -} - -void SGCannon::TimerToggle(Entity *self, bool start) { - if (start) { - self->SetNetworkVar<uint32_t>(CountVariable, self->GetVar<uint32_t>(TimeLimitVariable)); - self->SetVar<bool>(GameStartedVariable, true); - } else { - self->SetNetworkVar<bool>(StopVariable, true); - } -} - -void SGCannon::SpawnObject(Entity* self, const SGEnemy& toSpawn, bool spawnNow) { - auto activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable); - activeSpawns.push_back(toSpawn); - self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, activeSpawns); - - self->SetVar(SpawnNumberVariable, activeSpawns.size() - 1); - const auto timerName = DoSpawnTimer + std::to_string(activeSpawns.size() - 1); - - if (spawnNow) { - if (toSpawn.minSpawnTime > 0 && toSpawn.maxSpawnTime > 0) { - const auto spawnTime = GeneralUtils::GenerateRandomNumber<float_t>(toSpawn.minSpawnTime, toSpawn.maxSpawnTime); - - ActivityTimerStart(self, timerName, spawnTime, spawnTime); - } else { - ActivityTimerStart(self, timerName, 1, 1); - } - } else if (toSpawn.respawns) { - const auto spawnTime = GeneralUtils::GenerateRandomNumber<float_t>(toSpawn.minRespawnTime, toSpawn.maxRespawnTime); - - ActivityTimerStart(self, timerName, spawnTime, spawnTime); - } -} - -void SGCannon::RecordPlayerScore(Entity *self) { - const auto totalScore = self->GetVar<uint32_t>(TotalScoreVariable); - const auto currentWave = self->GetVar<uint32_t>(ThisWaveVariable); - - if (currentWave > 0) { - auto totalWaveScore = 0; - auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable); - - for (const auto& waveScore : playerScores) { - totalWaveScore += waveScore; - } - - if (currentWave >= playerScores.size()) { - playerScores.push_back(totalWaveScore); - } else { - playerScores[currentWave] = totalWaveScore; - } - } -} - -void SGCannon::PlaySceneAnimation(Entity* self, const std::u16string& animationName, bool onCannon, bool onPlayer, float_t priority) { - for (auto* cannon : EntityManager::Instance()->GetEntitiesInGroup("cannongroup")) { - GameMessages::SendPlayAnimation(cannon, animationName, priority); - } - - if (onCannon) { - GameMessages::SendPlayAnimation(self, animationName, priority); - } - - if (onPlayer) { - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player != nullptr) { - GameMessages::SendPlayAnimation(player, animationName, priority); - } - } -} - -void SGCannon::PauseChargeCannon(Entity *self) { - const auto time = std::max((uint32_t) std::ceil(ActivityTimerGetCurrentTime(self, SuperChargeTimer)), (uint32_t) 1); - - self->SetVar<bool>(SuperChargePausedVariable, true); - self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, time); - self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time); - - ActivityTimerStop(self, SuperChargeTimer); -} - -void SGCannon::StopGame(Entity *self, bool cancel) { - self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); - self->SetNetworkVar<bool>(HideSuperChargeVariable, true); - - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player == nullptr) - return; - - ToggleSuperCharge(self, false); - - // The player won, store all the score and send rewards - if (!cancel) { - auto percentage = 0; - auto misses = self->GetVar<uint32_t>(MissesVariable); - auto fired = self->GetVar<uint32_t>(ShotsFiredVariable); - - if (fired > 0) { - percentage = misses / fired; - } - - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, self->GetVar<uint32_t>(TotalScoreVariable), self->GetObjectID(), "performact_score"); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, self->GetVar<uint32_t>(MaxStreakVariable), self->GetObjectID(), "performact_streak"); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_CannonLot, 0, "", self->GetVar<uint32_t>(TotalScoreVariable)); - } - - LootGenerator::Instance().GiveActivityLoot(player, self, GetGameID(self), self->GetVar<uint32_t>(TotalScoreVariable)); - - StopActivity(self, player->GetObjectID(), self->GetVar<uint32_t>(TotalScoreVariable), self->GetVar<uint32_t>(MaxStreakVariable), percentage); - self->SetNetworkVar<bool>(AudioFinalWaveDoneVariable, true); - - // Give the player the model rewards they earned - auto* inventory = player->GetComponent<InventoryComponent>(); - if (inventory != nullptr) { - for (const auto rewardLot : self->GetVar<std::vector<LOT>>(RewardsVariable)) { - inventory->AddItem(rewardLot, 1, eLootSourceType::LOOT_SOURCE_ACTIVITY, eInventoryType::MODELS); - } - } - - self->SetNetworkVar<std::u16string>(u"UI_Rewards", - GeneralUtils::to_u16string(self->GetVar<uint32_t>(TotalScoreVariable)) + u"_0_0_0_0_0_0" - ); - - GameMessages::SendRequestActivitySummaryLeaderboardData( - player->GetObjectID(), - self->GetObjectID(), - player->GetSystemAddress(), - GetGameID(self), - 1, - 10, - 0, - false - ); - } - - GameMessages::SendActivityStop(self->GetObjectID(), false, cancel, player->GetSystemAddress()); - self->SetVar<bool>(GameStartedVariable, false); - ActivityTimerStopAllTimers(self); - - // Destroy all spawners - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup("SGEnemy")) { - entity->Kill(); - } - - ResetVars(self); -} - -void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& timerName) -{ - const auto& spawnInfo = target->GetVar<SGEnemy>(u"SpawnData"); - - if (spawnInfo.respawns) - { - const auto respawnTime = GeneralUtils::GenerateRandomNumber<float_t>(spawnInfo.minRespawnTime, spawnInfo.maxRespawnTime); - - ActivityTimerStart(self, timerName, respawnTime, respawnTime); - } - - int score = spawnInfo.score; - - if (score > 0) { - score += score * GetCurrentBonus(self); - - if (!self->GetVar<bool>(SuperChargeActiveVariable)) { - self->SetVar<uint32_t>(u"m_curStreak", self->GetVar<uint32_t>(u"m_curStreak") + 1); - } - } - else { - if (!self->GetVar<bool>(SuperChargeActiveVariable)) { - self->SetVar<uint32_t>(u"m_curStreak", 0); - } - - self->SetNetworkVar<bool>(u"hitFriend", true); - } - - auto lastSuperTotal = self->GetVar<uint32_t>(u"LastSuperTotal"); - - auto scScore = self->GetVar<uint32_t>(TotalScoreVariable) - lastSuperTotal; - - Game::logger->Log("SGCannon", "LastSuperTotal: %i, scScore: %i, constants.chargedPoints: %i\n", - lastSuperTotal, scScore, constants.chargedPoints - ); - - if (!self->GetVar<bool>(SuperChargeActiveVariable) && scScore >= constants.chargedPoints && score >= 0) { - StartChargedCannon(self); - self->SetNetworkVar<float>(u"SuperChargeBar", 100.0f); - self->SetVar<uint32_t>(u"LastSuperTotal", self->GetVar<uint32_t>(TotalScoreVariable)); - } - - UpdateStreak(self); - - GameMessages::SendNotifyClientShootingGalleryScore(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, - 0.0f, - score, - target->GetObjectID(), - target->GetPosition() - ); - - auto newScore = (int) self->GetVar<uint32_t>(TotalScoreVariable) + score; - - if (newScore < 0) { - newScore = 0; - } - - self->SetVar<uint32_t>(TotalScoreVariable, newScore); - - self->SetNetworkVar<uint32_t>(u"updateScore", newScore); - - self->SetNetworkVar<std::u16string>(u"beatHighScore", GeneralUtils::to_u16string(newScore)); - - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - if (player == nullptr) return; - - auto missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) return; - - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, spawnInfo.lot, self->GetObjectID()); -} - -void SGCannon::UpdateStreak(Entity* self) -{ - const auto streakBonus = GetCurrentBonus(self); - - const auto curStreak = self->GetVar<uint32_t>(u"m_curStreak"); - - const auto marks = curStreak % 3; - - self->SetNetworkVar<uint32_t>(u"cStreak", curStreak); - - if (curStreak >= 0 && curStreak < 13) { - if (marks == 1) { - self->SetNetworkVar<bool>(u"Mark1", true); - } - else if (marks == 2) { - self->SetNetworkVar<bool>(u"Mark2", true); - } - else if (marks == 0 && curStreak > 0) { - self->SetVar<float_t>(u"StreakBonus", streakBonus); - self->SetNetworkVar<bool>(u"ShowStreak", streakBonus + 1); - self->SetNetworkVar<bool>(u"Mark3", true); - } - else { - self->SetVar<float_t>(u"StreakBonus", streakBonus); - self->SetNetworkVar<bool>(u"UnMarkAll", true); - } - } - auto maxStreak = self->GetVar<uint32_t>(MaxStreakVariable); - if (maxStreak < curStreak) self->SetVar<uint32_t>(MaxStreakVariable, curStreak); -} - -float_t SGCannon::GetCurrentBonus(Entity* self) -{ - auto streak = self->GetVar<uint32_t>(u"m_curStreak"); - - if (streak > 12) { - streak = 12; - } - - return streak / 3; -} - -void SGCannon::ToggleSuperCharge(Entity *self, bool enable) { - if (enable && self->GetVar<bool>(SuperChargeActiveVariable)) - return; - - auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); - - if (player == nullptr) { - Game::logger->Log("SGCannon", "Player not found in toggle super charge\n"); - return; - } - - auto* inventoryComponent = player->GetComponent<InventoryComponent>(); - - auto equippedItems = inventoryComponent->GetEquippedItems(); - - Game::logger->Log("SGCannon", "Player has %d equipped items\n", equippedItems.size()); - - auto skillID = constants.cannonSkill; - auto coolDown = constants.cannonRefireRate; - - auto* selfInventoryComponent = self->GetComponent<InventoryComponent>(); - - if (inventoryComponent == nullptr) { - Game::logger->Log("SGCannon", "Inventory component not found\n"); - return; - } - - if (enable) { - Game::logger->Log("SGCannon", "Player is activating super charge\n"); - selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 6505, 1, 0 }); - selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 6506, 1, 0 }); - - // TODO: Equip items - skillID = constants.cannonSuperChargeSkill; - coolDown = 400; - } else { - selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); - selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); - - self->SetNetworkVar<float>(u"SuperChargeBar", 0); - - Game::logger->Log("SGCannon", "Player disables super charge\n"); - - // TODO: Unequip items - for (const auto& equipped : equippedItems) { - if (equipped.first == "special_r" || equipped.first == "special_l") { - Game::logger->Log("SGCannon", "Trying to unequip a weapon, %i\n", equipped.second.lot); - - auto* item = inventoryComponent->FindItemById(equipped.second.id); - - if (item != nullptr) { - inventoryComponent->UnEquipItem(item); - } - else { - Game::logger->Log("SGCannon", "Item not found, %i\n", equipped.second.lot); - } - } - } - - self->SetVar<uint32_t>(NumberOfChargesVariable, 0); - } - - const auto& constants = GetConstants(); - - auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); - - if (shootingGalleryComponent == nullptr) { - return; - } - - DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams(); - - properties.cannonFOV = 58.6f; - properties.cannonVelocity = 129.0; - properties.cannonRefireRate = 800; - properties.cannonMinDistance = 30; - properties.cannonTimeout = -1; - - shootingGalleryComponent->SetDynamicParams(properties); - - EntityManager::Instance()->SerializeEntity(self); - EntityManager::Instance()->SerializeEntity(player); - - self->SetNetworkVar<uint64_t>(CannonBallSkillIDVariable, skillID); - self->SetVar<bool>(SuperChargeActiveVariable, enable); -} - -std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { - return { - // Wave 1 - { - // Ship 1 - { - std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, - 6015, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 2 - { - std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, - 6300, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Sub 1 - { - std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 10.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Sub 2 - { - std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Friendly - { - std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, - 2168,0.0,5.0,true, 2.0, 5.0, - 1.0, -1000, false, 0.0, 1.0, - 1.0, false,true - } - }, - - // Wave 2 - { - // Ship 1 - { - std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, - 6015, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 2 - { - std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, - 6300, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 3 - { - std::vector<std::string> { "Wave_2_Ship_1" }, - 6300, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 4 - { - std::vector<std::string> { "Wave_2_Ship_2" }, - 6015, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Sub 1 - { - std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Sub 2 - { - std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Duck - { - std::vector<std::string> { "Wave_1_Duck_1", "Wave_1_Duck_2" }, - 5946, 5.0, 10.0, true, 5.0, 10.0, - 4.0, 5000, false, 0.0, 1.0, - 1.0, false, true - }, - - // Friendly - { - std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, - 2168,0.0,5.0,true, 2.0, 5.0, - 1.0, -1000, false, 0.0, 1.0, - 1.0, false,true - } - }, - - // Wave 3 - { - // Ship 1 - { - std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, - 6015, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 2 - { - std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, - 6300, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 3 - { - std::vector<std::string> { "Wave_2_Ship_1", "Wave_2_Ship_2" }, - 6015, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ship 4 - { - std::vector<std::string> { "Wave_3_Ship_1", "Wave_3_Ship_2" }, - 6300, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1500, false, 0.0, 1.0, - 1.0, false, true - }, - - // Sub 1 - { - std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Sub 2 - { - std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Sub 3 - { - std::vector<std::string> { "Wave_3_Sub_1", "Wave_3_Sub_2" }, - 6016, 0.0, 2.0, true, 0.0, 2.0, - 2.0, 1000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Duck - { - std::vector<std::string> { "Wave_1_Duck_1", "Wave_1_Duck_2" }, - 5946, 5.0, 10.0, true, 5.0, 10.0, - 4.0, 5000, false, 0.0, 1.0, - 1.0, false, true - }, - - // Ness - { - std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, - 2565, 10.0, 15.0, true, 10.0, 15.0, - 2.0, 10000, false, 0.0, 1.0, - 1.0, true, true - }, - - // Friendly 1 - { - std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, - 2168,0.0,5.0,true, 2.0, 5.0, - 1.0, -1000, false, 0.0, 1.0, - 1.0, false,true - }, - - // Friendly 2 - { - std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, - 2168,0.0,5.0,true, 2.0, 5.0, - 1.0, -1000, false, 0.0, 1.0, - 1.0, false,true - } - } - }; -} - -void SGCannon::ResetVars(Entity *self) { - self->SetVar<uint32_t>(SpawnNumberVariable, 0); - self->SetVar<uint32_t>(CurrentSpawnNumberVariable, 0); - self->SetVar<uint32_t>(ThisWaveVariable, 0); - self->SetVar<uint32_t>(GameScoreVariable, 0); - self->SetVar<uint32_t>(GameTimeVariable, 0); - self->SetVar<bool>(GameStartedVariable, false); - self->SetVar<uint32_t>(ShotsFiredVariable, 0); - self->SetVar<uint32_t>(MaxStreakVariable, 0); - self->SetVar<uint32_t>(MissesVariable, 0); - self->SetVar<uint32_t>(CurrentStreakVariable, 0); - self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, 0); - self->SetVar<std::vector<uint32_t>>(StreakBonusVariable, {}); - self->SetVar<uint32_t>(LastSuperTotalVariable, 0); - self->SetVar<LOT>(CurrentRewardVariable, LOT_NULL); - self->SetVar<std::vector<LOT>>(RewardsVariable, {}); - self->SetVar<uint32_t>(TotalScoreVariable, 0); - - const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear(); - self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {}); - - const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).clear(); - self->SetVar<std::vector<LWOOBJID>>(SpawnedObjects, {}); - - if (self->GetVar<bool>(InitVariable)) { - ToggleSuperCharge(self, false); - } - - self->SetVar<uint32_t>(ImpactSkillVariale, constants.impactSkillID); - self->SetVar<std::vector<int32_t>>(PlayerScoresVariable, {}); - ActivityTimerStopAllTimers(self); -} - -SGConstants SGCannon::GetConstants() { - return { - Vector3 { -908.542480, 229.773178, -908.542480 }, - Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 }, - 1864, - 34, - 1822, - Vector3 { 6.652, -2, 1.5 }, - 157, - 129.0, - 30.0, - 800.0, - Vector3 { 0, 4.3, 9 }, - 6297, - 1822, - 249, - 228, - -1, - 58.6, - true, - 2, - 10, - 25000, - "QBRewardGroup", - 1864, - 50000, - 157, - 100000, - 187, - 200000, - 188, - 400000, - 189, - 800000, - 190, - 4.0, - 7.0 - }; -} diff --git a/dScripts/SGCannon.h b/dScripts/SGCannon.h deleted file mode 100644 index 56db4c81..00000000 --- a/dScripts/SGCannon.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once -#include <regex> -#include "ActivityManager.h" - -struct SGEnemy { - std::vector<std::string> spawnPaths {}; - LOT lot; - float_t minSpawnTime; - float_t maxSpawnTime; - bool respawns; - float_t minRespawnTime; - float_t maxRespawnTime; - float_t initialSpeed; - int32_t score; - bool changeSpeedAtWaypoint; - float_t speedChangeChance; - float_t minSpeed; - float_t maxSpeed; - bool isMovingPlatform; - bool despawnOnLastWaypoint; -}; - -struct SGConstants { - Vector3 playerStartPosition; - Quaternion playerStartRotation; - LOT cannonLot; - uint32_t impactSkillID; - LOT projectileLot; - Vector3 playerOffset; - uint32_t rewardModelMatrix; - float_t cannonVelocity; - float_t cannonMinDistance; - float_t cannonRefireRate; - Vector3 cannonBarrelOffset; - LOT cannonSuperchargedProjectileLot; - LOT cannonProjectileLot; - uint32_t cannonSuperChargeSkill; - uint32_t cannonSkill; - int32_t cannonTimeout; - float_t cannonFOV; - bool useLeaderboards; - uint32_t streakModifier; - uint32_t chargedTime; - uint32_t chargedPoints; - std::string rewardModelGroup; - uint32_t activityID; - uint32_t scoreReward1; - uint32_t scoreLootMatrix1; - uint32_t scoreReward2; - uint32_t scoreLootMatrix2; - uint32_t scoreReward3; - uint32_t scoreLootMatrix3; - uint32_t scoreReward4; - uint32_t scoreLootMatrix4; - uint32_t scoreReward5; - uint32_t scoreLootMatrix5; - float_t firstWaveStartTime; - float_t inBetweenWavePause; -}; - -class SGCannon : public ActivityManager { -public: - void OnStartup(Entity *self) override; - void OnPlayerLoaded(Entity *self, Entity *player) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - void OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int32_t value1, - int32_t value2, const std::u16string& stringValue) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, - const std::u16string& userData) override; - void OnActivityTimerDone(Entity *self, const std::string &name) override; - void OnActivityTimerUpdate(Entity *self, const std::string &name, float_t timeRemaining, float_t elapsedTime) override; -private: - static std::vector<std::vector<SGEnemy>> GetWaves(); - static SGConstants GetConstants(); - void ResetVars(Entity* self); - void StartGame(Entity* self); - void DoGameStartup(Entity* self); - void SpawnNewModel(Entity* self); - void TimerToggle(Entity* self, bool start = false); - void SpawnObject(Entity* self, const SGEnemy& toSpawn, bool spawnNow = false); - void StartChargedCannon(Entity* self, uint32_t optionalTime = 0); - void ToggleSuperCharge(Entity* self, bool enable); - void RecordPlayerScore(Entity* self); - void PlaySceneAnimation(Entity* self, const std::u16string& animationName, bool onCannon, bool onPlayer, float_t priority); - static void RemovePlayer(LWOOBJID playerID); - void PauseChargeCannon(Entity* self); - void StopGame(Entity* self, bool cancel = false); - void RegisterHit(Entity* self, Entity* target, const std::string& timerName); - void UpdateStreak(Entity* self); - float_t GetCurrentBonus(Entity* self); - - LOT m_CannonLot = 1864; - std::u16string PlayerIDVariable = u"PlayerID"; - std::u16string HideScoreBoardVariable = u"HideScoreBoard"; - std::u16string ReSetSuperChargeVariable = u"ReSetSuperCharge"; - std::u16string ShowLoadingUI = u"showLoadingUI"; - std::u16string SpawnNumberVariable = u"SpawnNum"; - std::u16string CurrentSpawnNumberVariable = u"CurSpawnNum"; - std::u16string ThisWaveVariable = u"ThisWave"; - std::u16string GameScoreVariable = u"GameScore"; - std::u16string GameTimeVariable = u"GameTime"; - std::u16string GameStartedVariable = u"GameStarted"; - std::u16string ShotsFiredVariable = u"ShotsFired"; - std::u16string MaxStreakVariable = u"MaxStreak"; - std::u16string MissesVariable = u"Misses"; - std::u16string CurrentStreakVariable = u"CurrentStreak"; - std::u16string CurrentSuperChargedTimeVariable = u"CurrentSuperChargedTime"; - std::u16string StreakBonusVariable = u"StreakBonus"; - std::u16string LastSuperTotalVariable = u"LastSuperTotal"; - std::u16string CurrentRewardVariable = u"CurrentReward"; - std::u16string RewardsVariable = u"Rewards"; - std::u16string TotalScoreVariable = u"TotalScore"; - std::u16string InitVariable = u"Init"; - std::u16string ImpactSkillVariale = u"ImpactSkill"; - std::u16string PlayerScoresVariable = u"PlayerScores"; - std::u16string InitialVelocityVariable = u"InitialVelocity"; - std::u16string ValidActorsVariable = u"ValidActors"; - std::u16string ValidEffectsVariable = u"ValidEffects"; - std::u16string SuperChargeActiveVariable = u"SuperChargeActive"; - std::u16string MatrixVariable = u"Matrix"; - std::u16string TimeLimitVariable = u"game_timelimit"; - std::u16string AudioStartIntroVariable = u"Audio_Start_Intro"; - std::u16string ClearVariable = u"Clear"; - std::u16string FirstTimeDoneVariable = u"FirstTimeDone"; - std::u16string RewardAddedVariable = u"rewardAdded"; - std::u16string SuperChargePausedVariable = u"Super_Charge_Paused"; - std::u16string WaveStatusVariable = u"WaveStatus"; - std::u16string CountVariable = u"count"; - std::u16string StopVariable = u"Stop"; - std::u16string ActiveSpawnsVariable = u"ActiveSpawns"; - std::u16string SpawnedObjects = u"SpawnedObjects"; - std::u16string WaveNumVariable = u"wave.waveNum"; - std::u16string WaveStrVariable = u"wave.waveStr"; - std::u16string ChargeCountingVariable = u"charge_counting"; - std::u16string SuperChargeBarVariable = u"SuperChargeBar"; - std::u16string NumberOfChargesVariable = u"NumberOfCharges"; - std::u16string CannonBallSkillIDVariable = u"cbskill"; - std::u16string HideSuperChargeVariable = u"HideSuper"; - std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done"; - - std::string SpawnWaveTimer = "SpawnWave"; - std::string EndWaveTimer = "EndWave"; - std::string GameOverTimer = "GameOver"; - std::string DoSpawnTimer = "DoSpawn"; - std::string EndGameBufferTimer = "endGameBuffer"; - std::string SuperChargeTimer = "SuperChargeTimer"; - - std::string ModelToBuildEvent = "modelToBuild"; - - std::regex DoSpawnRegex = std::regex("\\d*"); - SGConstants constants {}; - std::vector<std::vector<SGEnemy>> m_Waves {}; -}; diff --git a/dScripts/ScriptComponent.cpp b/dScripts/ScriptComponent.cpp index 3c5c2584..272de5ab 100644 --- a/dScripts/ScriptComponent.cpp +++ b/dScripts/ScriptComponent.cpp @@ -18,27 +18,27 @@ ScriptComponent::~ScriptComponent() { } void ScriptComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (bIsInitialUpdate) { - const auto& networkSettings = m_Parent->GetNetworkSettings(); - auto hasNetworkSettings = !networkSettings.empty(); - outBitStream->Write(hasNetworkSettings); + if (bIsInitialUpdate) { + const auto& networkSettings = m_Parent->GetNetworkSettings(); + auto hasNetworkSettings = !networkSettings.empty(); + outBitStream->Write(hasNetworkSettings); - if (hasNetworkSettings) { + if (hasNetworkSettings) { - // First write the most inner LDF data - RakNet::BitStream ldfData; - ldfData.Write<uint8_t>(0); - ldfData.Write<uint32_t>(networkSettings.size()); + // First write the most inner LDF data + RakNet::BitStream ldfData; + ldfData.Write<uint8_t>(0); + ldfData.Write<uint32_t>(networkSettings.size()); - for (auto* networkSetting : networkSettings) { - networkSetting->WriteToPacket(&ldfData); - } + for (auto* networkSetting : networkSettings) { + networkSetting->WriteToPacket(&ldfData); + } - // Finally write everything to the stream - outBitStream->Write<uint32_t>(ldfData.GetNumberOfBytesUsed()); - outBitStream->Write(ldfData); - } - } + // Finally write everything to the stream + outBitStream->Write<uint32_t>(ldfData.GetNumberOfBytesUsed()); + outBitStream->Write(ldfData); + } + } } CppScripts::Script* ScriptComponent::GetScript() { @@ -46,7 +46,7 @@ CppScripts::Script* ScriptComponent::GetScript() { } void ScriptComponent::SetScript(const std::string& scriptName) { - //we don't need to delete the script because others may be using it :) + //we don't need to delete the script because others may be using it :) /*if (m_Client) { m_Script = new InvalidScript(); return; diff --git a/dScripts/ScriptComponent.h b/dScripts/ScriptComponent.h index 82d1f648..77dff5bf 100644 --- a/dScripts/ScriptComponent.h +++ b/dScripts/ScriptComponent.h @@ -9,6 +9,7 @@ #include "CppScripts.h" #include "Component.h" #include <string> +#include "eReplicaComponentType.h" class Entity; @@ -18,46 +19,46 @@ class Entity; */ class ScriptComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPT; - - ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client = false); - ~ScriptComponent() override; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SCRIPT; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client = false); + ~ScriptComponent() override; - /** - * Returns the script that's attached to this entity - * @return the script that's attached to this entity - */ + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); + + /** + * Returns the script that's attached to this entity + * @return the script that's attached to this entity + */ CppScripts::Script* GetScript(); - /** - * Sets whether the entity should be serialized, unused - * @param var whether the entity should be serialized - */ + /** + * Sets whether the entity should be serialized, unused + * @param var whether the entity should be serialized + */ void SetSerialized(const bool var) { m_Serialized = var; } - /** - * Sets the script using a path by looking through dScripts for a script that matches - * @param scriptName the name of the script to find - */ + /** + * Sets the script using a path by looking through dScripts for a script that matches + * @param scriptName the name of the script to find + */ void SetScript(const std::string& scriptName); private: - /** - * The script attached to this entity - */ + /** + * The script attached to this entity + */ CppScripts::Script* m_Script; - /** - * Whether or not the comp should be serialized, unused - */ + /** + * Whether or not the comp should be serialized, unused + */ bool m_Serialized; - /** - * Whether or not this script is a client script - */ + /** + * Whether or not this script is a client script + */ bool m_Client; }; diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index 91c25856..3c1d1cca 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -1,46 +1,47 @@ #include "ScriptedPowerupSpawner.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "Loot.h" -void ScriptedPowerupSpawner::OnTemplateStartup(Entity *self) { - self->SetVar<uint32_t>(u"currentCycle", 1); - self->AddTimer("timeToSpawn", self->GetVar<float_t>(u"delayToFirstCycle")); +void ScriptedPowerupSpawner::OnTemplateStartup(Entity* self) { + self->SetVar<uint32_t>(u"currentCycle", 1); + self->AddTimer("timeToSpawn", self->GetVar<float_t>(u"delayToFirstCycle")); } -void ScriptedPowerupSpawner::OnTimerDone(Entity *self, std::string message) { - if (message == "die") { - self->Smash(); - } else if (message == "timeToSpawn") { +void ScriptedPowerupSpawner::OnTimerDone(Entity* self, std::string message) { + if (message == "die") { + self->Smash(); + } else if (message == "timeToSpawn") { - const auto itemLOT = self->GetVar<LOT>(u"lootLOT"); + const auto itemLOT = self->GetVar<LOT>(u"lootLOT"); - // Build drop table - std::unordered_map<LOT, int32_t> drops; + // Build drop table + std::unordered_map<LOT, int32_t> drops; - drops.emplace(itemLOT, 1); + drops.emplace(itemLOT, 1); - // Spawn the required number of powerups - auto* owner = EntityManager::Instance()->GetEntity(self->GetSpawnerID()); - if (owner != nullptr) { - auto* renderComponent = self->GetComponent<RenderComponent>(); - for (auto i = 0; i < self->GetVar<uint32_t>(u"numberOfPowerups"); i++) { - if (renderComponent != nullptr) { - renderComponent->PlayEffect(0, u"cast", "N_cast"); - } + // Spawn the required number of powerups + auto* owner = EntityManager::Instance()->GetEntity(self->GetSpawnerID()); + if (owner != nullptr) { + auto* renderComponent = self->GetComponent<RenderComponent>(); + for (auto i = 0; i < self->GetVar<uint32_t>(u"numberOfPowerups"); i++) { + if (renderComponent != nullptr) { + renderComponent->PlayEffect(0, u"cast", "N_cast"); + } - LootGenerator::Instance().DropLoot(owner, self, drops, 0, 0); - } + LootGenerator::Instance().DropLoot(owner, self, drops, 0, 0); + } - // Increment the current cycle - if (self->GetVar<uint32_t>(u"currentCycle") < self->GetVar<uint32_t>(u"numCycles")) { - self->AddTimer("timeToSpawn", self->GetVar<float_t>(u"secPerCycle")); - self->SetVar<uint32_t>(u"currentCycle", self->GetVar<uint32_t>(u"currentCycle") + 1); - } + // Increment the current cycle + if (self->GetVar<uint32_t>(u"currentCycle") < self->GetVar<uint32_t>(u"numCycles")) { + self->AddTimer("timeToSpawn", self->GetVar<float_t>(u"secPerCycle")); + self->SetVar<uint32_t>(u"currentCycle", self->GetVar<uint32_t>(u"currentCycle") + 1); + } - // Kill if this was the last cycle - if (self->GetVar<uint32_t>(u"currentCycle") >= self->GetVar<uint32_t>(u"numCycles")) { - self->AddTimer("die", self->GetVar<float_t>(u"deathDelay")); - } - } - } + // Kill if this was the last cycle + if (self->GetVar<uint32_t>(u"currentCycle") >= self->GetVar<uint32_t>(u"numCycles")) { + self->AddTimer("die", self->GetVar<float_t>(u"deathDelay")); + } + } + } } diff --git a/dScripts/ScriptedPowerupSpawner.h b/dScripts/ScriptedPowerupSpawner.h index 597e8673..1fa57d90 100644 --- a/dScripts/ScriptedPowerupSpawner.h +++ b/dScripts/ScriptedPowerupSpawner.h @@ -13,11 +13,11 @@ */ class ScriptedPowerupSpawner : public CppScripts::Script { public: - /** - * Called by the child script after on startup - * \param self the object this script belongs to - */ - static void OnTemplateStartup(Entity* self); - void OnTimerDone(Entity* self, std::string message) override; + /** + * Called by the child script after on startup + * \param self the object this script belongs to + */ + static void OnTemplateStartup(Entity* self); + void OnTimerDone(Entity* self, std::string message) override; }; diff --git a/dScripts/SpawnGryphonServer.cpp b/dScripts/SpawnGryphonServer.cpp deleted file mode 100644 index d411569c..00000000 --- a/dScripts/SpawnGryphonServer.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "SpawnGryphonServer.h" -#include "InventoryComponent.h" -#include "GameMessages.h" -#include "MissionComponent.h" - -void SpawnGryphonServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 12433); - self->SetVar<std::string>(u"petType", "gryphon"); - self->SetVar<uint32_t>(u"maxPets", 2); - self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); - self->SetVar<std::u16string>(u"spawnCinematic", u"SentinelPet"); -} - -void SpawnGryphonServer::OnUse(Entity *self, Entity *user) { - auto* missionComponent = user->GetComponent<MissionComponent>(); - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - - // Little extra for handling the case of the egg being placed the first time - if (missionComponent != nullptr && inventoryComponent != nullptr - && missionComponent->GetMissionState(1391) == MissionState::MISSION_STATE_ACTIVE) { - inventoryComponent->RemoveItem(12483, inventoryComponent->GetLotCount(12483)); - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); - return; - } - - SpawnPetBaseServer::OnUse(self, user); -} diff --git a/dScripts/SpawnLionServer.cpp b/dScripts/SpawnLionServer.cpp deleted file mode 100644 index b19531a4..00000000 --- a/dScripts/SpawnLionServer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "SpawnLionServer.h" -#include "Entity.h" - -void SpawnLionServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 3520); - self->SetVar<std::string>(u"petType", "lion"); - self->SetVar<uint32_t>(u"maxPets", 5); - self->SetVar<std::u16string>(u"spawnAnim", u"spawn-lion"); - self->SetVar<std::u16string>(u"spawnCinematic", u"Lion_spawn"); -} diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index d23e371a..75b46382 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -2,81 +2,83 @@ #include "GameMessages.h" #include "EntityManager.h" #include "PetComponent.h" +#include "EntityInfo.h" +#include "eTerminateType.h" -void SpawnPetBaseServer::OnStartup(Entity *self) { - SetVariables(self); - self->SetVar<std::string>(u"spawnedPets", ""); +void SpawnPetBaseServer::OnStartup(Entity* self) { + SetVariables(self); + self->SetVar<std::string>(u"spawnedPets", ""); } -void SpawnPetBaseServer::OnUse(Entity *self, Entity *user) { - auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(u"petType") + "Spawner"); - if (possibleSpawners.empty()) - return; +void SpawnPetBaseServer::OnUse(Entity* self, Entity* user) { + auto possibleSpawners = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(u"petType") + "Spawner"); + if (possibleSpawners.empty()) + return; - if (!CheckNumberOfPets(self, user)) - return; + if (!CheckNumberOfPets(self, user)) + return; - auto* spawner = possibleSpawners.at(0); - auto petType = GeneralUtils::ASCIIToUTF16(self->GetVar<std::string>(u"petType")); + auto* spawner = possibleSpawners.at(0); + auto petType = GeneralUtils::ASCIIToUTF16(self->GetVar<std::string>(u"petType")); - EntityInfo info {}; - info.pos = spawner->GetPosition(); - info.rot = spawner->GetRotation(); - info.lot = self->GetVar<LOT>(u"petLOT"); - info.spawnerID = self->GetObjectID(); - info.settings = { - new LDFData<LWOOBJID>(u"tamer", user->GetObjectID()), - new LDFData<std::u16string>(u"groupID", petType + (GeneralUtils::to_u16string(user->GetObjectID())) + u";" + petType + u"s"), - new LDFData<std::u16string>(u"spawnAnim", self->GetVar<std::u16string>(u"spawnAnim")), - new LDFData<float_t>(u"spawnTimer", 1.0f) - }; + EntityInfo info{}; + info.pos = spawner->GetPosition(); + info.rot = spawner->GetRotation(); + info.lot = self->GetVar<LOT>(u"petLOT"); + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData<LWOOBJID>(u"tamer", user->GetObjectID()), + new LDFData<std::u16string>(u"groupID", petType + (GeneralUtils::to_u16string(user->GetObjectID())) + u";" + petType + u"s"), + new LDFData<std::u16string>(u"spawnAnim", self->GetVar<std::u16string>(u"spawnAnim")), + new LDFData<float_t>(u"spawnTimer", 1.0f) + }; - auto* pet = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(pet); + auto* pet = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(pet); - self->SetVar<std::string>(u"spawnedPets", self->GetVar<std::string>(u"spawnedPets") + "," - + std::to_string(pet->GetObjectID())); + self->SetVar<std::string>(u"spawnedPets", self->GetVar<std::string>(u"spawnedPets") + "," + + std::to_string(pet->GetObjectID())); - auto spawnCinematic = self->GetVar<std::u16string>(u"spawnCinematic"); - if (!spawnCinematic.empty()) { - GameMessages::SendPlayCinematic(user->GetObjectID(), spawnCinematic, UNASSIGNED_SYSTEM_ADDRESS); - } + auto spawnCinematic = self->GetVar<std::u16string>(u"spawnCinematic"); + if (!spawnCinematic.empty()) { + GameMessages::SendPlayCinematic(user->GetObjectID(), spawnCinematic, UNASSIGNED_SYSTEM_ADDRESS); + } - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); } -bool SpawnPetBaseServer::CheckNumberOfPets(Entity *self, Entity* user) { - auto petIDString = self->GetVar<std::string>(u"spawnedPets"); - auto petIDs = GeneralUtils::SplitString(petIDString, ','); +bool SpawnPetBaseServer::CheckNumberOfPets(Entity* self, Entity* user) { + auto petIDString = self->GetVar<std::string>(u"spawnedPets"); + auto petIDs = GeneralUtils::SplitString(petIDString, ','); - // Check all the pets that were tamed in the process or were smashed - std::vector<LWOOBJID> petsToKeep {}; - for (const auto& petID : petIDs) { - if (petID.empty()) - continue; + // Check all the pets that were tamed in the process or were smashed + std::vector<LWOOBJID> petsToKeep{}; + for (const auto& petID : petIDs) { + if (petID.empty()) + continue; - const auto* spawnedPet = EntityManager::Instance()->GetEntity(std::stoull(petID)); - if (spawnedPet == nullptr) - continue; + const auto* spawnedPet = EntityManager::Instance()->GetEntity(std::stoull(petID)); + if (spawnedPet == nullptr) + continue; - const auto* petComponent = spawnedPet->GetComponent<PetComponent>(); - if (petComponent == nullptr || petComponent->GetOwner() != nullptr) - continue; + const auto* petComponent = spawnedPet->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + continue; - // Each user can only spawn one pet - if (spawnedPet->GetVar<LWOOBJID>(u"tamer") == user->GetObjectID()) - return false; + // Each user can only spawn one pet + if (spawnedPet->GetVar<LWOOBJID>(u"tamer") == user->GetObjectID()) + return false; - petsToKeep.push_back(spawnedPet->GetObjectID()); - } + petsToKeep.push_back(spawnedPet->GetObjectID()); + } - self->SetNetworkVar<bool>(u"TooManyPets", petsToKeep.size() >= self->GetVar<uint32_t>(u"maxPets")); + self->SetNetworkVar<bool>(u"TooManyPets", petsToKeep.size() >= self->GetVar<uint32_t>(u"maxPets")); - std::string newPetIDs; - for (const auto petID : petsToKeep) { - newPetIDs += (std::to_string(petID) + ","); - } - self->SetVar<std::string>(u"spawnedPets", newPetIDs); + std::string newPetIDs; + for (const auto petID : petsToKeep) { + newPetIDs += (std::to_string(petID) + ","); + } + self->SetVar<std::string>(u"spawnedPets", newPetIDs); - return petsToKeep.size() < self->GetVar<uint32_t>(u"maxPets"); + return petsToKeep.size() < self->GetVar<uint32_t>(u"maxPets"); } diff --git a/dScripts/SpawnPetBaseServer.h b/dScripts/SpawnPetBaseServer.h index 80412b13..9ae51084 100644 --- a/dScripts/SpawnPetBaseServer.h +++ b/dScripts/SpawnPetBaseServer.h @@ -11,9 +11,9 @@ */ class SpawnPetBaseServer : public CppScripts::Script { public: - void OnStartup(Entity *self) override; - void OnUse(Entity *self, Entity *user) override; - virtual void SetVariables(Entity* self) {}; + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + virtual void SetVariables(Entity* self) {}; private: - static bool CheckNumberOfPets(Entity* self, Entity* user); + static bool CheckNumberOfPets(Entity* self, Entity* user); }; diff --git a/dScripts/SpawnSaberCatServer.cpp b/dScripts/SpawnSaberCatServer.cpp deleted file mode 100644 index e89d9df7..00000000 --- a/dScripts/SpawnSaberCatServer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "SpawnSaberCatServer.h" -#include "Entity.h" - -void SpawnSaberCatServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 12432); - self->SetVar<std::string>(u"petType", "sabercat"); - self->SetVar<uint32_t>(u"maxPets", 3); - self->SetVar<std::u16string>(u"spawnAnim", u"pq_m_drop-down"); - self->SetVar<std::u16string>(u"spawnCinematic", u"AssemblyPet"); -} diff --git a/dScripts/SpawnShrakeServer.cpp b/dScripts/SpawnShrakeServer.cpp deleted file mode 100644 index 5be55ebc..00000000 --- a/dScripts/SpawnShrakeServer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "SpawnShrakeServer.h" -#include "Entity.h" - -void SpawnShrakeServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 12434); - self->SetVar<std::string>(u"petType", "shrake"); - self->SetVar<uint32_t>(u"maxPets", 3); - self->SetVar<std::u16string>(u"spawnAnim", u"mf_u_g_TT_spawn-1"); - self->SetVar<std::u16string>(u"spawnCinematic", u"ParadoxPet"); -} diff --git a/dScripts/SpawnStegoServer.cpp b/dScripts/SpawnStegoServer.cpp deleted file mode 100644 index d845ff45..00000000 --- a/dScripts/SpawnStegoServer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "SpawnStegoServer.h" -#include "Entity.h" - -void SpawnStegoServer::SetVariables(Entity *self) { - self->SetVar<LOT>(u"petLOT", 12431); - self->SetVar<std::string>(u"petType", "stego"); - self->SetVar<uint32_t>(u"maxPets", 3); - self->SetVar<std::u16string>(u"spawnAnim", u"spawn"); - self->SetVar<std::u16string>(u"spawnCinematic", u"VenturePet"); -} diff --git a/dScripts/SpecialImaginePowerupSpawner.cpp b/dScripts/SpecialImaginePowerupSpawner.cpp deleted file mode 100644 index 8417efa2..00000000 --- a/dScripts/SpecialImaginePowerupSpawner.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "SpecialImaginePowerupSpawner.h" - -#include "GameMessages.h" -#include "SkillComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" - -void SpecialImaginePowerupSpawner::OnStartup(Entity* self) -{ - self->SetProximityRadius(1.5f, "powerupEnter"); - self->SetVar(u"bIsDead", false); -} - -void SpecialImaginePowerupSpawner::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) -{ - if (name != "powerupEnter" && status != "ENTER") - { - return; - } - - if (entering->GetLOT() != 1) - { - return; - } - - if (self->GetVar<bool>(u"bIsDead")) - { - return; - } - - GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); - - SkillComponent* skillComponent; - if (!self->TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) - { - return; - } - - const auto source = entering->GetObjectID(); - - skillComponent->CalculateBehavior(13, 20, source); - - DestroyableComponent* destroyableComponent; - if (!self->TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) - { - return; - } - - self->SetVar(u"bIsDead", true); - - self->AddCallbackTimer(1.0f, [self]() { - EntityManager::Instance()->ScheduleForKill(self); - }); -} diff --git a/dScripts/StinkyFishTarget.cpp b/dScripts/StinkyFishTarget.cpp deleted file mode 100644 index 57256b6b..00000000 --- a/dScripts/StinkyFishTarget.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "StinkyFishTarget.h" -#include "EntityManager.h" - -void StinkyFishTarget::OnStartup(Entity *self) { - auto position = self->GetPosition(); - position.SetY(position.GetY() - 0.5f); - self->SetPosition(position); -} - -void StinkyFishTarget::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - if (message != "stinkfish" || self->GetVar<bool>(u"used")) - return; - - self->SetVar<bool>(u"used", true); - self->SetVar<LWOOBJID>(u"player", caster->GetObjectID()); - - EntityInfo entityInfo {}; - entityInfo.pos = self->GetPosition(); - entityInfo.rot = self->GetRotation(); - entityInfo.spawnerID = self->GetObjectID(); - entityInfo.settings = { - new LDFData<bool>(u"no_timed_spawn", true) - }; - - auto* fish = EntityManager::Instance()->CreateEntity(entityInfo); - EntityManager::Instance()->ConstructEntity(fish); - - self->SetVar<LWOOBJID>(u"fish", fish->GetObjectID()); - self->AddTimer("smash", 5.0f); -} - -void StinkyFishTarget::OnTimerDone(Entity *self, std::string timerName) { - if (timerName == "smash") { - const auto playerID = self->GetVar<LWOOBJID>(u"player"); - auto* fish = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"fish")); - - if (fish != nullptr) { - fish->Smash(playerID); - self->Smash(playerID); - } - } -} diff --git a/dScripts/StinkyFishTarget.h b/dScripts/StinkyFishTarget.h deleted file mode 100644 index d88ce35e..00000000 --- a/dScripts/StinkyFishTarget.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class StinkyFishTarget : public CppScripts::Script { - void OnStartup(Entity *self) override; - void OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) override; - void OnTimerDone(Entity *self, std::string timerName) override; -}; diff --git a/dScripts/Sunflower.cpp b/dScripts/Sunflower.cpp deleted file mode 100644 index 436ca5f4..00000000 --- a/dScripts/Sunflower.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Sunflower.h" -#include "Entity.h" - -void Sunflower::OnStartup(Entity *self) { - self->SetVar<uint32_t>(u"numCycles", 6); - self->SetVar<float_t>(u"secPerCycle", 5.0f); - self->SetVar<float_t>(u"delayToFirstCycle", 1.5f); - self->SetVar<float_t>(u"deathDelay", 30.0f); - self->SetVar<uint32_t>(u"numberOfPowerups", 4); - self->SetVar<LOT>(u"lootLOT", 11910); - - // Initiate the actual script - OnTemplateStartup(self); -} diff --git a/dScripts/TreasureChestDragonServer.cpp b/dScripts/TreasureChestDragonServer.cpp deleted file mode 100644 index 80f8aa48..00000000 --- a/dScripts/TreasureChestDragonServer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "TreasureChestDragonServer.h" -#include "ScriptedActivityComponent.h" -#include "TeamManager.h" -#include "EntityManager.h" - -void TreasureChestDragonServer::OnStartup(Entity* self) -{ - -} - -void TreasureChestDragonServer::OnUse(Entity* self, Entity* user) -{ - if (self->GetVar<bool>(u"bUsed")) - { - return; - } - - self->SetVar<bool>(u"bUsed", true); - - auto* scriptedActivityComponent = self->GetComponent<ScriptedActivityComponent>(); - - if (scriptedActivityComponent == nullptr) - { - return; - } - - auto rating = 1; - - auto* team = TeamManager::Instance()->GetTeam(user->GetObjectID()); - - if (team != nullptr) - { - rating = team->members.size(); - - for (const auto member : team->members) - { - auto* memberObject = EntityManager::Instance()->GetEntity(member); - - if (memberObject == nullptr) continue; - - LootGenerator::Instance().DropActivityLoot(memberObject, self, scriptedActivityComponent->GetActivityID(), rating); - } - } - else - { - LootGenerator::Instance().DropActivityLoot(user, self, scriptedActivityComponent->GetActivityID(), rating); - } - - self->Smash(self->GetObjectID()); -} diff --git a/dScripts/VeBricksampleServer.cpp b/dScripts/VeBricksampleServer.cpp deleted file mode 100644 index 76486d78..00000000 --- a/dScripts/VeBricksampleServer.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "VeBricksampleServer.h" -#include "InventoryComponent.h" -#include "EntityManager.h" -#include "MissionComponent.h" -#include "GameMessages.h" - -void VeBricksampleServer::OnUse(Entity *self, Entity *user) { - auto* missionComponent = user->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(1183) == MissionState::MISSION_STATE_ACTIVE) { - const auto loot = self->GetVar<int32_t>(m_LootVariable); - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - - if (loot && inventoryComponent != nullptr && inventoryComponent->GetLotCount(loot) == 0) { - inventoryComponent->AddItem(loot, 1, eLootSourceType::LOOT_SOURCE_ACTIVITY); - - for (auto* brickEntity : EntityManager::Instance()->GetEntitiesInGroup("Bricks")) { - GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup"); - } - } - } -} diff --git a/dScripts/VeBricksampleServer.h b/dScripts/VeBricksampleServer.h deleted file mode 100644 index c983a962..00000000 --- a/dScripts/VeBricksampleServer.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class VeBricksampleServer : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; - const std::u16string m_LootVariable = u"Loot"; -}; diff --git a/dScripts/VeEpsilonServer.cpp b/dScripts/VeEpsilonServer.cpp deleted file mode 100644 index b3e24cf4..00000000 --- a/dScripts/VeEpsilonServer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "VeEpsilonServer.h" -#include "Character.h" -#include "EntityManager.h" -#include "GameMessages.h" - -void VeEpsilonServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { - auto* character = target->GetCharacter(); - if (character == nullptr) - return; - - // Resets the player flags that track which consoles they've used - if ((missionID == m_ConsoleMissionID || missionID == m_ConsoleRepeatMissionID) - && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE)) { - - for (auto i = 0; i < 10; i++) { - character->SetPlayerFlag(m_ConsoleBaseFlag + i, false); - } - } - - // Notify the client that all objects have updated - self->AddCallbackTimer(3.0f, [this]() { - for (const auto* console : EntityManager::Instance()->GetEntitiesInGroup(m_ConsoleGroup)) { - GameMessages::SendNotifyClientObject(console->GetObjectID(), u""); - } - }); -} diff --git a/dScripts/VeEpsilonServer.h b/dScripts/VeEpsilonServer.h deleted file mode 100644 index d89f378f..00000000 --- a/dScripts/VeEpsilonServer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class VeEpsilonServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; - const uint32_t m_ConsoleMissionID = 1220; - const uint32_t m_ConsoleRepeatMissionID = 1225; - const uint32_t m_ConsoleBaseFlag = 1010; - const std::string m_ConsoleGroup = "Consoles"; -}; diff --git a/dScripts/VeMech.cpp b/dScripts/VeMech.cpp deleted file mode 100644 index 87f2e88f..00000000 --- a/dScripts/VeMech.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "VeMech.h" - -void VeMech::OnStartup(Entity *self) { - BaseEnemyMech::OnStartup(self); - qbTurretLOT = 8432; -} diff --git a/dScripts/VeMissionConsole.cpp b/dScripts/VeMissionConsole.cpp deleted file mode 100644 index f815ebdc..00000000 --- a/dScripts/VeMissionConsole.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "VeMissionConsole.h" -#include "InventoryComponent.h" -#include "Character.h" -#include "GameMessages.h" - -void VeMissionConsole::OnUse(Entity *self, Entity *user) { - LootGenerator::Instance().DropActivityLoot(user, self, 12551); - - auto* inventoryComponent = user->GetComponent<InventoryComponent>(); - if (inventoryComponent != nullptr) { - inventoryComponent->AddItem(12547, 1, eLootSourceType::LOOT_SOURCE_ACTIVITY); // Add the panel required for pickup - } - - // The flag to set is 101<number> - const auto flagNumber = self->GetVar<std::u16string>(m_NumberVariable); - const auto flag = std::stoi("101" + GeneralUtils::UTF16ToWTF8(flagNumber)); - - auto* character = user->GetCharacter(); - if (character != nullptr) { - character->SetPlayerFlag(flag, true); - } - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u""); - GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); -} diff --git a/dScripts/WaveBossApe.cpp b/dScripts/WaveBossApe.cpp deleted file mode 100644 index f4d8a132..00000000 --- a/dScripts/WaveBossApe.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "WaveBossApe.h" -#include "BaseCombatAIComponent.h" -#include "Entity.h" - -void WaveBossApe::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - self->SetVar<LOT>(u"QuickbuildAnchorLOT", 12900); - self->SetVar<uint32_t>(u"GroundPoundSkill", 725); - self->SetVar<float_t>(u"reviveTime", 12); - self->SetVar<float_t>(u"AnchorDamageDelayTime", 0.5f); - self->SetVar<float_t>(u"spawnQBTime", 5.0f); - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(true); - combatAIComponent->SetStunImmune(true); - } - - self->AddToGroup("boss"); - - BaseEnemyApe::OnStartup(self); -} - -void WaveBossApe::OnDie(Entity *self, Entity *killer) { - BaseWavesGenericEnemy::OnDie(self, killer); - BaseEnemyApe::OnDie(self, killer); -} - -void WaveBossApe::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "startAI") { - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(false); - combatAIComponent->SetStunImmune(false); - } - } else { - BaseEnemyApe::OnFireEventServerSide(self, sender, args, param1, param2, param3); - } -} diff --git a/dScripts/WaveBossApe.h b/dScripts/WaveBossApe.h deleted file mode 100644 index 321a24b2..00000000 --- a/dScripts/WaveBossApe.h +++ /dev/null @@ -1,10 +0,0 @@ -#include "BaseWavesGenericEnemy.h" -#include "BaseEnemyApe.h" - -class WaveBossApe : public BaseEnemyApe, public BaseWavesGenericEnemy { - uint32_t GetPoints() override { return 5000; } - void OnStartup(Entity* self) override; - void OnDie(Entity* self, Entity *killer) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/WaveBossHammerling.cpp b/dScripts/WaveBossHammerling.cpp deleted file mode 100644 index 4775bf42..00000000 --- a/dScripts/WaveBossHammerling.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "WaveBossHammerling.h" -#include "BaseCombatAIComponent.h" -#include "Entity.h" - -void WaveBossHammerling::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(true); - combatAIComponent->SetStunImmune(true); - } - - self->AddToGroup("boss"); -} - -void WaveBossHammerling::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - if (args == "startAI") { - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(false); - } - } -} diff --git a/dScripts/WaveBossHammerling.h b/dScripts/WaveBossHammerling.h deleted file mode 100644 index 3ce22252..00000000 --- a/dScripts/WaveBossHammerling.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "BaseWavesGenericEnemy.h" - -class WaveBossHammerling : public BaseWavesGenericEnemy { - void OnStartup(Entity* self) override; - uint32_t GetPoints() override { return 1000; } - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/WaveBossHorsemen.cpp b/dScripts/WaveBossHorsemen.cpp deleted file mode 100644 index c129d654..00000000 --- a/dScripts/WaveBossHorsemen.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "WaveBossHorsemen.h" -#include "BaseCombatAIComponent.h" -#include "Entity.h" - -void WaveBossHorsemen::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(true); - combatAIComponent->SetStunImmune(true); - } - - self->AddToGroup("boss"); -} - -void -WaveBossHorsemen::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "startAI") { - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(false); - } - } -} diff --git a/dScripts/WaveBossHorsemen.h b/dScripts/WaveBossHorsemen.h deleted file mode 100644 index f6160034..00000000 --- a/dScripts/WaveBossHorsemen.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "BaseWavesGenericEnemy.h" - -class WaveBossHorsemen : public BaseWavesGenericEnemy { - uint32_t GetPoints() override { return 5000; } - void OnStartup(Entity* self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/WaveBossSpiderling.cpp b/dScripts/WaveBossSpiderling.cpp deleted file mode 100644 index 5c8f8766..00000000 --- a/dScripts/WaveBossSpiderling.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "WaveBossSpiderling.h" -#include "BaseCombatAIComponent.h" -#include "Entity.h" - -void WaveBossSpiderling::OnStartup(Entity *self) { - BaseWavesGenericEnemy::OnStartup(self); - - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(true); - combatAIComponent->SetStunImmune(true); - } - - self->AddToGroup("boss"); -} - -void WaveBossSpiderling::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { - if (args == "startAI") { - auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>(); - if (combatAIComponent != nullptr) { - combatAIComponent->SetDisabled(false); - combatAIComponent->SetStunImmune(false); - } - } -} diff --git a/dScripts/WaveBossSpiderling.h b/dScripts/WaveBossSpiderling.h deleted file mode 100644 index 23229efc..00000000 --- a/dScripts/WaveBossSpiderling.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "BaseWavesGenericEnemy.h" - -class WaveBossSpiderling : public BaseWavesGenericEnemy { - uint32_t GetPoints() override { return 5000; } - void OnStartup(Entity* self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -}; diff --git a/dScripts/WishingWellServer.cpp b/dScripts/WishingWellServer.cpp deleted file mode 100644 index 09e953ac..00000000 --- a/dScripts/WishingWellServer.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "WishingWellServer.h" -#include "ScriptedActivityComponent.h" -#include "GameMessages.h" - -void WishingWellServer::OnStartup(Entity* self) -{ -} - -void WishingWellServer::OnUse(Entity* self, Entity* user) -{ - auto* scriptedActivity = self->GetComponent<ScriptedActivityComponent>(); - - if (!scriptedActivity->TakeCost(user)) - { - return; - } - - const auto audio = self->GetVar<std::string>(u"sound1"); - - if (!audio.empty()) - { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), audio); - } - - LootGenerator::Instance().DropActivityLoot( - user, - self, - static_cast<uint32_t>(scriptedActivity->GetActivityID()), - GeneralUtils::GenerateRandomNumber<int32_t>(1, 1000) - ); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StartCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); - - const auto userID = user->GetObjectID(); - - self->AddCallbackTimer(10, [self, userID] () { - auto* user = EntityManager::Instance()->GetEntity(userID); - - if (user == nullptr) return; - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StopCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); - }); - - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); -} - -void WishingWellServer::OnTimerDone(Entity* self, std::string timerName) -{ -} diff --git a/dScripts/ZoneAgMedProperty.cpp b/dScripts/ZoneAgMedProperty.cpp deleted file mode 100644 index da8214b1..00000000 --- a/dScripts/ZoneAgMedProperty.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "ZoneAgMedProperty.h" -#include "Entity.h" - -void ZoneAgMedProperty::SetGameVariables(Entity *self) { - - self->SetVar<std::string>(ClaimMarkerGroup, "ClaimMarker"); - self->SetVar<std::string>(GeneratorGroup, "Generator"); - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(SpotsGroup, "Spots"); - self->SetVar<std::string>(MSCloudsGroup, "maelstrom"); - self->SetVar<std::string>(EnemiesGroup, "Enemies"); - self->SetVar<std::string>(FXManagerGroup, "FXObject"); - self->SetVar<std::string>(ImagOrbGroup, "Orb"); - self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); - - self->SetVar<std::vector<std::string>>(EnemiesSpawner, { - "StrombieWander", "Strombies", "Mechs", "OtherEnemy" - }); - self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); - self->SetVar<std::string>(GeneratorSpawner, "Generator"); - self->SetVar<std::string>(DamageFXSpawner, "MaelstromFX"); - self->SetVar<std::string>(FXSpotsSpawner, "MaelstromSpots"); - self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); - self->SetVar<std::string>(ImageOrbSpawner, "Orb"); - self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); - self->SetVar<std::string>(SmashablesSpawner, "Smashables"); - self->SetVar<std::string>(FXManagerSpawner, "FXObject"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "BirdFX", "SunBeam" }); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); - - self->SetVar<uint32_t>(defeatedProperyFlag, 118); - self->SetVar<uint32_t>(placedModelFlag, 119); - self->SetVar<uint32_t>(guardMissionFlag, 1293); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 1294); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 10118); - self->SetVar<LOT>(orbIDFlag, 10226); - self->SetVar<LOT>(behaviorQBID, 10445); -} diff --git a/dScripts/ZoneAgProperty.cpp b/dScripts/ZoneAgProperty.cpp deleted file mode 100644 index 44650a35..00000000 --- a/dScripts/ZoneAgProperty.cpp +++ /dev/null @@ -1,425 +0,0 @@ -#include "ZoneAgProperty.h" -#include "EntityManager.h" -#include "Character.h" -#include "Entity.h" -#include "GameMessages.h" -#include "dZoneManager.h" -#include "RenderComponent.h" -#include "MissionComponent.h" - -void ZoneAgProperty::SetGameVariables(Entity *self) { - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(PropertyBorderGroup, "PropertyBorder"); - self->SetVar<std::string>(LandTargetGroup, "Land_Target"); - self->SetVar<std::string>(SpiderScreamGroup, "Spider_Scream"); - self->SetVar<std::vector<std::string>>(ROFTargetsGroup, { "ROF_Targets_00", "ROF_Targets_01", "ROF_Targets_02", "ROF_Targets_03", "ROF_Targets_04" }); - self->SetVar<std::string>(SpiderEggsGroup, "SpiderEggs"); - self->SetVar<std::string>(RocksGroup, "Rocks"); - self->SetVar<std::string>(EnemiesGroup, "SpiderBoss"); - self->SetVar<std::vector<std::string>>(ZoneVolumesGroup, { "Zone1Vol", "Zone2Vol", "Zone3Vol", "Zone4Vol", "Zone5Vol", "Zone6Vol", "Zone7Vol", "Zone8Vol", "AggroVol", "TeleVol" }); - self->SetVar<std::string>(FXManagerGroup, "FXObject"); - - self->SetVar<std::string>(EnemiesSpawner, "SpiderBoss"); - self->SetVar<std::vector<std::string>>(BossSensorSpawner, { "Zone1Vol", "Zone2Vol", "Zone3Vol", "Zone4Vol", "Zone5Vol", "Zone6Vol", "Zone7Vol", "Zone8Vol", "RFS_Targets", "AggroVol", "TeleVol" }); - self->SetVar<std::string>(LandTargetSpawner, "Land_Target"); - self->SetVar<std::string>(SpiderScreamSpawner, "Spider_Scream"); - self->SetVar<std::vector<std::string>>(ROFTargetsSpawner,{ "ROF_Targets_00", "ROF_Targets_01", "ROF_Targets_02", "ROF_Targets_03", "ROF_Targets_04" }); - self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); - self->SetVar<std::string>(FXManagerSpawner, "FXObject"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::string>(SpiderEggsSpawner, "SpiderEggs"); - self->SetVar<std::string>(RocksSpawner, "Rocks"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "BirdFX", "SunBeam" }); - self->SetVar<std::vector<std::string>>(SpiderRocketSpawner, { "SpiderRocket_Bot", "SpiderRocket_Mid", "SpiderRocket_Top" }); - self->SetVar<std::string>(MailboxSpawner, "Mailbox"); - self->SetVar<std::string>(LauncherSpawner, "Launcher"); - self->SetVar<std::string>(InstancerSpawner, "Instancer"); - - self->SetVar<uint32_t>(defeatedProperyFlag, 71); - self->SetVar<uint32_t>(placedModelFlag, 73); - self->SetVar<uint32_t>(guardFirstMissionFlag, 891); - self->SetVar<uint32_t>(guardMissionFlag, 320); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 951); -} - -void ZoneAgProperty::OnStartup(Entity *self) { - LoadProperty(self); -} - -void ZoneAgProperty::OnPlayerLoaded(Entity* self, Entity* player) { - CheckForOwner(self); - - auto rented = self->GetVar<LWOOBJID>(u"PropertyOwner") == LWOOBJID_EMPTY; - self->SetVar<bool>(u"rented", rented); - - if (!rented) { - const auto numberOfPlayers = self->GetVar<int32_t>(u"numberOfPlayers"); - self->SetVar<int32_t>(u"numberOfPlayers", numberOfPlayers + 1); - } - - if (dZoneManager::Instance()->GetZone()->GetZoneID().GetMapID() == 1102) { - GameMessages::SendPlay2DAmbientSound(player, GUIDMaelstrom); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, - LWOOBJID_EMPTY, "", player->GetSystemAddress()); - - self->SetNetworkVar(u"unclaimed", true); - - return; - } - - BasePlayerLoaded(self, player); -} - -void ZoneAgProperty::PropGuardCheck(Entity* self, Entity* player) { - auto* missionComponent = player->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; - - const auto state = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)); - const auto firstState = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardFirstMissionFlag)); - - if (firstState < MissionState::MISSION_STATE_COMPLETE || (state != MissionState::MISSION_STATE_COMPLETE && state != MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE)) - ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); -} - -void ZoneAgProperty::OnZoneLoadedInfo(Entity* self) { - LoadProperty(self); -} - -void ZoneAgProperty::LoadInstance(Entity* self) { - SetGameVariables(self); - - for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(self->GetVar<std::string>(InstancerSpawner))) { - for (auto* spawnerNode : spawner->m_Info.nodes) { - spawnerNode->config.push_back( - new LDFData<std::string>(u"custom_script_server", - R"(scripts\ai\GENERAL\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua)")); - spawnerNode->config.push_back(new LDFData<std::u16string>(u"transferText", u"SPIDER_QUEEN_EXIT_QUESTION")); - } - } - - ActivateSpawner(self->GetVar<std::string>(InstancerSpawner)); -} - -void ZoneAgProperty::LoadProperty(Entity* self) { - SetGameVariables(self); - ActivateSpawner(self->GetVar<std::string>(LauncherSpawner)); - ActivateSpawner(self->GetVar<std::string>(MailboxSpawner)); -} - -void ZoneAgProperty::ProcessGroupObjects(Entity* self, std::string group) { -} - -void ZoneAgProperty::SpawnSpots(Entity* self) { - for (const auto& spot : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { - ActivateSpawner(spot); - } - - ActivateSpawner(self->GetVar<std::string>(LandTargetSpawner)); -} - -void ZoneAgProperty::KillSpots(Entity* self) { - for (const auto& spot : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { - DeactivateSpawner(spot); - } - - for (const auto& groupName : self->GetVar<std::vector<std::string>>(ROFTargetsGroup)) { - for (auto* spot : EntityManager::Instance()->GetEntitiesInGroup(groupName)) { - spot->Kill(); - } - } - - DeactivateSpawner(self->GetVar<std::string>(LandTargetSpawner)); - for (auto* landTarget : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(LandTargetSpawner))) { - landTarget->Kill(); - } -} - -void ZoneAgProperty::SpawnCrashedRocket(Entity* self) { - for (const auto& rocket : self->GetVar<std::vector<std::string>>(SpiderRocketSpawner)) { - ActivateSpawner(rocket); - } -} - -void ZoneAgProperty::KillCrashedRocket(Entity* self) { - for (const auto& rocket : self->GetVar<std::vector<std::string>>(SpiderRocketSpawner)) { - DeactivateSpawner(rocket); - DestroySpawner(rocket); - } -} - -void ZoneAgProperty::StartMaelstrom(Entity* self, Entity* player) -{ - ActivateSpawner(self->GetVar<std::string>(EnemiesSpawner)); - for (const auto& sensor : self->GetVar<std::vector<std::string>>(BossSensorSpawner)) { - ActivateSpawner(sensor); - } - - ActivateSpawner(self->GetVar<std::string>(FXManagerSpawner)); - ActivateSpawner(self->GetVar<std::string>(SpiderScreamSpawner)); - ActivateSpawner(self->GetVar<std::string>(SpiderEggsSpawner)); - ActivateSpawner(self->GetVar<std::string>(RocksSpawner)); - - SpawnCrashedRocket(self); - - for (const auto& ambient : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { - DeactivateSpawner(ambient); - DestroySpawner(ambient); - ResetSpawner(ambient); - } - - StartTornadoFx(self); - - if (player != nullptr) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); - } -} - -uint32_t ZoneAgProperty::RetrieveSpawnerId(Entity* self, const std::string& spawner) { - auto spawnerIDs = dZoneManager::Instance()->GetSpawnersByName(spawner); - if (spawnerIDs.empty()) - return 0; - - return spawnerIDs[0]->m_Info.spawnerID; -} - -void ZoneAgProperty::OnTimerDone(Entity *self, std::string timerName) { - BaseTimerDone(self, timerName); -} - -void ZoneAgProperty::BaseTimerDone(Entity *self, const std::string &timerName) { - if (timerName == "GuardFlyAway") { - const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); - if (zoneId != 1150) - return; - - const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(GuardGroup)); - if (entities.empty()) - return; - - auto* entity = entities[0]; - - GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, entity->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - LoadProperty(self); - - self->AddTimer("KillGuard", 5); - } else if (timerName == "KillGuard") { - KillGuard(self); - } else if (timerName == "tornadoOff") { - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { - auto* renderComponent = entity->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("TornadoDebris", false); - renderComponent->StopEffect("TornadoVortex", false); - renderComponent->StopEffect("silhouette", false); - } - } - - self->AddTimer("ShowVendor", 1.2f); - self->AddTimer("ShowClearEffects", 2); - } else if (timerName == "ShowClearEffects") { - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { - auto* renderComponent = entity->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->PlayEffect(-1, u"beamOn", "beam"); - } - } - - self->AddTimer("killSpider", 2); - self->AddTimer("turnSkyOff", 1.5f); - self->AddTimer("killFXObject", 8); - } else if (timerName == "turnSkyOff") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, - "", UNASSIGNED_SYSTEM_ADDRESS); - } else if (timerName == "killSpider") { - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(EnemiesGroup))) { - entity->Kill(); - } - - for (const auto& sensor : self->GetVar<std::vector<std::string>>(BossSensorSpawner)) { - DeactivateSpawner(sensor); - DestroySpawner(sensor); - } - - DeactivateSpawner(self->GetVar<std::string>(SpiderEggsSpawner)); - DestroySpawner(self->GetVar<std::string>(SpiderEggsSpawner)); - - DeactivateSpawner(self->GetVar<std::string>(RocksSpawner)); - DestroySpawner(self->GetVar<std::string>(RocksSpawner)); - - KillSpots(self); - KillCrashedRocket(self); - - DeactivateSpawner(self->GetVar<std::string>(SpiderScreamSpawner)); - DestroySpawner(self->GetVar<std::string>(SpiderScreamSpawner)); - - for (auto* player : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER)) { - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); - } - } else if (timerName == "ShowVendor") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - for (const auto& ambient : self->GetVar<std::vector<std::string>>(AmbientFXSpawner)) { - ActivateSpawner(ambient); - } - } else if (timerName == "BoundsVisOn") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - } else if (timerName == "runPlayerLoadedAgain") { - CheckForOwner(self); - } else if (timerName == "pollTornadoFX") { - StartTornadoFx(self); - } else if (timerName == "killFXObject") { - for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(FXManagerGroup))) { - auto* renderComponent = entity->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("beam"); - } - } - - DestroySpawner(self->GetVar<std::string>(FXManagerSpawner)); - - self->SetVar<bool>(u"FXObjectGone", true); - } else if (timerName == "ProcessGroupObj") { - // TODO - } -} - -void ZoneAgProperty::OnZonePropertyRented(Entity* self, Entity* player) { - BaseZonePropertyRented(self, player); - - auto* character = player->GetCharacter(); - if (character == nullptr) - return; - - character->SetPlayerFlag(108, true); -} - -void ZoneAgProperty::OnZonePropertyModelPlaced(Entity* self, Entity* player) { - auto* character = player->GetCharacter(); - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (!character->GetPlayerFlag(101)) { - BaseZonePropertyModelPlaced(self, player); - character->SetPlayerFlag(101, true); - if (missionComponent->GetMissionState(871) == MissionState::MISSION_STATE_ACTIVE) { - self->SetNetworkVar<std::u16string>(u"Tooltip", u"AnotherModel"); - } - - } else if (!character->GetPlayerFlag(102)) { - character->SetPlayerFlag(102, true); - if (missionComponent->GetMissionState(871) == MissionState::MISSION_STATE_ACTIVE) { - self->SetNetworkVar<std::u16string>(u"Tooltip", u"TwoMoreModels"); - } - - } else if (!character->GetPlayerFlag(103)) { - character->SetPlayerFlag(103, true); - } else if (!character->GetPlayerFlag(104)) { - character->SetPlayerFlag(104, true); - self->SetNetworkVar<std::u16string>(u"Tooltip", u"TwoMoreModelsOff"); - } else if (self->GetVar<std::string>(u"tutorial") == "place_model") { - self->SetVar<std::string>(u"tutorial", ""); - self->SetNetworkVar<std::u16string>(u"Tooltip", u"PutAway"); - } -} - -void ZoneAgProperty::OnZonePropertyModelPickedUp(Entity* self, Entity* player) { - auto* character = player->GetCharacter(); - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (!character->GetPlayerFlag(109)) { - character->SetPlayerFlag(109, true); - if (missionComponent->GetMissionState(891) == MissionState::MISSION_STATE_ACTIVE && !character->GetPlayerFlag(110)) { - self->SetNetworkVar<std::u16string>(u"Tooltip", u"Rotate"); - } - } -} - -void ZoneAgProperty::OnZonePropertyModelRemoved(Entity* self, Entity* player) { - auto* character = player->GetCharacter(); - character->SetPlayerFlag(111, true); -} - -void ZoneAgProperty::OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) { - ZoneAgProperty::OnZonePropertyModelRemoved(self, player); -} - -void ZoneAgProperty::OnZonePropertyModelRotated(Entity* self, Entity* player) { - auto* character = player->GetCharacter(); - auto* missionComponent = player->GetComponent<MissionComponent>(); - - if (!character->GetPlayerFlag(110)) { - character->SetPlayerFlag(110, true); - - if (missionComponent->GetMissionState(891) == MissionState::MISSION_STATE_ACTIVE) { - self->SetNetworkVar<std::u16string>(u"Tooltip", u"PlaceModel"); - self->SetVar<std::string>(u"tutorial", "place_model"); - } - } -} - -void ZoneAgProperty::OnZonePropertyModelEquipped(Entity* self) { - self->SetNetworkVar<std::u16string>(u"PlayerAction", u"ModelEquipped"); -} - -void ZoneAgProperty::OnZonePropertyEditBegin(Entity* self) { - self->SetNetworkVar<std::u16string>(u"PlayerAction", u"Enter"); -} - -void ZoneAgProperty::OnZonePropertyEditEnd(Entity* self) { - self->SetNetworkVar<std::u16string>(u"PlayerAction", u"Exit"); -} - -void ZoneAgProperty::OnPlayerExit(Entity* self) { - // TODO: Destroy stuff -} - -void ZoneAgProperty::RemovePlayerRef(Entity* self) { - // TODO: Destroy stuff -} - -void ZoneAgProperty::BaseOnFireEventServerSide(Entity *self, Entity *sender, std::string args) { - if (args == "propertyRented") { - const auto playerId = self->GetVar<LWOOBJID>(u"playerID"); - auto* player = EntityManager::Instance()->GetEntity(playerId); - if (player == nullptr) - return; - - OnZonePropertyRented(self, player); - } else if (args == "RetrieveZoneData") { - self->SetVar<LWOOBJID>(u"SpiderBossID", sender->GetObjectID()); - sender->SetVar<int32_t>(u"SpiderEggNetworkID", RetrieveSpawnerId(self, self->GetVar<std::string>(SpiderEggsSpawner))); - - std::vector<uint32_t> table; - - for (const auto& target : self->GetVar<std::vector<std::string>>(ROFTargetsSpawner)) { - table.push_back(RetrieveSpawnerId(self, target)); - } - - ROFTargetGroupIdTable = table; - - ProcessGroupObjects(self, self->GetVar<std::string>(LandTargetGroup)); - ProcessGroupObjects(self, self->GetVar<std::string>(SpiderScreamGroup)); -// ProcessGroupObjects(self, groups.ZoneVolumes); - } else if (args == "CheckForPropertyOwner") { - sender->SetNetworkVar<std::string>(u"PropertyOwnerID", std::to_string(self->GetVar<LWOOBJID>(u"PropertyOwner"))); - } else if (args == "ClearProperty") { - const auto playerId = self->GetVar<LWOOBJID>(u"playerID"); - auto* player = EntityManager::Instance()->GetEntity(playerId); - if (player == nullptr) - return; - - player->GetCharacter()->SetPlayerFlag(self->GetVar<uint32_t>(defeatedProperyFlag), true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, - LWOOBJID_EMPTY,destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); - - self->AddTimer("tornadoOff", 0.5f); - } -} - -void ZoneAgProperty::NotifyDie(Entity *self) { - // TODO -} diff --git a/dScripts/ZoneAgProperty.h b/dScripts/ZoneAgProperty.h deleted file mode 100644 index 4044be57..00000000 --- a/dScripts/ZoneAgProperty.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "BasePropertyServer.h" - -class ZoneAgProperty : public BasePropertyServer { -public: - void SetGameVariables(Entity *self) override; - void OnStartup(Entity* self) override; - void OnPlayerLoaded(Entity* self, Entity* player) override; - void OnZoneLoadedInfo(Entity* self); - void OnZonePropertyRented(Entity* self, Entity* player) override; - void OnZonePropertyModelPlaced(Entity* self, Entity* player) override; - void OnZonePropertyModelPickedUp(Entity* self, Entity* player) override; - void OnZonePropertyModelRemoved(Entity* self, Entity* player) override; - void OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) override; - void OnZonePropertyModelRotated(Entity* self, Entity* player) override; - void OnZonePropertyEditBegin(Entity* self) override; - void OnZonePropertyModelEquipped(Entity* self) override; - void OnZonePropertyEditEnd(Entity* self) override; - void OnPlayerExit(Entity* self); - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override { BaseOnFireEventServerSide(self, sender, args); } - virtual void BaseOnFireEventServerSide(Entity* self, Entity* sender, std::string args); - void OnTimerDone(Entity* self, std::string timerName) override; - - void BaseTimerDone(Entity *self, const std::string &timerName) override; - - void PropGuardCheck(Entity* self, Entity* player) override; - void LoadInstance(Entity* self); - void LoadProperty(Entity* self); - - void ProcessGroupObjects(Entity* self, std::string group); - - void SpawnSpots(Entity* self) override; - void KillSpots(Entity* self) override; - void StartMaelstrom(Entity* self, Entity* player) override; - void SpawnCrashedRocket(Entity* self); - void KillCrashedRocket(Entity* self); - - uint32_t RetrieveSpawnerId(Entity* self, const std::string& spawner); - - void NotifyDie(Entity* self); - void RemovePlayerRef(Entity* self); -protected: - std::string destroyedCinematic = "DestroyMaelstrom"; - std::vector<uint32_t> ROFTargetGroupIdTable {}; - std::u16string LandTargetGroup = u"LandTargetGroup"; - std::u16string SpiderScreamGroup = u"SpiderScreamGroup"; - std::u16string ROFTargetsGroup = u"ROFTargetsGroup"; - std::u16string SpiderEggsGroup = u"SpiderEggsGroup"; - std::u16string RocksGroup = u"RocksGroup"; - std::u16string ZoneVolumesGroup = u"ZoneVolumesGroup"; - - std::u16string EnemiesSpawner = u"EnemiesSpawner"; - std::u16string BossSensorSpawner = u"BossSensorSpawner"; - std::u16string LandTargetSpawner = u"LandTargetSpawner"; - std::u16string SpiderScreamSpawner = u"SpiderScreamSpawner"; - std::u16string ROFTargetsSpawner = u"ROFTargetsSpawner"; - std::u16string SpiderEggsSpawner = u"SpiderEggsSpawner"; - std::u16string RocksSpawner = u"RocksSpawner"; - std::u16string SpiderRocketSpawner = u"SpiderRocketSpawner"; - std::u16string MailboxSpawner = u"MailboxSpawner"; - std::u16string LauncherSpawner = u"LauncherSpawner"; - std::u16string InstancerSpawner = u"InstancerSpawner"; -}; diff --git a/dScripts/ZoneAgSpiderQueen.cpp b/dScripts/ZoneAgSpiderQueen.cpp deleted file mode 100644 index 27c11aa7..00000000 --- a/dScripts/ZoneAgSpiderQueen.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "ZoneAgSpiderQueen.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "ZoneAgProperty.h" -#include "DestroyableComponent.h" - -void ZoneAgSpiderQueen::SetGameVariables(Entity *self) { - ZoneAgProperty::SetGameVariables(self); - - // Disable property flags - self->SetVar<uint32_t>(defeatedProperyFlag, 0); - self->SetVar<uint32_t>(placedModelFlag, 0); - self->SetVar<uint32_t>(guardFirstMissionFlag, 0); - self->SetVar<uint32_t>(guardMissionFlag, 0); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 0); -} - -void ZoneAgSpiderQueen::OnStartup(Entity *self) { - LoadInstance(self); - - SpawnSpots(self); - StartMaelstrom(self, nullptr); -} - -void ZoneAgSpiderQueen::BasePlayerLoaded(Entity *self, Entity *player) { - ActivityManager::UpdatePlayer(self, player->GetObjectID()); - ActivityManager::TakeActivityCost(self, player->GetObjectID()); - - // Make sure the player has full stats when they join - auto* playerDestroyableComponent = player->GetComponent<DestroyableComponent>(); - if (playerDestroyableComponent != nullptr) { - playerDestroyableComponent->SetImagination(playerDestroyableComponent->GetMaxImagination()); - playerDestroyableComponent->SetArmor(playerDestroyableComponent->GetMaxArmor()); - playerDestroyableComponent->SetHealth(playerDestroyableComponent->GetMaxHealth()); - } - - self->SetNetworkVar(u"unclaimed", true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); -} - -void -ZoneAgSpiderQueen::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "ClearProperty") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, - LWOOBJID_EMPTY, destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); - self->AddTimer("tornadoOff", 0.5f); - } else { - ZoneAgProperty::BaseOnFireEventServerSide(self, sender, args); - } -} - -void ZoneAgSpiderQueen::OnPlayerExit(Entity *self, Entity *player) { - UpdatePlayer(self, player->GetObjectID(), true); -} - -void ZoneAgSpiderQueen::OnTimerDone(Entity *self, std::string timerName) { - - // Disable some stuff from the regular property - if (timerName == "BoundsVisOn" || timerName == "GuardFlyAway" || timerName == "ShowVendor") - return; - - if (timerName == "killSpider") { - auto spawnTargets = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(LandTargetGroup)); - for (auto* spawnTarget : spawnTargets) { - EntityInfo info{}; - - info.spawnerID = spawnTarget->GetObjectID(); - info.pos = spawnTarget->GetPosition(); - info.rot = spawnTarget->GetRotation(); - info.lot = chestObject; - info.settings = { - new LDFData<LWOOBJID>(u"parent_tag", self->GetObjectID()) - }; - - auto* chest = EntityManager::Instance()->CreateEntity(info); - EntityManager::Instance()->ConstructEntity(chest); - } - } - - ZoneAgProperty::BaseTimerDone(self, timerName); -} \ No newline at end of file diff --git a/dScripts/ZoneAgSpiderQueen.h b/dScripts/ZoneAgSpiderQueen.h deleted file mode 100644 index 5536f47a..00000000 --- a/dScripts/ZoneAgSpiderQueen.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "ActivityManager.h" -#include "ZoneAgProperty.h" - -class ZoneAgSpiderQueen : ZoneAgProperty, ActivityManager { -public: - void OnStartup(Entity* self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; - void OnTimerDone(Entity *self, std::string timerName) override; - void OnPlayerExit(Entity* self, Entity* player) override; - void BasePlayerLoaded(Entity* self, Entity* player) override; - void SetGameVariables(Entity *self) override; -protected: - std::string destroyedCinematic = "DesMaelstromInstance"; - const LOT chestObject = 16318; -}; diff --git a/dScripts/ZoneAgSurvival.cpp b/dScripts/ZoneAgSurvival.cpp deleted file mode 100644 index 5be11f99..00000000 --- a/dScripts/ZoneAgSurvival.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "ZoneAgSurvival.h" - -Constants ZoneAgSurvival::GetConstants() { - return Constants { - 60, - 2, - 7, - 5, - 10, - 5, - 15, - 10, - 0, - true, - std::vector<uint32_t> {8, 13, 18, 23, 28, 32}, - std::vector<uint32_t> {2, 10, 15, 20, 25, 30} - }; -} - -MobSets ZoneAgSurvival::GetMobSets() { - return MobSets { - std::map<std::string, std::vector<LOT>> { - {"MobA", {6351, 8088, 8089} }, - {"MobB", {6668, 8090, 8091} }, - {"MobC", {6454, 8096, 8097} }, - }, - std::map<std::string, std::vector<std::vector<std::vector<uint32_t>>>> { - { BaseMobSet, { - { {3, 0, 0}, }, - { {2, 1, 0}, }, - { {4, 1, 0}, }, - { {1, 2, 0}, }, - { {0, 1, 1}, }, - { {0, 2, 2}, } - }}, - { RandMobSet, { - { {4, 0, 0}, {4, 0, 0}, {4, 0, 0}, {4, 0, 0}, {3, 1, 0} }, - { {4, 1, 0}, {4, 1, 0}, {4, 1, 0}, {4, 1, 0}, {2, 1, 1} }, - { {1, 2, 0}, {1, 2, 0}, {1, 2, 0}, {1, 2, 0}, {0, 1, 1} }, - { {1, 2, 1}, {1, 2, 1}, {1, 2, 1}, {0, 2, 1}, {0, 2, 2} }, - { {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 3}, {0, 1, 3} }, - { {0, 2, 3}, {0, 2, 3}, {0, 2, 3}, {0, 2, 3}, {0, 2, 3} }, - }} - } - }; -} - -SpawnerNetworks ZoneAgSurvival::GetSpawnerNetworks() { - return SpawnerNetworks { - SpawnerNetworkCollection { - BaseMobSet, - { - SpawnerNetwork { - std::vector<std::string> { "Base_MobA", "Base_MobB", "Base_MobC" }, - "", - false, - false - }, - } - }, - SpawnerNetworkCollection { - RandMobSet, - { - SpawnerNetwork { - std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, - "01", - false, - false - }, - SpawnerNetwork { - std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, - "02", - false, - false - }, - SpawnerNetwork { - std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, - "03", - true, - false - }, - } - }, - SpawnerNetworkCollection { - "", - { - SpawnerNetwork { - std::vector<std::string> { "Rewards_" }, - "01", - false, - false - }, - } - }, - SpawnerNetworkCollection { - "", - { - SpawnerNetwork { - std::vector<std::string> { "Smash_" }, - "01", - false, - false - }, - } - } - }; -} - -std::map<uint32_t, uint32_t> ZoneAgSurvival::GetMissionsToUpdate() { - return std::map<uint32_t, uint32_t> { - { 479, 60 }, - { 1153, 180 }, - { 1618, 420 }, - { 1628, 420 }, - { 1638, 420 }, - { 1648, 420 }, - { 1412, 120 }, - { 1510, 120 }, - { 1547, 120 }, - { 1584, 120 }, - { 1426, 300 }, - { 1524, 300 }, - { 1561, 300 }, - { 1598, 300 }, - { 1865, 180 } - }; -} diff --git a/dScripts/ZoneAgSurvival.h b/dScripts/ZoneAgSurvival.h deleted file mode 100644 index c5d803ae..00000000 --- a/dScripts/ZoneAgSurvival.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "BaseSurvivalServer.h" -#include <map> - -class ZoneAgSurvival : public BaseSurvivalServer { - Constants GetConstants() override; - SpawnerNetworks GetSpawnerNetworks() override; - MobSets GetMobSets() override; - std::map<uint32_t, uint32_t> GetMissionsToUpdate() override; -}; diff --git a/dScripts/ZoneFvProperty.cpp b/dScripts/ZoneFvProperty.cpp deleted file mode 100644 index 64aaad9e..00000000 --- a/dScripts/ZoneFvProperty.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "ZoneFvProperty.h" -#include "Entity.h" - -void ZoneFvProperty::SetGameVariables(Entity *self) { - self->SetVar<std::string>(ClaimMarkerGroup, "Platform"); - self->SetVar<std::string>(GeneratorGroup, "Generator"); - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(SpotsGroup, "Spots"); - self->SetVar<std::string>(MSCloudsGroup, "Clouds"); - self->SetVar<std::string>(EnemiesGroup, "Enemies"); - self->SetVar<std::string>(FXManagerGroup, "FXManager"); - self->SetVar<std::string>(ImagOrbGroup, "Orb"); - self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); - - self->SetVar<std::vector<std::string>>(EnemiesSpawner, - { "RoninWander", "RoninGen", "HorsemenGen" }); - self->SetVar<std::string>(ClaimMarkerSpawner, "Platform"); - self->SetVar<std::string>(GeneratorSpawner, "Generator"); - self->SetVar<std::string>(DamageFXSpawner, "Clouds"); - self->SetVar<std::string>(FXSpotsSpawner, "Spots"); - self->SetVar<std::string>(PropertyMGSpawner, "Guard"); - self->SetVar<std::string>(ImageOrbSpawner, "Orb"); - self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); - self->SetVar<std::string>(SmashablesSpawner, "Smashables"); - self->SetVar<std::string>(FXManagerSpawner, "FXManager"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Ash", "FX", "Fog"}); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); - - self->SetVar<uint32_t>(defeatedProperyFlag, 99); - self->SetVar<uint32_t>(placedModelFlag, 107); - self->SetVar<uint32_t>(guardMissionFlag, 874); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 950); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 11023); - self->SetVar<LOT>(orbIDFlag, 10226); - self->SetVar<LOT>(behaviorQBID, 11011); -} diff --git a/dScripts/ZoneGfProperty.cpp b/dScripts/ZoneGfProperty.cpp deleted file mode 100644 index 925320c3..00000000 --- a/dScripts/ZoneGfProperty.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "ZoneGfProperty.h" -#include "Entity.h" - -void ZoneGfProperty::SetGameVariables(Entity *self) { - self->SetVar<std::string>(ClaimMarkerGroup, "BehavQB"); - self->SetVar<std::string>(GeneratorGroup, "Generator"); - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(SpotsGroup, "Spots"); - self->SetVar<std::string>(MSCloudsGroup, "Clouds"); - self->SetVar<std::string>(EnemiesGroup, "Enemies"); - self->SetVar<std::string>(FXManagerGroup, "FXManager"); - self->SetVar<std::string>(ImagOrbGroup, "Orb"); - self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); - - self->SetVar<std::vector<std::string>>(EnemiesSpawner, - { "PiratesWander", "PiratesGen", "AdmiralsWander", "AdmiralsGen" }); - self->SetVar<std::string>(ClaimMarkerSpawner, "BehavPlat"); - self->SetVar<std::string>(GeneratorSpawner, "Generator"); - self->SetVar<std::string>(DamageFXSpawner, "Clouds"); - self->SetVar<std::string>(FXSpotsSpawner, "Spots"); - self->SetVar<std::string>(PropertyMGSpawner, "Guard"); - self->SetVar<std::string>(ImageOrbSpawner, "Orb"); - self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); - self->SetVar<std::string>(SmashablesSpawner, "Smashables"); - self->SetVar<std::string>(FXManagerSpawner, "FXManager"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Birds", "Falls", "Sunbeam" }); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, { "TrappedPlatform", "IceBarrier", "FireBeast" }); - - self->SetVar<uint32_t>(defeatedProperyFlag, 98); - self->SetVar<uint32_t>(placedModelFlag, 106); - self->SetVar<uint32_t>(guardMissionFlag, 873); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 949); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 11109); - self->SetVar<LOT>(orbIDFlag, 10226); - self->SetVar<LOT>(behaviorQBID, 11001); -} diff --git a/dScripts/ZoneNsMedProperty.cpp b/dScripts/ZoneNsMedProperty.cpp deleted file mode 100644 index feaadf31..00000000 --- a/dScripts/ZoneNsMedProperty.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "ZoneNsMedProperty.h" -#include "Entity.h" - -void ZoneNsMedProperty::SetGameVariables(Entity *self) { - self->SetVar<std::string>(ClaimMarkerGroup, "ClaimMarker"); - self->SetVar<std::string>(GeneratorGroup, "Generator"); - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(SpotsGroup, "Spots"); - self->SetVar<std::string>(MSCloudsGroup, "maelstrom"); - self->SetVar<std::string>(EnemiesGroup, "Enemies"); - self->SetVar<std::string>(FXManagerGroup, "FXObject"); - self->SetVar<std::string>(ImagOrbGroup, "Orb"); - self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); - - self->SetVar<std::vector<std::string>>(EnemiesSpawner, - { "Admirals", "AdmiralsWander", "Mechs", "Ronin", "RoninWander" }); - self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); - self->SetVar<std::string>(GeneratorSpawner, "Generator"); - self->SetVar<std::string>(DamageFXSpawner, "MaelstromFX"); - self->SetVar<std::string>(FXSpotsSpawner, "MaelstromSpots"); - self->SetVar<std::string>(PropertyMGSpawner, "PropertyGuard"); - self->SetVar<std::string>(ImageOrbSpawner, "Orb"); - self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); - self->SetVar<std::string>(SmashablesSpawner, "Smashables"); - self->SetVar<std::string>(FXManagerSpawner, "FXObject"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Rockets" }); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, { }); - - self->SetVar<uint32_t>(defeatedProperyFlag, 122); - self->SetVar<uint32_t>(placedModelFlag, 123); - self->SetVar<uint32_t>(guardMissionFlag, 1322); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 1294); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 11031); - self->SetVar<LOT>(orbIDFlag, 10226); - self->SetVar<LOT>(behaviorQBID, 10445); -} diff --git a/dScripts/ZoneNsProperty.cpp b/dScripts/ZoneNsProperty.cpp deleted file mode 100644 index 72eb1ead..00000000 --- a/dScripts/ZoneNsProperty.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "ZoneNsProperty.h" -#include "Entity.h" - -void ZoneNsProperty::SetGameVariables(Entity *self) { - self->SetVar<std::string>(ClaimMarkerGroup, "Rhino"); - self->SetVar<std::string>(GeneratorGroup, "Generator"); - self->SetVar<std::string>(GuardGroup, "Guard"); - self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); - self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); - self->SetVar<std::string>(SpotsGroup, "Spots"); - self->SetVar<std::string>(MSCloudsGroup, "Clouds"); - self->SetVar<std::string>(EnemiesGroup, "Enemies"); - self->SetVar<std::string>(FXManagerGroup, "FXManager"); - self->SetVar<std::string>(ImagOrbGroup, "Orb"); - self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); - - self->SetVar<std::vector<std::string>>(EnemiesSpawner, { - "StrombieWander", "StrombieGen", "PirateWander", "PirateGen", "RoninGen" - }); - self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); - self->SetVar<std::string>(GeneratorSpawner, "Generator"); - self->SetVar<std::string>(DamageFXSpawner, "MSClouds"); - self->SetVar<std::string>(FXSpotsSpawner, "Spots"); - self->SetVar<std::string>(PropertyMGSpawner, "Guard"); - self->SetVar<std::string>(ImageOrbSpawner, "Orb"); - self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); - self->SetVar<std::string>(SmashablesSpawner, "Smashables"); - self->SetVar<std::string>(FXManagerSpawner, "FXManager"); - self->SetVar<std::string>(PropObjsSpawner, "BankObj"); - self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Rockets" }); - self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner,{ "Cage", "Platform", "Door" }); - - self->SetVar<uint32_t>(defeatedProperyFlag, 97); - self->SetVar<uint32_t>(placedModelFlag, 105); - self->SetVar<uint32_t>(guardMissionFlag, 872); - self->SetVar<uint32_t>(brickLinkMissionIDFlag, 948); - self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); - self->SetVar<LOT>(generatorIdFlag, 11031); - self->SetVar<LOT>(orbIDFlag, 10226); - self->SetVar<LOT>(behaviorQBID, 11009); -} diff --git a/dScripts/ZoneNsWaves.cpp b/dScripts/ZoneNsWaves.cpp deleted file mode 100644 index 9f54ae49..00000000 --- a/dScripts/ZoneNsWaves.cpp +++ /dev/null @@ -1,500 +0,0 @@ -#include "ZoneNsWaves.h" - -WaveConstants ZoneNsWaves::GetConstants() { - return { - 60, - 2, - 6, - 2, - "surprise", - "intro" - }; -} - -std::vector<std::string> ZoneNsWaves::GetSpawnerNames() { - return { - "Base_MobA", - "Base_MobB", - "Base_MobC", - "MobA_01", - "MobB_01", - "MobC_01", - "MobA_02", - "MobB_02", - "MobC_02", - "MobA_03", - "MobB_03", - "MobC_03", - "Reward_01", - "Base_Reward", - "Obstacle_01", - "Boss", - "Ape_Boss", - "Geyser_01", - "Treasure_01", - "Cavalry_Boss", - "Horseman_01", - "Horseman_02", - "Horseman_03", - "Horseman_04" - }; -} - -std::vector<WaveMission> ZoneNsWaves::GetWaveMissions() { - return { - {190, 7, 1242}, - {240, 7, 1226}, - {450, 15, 1243}, - {600, 15, 1227}, - {720, 22, 1244}, - {840, 22, 1228}, - {1080, 29, 1245}, - {1200, 29, 1229}, - }; -} - -std::vector<Wave> ZoneNsWaves::GetWaves() { - return { - // Wave 1 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling_minifig, 8, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::stromling_minifig, 2, GetSpawnerName(SpawnerName::gf_A) }, - } - }, - - // Wave 2 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling, 8, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, - } - }, - - // Wave 3 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::gf_A) }, - }, - }, - - // Wave 4 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling, 3, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 5 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::stromling, 1, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::stromling, 1, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 6 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::stromling, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 7 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::stromling_boss, 1, GetSpawnerName(SpawnerName::Boss) }, - }, - {1885}, - {}, - "Stromling_Boss", - 5.0f - }, - - // Wave 8 - Wave { - std::vector<MobDefinition> { - {SpawnLOTS::mushroom, 6, GetSpawnerName(SpawnerName::Reward_01) }, - {SpawnLOTS::mushroom, 3, GetSpawnerName(SpawnerName::interior_Reward) }, - }, {}, {}, "", -1.0f, - 25, - }, - - // Wave 9 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 10 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 11 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::gf_C) }, - } - }, - - // Wave 12 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_C) }, - } - }, - - // Wave 13 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 3, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 14 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::mech, 2, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::mech, 1, GetSpawnerName(SpawnerName::gf_C) }, - } - }, - - // Wave 15 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::ape_boss, 1, GetSpawnerName(SpawnerName::Ape_Boss) }, - - }, - {1886}, - {}, - "Gorilla_Boss", - 5.0f - }, - - // Wave 16 - Wave { - std::vector<MobDefinition> { - {SpawnLOTS::outhouse, 3, GetSpawnerName(SpawnerName::interior_Reward) }, - {SpawnLOTS::mushroom, 6, GetSpawnerName(SpawnerName::Reward_01) }, - }, {}, {}, "", -1.0f, - 25, - }, - - // Wave 17 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::hammerling_melee, 1, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 18 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::hammerling_melee, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::hammerling_melee, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 19 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::hammerling, 4, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::sentry, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::hammerling, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::gf_B) }, - } - }, - - // Wave 20 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::sentry, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::hammerling, 1, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::sentry, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_C) }, - } - }, - - // Wave 21 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::admiral, 2, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::ronin, 2, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::spiderling_ve, 2, GetSpawnerName(SpawnerName::interior_C) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::admiral, 1, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::ronin, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_C) }, - } - }, - - // Wave 22 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::spiderling_boss, 1, GetSpawnerName(SpawnerName::Cavalry_Boss) }, - }, - {1887}, - {}, - "Spiderling_Boss", - 5.0f - }, - - // Wave 23 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::outhouse, 6, GetSpawnerName(SpawnerName::Reward_01) }, - { SpawnLOTS::outhouse, 3, GetSpawnerName(SpawnerName::interior_Reward) }, - { SpawnLOTS::maelstrom_chest, 4, GetSpawnerName(SpawnerName::Obstacle) }, - }, {}, {}, "", -1.0f, - 25, - }, - - // Wave 24 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::pirate, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::pirate, 3, GetSpawnerName(SpawnerName::ag_A) }, - { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::ronin, 2, GetSpawnerName(SpawnerName::interior_B) }, - } - }, - - // Wave 25 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::cavalry, 2, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::gf_A) }, - { SpawnLOTS::spiderling, 2, GetSpawnerName(SpawnerName::concert_A) }, - { SpawnLOTS::spiderling, 1, GetSpawnerName(SpawnerName::ag_A) }, - } - }, - - // Wave 26 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::ronin, 3, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::spiderling_ve, 1, GetSpawnerName(SpawnerName::concert_B) }, - { SpawnLOTS::admiral_cp, 2, GetSpawnerName(SpawnerName::gf_C) }, - { SpawnLOTS::admiral_cp, 2, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_C) }, - } - }, - - // Wave 27 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::ronin, 5, GetSpawnerName(SpawnerName::interior_A) }, - { SpawnLOTS::ronin, 4, GetSpawnerName(SpawnerName::interior_B) }, - { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::ag_C) }, - { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::gf_C) }, - { SpawnLOTS::cavalry, 1, GetSpawnerName(SpawnerName::concert_C) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::ag_B) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::gf_B) }, - { SpawnLOTS::admiral_cp, 1, GetSpawnerName(SpawnerName::concert_B) }, - } - }, - - // Wave 28 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::dragon_statue, 12, GetSpawnerName(SpawnerName::Reward_01) }, - }, {}, {}, "", -1.0f, - 30, - }, - - // Wave 29 - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::horseman_boss01, 1, GetSpawnerName(SpawnerName::Horseman_01) }, - { SpawnLOTS::horseman_boss02, 1, GetSpawnerName(SpawnerName::Horseman_02) }, - { SpawnLOTS::horseman_boss03, 1, GetSpawnerName(SpawnerName::Horseman_03) }, - { SpawnLOTS::horseman_boss04, 1, GetSpawnerName(SpawnerName::Horseman_04) }, - }, - {1888}, - {1236, 1237, 1249}, - "Horsemen_Boss", - 5.0f - }, - - // Wave 30 (treasure) - Wave { - std::vector<MobDefinition> { - { SpawnLOTS::treasure_chest, 1, GetSpawnerName(SpawnerName::Treasure_01) }, - }, {}, {}, - "Treasure_Camera", - 5.0f, - (uint32_t) -1, - true, - 30, - }, - }; -} - -std::string ZoneNsWaves::GetSpawnerName(SpawnerName spawnerName) { - switch (spawnerName) { - case interior_A: - return "Base_MobA"; - case interior_B: - return "Base_MobB"; - case interior_C: - return "Base_MobC"; - case gf_A: - return "MobA_01"; - case gf_B: - return "MobB_01"; - case gf_C: - return "MobC_01"; - case concert_A: - return "MobA_02"; - case concert_B: - return "MobB_02"; - case concert_C: - return "MobC_02"; - case ag_A: - return "MobA_03"; - case ag_B: - return "MobB_03"; - case ag_C: - return "MobC_03"; - case Reward_01: - return "Reward_01"; - case interior_Reward: - return "Base_Reward"; - case Obstacle: - return "Obstacle_01"; - case Boss: - return "Boss"; - case Ape_Boss: - return "Ape_Boss"; - case Geyser: - return "Geyser_01"; - case Treasure_01: - return "Treasure_01"; - case Cavalry_Boss: - return "Cavalry_Boss"; - case Horseman_01: - return "Horseman_01"; - case Horseman_02: - return "Horseman_02"; - case Horseman_03: - return "Horseman_03"; - case Horseman_04: - return "Horseman_04"; - default: - return ""; - } -} diff --git a/dScripts/ZoneNsWaves.h b/dScripts/ZoneNsWaves.h deleted file mode 100644 index c1a63db6..00000000 --- a/dScripts/ZoneNsWaves.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include "BaseWavesServer.h" - -enum SpawnerName { - interior_A, - interior_B, - interior_C, - gf_A, - gf_B, - gf_C, - concert_A, - concert_B, - concert_C, - ag_A, - ag_B, - ag_C, - Reward_01, - interior_Reward, - Obstacle, - Boss, - Ape_Boss, - Geyser, - Treasure_01, - Cavalry_Boss, - Horseman_01, - Horseman_02, - Horseman_03, - Horseman_04, -}; - -enum SpawnLOTS : LOT { - stromling = 12586, - mech = 12587, - spiderling = 12588, - pirate = 12589, - admiral = 12590, - ape_boss = 12591, - stromling_boss = 12600, - hammerling = 12602, - sentry = 12604, - spiderling_ve = 12605, - spiderling_boss = 12609, - ronin = 12610, - cavalry = 12611, - dragon_boss = 12612, - stromling_minifig = 12586, - mushroom = 12614, - maelstrom_chest = 4894, - outhouse = 12616, - dragon_statue = 12617, - treasure_chest = 12423, - hammerling_melee = 12653, - maelstrom_geyser = 10314, - ronin_statue = 12611, - horseman_boss01 = 11999, - horseman_boss02 = 12467, - horseman_boss03 = 12468, - horseman_boss04 = 12469, - admiral_cp = 13523, -}; - -class ZoneNsWaves : public BaseWavesServer { - WaveConstants GetConstants() override; - std::vector<std::string> GetSpawnerNames() override; - std::vector<WaveMission> GetWaveMissions() override; - std::vector<Wave> GetWaves() override; -private: - static std::string GetSpawnerName(SpawnerName spawnerName); -}; diff --git a/dScripts/ZoneSGServer.cpp b/dScripts/ZoneSGServer.cpp deleted file mode 100644 index 8149ec55..00000000 --- a/dScripts/ZoneSGServer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ZoneSGServer.h" -#include "EntityManager.h" - -void ZoneSGServer::OnStartup(Entity *self) { - const auto cannons = EntityManager::Instance()->GetEntitiesByLOT(1864); - for (const auto& cannon : cannons) - self->SetVar<LWOOBJID>(CannonIDVariable, cannon->GetObjectID()); -} - -void ZoneSGServer::OnActivityStateChangeRequest(Entity *self, const LWOOBJID senderID, const int32_t value1, - const int32_t value2, const std::u16string &stringValue) { - - auto* cannon = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(CannonIDVariable)); - if (cannon != nullptr) { - cannon->OnActivityStateChangeRequest(senderID, value1, value2, stringValue); - } -} - -void ZoneSGServer::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - - auto* cannon = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(CannonIDVariable)); - if (cannon != nullptr) { - cannon->OnFireEventServerSide(sender, args, param1, param2, param3); - } -} diff --git a/dScripts/ZoneSGServer.h b/dScripts/ZoneSGServer.h deleted file mode 100644 index 4198157f..00000000 --- a/dScripts/ZoneSGServer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class ZoneSGServer : public CppScripts::Script { -public: - void OnStartup(Entity *self) override; - void OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int32_t value1, - int32_t value2, const std::u16string& stringValue) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; -private: - std::u16string CannonIDVariable = u"CannonID"; -}; diff --git a/dScripts/ActMine.cpp b/dScripts/ai/ACT/ActMine.cpp similarity index 93% rename from dScripts/ActMine.cpp rename to dScripts/ai/ACT/ActMine.cpp index 9cc116b1..9651e13d 100644 --- a/dScripts/ActMine.cpp +++ b/dScripts/ai/ACT/ActMine.cpp @@ -8,9 +8,8 @@ void ActMine::OnStartup(Entity* self) { self->SetProximityRadius(MINE_RADIUS, "mineRadius"); } -void ActMine::OnRebuildNotifyState(Entity* self, eRebuildState state) -{ - if (state == eRebuildState::REBUILD_COMPLETED) { +void ActMine::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { auto* rebuild = self->GetComponent<RebuildComponent>(); if (rebuild) { auto* builder = rebuild->GetBuilder(); @@ -35,7 +34,7 @@ void ActMine::OnProximityUpdate(Entity* self, Entity* entering, std::string name void ActMine::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "Tick") { - if (self->GetVar<int>(u"NumWarnings") >= MAX_WARNINGS){ + if (self->GetVar<int>(u"NumWarnings") >= MAX_WARNINGS) { auto* skill = self->GetComponent<SkillComponent>(); if (!skill) return; skill->CalculateBehavior(SKILL_ID, BEHAVIOR_ID, LWOOBJID_EMPTY); @@ -50,4 +49,4 @@ void ActMine::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "BlowedUp") { self->Kill(self); } -} \ No newline at end of file +} diff --git a/dScripts/ai/ACT/ActMine.h b/dScripts/ai/ACT/ActMine.h new file mode 100644 index 00000000..fb222f2e --- /dev/null +++ b/dScripts/ai/ACT/ActMine.h @@ -0,0 +1,18 @@ +#pragma once +#include "CppScripts.h" + +class ActMine : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + int MAX_WARNINGS = 3; + float MINE_RADIUS = 10.0; + float TICK_TIME = 0.25; + float BLOWED_UP_TIME = 0.1; + uint32_t SKILL_ID = 317; + uint32_t BEHAVIOR_ID = 3719; +}; + diff --git a/dScripts/ActPlayerDeathTrigger.cpp b/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp similarity index 73% rename from dScripts/ActPlayerDeathTrigger.cpp rename to dScripts/ai/ACT/ActPlayerDeathTrigger.cpp index 0601e25d..0674f0dd 100644 --- a/dScripts/ActPlayerDeathTrigger.cpp +++ b/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp @@ -1,8 +1,9 @@ #include "ActPlayerDeathTrigger.h" -void ActPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) -{ +#include "Entity.h" + +void ActPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { if (!target->IsPlayer() || target->GetIsDead() || !target->GetPlayerReadyForUpdates()) return; //Don't kill already dead players or players not ready - - target->Smash(self->GetObjectID(), eKillType::SILENT); + + target->Smash(self->GetObjectID(), eKillType::SILENT); } diff --git a/dScripts/ActPlayerDeathTrigger.h b/dScripts/ai/ACT/ActPlayerDeathTrigger.h similarity index 100% rename from dScripts/ActPlayerDeathTrigger.h rename to dScripts/ai/ACT/ActPlayerDeathTrigger.h diff --git a/dScripts/ai/ACT/ActVehicleDeathTrigger.cpp b/dScripts/ai/ACT/ActVehicleDeathTrigger.cpp new file mode 100644 index 00000000..76c0289e --- /dev/null +++ b/dScripts/ai/ACT/ActVehicleDeathTrigger.cpp @@ -0,0 +1,52 @@ +#include "ActVehicleDeathTrigger.h" +#include "PossessableComponent.h" +#include "GameMessages.h" +#include "RacingControlComponent.h" +#include "dZoneManager.h" +#include "EntityManager.h" +#include "PossessorComponent.h" + + +void ActVehicleDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { + auto* possessableComponent = target->GetComponent<PossessableComponent>(); + + Entity* vehicle; + Entity* player; + + if (possessableComponent != nullptr) { + auto* player = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + + if (player == nullptr) { + return; + } + + return; + } else if (target->IsPlayer()) { + auto* possessorComponent = target->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) { + return; + } + + vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) { + return; + } + + player = target; + } else { + return; + } + + + GameMessages::SendDie(vehicle, self->GetObjectID(), LWOOBJID_EMPTY, true, eKillType::VIOLENT, u"", 0, 0, 0, true, false, 0); + + auto* zoneController = dZoneManager::Instance()->GetZoneControlObject(); + + auto* racingControlComponent = zoneController->GetComponent<RacingControlComponent>(); + + if (racingControlComponent != nullptr) { + racingControlComponent->OnRequestDie(player); + } +} diff --git a/dScripts/ActVehicleDeathTrigger.h b/dScripts/ai/ACT/ActVehicleDeathTrigger.h similarity index 100% rename from dScripts/ActVehicleDeathTrigger.h rename to dScripts/ai/ACT/ActVehicleDeathTrigger.h diff --git a/dScripts/ai/ACT/CMakeLists.txt b/dScripts/ai/ACT/CMakeLists.txt new file mode 100644 index 00000000..79deeded --- /dev/null +++ b/dScripts/ai/ACT/CMakeLists.txt @@ -0,0 +1,12 @@ +set(DSCRIPTS_SOURCES_AI_ACT + "ActMine.cpp" + "ActPlayerDeathTrigger.cpp" + "ActVehicleDeathTrigger.cpp") + +add_subdirectory(FootRace) + +foreach(file ${DSCRIPTS_SOURCES_AI_ACT_FOOTRACE}) + set(DSCRIPTS_SOURCES_AI_ACT ${DSCRIPTS_SOURCES_AI_ACT} "FootRace/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_ACT ${DSCRIPTS_SOURCES_AI_ACT} PARENT_SCOPE) diff --git a/dScripts/ai/ACT/FootRace/BaseFootRaceManager.cpp b/dScripts/ai/ACT/FootRace/BaseFootRaceManager.cpp new file mode 100644 index 00000000..4d1ae5f5 --- /dev/null +++ b/dScripts/ai/ACT/FootRace/BaseFootRaceManager.cpp @@ -0,0 +1,48 @@ +#include "BaseFootRaceManager.h" +#include "EntityManager.h" +#include "Character.h" + +void BaseFootRaceManager::OnStartup(Entity* self) { + // TODO: Add to FootRaceStarter group +} + +void BaseFootRaceManager::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + const auto splitArguments = GeneralUtils::SplitString(args, '_'); + if (splitArguments.size() > 1) { + + const auto eventName = splitArguments[0]; + const auto player = EntityManager::Instance()->GetEntity(std::stoull(splitArguments[1])); + + if (player != nullptr) { + if (eventName == "updatePlayer") { + UpdatePlayer(self, player->GetObjectID()); + } else if (IsPlayerInActivity(self, player->GetObjectID())) { + if (eventName == "initialActivityScore") { + auto* character = player->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(115, true); + } + + SetActivityScore(self, player->GetObjectID(), 1); + } else if (eventName == "updatePlayerTrue") { + auto* character = player->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(115, false); + } + + UpdatePlayer(self, player->GetObjectID(), true); + } else if (eventName == "PlayerWon") { + auto* character = player->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(115, false); + if (param2 != -1) // Certain footraces set a flag + character->SetPlayerFlag(static_cast<uint32_t>(param2), true); + } + + StopActivity(self, player->GetObjectID(), 0, param1); + } + } + } + } +} diff --git a/dScripts/ai/ACT/FootRace/BaseFootRaceManager.h b/dScripts/ai/ACT/FootRace/BaseFootRaceManager.h new file mode 100644 index 00000000..477a6eb9 --- /dev/null +++ b/dScripts/ai/ACT/FootRace/BaseFootRaceManager.h @@ -0,0 +1,9 @@ +#pragma once +#include "ActivityManager.h" +#include "CppScripts.h" + +class BaseFootRaceManager : public ActivityManager { + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/ai/ACT/FootRace/CMakeLists.txt b/dScripts/ai/ACT/FootRace/CMakeLists.txt new file mode 100644 index 00000000..c56986ff --- /dev/null +++ b/dScripts/ai/ACT/FootRace/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_ACT_FOOTRACE + "BaseFootRaceManager.cpp" + PARENT_SCOPE) diff --git a/dScripts/ActSharkPlayerDeathTrigger.cpp b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp similarity index 59% rename from dScripts/ActSharkPlayerDeathTrigger.cpp rename to dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp index a8aaac8b..49fb6b87 100644 --- a/dScripts/ActSharkPlayerDeathTrigger.cpp +++ b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp @@ -1,15 +1,15 @@ #include "ActSharkPlayerDeathTrigger.h" #include "MissionComponent.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" #include "Entity.h" -void ActSharkPlayerDeathTrigger::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, - int32_t param2, int32_t param3) { +void ActSharkPlayerDeathTrigger::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { if (args == "achieve") { auto missionComponent = sender->GetComponent<MissionComponent>(); if (!missionComponent) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, 8419); + missionComponent->Progress(eMissionTaskType::SCRIPT, 8419); if (sender->GetIsDead() || !sender->GetPlayerReadyForUpdates()) return; //Don't kill already dead players or players not ready diff --git a/dScripts/ActSharkPlayerDeathTrigger.h b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.h similarity index 56% rename from dScripts/ActSharkPlayerDeathTrigger.h rename to dScripts/ai/AG/ActSharkPlayerDeathTrigger.h index cbd3c960..d76ae5be 100644 --- a/dScripts/ActSharkPlayerDeathTrigger.h +++ b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.h @@ -4,7 +4,7 @@ class ActSharkPlayerDeathTrigger : public CppScripts::Script { public: - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; }; diff --git a/dScripts/AgBusDoor.cpp b/dScripts/ai/AG/AgBusDoor.cpp similarity index 93% rename from dScripts/AgBusDoor.cpp rename to dScripts/ai/AG/AgBusDoor.cpp index 4453fcad..4910d0c5 100644 --- a/dScripts/AgBusDoor.cpp +++ b/dScripts/ai/AG/AgBusDoor.cpp @@ -23,14 +23,12 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na m_Counter = 0; m_OuterCounter = 0; - for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoor")) - { + for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoor")) { auto* entity = EntityManager::Instance()->GetEntity(pair.first); if (entity != nullptr && entity->IsPlayer()) m_Counter++; } - for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoorOuter")) - { + for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoorOuter")) { auto* entity = EntityManager::Instance()->GetEntity(pair.first); if (entity != nullptr && entity->IsPlayer()) m_OuterCounter++; } @@ -40,8 +38,7 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na if (m_Counter > 0) { MoveDoor(self, true); } - } - else if (status == "LEAVE") { + } else if (status == "LEAVE") { // move down when no players are inside either radii if (m_Counter <= 0) { MoveDoor(self, false); @@ -52,13 +49,12 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na void AgBusDoor::MoveDoor(Entity* self, bool bOpen) { if (bOpen) { GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 1, 0); - } - else { + } else { GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, 1); self->AddTimer("dustTimer", 2.0f); } - //This is currently commented out because it might be the reason that people's audio is cutting out. + //This is currently commented out because it might be the reason that people's audio is cutting out. GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, "{9a24f1fa-3177-4745-a2df-fbd996d6e1e3}"); } @@ -66,4 +62,4 @@ void AgBusDoor::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "dustTimer") { GameMessages::SendPlayFXEffect(self->GetObjectID(), 642, u"create", "busDust", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } -} \ No newline at end of file +} diff --git a/dScripts/AgBusDoor.h b/dScripts/ai/AG/AgBusDoor.h similarity index 100% rename from dScripts/AgBusDoor.h rename to dScripts/ai/AG/AgBusDoor.h diff --git a/dScripts/ai/AG/AgDarkSpiderling.cpp b/dScripts/ai/AG/AgDarkSpiderling.cpp new file mode 100644 index 00000000..5dbd350a --- /dev/null +++ b/dScripts/ai/AG/AgDarkSpiderling.cpp @@ -0,0 +1,9 @@ +#include "AgDarkSpiderling.h" +#include "BaseCombatAIComponent.h" + +void AgDarkSpiderling::OnStartup(Entity* self) { + auto* combatAI = self->GetComponent<BaseCombatAIComponent>(); + if (combatAI != nullptr) { + combatAI->SetStunImmune(true); + } +} diff --git a/dScripts/AgDarkSpiderling.h b/dScripts/ai/AG/AgDarkSpiderling.h similarity index 68% rename from dScripts/AgDarkSpiderling.h rename to dScripts/ai/AG/AgDarkSpiderling.h index fe680f9c..8797812c 100644 --- a/dScripts/AgDarkSpiderling.h +++ b/dScripts/ai/AG/AgDarkSpiderling.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class AgDarkSpiderling : public CppScripts::Script { - void OnStartup(Entity *self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/AgFans.cpp b/dScripts/ai/AG/AgFans.cpp similarity index 84% rename from dScripts/AgFans.cpp rename to dScripts/ai/AG/AgFans.cpp index dbc09547..e05fe68d 100644 --- a/dScripts/AgFans.cpp +++ b/dScripts/ai/AG/AgFans.cpp @@ -4,6 +4,7 @@ #include "GameMessages.h" #include "PhantomPhysicsComponent.h" #include "RenderComponent.h" +#include "eReplicaComponentType.h" void AgFans::OnStartup(Entity* self) { self->SetVar<bool>(u"alive", true); @@ -11,7 +12,7 @@ void AgFans::OnStartup(Entity* self) { ToggleFX(self, false); - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) { return; @@ -24,12 +25,12 @@ void AgFans::ToggleFX(Entity* self, bool hit) { std::string fanGroup = self->GetGroups()[0]; std::vector<Entity*> fanVolumes = EntityManager::Instance()->GetEntitiesInGroup(fanGroup); - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) { return; } - + if (fanVolumes.size() == 0 || !self->GetVar<bool>(u"alive")) return; if (self->GetVar<bool>(u"on")) { @@ -37,9 +38,9 @@ void AgFans::ToggleFX(Entity* self, bool hit) { renderComponent->StopEffect("fanOn"); self->SetVar<bool>(u"on", false); - + for (Entity* volume : fanVolumes) { - PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (!volumePhys) continue; volumePhys->SetPhysicsEffectActive(false); EntityManager::Instance()->SerializeEntity(volume); @@ -48,15 +49,14 @@ void AgFans::ToggleFX(Entity* self, bool hit) { GameMessages::SendPlayAnimation(fxObj, u"trigger"); } } - } - else if (!self->GetVar<bool>(u"on") && self->GetVar<bool>(u"alive")) { + } else if (!self->GetVar<bool>(u"on") && self->GetVar<bool>(u"alive")) { GameMessages::SendPlayAnimation(self, u"fan-on"); renderComponent->PlayEffect(495, u"fanOn", "fanOn"); self->SetVar<bool>(u"on", true); for (Entity* volume : fanVolumes) { - PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (!volumePhys) continue; volumePhys->SetPhysicsEffectActive(true); EntityManager::Instance()->SerializeEntity(volume); @@ -68,8 +68,8 @@ void AgFans::ToggleFX(Entity* self, bool hit) { } } -void AgFans::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { +void AgFans::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { if (args.length() == 0 || !self->GetVar<bool>(u"alive")) return; if ((args == "turnOn" && self->GetVar<bool>(u"on")) || (args == "turnOff" && !self->GetVar<bool>(u"on"))) return; @@ -81,4 +81,4 @@ void AgFans::OnDie(Entity* self, Entity* killer) { ToggleFX(self, true); } self->SetVar<bool>(u"alive", false); -} \ No newline at end of file +} diff --git a/dScripts/AgFans.h b/dScripts/ai/AG/AgFans.h similarity index 91% rename from dScripts/AgFans.h rename to dScripts/ai/AG/AgFans.h index 800267af..01f919d1 100644 --- a/dScripts/AgFans.h +++ b/dScripts/ai/AG/AgFans.h @@ -7,8 +7,8 @@ public: void OnStartup(Entity* self) override; void OnDie(Entity* self, Entity* killer) override; void OnFireEventServerSide( - Entity *self, - Entity *sender, + Entity* self, + Entity* sender, std::string args, int32_t param1, int32_t param2, diff --git a/dScripts/AgImagSmashable.cpp b/dScripts/ai/AG/AgImagSmashable.cpp similarity index 90% rename from dScripts/AgImagSmashable.cpp rename to dScripts/ai/AG/AgImagSmashable.cpp index 593294e5..5e8331b1 100644 --- a/dScripts/AgImagSmashable.cpp +++ b/dScripts/ai/AG/AgImagSmashable.cpp @@ -2,13 +2,15 @@ #include "EntityManager.h" #include "GeneralUtils.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void AgImagSmashable::OnDie(Entity* self, Entity* killer) { bool maxImagGreaterThanZero = false; if (killer) { - DestroyableComponent* dest = static_cast<DestroyableComponent*>(killer->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + DestroyableComponent* dest = static_cast<DestroyableComponent*>(killer->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { maxImagGreaterThanZero = dest->GetMaxImagination() > 0; } diff --git a/dScripts/AgImagSmashable.h b/dScripts/ai/AG/AgImagSmashable.h similarity index 98% rename from dScripts/AgImagSmashable.h rename to dScripts/ai/AG/AgImagSmashable.h index fd047c34..1cea25b9 100644 --- a/dScripts/AgImagSmashable.h +++ b/dScripts/ai/AG/AgImagSmashable.h @@ -6,4 +6,4 @@ public: void OnDie(Entity* self, Entity* killer); private: void CrateAnimal(Entity* self); -}; \ No newline at end of file +}; diff --git a/dScripts/ai/AG/AgJetEffectServer.cpp b/dScripts/ai/AG/AgJetEffectServer.cpp new file mode 100644 index 00000000..3d132991 --- /dev/null +++ b/dScripts/ai/AG/AgJetEffectServer.cpp @@ -0,0 +1,59 @@ +#include "AgJetEffectServer.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "SkillComponent.h" +#include "eReplicaComponentType.h" + +void AgJetEffectServer::OnUse(Entity* self, Entity* user) { + if (inUse || self->GetLOT() != 6859) return; + GameMessages::SendNotifyClientObject( + self->GetObjectID(), u"toggleInUse", 1, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS + ); + inUse = true; + + auto entities = EntityManager::Instance()->GetEntitiesInGroup("Jet_FX"); + if (entities.empty()) return; + GameMessages::SendPlayFXEffect(entities.at(0), 641, u"create", "radarDish", LWOOBJID_EMPTY, 1, 1, true); + self->AddTimer("radarDish", 2.0f); + self->AddTimer("PlayEffect", 2.5f); + self->AddTimer("CineDone", 7.5f + 5.0f); // 7.5f is time the cinematic takes to play +} + +void AgJetEffectServer::OnRebuildComplete(Entity* self, Entity* target) { + if (self->GetLOT() != 6209) return; + auto entities = EntityManager::Instance()->GetEntitiesInGroup("Jet_FX"); + if (entities.empty()) return; + GameMessages::SendPlayAnimation(entities.at(0), u"jetFX"); + + // So we can give kill credit to person who build this + builder = target->GetObjectID(); + + auto groups = self->GetGroups(); + if (!groups.empty() && groups.at(0) == "Base_Radar") { + self->AddTimer("PlayEffect", 2.5f); + self->AddTimer("CineDone", 7.5f + 5.0f); // 7.5f is time the cinematic takes to play + } +} + +void AgJetEffectServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "radarDish") { + GameMessages::SendStopFXEffect(self, true, "radarDish"); + } else if (timerName == "PlayEffect") { + auto entities = EntityManager::Instance()->GetEntitiesInGroup("mortarMain"); + if (entities.empty()) return; + + const auto selected = GeneralUtils::GenerateRandomNumber<int>(0, entities.size() - 1); + auto* mortar = entities.at(selected); + + // so we give proper credit to the builder for the kills from this skill + mortar->SetOwnerOverride(builder); + + auto* skillComponent = mortar->GetComponent<SkillComponent>(); + if (skillComponent) skillComponent->CastSkill(318); + } else if (timerName == "CineDone") { + GameMessages::SendNotifyClientObject( + self->GetObjectID(), u"toggleInUse", -1, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS + ); + inUse = false; + } +} diff --git a/dScripts/AgJetEffectServer.h b/dScripts/ai/AG/AgJetEffectServer.h similarity index 95% rename from dScripts/AgJetEffectServer.h rename to dScripts/ai/AG/AgJetEffectServer.h index 094c73d2..3cb3bd83 100644 --- a/dScripts/AgJetEffectServer.h +++ b/dScripts/ai/AG/AgJetEffectServer.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" class AgJetEffectServer final : public CppScripts::Script diff --git a/dScripts/ai/AG/AgPicnicBlanket.cpp b/dScripts/ai/AG/AgPicnicBlanket.cpp new file mode 100644 index 00000000..bec5577c --- /dev/null +++ b/dScripts/ai/AG/AgPicnicBlanket.cpp @@ -0,0 +1,19 @@ +#include "AgPicnicBlanket.h" +#include "Loot.h" +#include "GameMessages.h" +#include "Entity.h" +#include "eTerminateType.h" + +void AgPicnicBlanket::OnUse(Entity* self, Entity* user) { + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + if (self->GetVar<bool>(u"active")) + return; + self->SetVar<bool>(u"active", true); + + auto lootTable = std::unordered_map<LOT, int32_t>{ {935, 3} }; + LootGenerator::Instance().DropLoot(user, self, lootTable, 0, 0); + + self->AddCallbackTimer(5.0f, [self]() { + self->SetVar<bool>(u"active", false); + }); +} diff --git a/dScripts/AgPicnicBlanket.h b/dScripts/ai/AG/AgPicnicBlanket.h similarity index 63% rename from dScripts/AgPicnicBlanket.h rename to dScripts/ai/AG/AgPicnicBlanket.h index af603dd7..2a5a0d7a 100644 --- a/dScripts/AgPicnicBlanket.h +++ b/dScripts/ai/AG/AgPicnicBlanket.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class AgPicnicBlanket : public CppScripts::Script { - void OnUse(Entity *self, Entity *user) override; + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/AgQbElevator.cpp b/dScripts/ai/AG/AgQbElevator.cpp similarity index 82% rename from dScripts/AgQbElevator.cpp rename to dScripts/ai/AG/AgQbElevator.cpp index 3ef0cf0b..e1d78a21 100644 --- a/dScripts/AgQbElevator.cpp +++ b/dScripts/ai/AG/AgQbElevator.cpp @@ -3,7 +3,7 @@ #include "GameMessages.h" void AgQbElevator::OnStartup(Entity* self) { - + } //when the QB is finished being built by a player @@ -15,7 +15,7 @@ void AgQbElevator::OnRebuildComplete(Entity* self, Entity* target) { if (delayTime < 1) delayTime = 1; GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); + 0, 0, eMovementPlatformState::Stationary); //add a timer that will kill the QB if no players get on in the killTime self->AddTimer("startKillTimer", killTime); @@ -33,9 +33,8 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string self->CancelTimer("StartElevator"); GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); - } - else if (!self->GetBoolean(u"StartTimer")) { + 1, 1, eMovementPlatformState::Moving); + } else if (!self->GetBoolean(u"StartTimer")) { self->SetBoolean(u"StartTimer", true); self->AddTimer("StartElevator", startTime); } @@ -46,12 +45,11 @@ void AgQbElevator::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "StartElevator") { GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); - } - else if (timerName == "startKillTimer") { + 1, 1, eMovementPlatformState::Moving); + } else if (timerName == "startKillTimer") { killTimerStartup(self); } else if (timerName == "KillTimer") { - self->Smash(self->GetObjectID(), VIOLENT); + self->Smash(self->GetObjectID(), eKillType::VIOLENT); } } diff --git a/dScripts/AgQbElevator.h b/dScripts/ai/AG/AgQbElevator.h similarity index 99% rename from dScripts/AgQbElevator.h rename to dScripts/ai/AG/AgQbElevator.h index ab4f9a6d..4d07b8a2 100644 --- a/dScripts/AgQbElevator.h +++ b/dScripts/ai/AG/AgQbElevator.h @@ -16,4 +16,4 @@ private: float startTime = 8.0f; float killTime = 10.0f; float proxRadius = 5.0f; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/AG/AgQbWall.cpp b/dScripts/ai/AG/AgQbWall.cpp new file mode 100644 index 00000000..d6222419 --- /dev/null +++ b/dScripts/ai/AG/AgQbWall.cpp @@ -0,0 +1,15 @@ +#include "AgQbWall.h" + +void AgQbWall::OnRebuildComplete(Entity* self, Entity* player) { + self->SetVar(u"player", player->GetObjectID()); + auto targetWallSpawners = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner")); + if (targetWallSpawners != "") { + auto groupObjs = EntityManager::Instance()->GetEntitiesInGroup(targetWallSpawners); + for (auto* obj : groupObjs) { + if (obj) { + obj->SetVar(u"player", player->GetObjectID()); + obj->OnFireEventServerSide(self, "spawnMobs"); + } + } + } +} diff --git a/dScripts/ai/AG/AgQbWall.h b/dScripts/ai/AG/AgQbWall.h new file mode 100644 index 00000000..93187e0e --- /dev/null +++ b/dScripts/ai/AG/AgQbWall.h @@ -0,0 +1,7 @@ +#pragma once +#include "CppScripts.h" + +class AgQbWall : public CppScripts::Script { +public: + void OnRebuildComplete(Entity* self, Entity* player) override; +}; diff --git a/dScripts/AgSalutingNpcs.cpp b/dScripts/ai/AG/AgSalutingNpcs.cpp similarity index 67% rename from dScripts/AgSalutingNpcs.cpp rename to dScripts/ai/AG/AgSalutingNpcs.cpp index 618dc631..4e4d8b2c 100644 --- a/dScripts/AgSalutingNpcs.cpp +++ b/dScripts/ai/AG/AgSalutingNpcs.cpp @@ -1,11 +1,9 @@ -#include "AgSalutingNpcs.h" +#include "AgSalutingNpcs.h" #include "GameMessages.h" -void AgSalutingNpcs::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) -{ - if (emote != 356) - { +void AgSalutingNpcs::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) { + if (emote != 356) { return; } diff --git a/dScripts/AgSalutingNpcs.h b/dScripts/ai/AG/AgSalutingNpcs.h similarity index 91% rename from dScripts/AgSalutingNpcs.h rename to dScripts/ai/AG/AgSalutingNpcs.h index 7dd20316..c53d03b2 100644 --- a/dScripts/AgSalutingNpcs.h +++ b/dScripts/ai/AG/AgSalutingNpcs.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" class AgSalutingNpcs final : public CppScripts::Script diff --git a/dScripts/AgShipPlayerDeathTrigger.cpp b/dScripts/ai/AG/AgShipPlayerDeathTrigger.cpp similarity index 99% rename from dScripts/AgShipPlayerDeathTrigger.cpp rename to dScripts/ai/AG/AgShipPlayerDeathTrigger.cpp index d20edee7..a580be6e 100644 --- a/dScripts/AgShipPlayerDeathTrigger.cpp +++ b/dScripts/ai/AG/AgShipPlayerDeathTrigger.cpp @@ -5,4 +5,4 @@ void AgShipPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) if (target->GetLOT() == 1 && !target->GetIsDead()) { target->Smash(self->GetObjectID(), eKillType::VIOLENT, u"electro-shock-death"); } -} \ No newline at end of file +} diff --git a/dScripts/AgShipPlayerDeathTrigger.h b/dScripts/ai/AG/AgShipPlayerDeathTrigger.h similarity index 100% rename from dScripts/AgShipPlayerDeathTrigger.h rename to dScripts/ai/AG/AgShipPlayerDeathTrigger.h diff --git a/dScripts/AgShipPlayerShockServer.cpp b/dScripts/ai/AG/AgShipPlayerShockServer.cpp similarity index 86% rename from dScripts/AgShipPlayerShockServer.cpp rename to dScripts/ai/AG/AgShipPlayerShockServer.cpp index 628f0bb4..9e6c90d4 100644 --- a/dScripts/AgShipPlayerShockServer.cpp +++ b/dScripts/ai/AG/AgShipPlayerShockServer.cpp @@ -1,8 +1,8 @@ #include "AgShipPlayerShockServer.h" #include "GameMessages.h" +#include "eTerminateType.h" -void AgShipPlayerShockServer::OnUse(Entity* self, Entity* user) -{ +void AgShipPlayerShockServer::OnUse(Entity* self, Entity* user) { GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); if (active) { return; @@ -15,8 +15,7 @@ void AgShipPlayerShockServer::OnUse(Entity* self, Entity* user) self->AddTimer("FXTime", fxTime); } -void AgShipPlayerShockServer::OnTimerDone(Entity* self, std::string timerName) -{ +void AgShipPlayerShockServer::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendStopFXEffect(self, true, "console_sparks"); active = false; } diff --git a/dScripts/AgShipPlayerShockServer.h b/dScripts/ai/AG/AgShipPlayerShockServer.h similarity index 100% rename from dScripts/AgShipPlayerShockServer.h rename to dScripts/ai/AG/AgShipPlayerShockServer.h diff --git a/dScripts/AgSpaceStuff.cpp b/dScripts/ai/AG/AgSpaceStuff.cpp similarity index 94% rename from dScripts/AgSpaceStuff.cpp rename to dScripts/ai/AG/AgSpaceStuff.cpp index 18e4eb47..30929ebf 100644 --- a/dScripts/AgSpaceStuff.cpp +++ b/dScripts/ai/AG/AgSpaceStuff.cpp @@ -1,4 +1,5 @@ #include "AgSpaceStuff.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "GameMessages.h" #include "EntityManager.h" @@ -28,18 +29,15 @@ void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendPlayAnimation(self, u"scale_0" + GeneralUtils::to_u16string(scaleType)); self->AddTimer("FloaterPath", 0.4); - } - else if (timerName == "FloaterPath") { + } else if (timerName == "FloaterPath") { int pathType = GeneralUtils::GenerateRandomNumber<int>(1, 4); int randTime = GeneralUtils::GenerateRandomNumber<int>(20, 25); GameMessages::SendPlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType))); self->AddTimer("FloaterScale", randTime); - } - else if (timerName == "ShipShakeExplode") { + } else if (timerName == "ShipShakeExplode") { DoShake(self, true); - } - else if (timerName == "ShipShakeIdle") { + } else if (timerName == "ShipShakeIdle") { DoShake(self, false); } } @@ -79,8 +77,7 @@ void AgSpaceStuff::DoShake(Entity* self, bool explodeIdle) { auto* shipFxObject2 = GetEntityInGroup(ShipFX2); if (shipFxObject2) GameMessages::SendPlayAnimation(shipFxObject2, u"explosion"); - } - else { + } else { auto* shipFxObject = GetEntityInGroup(ShipFX); auto* shipFxObject2 = GetEntityInGroup(ShipFX2); diff --git a/dScripts/AgSpaceStuff.h b/dScripts/ai/AG/AgSpaceStuff.h similarity index 100% rename from dScripts/AgSpaceStuff.h rename to dScripts/ai/AG/AgSpaceStuff.h diff --git a/dScripts/ai/AG/AgStagePlatforms.cpp b/dScripts/ai/AG/AgStagePlatforms.cpp new file mode 100644 index 00000000..9ba4c4b7 --- /dev/null +++ b/dScripts/ai/AG/AgStagePlatforms.cpp @@ -0,0 +1,16 @@ +#include "AgStagePlatforms.h" +#include "MovingPlatformComponent.h" + +void AgStagePlatforms::OnStartup(Entity* self) { + auto* component = self->GetComponent<MovingPlatformComponent>(); + if (component) { + component->SetNoAutoStart(true); + component->StopPathing(); + } +} + +void AgStagePlatforms::OnWaypointReached(Entity* self, uint32_t waypointIndex) { + auto* component = self->GetComponent<MovingPlatformComponent>(); + if (waypointIndex == 0 && component) + component->StopPathing(); +} diff --git a/dScripts/ai/AG/AgStagePlatforms.h b/dScripts/ai/AG/AgStagePlatforms.h new file mode 100644 index 00000000..62c6bc91 --- /dev/null +++ b/dScripts/ai/AG/AgStagePlatforms.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class AgStagePlatforms : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnWaypointReached(Entity* self, uint32_t waypointIndex) override; +}; diff --git a/dScripts/ai/AG/AgStromlingProperty.cpp b/dScripts/ai/AG/AgStromlingProperty.cpp new file mode 100644 index 00000000..9a9ae33b --- /dev/null +++ b/dScripts/ai/AG/AgStromlingProperty.cpp @@ -0,0 +1,17 @@ +#include "AgStromlingProperty.h" +#include "MovementAIComponent.h" +#include "eReplicaComponentType.h" + +void AgStromlingProperty::OnStartup(Entity* self) { + auto movementInfo = MovementAIInfo{ + "Wander", + 71, + 3, + 100, + 1, + 4 + }; + + auto* movementAIComponent = new MovementAIComponent(self, movementInfo); + self->AddComponent(eReplicaComponentType::MOVEMENT_AI, movementAIComponent); +} diff --git a/dScripts/AgStromlingProperty.h b/dScripts/ai/AG/AgStromlingProperty.h similarity index 69% rename from dScripts/AgStromlingProperty.h rename to dScripts/ai/AG/AgStromlingProperty.h index 92a179f5..12128b03 100644 --- a/dScripts/AgStromlingProperty.h +++ b/dScripts/ai/AG/AgStromlingProperty.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class AgStromlingProperty : public CppScripts::Script { - void OnStartup(Entity *self) override; + void OnStartup(Entity* self) override; }; diff --git a/dScripts/AgTurret.cpp b/dScripts/ai/AG/AgTurret.cpp similarity index 100% rename from dScripts/AgTurret.cpp rename to dScripts/ai/AG/AgTurret.cpp diff --git a/dScripts/AgTurret.h b/dScripts/ai/AG/AgTurret.h similarity index 98% rename from dScripts/AgTurret.h rename to dScripts/ai/AG/AgTurret.h index 2aa12432..1cbba31a 100644 --- a/dScripts/AgTurret.h +++ b/dScripts/ai/AG/AgTurret.h @@ -5,4 +5,4 @@ class AgTurret : public CppScripts::Script { void OnStartup(Entity* self); void OnTimerDone(Entity* self, std::string timerName); void OnRebuildStart(Entity* self, Entity* user); -}; \ No newline at end of file +}; diff --git a/dScripts/ai/AG/CMakeLists.txt b/dScripts/ai/AG/CMakeLists.txt new file mode 100644 index 00000000..092b8de7 --- /dev/null +++ b/dScripts/ai/AG/CMakeLists.txt @@ -0,0 +1,18 @@ +set(DSCRIPTS_SOURCES_AI_AG + "AgShipPlayerDeathTrigger.cpp" + "AgSpaceStuff.cpp" + "AgShipPlayerShockServer.cpp" + "AgImagSmashable.cpp" + "ActSharkPlayerDeathTrigger.cpp" + "AgBusDoor.cpp" + "AgTurret.cpp" + "AgFans.cpp" + "AgSalutingNpcs.cpp" + "AgJetEffectServer.cpp" + "AgQbElevator.cpp" + "AgStromlingProperty.cpp" + "AgDarkSpiderling.cpp" + "AgPicnicBlanket.cpp" + "AgStagePlatforms.cpp" + "AgQbWall.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/CMakeLists.txt b/dScripts/ai/CMakeLists.txt new file mode 100644 index 00000000..44944b90 --- /dev/null +++ b/dScripts/ai/CMakeLists.txt @@ -0,0 +1,81 @@ +set(DSCRIPTS_SOURCES_AI) + +add_subdirectory(ACT) + +foreach(file ${DSCRIPTS_SOURCES_AI_ACT}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "ACT/${file}") +endforeach() + +add_subdirectory(AG) + +foreach(file ${DSCRIPTS_SOURCES_AI_AG}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "AG/${file}") +endforeach() + +add_subdirectory(FV) + +foreach(file ${DSCRIPTS_SOURCES_AI_FV}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "FV/${file}") +endforeach() + +add_subdirectory(GENERAL) + +foreach(file ${DSCRIPTS_SOURCES_AI_GENERAL}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "GENERAL/${file}") +endforeach() + +add_subdirectory(GF) + +foreach(file ${DSCRIPTS_SOURCES_AI_GF}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "GF/${file}") +endforeach() + +add_subdirectory(MINIGAME) + +foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "MINIGAME/${file}") +endforeach() + +add_subdirectory(NP) + +foreach(file ${DSCRIPTS_SOURCES_AI_NP}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "NP/${file}") +endforeach() + +add_subdirectory(NS) + +foreach(file ${DSCRIPTS_SOURCES_AI_NS}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "NS/${file}") +endforeach() + +add_subdirectory(PETS) + +foreach(file ${DSCRIPTS_SOURCES_AI_PETS}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "PETS/${file}") +endforeach() + +add_subdirectory(PROPERTY) + +foreach(file ${DSCRIPTS_SOURCES_AI_PROPERTY}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "PROPERTY/${file}") +endforeach() + +add_subdirectory(RACING) + +foreach(file ${DSCRIPTS_SOURCES_AI_RACING}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "RACING/${file}") +endforeach() + +add_subdirectory(SPEC) + +foreach(file ${DSCRIPTS_SOURCES_AI_SPEC}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "SPEC/${file}") +endforeach() + +add_subdirectory(WILD) + +foreach(file ${DSCRIPTS_SOURCES_AI_WILD}) + set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} "WILD/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI ${DSCRIPTS_SOURCES_AI} PARENT_SCOPE) diff --git a/dScripts/ai/FV/ActNinjaSensei.cpp b/dScripts/ai/FV/ActNinjaSensei.cpp new file mode 100644 index 00000000..27e42219 --- /dev/null +++ b/dScripts/ai/FV/ActNinjaSensei.cpp @@ -0,0 +1,78 @@ +#include "ActNinjaSensei.h" +#include "Entity.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void ActNinjaSensei::OnStartup(Entity* self) { + auto students = EntityManager::Instance()->GetEntitiesInGroup(this->m_StudentGroup); + std::vector<Entity*> validStudents = {}; + for (auto* student : students) { + if (student && student->GetLOT() == this->m_StudentLOT) validStudents.push_back(student); + } + self->SetVar(u"students", validStudents); + self->AddTimer("crane", 5); +} + +void ActNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { + auto students = self->GetVar<std::vector<Entity*>>(u"students"); + if (students.empty()) return; + + if (timerName == "crane") { + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"crane"); + } + GameMessages::SendPlayAnimation(self, u"crane"); + self->AddTimer("bow", 15.33); + } + + if (timerName == "bow") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("tiger", 5); + } + + if (timerName == "tiger") { + GameMessages::SendPlayAnimation(self, u"tiger"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"tiger"); + } + GameMessages::SendPlayAnimation(self, u"tiger"); + self->AddTimer("bow2", 15.33); + } + + if (timerName == "bow2") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("mantis", 5); + } + + if (timerName == "mantis") { + GameMessages::SendPlayAnimation(self, u"mantis"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"mantis"); + } + GameMessages::SendPlayAnimation(self, u"mantis"); + self->AddTimer("bow3", 15.3); + } + + if (timerName == "bow3") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("repeat", 5); + } + + if (timerName == "repeat") { + self->CancelAllTimers(); + self->AddTimer("crane", 5); + } +} + diff --git a/dScripts/ai/FV/ActNinjaSensei.h b/dScripts/ai/FV/ActNinjaSensei.h new file mode 100644 index 00000000..c35ede12 --- /dev/null +++ b/dScripts/ai/FV/ActNinjaSensei.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class ActNinjaSensei : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + std::string m_StudentGroup = "Sensei_kids"; + LOT m_StudentLOT = 2497; +}; diff --git a/dScripts/ai/FV/ActNinjaTurret.cpp b/dScripts/ai/FV/ActNinjaTurret.cpp new file mode 100644 index 00000000..ea6e2278 --- /dev/null +++ b/dScripts/ai/FV/ActNinjaTurret.cpp @@ -0,0 +1,18 @@ +#include "ActNinjaTurret.h" +#include "eRebuildState.h" + +void ActNinjaTurret::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { + self->SetVar(u"AmBuilt", true); + } else if (state == eRebuildState::RESETTING) { + self->SetVar(u"AmBuilt", false); + } +} + +void +ActNinjaTurret::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "ISpawned" && self->GetVar<bool>(u"AmBuilt")) { + sender->Smash(); + } +} diff --git a/dScripts/ActNinjaTurret.h b/dScripts/ai/FV/ActNinjaTurret.h similarity index 64% rename from dScripts/ActNinjaTurret.h rename to dScripts/ai/FV/ActNinjaTurret.h index 5251750a..d06e6afd 100644 --- a/dScripts/ActNinjaTurret.h +++ b/dScripts/ai/FV/ActNinjaTurret.h @@ -5,7 +5,7 @@ class ActNinjaTurret : public CppScripts::Script { public: void OnRebuildNotifyState(Entity* self, eRebuildState state) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; }; diff --git a/dScripts/ai/FV/ActParadoxPipeFix.cpp b/dScripts/ai/FV/ActParadoxPipeFix.cpp new file mode 100644 index 00000000..10a1e652 --- /dev/null +++ b/dScripts/ai/FV/ActParadoxPipeFix.cpp @@ -0,0 +1,62 @@ +#include "ActParadoxPipeFix.h" +#include "EntityManager.h" +#include "RebuildComponent.h" +#include "GameMessages.h" +#include "MissionComponent.h" +#include "eEndBehavior.h" + +void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) { + const auto myGroup = "AllPipes"; + + const auto groupObjs = EntityManager::Instance()->GetEntitiesInGroup(myGroup); + + auto indexCount = 0; + + self->SetVar(u"PlayerID", target->GetObjectID()); + + for (auto* object : groupObjs) { + if (object == self) { + continue; + } + + auto* rebuildComponent = object->GetComponent<RebuildComponent>(); + + if (rebuildComponent->GetState() == eRebuildState::COMPLETED) { + indexCount++; + } + } + + if (indexCount >= 2) { + const auto refinery = EntityManager::Instance()->GetEntitiesInGroup("Paradox"); + + if (!refinery.empty()) { + GameMessages::SendPlayFXEffect(refinery[0]->GetObjectID(), 3999, u"create", "pipeFX"); + } + + for (auto* object : groupObjs) { + auto* player = EntityManager::Instance()->GetEntity(object->GetVar<LWOOBJID>(u"PlayerID")); + + if (player != nullptr) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->ForceProgressTaskType(769, 1, 1, false); + } + + GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, eEndBehavior::RETURN, false, 2.0f); + } + + object->SetVar(u"PlayerID", LWOOBJID_EMPTY); + } + } +} + +void ActParadoxPipeFix::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::RESETTING) { + const auto refinery = EntityManager::Instance()->GetEntitiesInGroup("Paradox"); + + if (!refinery.empty()) { + GameMessages::SendStopFXEffect(refinery[0], true, "pipeFX"); + } + } +} diff --git a/dScripts/ActParadoxPipeFix.h b/dScripts/ai/FV/ActParadoxPipeFix.h similarity index 72% rename from dScripts/ActParadoxPipeFix.h rename to dScripts/ai/FV/ActParadoxPipeFix.h index b8b19cc2..df323b00 100644 --- a/dScripts/ActParadoxPipeFix.h +++ b/dScripts/ai/FV/ActParadoxPipeFix.h @@ -4,7 +4,7 @@ class ActParadoxPipeFix : public CppScripts::Script { public: - void OnRebuildComplete(Entity* self, Entity* target) override; + void OnRebuildComplete(Entity* self, Entity* target) override; void OnRebuildNotifyState(Entity* self, eRebuildState state) override; }; diff --git a/dScripts/ai/FV/CMakeLists.txt b/dScripts/ai/FV/CMakeLists.txt new file mode 100644 index 00000000..56418706 --- /dev/null +++ b/dScripts/ai/FV/CMakeLists.txt @@ -0,0 +1,20 @@ +set(DSCRIPTS_SOURCES_AI_FV + "ActNinjaSensei.cpp" + "ActNinjaTurret.cpp" + "FvFlyingCreviceDragon.cpp" + "FvDragonSmashingGolemQb.cpp" + "FvFreeGfNinjas.cpp" + "FvPandaSpawnerServer.cpp" + "FvPandaServer.cpp" + "FvBrickPuzzleServer.cpp" + "FvConsoleLeftQuickbuild.cpp" + "FvConsoleRightQuickbuild.cpp" + "FvFacilityBrick.cpp" + "FvFacilityPipes.cpp" + "ActParadoxPipeFix.cpp" + "FvNinjaGuard.cpp" + "FvPassThroughWall.cpp" + "FvBounceOverWall.cpp" + "FvMaelstromGeyser.cpp" + "TriggerGas.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/FV/FvBounceOverWall.cpp b/dScripts/ai/FV/FvBounceOverWall.cpp new file mode 100644 index 00000000..294c11f0 --- /dev/null +++ b/dScripts/ai/FV/FvBounceOverWall.cpp @@ -0,0 +1,10 @@ +#include "FvBounceOverWall.h" +#include "MissionComponent.h" + +void FvBounceOverWall::OnCollisionPhantom(Entity* self, Entity* target) { + auto missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) return; + + // We force progress here to the Gate Crasher mission due to an overlap in LOTs with the 'Shark Bite' missions. + missionComponent->ForceProgress(GateCrasherMissionId, GateCrasherMissionUid, 1); +} diff --git a/dScripts/ai/FV/FvBounceOverWall.h b/dScripts/ai/FV/FvBounceOverWall.h new file mode 100644 index 00000000..ee8c8b3a --- /dev/null +++ b/dScripts/ai/FV/FvBounceOverWall.h @@ -0,0 +1,22 @@ +#pragma once +#include "CppScripts.h" + +class FvBounceOverWall : public CppScripts::Script +{ + /** + * @brief When a collision has been made with self this method is called. + * + * @param self The Entity that called this function. + * @param target The target Entity of self. + */ + void OnCollisionPhantom(Entity* self, Entity* target) override; +private: + /** + * MissionId for the Gate Crasher mission. + */ + int32_t GateCrasherMissionId = 849; + /** + * MissionUid for the Gate Crasher mission. + */ + int32_t GateCrasherMissionUid = 1241; +}; diff --git a/dScripts/ai/FV/FvBrickPuzzleServer.cpp b/dScripts/ai/FV/FvBrickPuzzleServer.cpp new file mode 100644 index 00000000..887b9a4d --- /dev/null +++ b/dScripts/ai/FV/FvBrickPuzzleServer.cpp @@ -0,0 +1,68 @@ +#include "FvBrickPuzzleServer.h" +#include "GeneralUtils.h" +#include "dZoneManager.h" +#include "Spawner.h" +#include "RebuildComponent.h" + +void FvBrickPuzzleServer::OnStartup(Entity* self) { + const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); + + int32_t pipeNum = 0; + if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) { + return; + } + + if (pipeNum != 1) { + self->AddTimer("reset", 30); + } +} + +void FvBrickPuzzleServer::OnDie(Entity* self, Entity* killer) { + const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name")); + + int32_t pipeNum = 0; + if (!GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1), pipeNum)) { + return; + } + + const auto pipeGroup = myGroup.substr(0, 10); + + const auto nextPipeNum = pipeNum + 1; + + const auto samePipeSpawners = dZoneManager::Instance()->GetSpawnersByName(myGroup); + + if (!samePipeSpawners.empty()) { + samePipeSpawners[0]->SoftReset(); + + samePipeSpawners[0]->Deactivate(); + } + + if (killer != nullptr && killer->IsPlayer()) { + const auto nextPipe = pipeGroup + std::to_string(nextPipeNum); + + const auto nextPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); + + if (!nextPipeSpawners.empty()) { + nextPipeSpawners[0]->Activate(); + } + } else { + const auto nextPipe = pipeGroup + "1"; + + const auto firstPipeSpawners = dZoneManager::Instance()->GetSpawnersByName(nextPipe); + + if (!firstPipeSpawners.empty()) { + firstPipeSpawners[0]->Activate(); + } + } + +} + +void FvBrickPuzzleServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "reset") { + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + + if (rebuildComponent != nullptr && rebuildComponent->GetState() == eRebuildState::OPEN) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } + } +} diff --git a/dScripts/FvBrickPuzzleServer.h b/dScripts/ai/FV/FvBrickPuzzleServer.h similarity index 78% rename from dScripts/FvBrickPuzzleServer.h rename to dScripts/ai/FV/FvBrickPuzzleServer.h index f5eceaee..4297100e 100644 --- a/dScripts/FvBrickPuzzleServer.h +++ b/dScripts/ai/FV/FvBrickPuzzleServer.h @@ -1,10 +1,10 @@ #pragma once #include "CppScripts.h" -class FvBrickPuzzleServer : public CppScripts::Script +class FvBrickPuzzleServer : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnDie(Entity* self, Entity* killer) override; void OnTimerDone(Entity* self, std::string timerName) override; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp b/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp new file mode 100644 index 00000000..3f495ed7 --- /dev/null +++ b/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp @@ -0,0 +1,49 @@ +#include "FvConsoleLeftQuickbuild.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "eTerminateType.h" +#include "eRebuildState.h" + +void FvConsoleLeftQuickbuild::OnStartup(Entity* self) { + self->SetVar(u"IAmBuilt", false); + self->SetVar(u"AmActive", false); +} + +void FvConsoleLeftQuickbuild::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { + self->SetVar(u"IAmBuilt", true); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleLeftUp"); + } + } else if (state == eRebuildState::RESETTING) { + self->SetVar(u"IAmBuilt", false); + self->SetVar(u"AmActive", false); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleLeftDown"); + } + } +} + +void FvConsoleLeftQuickbuild::OnUse(Entity* self, Entity* user) { + if (self->GetVar<bool>(u"AmActive")) { + return; + } + + if (self->GetVar<bool>(u"IAmBuilt")) { + self->SetVar(u"AmActive", true); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleLeftActive"); + } + } + + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/FvConsoleLeftQuickbuild.h b/dScripts/ai/FV/FvConsoleLeftQuickbuild.h similarity index 77% rename from dScripts/FvConsoleLeftQuickbuild.h rename to dScripts/ai/FV/FvConsoleLeftQuickbuild.h index 8c796e0f..bbdea27e 100644 --- a/dScripts/FvConsoleLeftQuickbuild.h +++ b/dScripts/ai/FV/FvConsoleLeftQuickbuild.h @@ -1,10 +1,10 @@ #pragma once #include "CppScripts.h" -class FvConsoleLeftQuickbuild : public CppScripts::Script +class FvConsoleLeftQuickbuild : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnRebuildNotifyState(Entity* self, eRebuildState state) override; void OnUse(Entity* self, Entity* user) override; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp b/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp new file mode 100644 index 00000000..e03e4135 --- /dev/null +++ b/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp @@ -0,0 +1,49 @@ +#include "FvConsoleRightQuickbuild.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "eTerminateType.h" +#include "eRebuildState.h" + +void FvConsoleRightQuickbuild::OnStartup(Entity* self) { + self->SetVar(u"IAmBuilt", false); + self->SetVar(u"AmActive", false); +} + +void FvConsoleRightQuickbuild::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { + self->SetVar(u"IAmBuilt", true); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleRightUp"); + } + } else if (state == eRebuildState::RESETTING) { + self->SetVar(u"IAmBuilt", false); + self->SetVar(u"AmActive", false); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleRightDown"); + } + } +} + +void FvConsoleRightQuickbuild::OnUse(Entity* self, Entity* user) { + if (self->GetVar<bool>(u"AmActive")) { + return; + } + + if (self->GetVar<bool>(u"IAmBuilt")) { + self->SetVar(u"AmActive", true); + + const auto objects = EntityManager::Instance()->GetEntitiesInGroup("Facility"); + + if (!objects.empty()) { + objects[0]->NotifyObject(self, "ConsoleRightActive"); + } + } + + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/FvConsoleRightQuickbuild.h b/dScripts/ai/FV/FvConsoleRightQuickbuild.h similarity index 77% rename from dScripts/FvConsoleRightQuickbuild.h rename to dScripts/ai/FV/FvConsoleRightQuickbuild.h index cd0f4a04..fab8c814 100644 --- a/dScripts/FvConsoleRightQuickbuild.h +++ b/dScripts/ai/FV/FvConsoleRightQuickbuild.h @@ -1,10 +1,10 @@ #pragma once #include "CppScripts.h" -class FvConsoleRightQuickbuild : public CppScripts::Script +class FvConsoleRightQuickbuild : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnRebuildNotifyState(Entity* self, eRebuildState state) override; void OnUse(Entity* self, Entity* user) override; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/FV/FvDragonSmashingGolemQb.cpp b/dScripts/ai/FV/FvDragonSmashingGolemQb.cpp new file mode 100644 index 00000000..9cf7fa18 --- /dev/null +++ b/dScripts/ai/FV/FvDragonSmashingGolemQb.cpp @@ -0,0 +1,31 @@ +#include "FvDragonSmashingGolemQb.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "eRebuildState.h" + +void FvDragonSmashingGolemQb::OnStartup(Entity* self) { + self->AddTimer("GolemBreakTimer", 10.5f); +} + +void FvDragonSmashingGolemQb::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "GolemBreakTimer") { + self->Smash(); + } +} + +void FvDragonSmashingGolemQb::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::COMPLETED) { + GameMessages::SendPlayAnimation(self, u"dragonsmash"); + + const auto dragonId = self->GetVar<LWOOBJID>(u"Dragon"); + + auto* dragon = EntityManager::Instance()->GetEntity(dragonId); + + if (dragon != nullptr) { + dragon->OnFireEventServerSide(self, "rebuildDone"); + } + + self->CancelTimer("GolemBreakTimer"); + self->AddTimer("GolemBreakTimer", 10.5f); + } +} diff --git a/dScripts/ai/FV/FvDragonSmashingGolemQb.h b/dScripts/ai/FV/FvDragonSmashingGolemQb.h new file mode 100644 index 00000000..8aa772a3 --- /dev/null +++ b/dScripts/ai/FV/FvDragonSmashingGolemQb.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class FvDragonSmashingGolemQb : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; +}; diff --git a/dScripts/ai/FV/FvFacilityBrick.cpp b/dScripts/ai/FV/FvFacilityBrick.cpp new file mode 100644 index 00000000..6ff12750 --- /dev/null +++ b/dScripts/ai/FV/FvFacilityBrick.cpp @@ -0,0 +1,97 @@ +#include "FvFacilityBrick.h" +#include "GameMessages.h" +#include "dZoneManager.h" +#include "EntityManager.h" + +void FvFacilityBrick::OnStartup(Entity* self) { + self->SetVar(u"ConsoleLEFTActive", false); + self->SetVar(u"ConsoleRIGHTtActive", false); +} + +void FvFacilityBrick::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + auto* brickSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationBrick")[0]; + auto* bugSpawner = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug")[0]; + auto* canisterSpawner = dZoneManager::Instance()->GetSpawnersByName("BrickCanister")[0]; + + if (name == "ConsoleLeftUp") { + GameMessages::SendStopFXEffect(self, true, "LeftPipeOff"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2775, u"create", "LeftPipeEnergy"); + } else if (name == "ConsoleLeftDown") { + self->SetVar(u"ConsoleLEFTActive", false); + + GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); + GameMessages::SendStopFXEffect(self, true, "LeftPipeOn"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); + } else if (name == "ConsoleLeftActive") { + self->SetVar(u"ConsoleLEFTActive", true); + + GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2776, u"create", "LeftPipeOn"); + } + + else if (name == "ConsoleRightUp") { + GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2778, u"create", "RightPipeEnergy"); + } else if (name == "ConsoleRightDown") { + self->SetVar(u"ConsoleRIGHTActive", false); + + GameMessages::SendStopFXEffect(self, true, "RightPipeEnergy"); + GameMessages::SendStopFXEffect(self, true, "RightPipeOn"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); + } else if (name == "ConsoleRightActive") { + self->SetVar(u"ConsoleRIGHTActive", true); + + GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2779, u"create", "RightPipeEnergy"); + } + + if (self->GetVar<bool>(u"ConsoleLEFTActive") && self->GetVar<bool>(u"ConsoleRIGHTActive")) { + auto* object = EntityManager::Instance()->GetEntitiesInGroup("Brick")[0]; + + if (object != nullptr) { + GameMessages::SendPlayFXEffect(object->GetObjectID(), 122, u"create", "bluebrick"); + GameMessages::SendPlayFXEffect(object->GetObjectID(), 1034, u"cast", "imaginationexplosion"); + } + + object = EntityManager::Instance()->GetEntitiesInGroup("Canister")[0]; + + if (object != nullptr) { + object->Smash(self->GetObjectID(), eKillType::SILENT); + } + + canisterSpawner->Reset(); + canisterSpawner->Deactivate(); + } else if (self->GetVar<bool>(u"ConsoleLEFTActive") || self->GetVar<bool>(u"ConsoleRIGHTActive")) { + brickSpawner->Activate(); + + auto* object = EntityManager::Instance()->GetEntitiesInGroup("Brick")[0]; + + if (object != nullptr) { + GameMessages::SendStopFXEffect(object, true, "bluebrick"); + } + + bugSpawner->Reset(); + bugSpawner->Deactivate(); + + canisterSpawner->Reset(); + canisterSpawner->Activate(); + } else { + brickSpawner->Reset(); + brickSpawner->Deactivate(); + + bugSpawner->Reset(); + bugSpawner->Activate(); + } +} + +void FvFacilityBrick::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args != "PlayFX") { + return; + } + + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2750, u"create", "imagination_canister"); + GameMessages::SendPlayFXEffect(self->GetObjectID(), 2751, u"create", "canister_light_filler"); +} diff --git a/dScripts/ai/FV/FvFacilityBrick.h b/dScripts/ai/FV/FvFacilityBrick.h new file mode 100644 index 00000000..c7580c25 --- /dev/null +++ b/dScripts/ai/FV/FvFacilityBrick.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class FvFacilityBrick : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/ai/FV/FvFacilityPipes.cpp b/dScripts/ai/FV/FvFacilityPipes.cpp new file mode 100644 index 00000000..dd35ffe1 --- /dev/null +++ b/dScripts/ai/FV/FvFacilityPipes.cpp @@ -0,0 +1,10 @@ +#include "FvFacilityPipes.h" +#include "GameMessages.h" + +void FvFacilityPipes::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "startFX") { + GameMessages::SendPlayFXEffect(self->GetObjectID(), m_LeftPipeEffectID, m_EffectType, m_LeftPipeEffectName); + GameMessages::SendPlayFXEffect(self->GetObjectID(), m_RightPipeEffectID, m_EffectType, m_RightPipeEffectName); + GameMessages::SendPlayFXEffect(self->GetObjectID(), m_ImaginationCanisterEffectID, m_EffectType, m_ImaginationCanisterEffectName); + } +} diff --git a/dScripts/ai/FV/FvFacilityPipes.h b/dScripts/ai/FV/FvFacilityPipes.h new file mode 100644 index 00000000..8a33976c --- /dev/null +++ b/dScripts/ai/FV/FvFacilityPipes.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +class FvFacilityPipes : public CppScripts::Script { +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +private: + const std::u16string m_EffectType = u"create"; + const std::string m_LeftPipeEffectName = "LeftPipeOff"; + const int32_t m_LeftPipeEffectID = 2774; + const std::string m_RightPipeEffectName = "RightPipeOff"; + const int32_t m_RightPipeEffectID = 2777; + const std::string m_ImaginationCanisterEffectName = "imagination_canister"; + const int32_t m_ImaginationCanisterEffectID = 2750; +}; diff --git a/dScripts/ai/FV/FvFlyingCreviceDragon.cpp b/dScripts/ai/FV/FvFlyingCreviceDragon.cpp new file mode 100644 index 00000000..16eda512 --- /dev/null +++ b/dScripts/ai/FV/FvFlyingCreviceDragon.cpp @@ -0,0 +1,107 @@ +#include "FvFlyingCreviceDragon.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "SkillComponent.h" +#include "GeneralUtils.h" + +void FvFlyingCreviceDragon::OnStartup(Entity* self) { + self->AddTimer("waypoint", 5); +} + +void FvFlyingCreviceDragon::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "waypoint") { + auto point = self->GetVar<int32_t>(u"waypoint"); + + if (point >= 20) { + point = 0; + } + + self->SetVar<int32_t>(u"waypoint", point + 1); + + self->AddTimer("waypoint", 5); + + OnArrived(self); + + return; + } + + std::string groupName = ""; + + if (timerName == "platform1attack") { + groupName = "dragonFireballs1"; + } else if (timerName == "platform3attack") { + groupName = "dragonFireballs3"; + } + + const auto& group = EntityManager::Instance()->GetEntitiesInGroup(groupName); + + if (group.empty()) { + return; + } + + auto* skillComponent = group[0]->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY, true); + } + + auto minionCount = 1; + for (size_t i = 1; i < group.size(); i++) { + if (minionCount == 4) { + return; + } + + if (/*GeneralUtils::GenerateRandomNumber<int32_t>(1, 5) > 3*/ true) { + skillComponent = group[i]->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY); + + ++minionCount; + } + } + } +} + +void FvFlyingCreviceDragon::OnArrived(Entity* self) { + auto point = self->GetVar<int32_t>(u"waypoint"); + + if (point == 4) { + GameMessages::SendPlayAnimation(self, u"attack1", 2); + self->AddTimer("platform1attack", 1.75f); + } else if (point == 12) { + GameMessages::SendPlayAnimation(self, u"attack2", 2); + + const auto& group2 = EntityManager::Instance()->GetEntitiesInGroup("dragonFireballs2"); + + if (group2.empty()) { + return; + } + + auto* skillComponent = group2[0]->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY); + } + + auto minionCount = 1; + for (size_t i = 1; i < group2.size(); i++) { + if (minionCount == 4) { + return; + } + + if (GeneralUtils::GenerateRandomNumber<int32_t>(1, 5) > 3) { + skillComponent = group2[i]->GetComponent<SkillComponent>(); + + if (skillComponent != nullptr) { + skillComponent->CalculateBehavior(762, 12506, LWOOBJID_EMPTY, true); + + ++minionCount; + } + } + } + } else if (point == 16) { + GameMessages::SendPlayAnimation(self, u"attack3", 2); + self->AddTimer("platform3attack", 0.5f); + } +} diff --git a/dScripts/ai/FV/FvFlyingCreviceDragon.h b/dScripts/ai/FV/FvFlyingCreviceDragon.h new file mode 100644 index 00000000..92e95d26 --- /dev/null +++ b/dScripts/ai/FV/FvFlyingCreviceDragon.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class FvFlyingCreviceDragon : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnArrived(Entity* self); +}; diff --git a/dScripts/ai/FV/FvFreeGfNinjas.cpp b/dScripts/ai/FV/FvFreeGfNinjas.cpp new file mode 100644 index 00000000..d690a6f7 --- /dev/null +++ b/dScripts/ai/FV/FvFreeGfNinjas.cpp @@ -0,0 +1,43 @@ +#include "FvFreeGfNinjas.h" +#include "Character.h" +#include "MissionComponent.h" +#include "eMissionState.h" + +void FvFreeGfNinjas::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 705 && missionState == eMissionState::AVAILABLE) { + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; + + missionComponent->AcceptMission(701); + missionComponent->AcceptMission(702); + missionComponent->AcceptMission(703); + missionComponent->AcceptMission(704); + + auto* character = target->GetCharacter(); + if (character != nullptr) + character->SetPlayerFlag(68, true); + } else if (missionID == 786) { + auto* character = target->GetCharacter(); + if (character != nullptr) + character->SetPlayerFlag(81, true); + } +} + +void FvFreeGfNinjas::OnUse(Entity* self, Entity* user) { + // To allow player who already have the mission to progress. + auto* missionComponent = user->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; + + if (missionComponent->GetMissionState(705) == eMissionState::ACTIVE) { + auto* character = user->GetCharacter(); + if (character != nullptr) + character->SetPlayerFlag(68, true); + + missionComponent->AcceptMission(701, true); + missionComponent->AcceptMission(702, true); + missionComponent->AcceptMission(703, true); + missionComponent->AcceptMission(704, true); + } +} diff --git a/dScripts/ai/FV/FvFreeGfNinjas.h b/dScripts/ai/FV/FvFreeGfNinjas.h new file mode 100644 index 00000000..01b0b6bd --- /dev/null +++ b/dScripts/ai/FV/FvFreeGfNinjas.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class FvFreeGfNinjas : public CppScripts::Script { +public: + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/FV/FvMaelstromGeyser.cpp b/dScripts/ai/FV/FvMaelstromGeyser.cpp new file mode 100644 index 00000000..66aa43dc --- /dev/null +++ b/dScripts/ai/FV/FvMaelstromGeyser.cpp @@ -0,0 +1,18 @@ +#include "FvMaelstromGeyser.h" +#include "SkillComponent.h" + +void FvMaelstromGeyser::OnStartup(Entity* self) { + self->AddTimer(m_StartSkillTimerName, m_StartSkillTimerTime); + self->AddTimer(m_KillSelfTimerName, m_KillSelfTimerTime); +} + +void FvMaelstromGeyser::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == m_StartSkillTimerName) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + skillComponent->CalculateBehavior(m_SkillID, m_BehaviorID, LWOOBJID_EMPTY, true); + } + if (timerName == m_KillSelfTimerName) { + self->Smash(LWOOBJID_EMPTY, eKillType::SILENT); + } +} + diff --git a/dScripts/ai/FV/FvMaelstromGeyser.h b/dScripts/ai/FV/FvMaelstromGeyser.h new file mode 100644 index 00000000..245eb56e --- /dev/null +++ b/dScripts/ai/FV/FvMaelstromGeyser.h @@ -0,0 +1,18 @@ +#pragma once +#include "CppScripts.h" + +class FvMaelstromGeyser final : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + + +private: + const std::string m_StartSkillTimerName = "startSkill"; + const float m_StartSkillTimerTime = 2.0; + const std::string m_KillSelfTimerName = "killSelf"; + const float m_KillSelfTimerTime = 5.5; + const uint32_t m_SkillID = 831; + const uint32_t m_BehaviorID = 15500; +}; diff --git a/dScripts/FvNinjaGuard.cpp b/dScripts/ai/FV/FvNinjaGuard.cpp similarity index 52% rename from dScripts/FvNinjaGuard.cpp rename to dScripts/ai/FV/FvNinjaGuard.cpp index dc2bb54b..58267999 100644 --- a/dScripts/FvNinjaGuard.cpp +++ b/dScripts/ai/FV/FvNinjaGuard.cpp @@ -1,23 +1,17 @@ -#include "FvNinjaGuard.h" +#include "FvNinjaGuard.h" #include "GameMessages.h" #include "MissionComponent.h" -void FvNinjaGuard::OnStartup(Entity* self) -{ - if (self->GetLOT() == 7412) - { +void FvNinjaGuard::OnStartup(Entity* self) { + if (self->GetLOT() == 7412) { m_LeftGuard = self->GetObjectID(); - } - else if (self->GetLOT() == 11128) - { + } else if (self->GetLOT() == 11128) { m_RightGuard = self->GetObjectID(); } } -void FvNinjaGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) -{ - if (emote != 392) - { +void FvNinjaGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* target) { + if (emote != 392) { GameMessages::SendPlayAnimation(self, u"no"); return; @@ -25,30 +19,17 @@ void FvNinjaGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* ta GameMessages::SendPlayAnimation(self, u"scared"); - auto* missionComponent = target->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr && missionComponent->HasMission(737)) - { - missionComponent->ForceProgressTaskType(737, 5, 1, false); - } - - if (self->GetLOT() == 7412) - { + if (self->GetLOT() == 7412) { auto* rightGuard = EntityManager::Instance()->GetEntity(m_RightGuard); - if (rightGuard != nullptr) - { + if (rightGuard != nullptr) { GameMessages::SendPlayAnimation(rightGuard, u"laugh_rt"); } - } - else if (self->GetLOT() == 11128) - { + } else if (self->GetLOT() == 11128) { auto* leftGuard = EntityManager::Instance()->GetEntity(m_LeftGuard); - if (leftGuard != nullptr) - { + if (leftGuard != nullptr) { GameMessages::SendPlayAnimation(leftGuard, u"laugh_lt"); } } } - diff --git a/dScripts/FvNinjaGuard.h b/dScripts/ai/FV/FvNinjaGuard.h similarity index 94% rename from dScripts/FvNinjaGuard.h rename to dScripts/ai/FV/FvNinjaGuard.h index f3deb140..8a87e8bc 100644 --- a/dScripts/FvNinjaGuard.h +++ b/dScripts/ai/FV/FvNinjaGuard.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" class FvNinjaGuard final : public CppScripts::Script diff --git a/dScripts/ai/FV/FvPandaServer.cpp b/dScripts/ai/FV/FvPandaServer.cpp new file mode 100644 index 00000000..f29f7f2e --- /dev/null +++ b/dScripts/ai/FV/FvPandaServer.cpp @@ -0,0 +1,36 @@ +#include "FvPandaServer.h" +#include "PetComponent.h" +#include "Character.h" +#include "ePetTamingNotifyType.h" + +void FvPandaServer::OnStartup(Entity* self) { + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { + self->SetNetworkVar<std::string>(u"pandatamer", std::to_string(self->GetVar<LWOOBJID>(u"tamer"))); + self->AddTimer("killSelf", 45); + } +} + +void FvPandaServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) { + if (type == ePetTamingNotifyType::BEGIN) { + self->CancelAllTimers(); + } else if (type == ePetTamingNotifyType::QUIT || type == ePetTamingNotifyType::FAILED) { + self->Smash(); + } else if (type == ePetTamingNotifyType::SUCCESS) { + // TODO: Remove from groups + + auto* character = tamer->GetCharacter(); + if (character != nullptr) { + character->SetPlayerFlag(82, true); + } + } +} + +void FvPandaServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "killSelf") { + const auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent != nullptr && petComponent->GetOwner() == nullptr) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } + } +} diff --git a/dScripts/ai/FV/FvPandaServer.h b/dScripts/ai/FV/FvPandaServer.h new file mode 100644 index 00000000..5db060a0 --- /dev/null +++ b/dScripts/ai/FV/FvPandaServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class FvPandaServer : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/ai/FV/FvPandaSpawnerServer.cpp b/dScripts/ai/FV/FvPandaSpawnerServer.cpp new file mode 100644 index 00000000..d7dcabcd --- /dev/null +++ b/dScripts/ai/FV/FvPandaSpawnerServer.cpp @@ -0,0 +1,49 @@ +#include "FvPandaSpawnerServer.h" +#include "Character.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "EntityInfo.h" +#include "ScriptedActivityComponent.h" + +void FvPandaSpawnerServer::OnCollisionPhantom(Entity* self, Entity* target) { + auto* character = target->GetCharacter(); + if (character != nullptr && character->GetPlayerFlag(81)) { + + auto raceObjects = EntityManager::Instance()->GetEntitiesInGroup("PandaRaceObject"); + if (raceObjects.empty()) + return; + + // Check if the player is currently in a footrace + auto* scriptedActivityComponent = raceObjects.at(0)->GetComponent<ScriptedActivityComponent>(); + if (scriptedActivityComponent == nullptr || !scriptedActivityComponent->IsPlayedBy(target)) + return; + + // If the player already spawned a panda + auto playerPandas = EntityManager::Instance()->GetEntitiesInGroup("panda" + std::to_string(target->GetObjectID())); + if (!playerPandas.empty()) { + GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"playerPanda", + target->GetObjectID(), 0, 0, target->GetObjectID()); + return; + } + + // If there's already too many spawned pandas + auto pandas = EntityManager::Instance()->GetEntitiesInGroup("pandas"); + if (pandas.size() > 4) { + GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"tooManyPandas", + target->GetObjectID(), 0, 0, target->GetObjectID()); + return; + } + + EntityInfo info{}; + info.spawnerID = target->GetObjectID(); + info.pos = self->GetPosition(); + info.lot = 5643; + info.settings = { + new LDFData<LWOOBJID>(u"tamer", target->GetObjectID()), + new LDFData<std::u16string>(u"groupID", u"panda" + (GeneralUtils::to_u16string(target->GetObjectID())) + u";pandas") + }; + + auto* panda = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(panda); + } +} diff --git a/dScripts/FvPandaSpawnerServer.h b/dScripts/ai/FV/FvPandaSpawnerServer.h similarity index 59% rename from dScripts/FvPandaSpawnerServer.h rename to dScripts/ai/FV/FvPandaSpawnerServer.h index 0aa459e5..5c138240 100644 --- a/dScripts/FvPandaSpawnerServer.h +++ b/dScripts/ai/FV/FvPandaSpawnerServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class FvPandaSpawnerServer : public CppScripts::Script { - void OnCollisionPhantom(Entity *self, Entity *target) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; }; diff --git a/dScripts/ai/FV/FvPassThroughWall.cpp b/dScripts/ai/FV/FvPassThroughWall.cpp new file mode 100644 index 00000000..08de5a77 --- /dev/null +++ b/dScripts/ai/FV/FvPassThroughWall.cpp @@ -0,0 +1,18 @@ +#include "FvPassThroughWall.h" +#include "InventoryComponent.h" +#include "MissionComponent.h" + +void FvPassThroughWall::OnCollisionPhantom(Entity* self, Entity* target) { + auto missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) return; + + //Because at the moment we do not have an ItemComponent component, we check to make sure a Maelstrom-Infused hood is equipped. There are only three in the game right now. + auto inventoryComponent = target->GetComponent<InventoryComponent>(); + // If no inventory component is found then abort. + if (inventoryComponent == nullptr) return; + // If no Maelstrom hoods are equipped then abort. + if (!inventoryComponent->IsEquipped(WhiteMaelstromHood) && !inventoryComponent->IsEquipped(BlackMaelstromHood) && !inventoryComponent->IsEquipped(RedMaelstromHood)) return; + + // Progress mission Friend of the Ninja since all prerequisites are met. + missionComponent->ForceProgress(friendOfTheNinjaMissionId, friendOfTheNinjaMissionUid, 1); +} diff --git a/dScripts/ai/FV/FvPassThroughWall.h b/dScripts/ai/FV/FvPassThroughWall.h new file mode 100644 index 00000000..2f996118 --- /dev/null +++ b/dScripts/ai/FV/FvPassThroughWall.h @@ -0,0 +1,34 @@ +#pragma once +#include "CppScripts.h" + +class FvPassThroughWall : public CppScripts::Script +{ + /** + * @brief This method is called when there is a collision with self from target. + * + * @param self The Entity that called this method. + * @param target The Entity that self is targetting. + */ + void OnCollisionPhantom(Entity* self, Entity* target) override; +private: + /** + * Mission ID for Friend of the Ninjas. + */ + int32_t friendOfTheNinjaMissionId = 848; + /** + * Mission UID for Friend of the Ninjas. + */ + int32_t friendOfTheNinjaMissionUid = 1221; + /** + * Item LOT for Maelstrom-Infused White Ninja Hood + */ + int32_t WhiteMaelstromHood = 2641; + /** + * Item LOT for Maelstrom-Infused Black Ninja Hood + */ + int32_t BlackMaelstromHood = 2642; + /** + * Item LOT for Red Ninja Hood - Maelstrom Infused + */ + int32_t RedMaelstromHood = 1889; +}; diff --git a/dScripts/ai/FV/TriggerGas.cpp b/dScripts/ai/FV/TriggerGas.cpp new file mode 100644 index 00000000..7e9762e3 --- /dev/null +++ b/dScripts/ai/FV/TriggerGas.cpp @@ -0,0 +1,49 @@ +#include "TriggerGas.h" +#include "InventoryComponent.h" +#include "SkillComponent.h" +#include "Entity.h" +#include "dLogger.h" + + +void TriggerGas::OnStartup(Entity* self) { + self->AddTimer(this->m_TimerName, this->m_Time); +} + +void TriggerGas::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target->IsPlayer()) return; + auto players = self->GetVar<std::vector<Entity*>>(u"players"); + players.push_back(target); + self->SetVar(u"players", players); +} + +void TriggerGas::OnOffCollisionPhantom(Entity* self, Entity* target) { + auto players = self->GetVar<std::vector<Entity*>>(u"players"); + if (!target->IsPlayer() || players.empty()) return; + auto position = std::find(players.begin(), players.end(), target); + if (position != players.end()) players.erase(position); + self->SetVar(u"players", players); +} + +void TriggerGas::OnTimerDone(Entity* self, std::string timerName) { + if (timerName != this->m_TimerName) return; + auto players = self->GetVar<std::vector<Entity*>>(u"players"); + for (auto player : players) { + if (player->GetIsDead() || !player){ + auto position = std::find(players.begin(), players.end(), player); + if (position != players.end()) players.erase(position); + continue; + } + auto inventoryComponent = player->GetComponent<InventoryComponent>(); + if (inventoryComponent) { + if (!inventoryComponent->IsEquipped(this->m_MaelstromHelmet)) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent) { + skillComponent->CastSkill(this->m_FogDamageSkill, player->GetObjectID()); + } + } + } + } + self->SetVar(u"players", players); + self->AddTimer(this->m_TimerName, this->m_Time); +} + diff --git a/dScripts/ai/FV/TriggerGas.h b/dScripts/ai/FV/TriggerGas.h new file mode 100644 index 00000000..284f2485 --- /dev/null +++ b/dScripts/ai/FV/TriggerGas.h @@ -0,0 +1,14 @@ +#pragma once +#include "CppScripts.h" + +class TriggerGas : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnOffCollisionPhantom(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + std::string m_TimerName = "gasTriggerDamage"; + float m_Time = 3.0f; + uint32_t m_MaelstromHelmet = 3068; + uint32_t m_FogDamageSkill = 103; +}; diff --git a/dScripts/ai/GENERAL/CMakeLists.txt b/dScripts/ai/GENERAL/CMakeLists.txt new file mode 100644 index 00000000..da973658 --- /dev/null +++ b/dScripts/ai/GENERAL/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_AI_GENERAL + "InstanceExitTransferPlayerToLastNonInstance.cpp" + "LegoDieRoll.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp new file mode 100644 index 00000000..de1c62e0 --- /dev/null +++ b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp @@ -0,0 +1,57 @@ +#include "InstanceExitTransferPlayerToLastNonInstance.h" +#include "GameMessages.h" +#include "Player.h" +#include "Character.h" +#include "dServer.h" +#include "eTerminateType.h" + +void InstanceExitTransferPlayerToLastNonInstance::OnUse(Entity* self, Entity* user) { + auto transferText = self->GetVar<std::u16string>(u"transferText"); + if (transferText.empty()) + transferText = u"DRAGON_EXIT_QUESTION"; + + GameMessages::SendDisplayMessageBox( + user->GetObjectID(), + true, + self->GetObjectID(), + u"Instance_Exit", + 1, + transferText, + u"", + user->GetSystemAddress() + ); +} + +void InstanceExitTransferPlayerToLastNonInstance::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { + auto* player = dynamic_cast<Player*>(sender); + if (player == nullptr) + return; + + auto* character = sender->GetCharacter(); + if (character != nullptr) { + if (identifier == u"Instance_Exit" && button == 1) { + auto lastInstance = character->GetLastNonInstanceZoneID(); + + // Sanity check + if (lastInstance == 0) { + switch (Game::server->GetZoneID()) { + case 2001: + lastInstance = 2000; + break; + case 1402: + lastInstance = 1400; + break; + default: + lastInstance = 1100; + break; + } + } + + player->SendToZone(lastInstance); + } + } + + GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); +} + + diff --git a/dScripts/InstanceExitTransferPlayerToLastNonInstance.h b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.h similarity index 95% rename from dScripts/InstanceExitTransferPlayerToLastNonInstance.h rename to dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.h index 3321191d..01e9fe3f 100644 --- a/dScripts/InstanceExitTransferPlayerToLastNonInstance.h +++ b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.h @@ -1,7 +1,7 @@ #pragma once #include "CppScripts.h" -class InstanceExitTransferPlayerToLastNonInstance : public CppScripts::Script +class InstanceExitTransferPlayerToLastNonInstance : public CppScripts::Script { public: void OnUse(Entity* self, Entity* user) override; diff --git a/dScripts/ai/GENERAL/LegoDieRoll.cpp b/dScripts/ai/GENERAL/LegoDieRoll.cpp new file mode 100644 index 00000000..18082065 --- /dev/null +++ b/dScripts/ai/GENERAL/LegoDieRoll.cpp @@ -0,0 +1,53 @@ +#include "LegoDieRoll.h" +#include "Entity.h" +#include "GameMessages.h" +#include "MissionComponent.h" +#include "eMissionState.h" + +void LegoDieRoll::OnStartup(Entity* self) { + self->AddTimer("DoneRolling", 10.0f); + self->AddTimer("ThrowDice", LegoDieRoll::animTime); +} + +void LegoDieRoll::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "DoneRolling") { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } else if (timerName == "ThrowDice") { + int dieRoll = GeneralUtils::GenerateRandomNumber<int>(1, 6); + + switch (dieRoll) { + case 1: + GameMessages::SendPlayAnimation(self, u"roll-die-1"); + break; + case 2: + GameMessages::SendPlayAnimation(self, u"roll-die-2"); + break; + case 3: + GameMessages::SendPlayAnimation(self, u"roll-die-3"); + break; + case 4: + GameMessages::SendPlayAnimation(self, u"roll-die-4"); + break; + case 5: + GameMessages::SendPlayAnimation(self, u"roll-die-5"); + break; + case 6: + { + GameMessages::SendPlayAnimation(self, u"roll-die-6"); + // tracking the It's Truly Random Achievement + auto* owner = self->GetOwner(); + auto* missionComponent = owner->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + const auto rollMissionState = missionComponent->GetMissionState(756); + if (rollMissionState == eMissionState::ACTIVE) { + missionComponent->ForceProgress(756, 1103, 1); + } + } + break; + } + default: + break; + } + } +} diff --git a/dScripts/LegoDieRoll.h b/dScripts/ai/GENERAL/LegoDieRoll.h similarity index 79% rename from dScripts/LegoDieRoll.h rename to dScripts/ai/GENERAL/LegoDieRoll.h index 3b28d529..ea047e04 100644 --- a/dScripts/LegoDieRoll.h +++ b/dScripts/ai/GENERAL/LegoDieRoll.h @@ -6,6 +6,6 @@ public: void OnStartup(Entity* self); void OnTimerDone(Entity* self, std::string timerName); private: - constexpr static const float animTime = 2.0f; + constexpr static const float animTime = 2.0f; }; diff --git a/dScripts/ai/GF/CMakeLists.txt b/dScripts/ai/GF/CMakeLists.txt new file mode 100644 index 00000000..9937618c --- /dev/null +++ b/dScripts/ai/GF/CMakeLists.txt @@ -0,0 +1,14 @@ +set(DSCRIPTS_SOURCES_AI_GF + "GfCampfire.cpp" + "GfOrgan.cpp" + "GfBanana.cpp" + "GfBananaCluster.cpp" + "GfJailkeepMission.cpp" + "TriggerAmbush.cpp" + "GfJailWalls.cpp" + "PetDigBuild.cpp" + "GfArchway.cpp" + "GfMaelstromGeyser.cpp" + "PirateRep.cpp" + "GfParrotCrash.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/GF/GfArchway.cpp b/dScripts/ai/GF/GfArchway.cpp new file mode 100644 index 00000000..429f62ae --- /dev/null +++ b/dScripts/ai/GF/GfArchway.cpp @@ -0,0 +1,8 @@ +#include "GfArchway.h" +#include "Entity.h" +#include "SkillComponent.h" + +void GfArchway::OnRebuildComplete(Entity* self, Entity* target) { + auto* skillComponent = target->GetComponent<SkillComponent>(); + if (skillComponent) skillComponent->CalculateBehavior(SHIELDING_SKILL, SHIELDING_BEHAVIOR, target->GetObjectID(), true); +} diff --git a/dScripts/ai/GF/GfArchway.h b/dScripts/ai/GF/GfArchway.h new file mode 100644 index 00000000..b60b2a9f --- /dev/null +++ b/dScripts/ai/GF/GfArchway.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class GfArchway : public CppScripts::Script { +public: + void OnRebuildComplete(Entity* self, Entity* target) override; +private: + const uint32_t SHIELDING_SKILL = 863; + const uint32_t SHIELDING_BEHAVIOR = 3788; +}; diff --git a/dScripts/GfBanana.cpp b/dScripts/ai/GF/GfBanana.cpp similarity index 82% rename from dScripts/GfBanana.cpp rename to dScripts/ai/GF/GfBanana.cpp index 346c9ad7..95a831cd 100644 --- a/dScripts/GfBanana.cpp +++ b/dScripts/ai/GF/GfBanana.cpp @@ -1,19 +1,19 @@ -#include "GfBanana.h" +#include "GfBanana.h" #include "Entity.h" #include "DestroyableComponent.h" +#include "EntityInfo.h" #include "EntityManager.h" -void GfBanana::SpawnBanana(Entity* self) -{ +void GfBanana::SpawnBanana(Entity* self) { auto position = self->GetPosition(); const auto rotation = self->GetRotation(); - + position.y += 12; position.x -= rotation.GetRightVector().x * 5; position.z -= rotation.GetRightVector().z * 5; - EntityInfo info {}; + EntityInfo info{}; info.pos = position; info.rot = rotation; @@ -26,21 +26,18 @@ void GfBanana::SpawnBanana(Entity* self) self->SetVar(u"banana", entity->GetObjectID()); - entity->AddDieCallback([self]() - { + entity->AddDieCallback([self]() { self->SetVar(u"banana", LWOOBJID_EMPTY); self->AddTimer("bananaTimer", 30); - }); + }); } -void GfBanana::OnStartup(Entity* self) -{ +void GfBanana::OnStartup(Entity* self) { SpawnBanana(self); } -void GfBanana::OnHit(Entity* self, Entity* attacker) -{ +void GfBanana::OnHit(Entity* self, Entity* attacker) { auto* destroyable = self->GetComponent<DestroyableComponent>(); destroyable->SetHealth(9999); @@ -51,15 +48,14 @@ void GfBanana::OnHit(Entity* self, Entity* attacker) auto* bananaEntity = EntityManager::Instance()->GetEntity(bananaId); - if (bananaEntity == nullptr) - { + if (bananaEntity == nullptr) { self->SetVar(u"banana", LWOOBJID_EMPTY); self->AddTimer("bananaTimer", 30); return; } - + bananaEntity->SetPosition(bananaEntity->GetPosition() - NiPoint3::UNIT_Y * 8); auto* bananaDestroyable = bananaEntity->GetComponent<DestroyableComponent>(); @@ -71,7 +67,7 @@ void GfBanana::OnHit(Entity* self, Entity* attacker) /* auto position = self->GetPosition(); const auto rotation = self->GetRotation(); - + position.y += 12; position.x -= rotation.GetRightVector().x * 5; position.z -= rotation.GetRightVector().z * 5; @@ -91,10 +87,8 @@ void GfBanana::OnHit(Entity* self, Entity* attacker) EntityManager::Instance()->SerializeEntity(self); } -void GfBanana::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "bananaTimer") - { +void GfBanana::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "bananaTimer") { SpawnBanana(self); } -} \ No newline at end of file +} diff --git a/dScripts/GfBanana.h b/dScripts/ai/GF/GfBanana.h similarity index 93% rename from dScripts/GfBanana.h rename to dScripts/ai/GF/GfBanana.h index d572c8d9..a33bddf6 100644 --- a/dScripts/GfBanana.h +++ b/dScripts/ai/GF/GfBanana.h @@ -1,13 +1,13 @@ -#pragma once +#pragma once #include "CppScripts.h" class GfBanana final : public CppScripts::Script { public: void SpawnBanana(Entity* self); - + void OnStartup(Entity* self) override; - + void OnHit(Entity* self, Entity* attacker) override; void OnTimerDone(Entity* self, std::string timerName) override; diff --git a/dScripts/GfBananaCluster.cpp b/dScripts/ai/GF/GfBananaCluster.cpp similarity index 58% rename from dScripts/GfBananaCluster.cpp rename to dScripts/ai/GF/GfBananaCluster.cpp index aacba224..6e5e91db 100644 --- a/dScripts/GfBananaCluster.cpp +++ b/dScripts/ai/GF/GfBananaCluster.cpp @@ -1,15 +1,12 @@ -#include "GfBananaCluster.h" +#include "GfBananaCluster.h" #include "Entity.h" -void GfBananaCluster::OnStartup(Entity* self) -{ +void GfBananaCluster::OnStartup(Entity* self) { self->AddTimer("startup", 100); } -void GfBananaCluster::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "startup") - { +void GfBananaCluster::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "startup") { self->ScheduleKillAfterUpdate(nullptr); } } diff --git a/dScripts/GfBananaCluster.h b/dScripts/ai/GF/GfBananaCluster.h similarity index 92% rename from dScripts/GfBananaCluster.h rename to dScripts/ai/GF/GfBananaCluster.h index 05e5ee0a..81bb8b0b 100644 --- a/dScripts/GfBananaCluster.h +++ b/dScripts/ai/GF/GfBananaCluster.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CppScripts.h" class GfBananaCluster final : public CppScripts::Script diff --git a/dScripts/GfCampfire.cpp b/dScripts/ai/GF/GfCampfire.cpp similarity index 64% rename from dScripts/GfCampfire.cpp rename to dScripts/ai/GF/GfCampfire.cpp index 48170c66..6a10b39e 100644 --- a/dScripts/GfCampfire.cpp +++ b/dScripts/ai/GF/GfCampfire.cpp @@ -4,24 +4,24 @@ #include "MissionComponent.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "eReplicaComponentType.h" void GfCampfire::OnStartup(Entity* self) { self->SetI32(u"counter", static_cast<int32_t>(0)); self->SetProximityRadius(2.0f, "placeholder"); self->SetBoolean(u"isBurning", true); - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; render->PlayEffect(295, u"running", "Burn"); } -void GfCampfire::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { - if (args == "physicsReady") - { - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); +void GfCampfire::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "physicsReady") { + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); render->PlayEffect(295, u"running", "Burn"); } @@ -45,14 +45,12 @@ void GfCampfire::OnProximityUpdate(Entity* self, Entity* entering, std::string n auto* missionComponet = entering->GetComponent<MissionComponent>(); - if (missionComponet != nullptr) - { + if (missionComponet != nullptr) { missionComponet->ForceProgress(440, 658, 1); } } } - } - else { + } else { int32_t counter = self->GetI32(u"counter"); if (counter > 0) { counter = counter - 1; @@ -65,22 +63,21 @@ void GfCampfire::OnProximityUpdate(Entity* self, Entity* entering, std::string n } } -void GfCampfire::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { - if (message == "waterspray" && self->GetVar<bool>(u"isBurning")) { - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("Burn"); - renderComponent->PlayEffect(295, u"idle", "Off"); +void GfCampfire::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { + if (message == "waterspray" && self->GetVar<bool>(u"isBurning")) { + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("Burn"); + renderComponent->PlayEffect(295, u"idle", "Off"); - self->SetVar<bool>(u"isBurning", false); - self->AddTimer("FireRestart", 37); - } - } + self->SetVar<bool>(u"isBurning", false); + self->AddTimer("FireRestart", 37); + } + } } void GfCampfire::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "TimeBetweenCast") - { + if (timerName == "TimeBetweenCast") { /* self->AddTimer("TimeBetweenCast", FIRE_COOLDOWN); @@ -90,15 +87,15 @@ void GfCampfire::OnTimerDone(Entity* self, std::string timerName) { if (entering == nullptr) { - + } */ } else if (timerName == "FireRestart" && !self->GetVar<bool>(u"isBurning")) { - auto* renderComponent = self->GetComponent<RenderComponent>(); - if (renderComponent != nullptr) { - renderComponent->StopEffect("Off"); - renderComponent->PlayEffect(295, u"running", "Burn"); - self->SetVar<bool>(u"isBurning", true); - } + auto* renderComponent = self->GetComponent<RenderComponent>(); + if (renderComponent != nullptr) { + renderComponent->StopEffect("Off"); + renderComponent->PlayEffect(295, u"running", "Burn"); + self->SetVar<bool>(u"isBurning", true); + } } } diff --git a/dScripts/GfCampfire.h b/dScripts/ai/GF/GfCampfire.h similarity index 58% rename from dScripts/GfCampfire.h rename to dScripts/ai/GF/GfCampfire.h index 9e678419..b1d61721 100644 --- a/dScripts/GfCampfire.h +++ b/dScripts/ai/GF/GfCampfire.h @@ -1,16 +1,16 @@ #pragma once #include "CppScripts.h" -class GfCampfire : public CppScripts::Script +class GfCampfire : public CppScripts::Script { public: void OnStartup(Entity* self) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; void OnTimerDone(Entity* self, std::string timerName) override; - void OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) override; + void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; private: int32_t m_skillCastId = 43; int32_t FIRE_COOLDOWN = 2; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/GF/GfJailWalls.cpp b/dScripts/ai/GF/GfJailWalls.cpp new file mode 100644 index 00000000..1835faa2 --- /dev/null +++ b/dScripts/ai/GF/GfJailWalls.cpp @@ -0,0 +1,30 @@ +#include "GfJailWalls.h" +#include "dZoneManager.h" +#include "GeneralUtils.h" +#include "eRebuildState.h" + +void GfJailWalls::OnRebuildComplete(Entity* self, Entity* target) { + const auto wall = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Wall")); + + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("Jail0" + wall)) { + spawner->Deactivate(); + } + + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("JailCaptain0" + wall)) { + spawner->Deactivate(); + } +} + +void GfJailWalls::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state != eRebuildState::RESETTING) return; + + const auto wall = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"Wall")); + + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("Jail0" + wall)) { + spawner->Activate(); + } + + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName("JailCaptain0" + wall)) { + spawner->Activate(); + } +} diff --git a/dScripts/ai/GF/GfJailWalls.h b/dScripts/ai/GF/GfJailWalls.h new file mode 100644 index 00000000..f755f4d7 --- /dev/null +++ b/dScripts/ai/GF/GfJailWalls.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class GfJailWalls final : public CppScripts::Script +{ +public: + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; +}; diff --git a/dScripts/ai/GF/GfJailkeepMission.cpp b/dScripts/ai/GF/GfJailkeepMission.cpp new file mode 100644 index 00000000..b8d4cd30 --- /dev/null +++ b/dScripts/ai/GF/GfJailkeepMission.cpp @@ -0,0 +1,39 @@ +#include "GfJailkeepMission.h" +#include "MissionComponent.h" +#include "Character.h" +#include "eMissionState.h" + +void GfJailkeepMission::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; + + if (missionID == 385 && missionState == eMissionState::AVAILABLE) { + missionComponent->AcceptMission(386, true); + missionComponent->AcceptMission(387, true); + missionComponent->AcceptMission(388, true); + missionComponent->AcceptMission(390, true); + } else if (missionID == 385 && missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + auto* character = target->GetCharacter(); + if (character != nullptr && character->GetPlayerFlag(68)) { + missionComponent->AcceptMission(701); + missionComponent->AcceptMission(702); + missionComponent->AcceptMission(703); + missionComponent->AcceptMission(704); + } + } +} + +void GfJailkeepMission::OnUse(Entity* self, Entity* user) { + auto* missionComponent = user->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; + + if (missionComponent->GetMissionState(385) == eMissionState::ACTIVE) { + missionComponent->AcceptMission(386, true); + missionComponent->AcceptMission(387, true); + missionComponent->AcceptMission(388, true); + missionComponent->AcceptMission(390, true); + } +} + diff --git a/dScripts/ai/GF/GfJailkeepMission.h b/dScripts/ai/GF/GfJailkeepMission.h new file mode 100644 index 00000000..651a6e1b --- /dev/null +++ b/dScripts/ai/GF/GfJailkeepMission.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class GfJailkeepMission final : public CppScripts::Script +{ +public: + void OnUse(Entity* self, Entity* user) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +}; diff --git a/dScripts/ai/GF/GfMaelstromGeyser.cpp b/dScripts/ai/GF/GfMaelstromGeyser.cpp new file mode 100644 index 00000000..825307a7 --- /dev/null +++ b/dScripts/ai/GF/GfMaelstromGeyser.cpp @@ -0,0 +1,18 @@ +#include "GfMaelstromGeyser.h" +#include "SkillComponent.h" + +void GfMaelstromGeyser::OnStartup(Entity* self) { + self->AddTimer(m_StartSkillTimerName, m_StartSkillTimerTime); + self->AddTimer(m_KillSelfTimerName, m_KillSelfTimerTime); +} + +void GfMaelstromGeyser::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == m_StartSkillTimerName) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + skillComponent->CalculateBehavior(m_SkillID, m_BehaviorID, LWOOBJID_EMPTY, true); + } + if (timerName == m_KillSelfTimerName) { + self->Smash(LWOOBJID_EMPTY, eKillType::SILENT); + } +} + diff --git a/dScripts/ai/GF/GfMaelstromGeyser.h b/dScripts/ai/GF/GfMaelstromGeyser.h new file mode 100644 index 00000000..60e42798 --- /dev/null +++ b/dScripts/ai/GF/GfMaelstromGeyser.h @@ -0,0 +1,17 @@ +#pragma once +#include "CppScripts.h" + +class GfMaelstromGeyser final : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + const std::string m_StartSkillTimerName = "startSkill"; + const float m_StartSkillTimerTime = 2.0; + const std::string m_KillSelfTimerName = "killSelf"; + const float m_KillSelfTimerTime = 7.5; + const uint32_t m_SkillID = 607; + const uint32_t m_BehaviorID = 10500; +}; diff --git a/dScripts/GfOrgan.cpp b/dScripts/ai/GF/GfOrgan.cpp similarity index 100% rename from dScripts/GfOrgan.cpp rename to dScripts/ai/GF/GfOrgan.cpp diff --git a/dScripts/GfOrgan.h b/dScripts/ai/GF/GfOrgan.h similarity index 98% rename from dScripts/GfOrgan.h rename to dScripts/ai/GF/GfOrgan.h index 1ebd66a6..6af2d554 100644 --- a/dScripts/GfOrgan.h +++ b/dScripts/ai/GF/GfOrgan.h @@ -8,4 +8,4 @@ public: void OnTimerDone(Entity* self, std::string timerName); private: bool m_canUse; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/GF/GfParrotCrash.cpp b/dScripts/ai/GF/GfParrotCrash.cpp new file mode 100644 index 00000000..6b76a51d --- /dev/null +++ b/dScripts/ai/GF/GfParrotCrash.cpp @@ -0,0 +1,13 @@ +#include "GfParrotCrash.h" +#include "SkillComponent.h" +#include "Entity.h" +#include "dLogger.h" + +void GfParrotCrash::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (args == "Slow") { + skillComponent->CalculateBehavior(m_SlowSkillID, m_SlowBehaviorID, sender->GetObjectID()); + } else if (args == "Unslow") { + skillComponent->CalculateBehavior(m_UnslowSkillID, m_UnslowBehaviorID, sender->GetObjectID()); + } +} diff --git a/dScripts/ai/GF/GfParrotCrash.h b/dScripts/ai/GF/GfParrotCrash.h new file mode 100644 index 00000000..fe70a16c --- /dev/null +++ b/dScripts/ai/GF/GfParrotCrash.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class GfParrotCrash : public CppScripts::Script { +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +private: + const uint32_t m_SlowSkillID = 795; + const uint32_t m_SlowBehaviorID = 14214; + const uint32_t m_UnslowSkillID = 796; + const uint32_t m_UnslowBehaviorID = 14215; +}; + diff --git a/dScripts/ai/GF/PetDigBuild.cpp b/dScripts/ai/GF/PetDigBuild.cpp new file mode 100644 index 00000000..504a1199 --- /dev/null +++ b/dScripts/ai/GF/PetDigBuild.cpp @@ -0,0 +1,51 @@ +#include "PetDigBuild.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "MissionComponent.h" +#include "eMissionState.h" + +void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { + auto flagNumber = self->GetVar<std::u16string>(u"flagNum"); + + EntityInfo info{}; + auto pos = self->GetPosition(); + pos.SetY(pos.GetY() + 0.5f); + info.pos = pos; + info.rot = self->GetRotation(); + info.spawnerID = self->GetSpawnerID(); + info.settings = { + new LDFData<LWOOBJID>(u"builder", target->GetObjectID()), + new LDFData<LWOOBJID>(u"X", self->GetObjectID()) + }; + + if (!flagNumber.empty()) { + info.lot = 7410; // Normal GF treasure + info.settings.push_back(new LDFData<std::u16string>(u"groupID", u"Flag" + flagNumber)); + } else { + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent != nullptr && missionComponent->GetMissionState(746) == eMissionState::ACTIVE) { + info.lot = 9307; // Special Captain Jack treasure that drops a mission item + } else { + info.lot = 3495; // Normal AG treasure + } + } + + auto* treasure = EntityManager::Instance()->CreateEntity(info); + EntityManager::Instance()->ConstructEntity(treasure); + self->SetVar<LWOOBJID>(u"chestObj", treasure->GetObjectID()); +} + +void PetDigBuild::OnDie(Entity* self, Entity* killer) { + auto treasureID = self->GetVar<LWOOBJID>(u"chestObj"); + if (treasureID == LWOOBJID_EMPTY) + return; + + auto treasure = EntityManager::Instance()->GetEntity(treasureID); + if (treasure == nullptr) + return; + + // If the quick build expired and the treasure was not collected, hide the treasure + if (!treasure->GetIsDead()) { + treasure->Smash(self->GetObjectID(), eKillType::SILENT); + } +} diff --git a/dScripts/ai/GF/PetDigBuild.h b/dScripts/ai/GF/PetDigBuild.h new file mode 100644 index 00000000..f342d7bb --- /dev/null +++ b/dScripts/ai/GF/PetDigBuild.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class PetDigBuild : public CppScripts::Script +{ +public: + void OnRebuildComplete(Entity* self, Entity* target); + void OnDie(Entity* self, Entity* killer); +}; diff --git a/dScripts/ai/GF/PirateRep.cpp b/dScripts/ai/GF/PirateRep.cpp new file mode 100644 index 00000000..33d6ab63 --- /dev/null +++ b/dScripts/ai/GF/PirateRep.cpp @@ -0,0 +1,14 @@ +#include "PirateRep.h" +#include "Character.h" +#include "eMissionState.h" +#include "Entity.h" +#include "ePlayerFlag.h" + +void PirateRep::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == m_PirateRepMissionID && missionState >= eMissionState::READY_TO_COMPLETE) { + auto* character = target->GetCharacter(); + if (character) { + character->SetPlayerFlag(ePlayerFlag::GF_PIRATE_REP, true); + } + } +} diff --git a/dScripts/ai/GF/PirateRep.h b/dScripts/ai/GF/PirateRep.h new file mode 100644 index 00000000..754971be --- /dev/null +++ b/dScripts/ai/GF/PirateRep.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class PirateRep : public CppScripts::Script { +public: + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +private: + const int m_PirateRepMissionID = 301; +}; diff --git a/dScripts/TriggerAmbush.cpp b/dScripts/ai/GF/TriggerAmbush.cpp similarity index 78% rename from dScripts/TriggerAmbush.cpp rename to dScripts/ai/GF/TriggerAmbush.cpp index f9fb8cf7..726b45d7 100644 --- a/dScripts/TriggerAmbush.cpp +++ b/dScripts/ai/GF/TriggerAmbush.cpp @@ -1,14 +1,12 @@ -#include "TriggerAmbush.h" +#include "TriggerAmbush.h" #include "dZoneManager.h" -void TriggerAmbush::OnStartup(Entity* self) -{ +void TriggerAmbush::OnStartup(Entity* self) { self->SetProximityRadius(20, "ambush"); } -void TriggerAmbush::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) -{ +void TriggerAmbush::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { if (name != "ambush" || status != "ENTER" || !entering->IsPlayer()) return; if (self->GetVar<bool>(u"triggered")) return; @@ -17,26 +15,23 @@ void TriggerAmbush::OnProximityUpdate(Entity* self, Entity* entering, std::strin const auto spawners = dZoneManager::Instance()->GetSpawnersByName("Ambush"); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Activate(); } self->AddTimer("TriggeredTimer", 45); } -void TriggerAmbush::OnTimerDone(Entity* self, std::string timerName) -{ +void TriggerAmbush::OnTimerDone(Entity* self, std::string timerName) { if (timerName != "TriggeredTimer") return; self->SetVar(u"triggered", false); const auto spawners = dZoneManager::Instance()->GetSpawnersByName("Ambush"); - for (auto* spawner : spawners) - { + for (auto* spawner : spawners) { spawner->Reset(); - + spawner->Deactivate(); } } diff --git a/dScripts/TriggerAmbush.h b/dScripts/ai/GF/TriggerAmbush.h similarity index 93% rename from dScripts/TriggerAmbush.h rename to dScripts/ai/GF/TriggerAmbush.h index 2ca7cd36..e4388fbe 100644 --- a/dScripts/TriggerAmbush.h +++ b/dScripts/ai/GF/TriggerAmbush.h @@ -1,12 +1,12 @@ -#pragma once +#pragma once #include "CppScripts.h" class TriggerAmbush : public CppScripts::Script { public: void OnStartup(Entity* self) override; - + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; - + void OnTimerDone(Entity* self, std::string timerName) override; }; diff --git a/dScripts/ai/MINIGAME/CMakeLists.txt b/dScripts/ai/MINIGAME/CMakeLists.txt new file mode 100644 index 00000000..d4517519 --- /dev/null +++ b/dScripts/ai/MINIGAME/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DSCRIPTS_SOURCES_AI_MINIGAME) + +add_subdirectory(SG_GF) + +foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF}) + set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} "SG_GF/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} PARENT_SCOPE) diff --git a/dScripts/ai/MINIGAME/SG_GF/CMakeLists.txt b/dScripts/ai/MINIGAME/SG_GF/CMakeLists.txt new file mode 100644 index 00000000..87bd879a --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF + "ZoneSGServer.cpp") + +add_subdirectory(SERVER) + +foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF_SERVER}) + set(DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF ${DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF} "SERVER/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF ${DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF} PARENT_SCOPE) diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/CMakeLists.txt b/dScripts/ai/MINIGAME/SG_GF/SERVER/CMakeLists.txt new file mode 100644 index 00000000..fb79c0e9 --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_MINIGAME_SG_GF_SERVER + "SGCannon.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp new file mode 100644 index 00000000..50cd229a --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -0,0 +1,1077 @@ +#include "SGCannon.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "dZoneManager.h" +#include "Player.h" +#include "Character.h" +#include "ShootingGalleryComponent.h" +#include "PossessorComponent.h" +#include "CharacterComponent.h" +#include "SimplePhysicsComponent.h" +#include "MovementAIComponent.h" +#include "../dWorldServer/ObjectIDManager.h" +#include "MissionComponent.h" +#include "Loot.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" +#include "eGameActivity.h" + +void SGCannon::OnStartup(Entity* self) { + Game::logger->Log("SGCannon", "OnStartup"); + + m_Waves = GetWaves(); + constants = GetConstants(); + + ResetVars(self); + + self->SetVar<bool>(GameStartedVariable, false); + self->SetVar<Vector3>(InitialVelocityVariable, {}); + self->SetVar<uint32_t>(ImpactSkillVariale, constants.impactSkillID); + + auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); + if (shootingGalleryComponent != nullptr) { + shootingGalleryComponent->SetStaticParams({ + Vector3 { -327.8609924316406, 256.8999938964844, 1.6482199430465698 }, + Vector3 { -181.4320068359375, 212.39999389648438, 2.5182199478149414 } + }); + + shootingGalleryComponent->SetDynamicParams({ + Vector3 { 0.0, 4.3, 9.0 }, + Vector3 { }, + 129.0, + 800.0, + 30.0, + 0.0, + -1.0, + 58.6 + }); + } + + self->SetVar<uint32_t>(TimeLimitVariable, 30); + self->SetVar<std::vector<LOT>>(ValidActorsVariable, { 3109, 3110, 3111, 3112, 3125, 3126 }); + self->SetVar<std::vector<LOT>>(ValidEffectsVariable, { 3122 }); + self->SetVar<std::vector<uint32_t>>(StreakBonusVariable, { 1, 2, 5, 10 }); + self->SetVar<bool>(SuperChargeActiveVariable, false); + self->SetVar<uint32_t>(MatrixVariable, 1); + self->SetVar<bool>(InitVariable, true); + + auto* simplePhysicsComponent = self->GetComponent<SimplePhysicsComponent>(); + + if (simplePhysicsComponent != nullptr) { + simplePhysicsComponent->SetPhysicsMotionState(5); + } +} + +void SGCannon::OnPlayerLoaded(Entity* self, Entity* player) { + Game::logger->Log("SGCannon", "Player loaded"); + self->SetVar<LWOOBJID>(PlayerIDVariable, player->GetObjectID()); +} + +void SGCannon::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + Script::OnFireEventServerSide(self, sender, args, param1, param2, param3); +} + +void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int32_t value1, int32_t value2, + const std::u16string& stringValue) { + Game::logger->Log("SGCannon", "Got activity state change request: %s", GeneralUtils::UTF16ToWTF8(stringValue).c_str()); + if (stringValue == u"clientready") { + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + Game::logger->Log("SGCannon", "Player is ready"); + /*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true);*/ + + Game::logger->Log("SGCannon", "Sending ActivityEnter"); + + GameMessages::SendActivityEnter(self->GetObjectID(), player->GetSystemAddress()); + + auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); + + if (shootingGalleryComponent != nullptr) { + shootingGalleryComponent->SetCurrentPlayerID(player->GetObjectID()); + + Game::logger->Log("SGCannon", "Setting player ID"); + + EntityManager::Instance()->SerializeEntity(self); + } else { + Game::logger->Log("SGCannon", "Shooting gallery component is null"); + } + + auto* characterComponent = player->GetComponent<CharacterComponent>(); + + if (characterComponent != nullptr) { + characterComponent->SetIsRacing(true); + characterComponent->SetCurrentActivity(eGameActivity::SHOOTING_GALLERY); + auto possessor = player->GetComponent<PossessorComponent>(); + if (possessor) { + possessor->SetPossessable(self->GetObjectID()); + possessor->SetPossessableType(ePossessionType::NO_POSSESSION); + } + + EntityManager::Instance()->SerializeEntity(player); + } + + self->SetNetworkVar<bool>(HideScoreBoardVariable, true); + self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); + self->SetNetworkVar<bool>(ShowLoadingUI, true); + + /* + GameMessages::SendTeleport( + player->GetObjectID(), + {-292.6415710449219, 230.20237731933594, -3.9090466499328613}, + {0.7067984342575073, -6.527870573336259e-05, 0.707414984703064, 0.00021762956748716533}, + player->GetSystemAddress(), true + ); + */ + + //GameMessages::SendRequestActivityEnter(self->GetObjectID(), player->GetSystemAddress(), false, player->GetObjectID()); + } else { + Game::logger->Log("SGCannon", "Player not found"); + } + } else if (value1 == 1200) { + StartGame(self); + } +} + +void SGCannon::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, + const std::u16string& userData) { + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + if (button == 1 && identifier == u"Shooting_Gallery_Stop") { + UpdatePlayer(self, player->GetObjectID(), true); + RemovePlayer(player->GetObjectID()); + StopGame(self, true); + return; + } + + if (identifier == u"Scoreboardinfo") { + GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, + dZoneManager::Instance()->GetZoneControlObject()->GetObjectID(), + u"Shooting_Gallery_Retry?", 2, u"Retry?", + u"", player->GetSystemAddress()); + } else { + if ((button == 1 && (identifier == u"Shooting_Gallery_Retry" || identifier == u"RePlay")) + || identifier == u"SG1" || button == 0) { + + if (identifier == u"RePlay") { + static_cast<Player*>(player)->SendToZone(1300); + + return; + } + + self->SetNetworkVar<bool>(ClearVariable, true); + StartGame(self); + } else if (button == 1 && identifier == u"Shooting_Gallery_Exit") { + UpdatePlayer(self, player->GetObjectID(), true); + RemovePlayer(player->GetObjectID()); + } + } + } +} + +void SGCannon::OnActivityTimerDone(Entity* self, const std::string& name) { + if (name == SuperChargeTimer && !self->GetVar<bool>(SuperChargePausedVariable)) { + if (self->GetVar<bool>(WaveStatusVariable) || self->GetVar<uint32_t>(CurrentSuperChargedTimeVariable) < 1) { + self->SetNetworkVar<uint32_t>(ChargeCountingVariable, 99); + self->SetNetworkVar<uint32_t>(SuperChargeBarVariable, 0); + ToggleSuperCharge(self, false); + } + } else if (name == SpawnWaveTimer) { + if (self->GetVar<bool>(GameStartedVariable)) { + self->SetVar<bool>(WaveStatusVariable, true); + const auto wave = (int32_t)self->GetVar<uint32_t>(ThisWaveVariable); + + if (wave != 0 && self->GetVar<bool>(SuperChargePausedVariable)) { + StartChargedCannon(self, self->GetVar<uint32_t>(CurrentSuperChargedTimeVariable)); + self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, 0); + } + + TimerToggle(self, true); + + for (const auto& enemyToSpawn : m_Waves.at(self->GetVar<uint32_t>(ThisWaveVariable))) { + SpawnObject(self, enemyToSpawn, true); + } + + Game::logger->Log("SGCannon", "Current wave spawn: %i/%i", wave, m_Waves.size()); + + // All waves completed + const auto timeLimit = (float_t)self->GetVar<uint32_t>(TimeLimitVariable); + if (wave >= m_Waves.size()) { + ActivityTimerStart(self, GameOverTimer, timeLimit, timeLimit); + } else { + ActivityTimerStart(self, EndWaveTimer, timeLimit, timeLimit); + } + + const auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + GameMessages::SendPlayFXEffect(player->GetObjectID(), -1, u"SG-start", ""); + + GameMessages::SendStartActivityTime(self->GetObjectID(), timeLimit, player->GetSystemAddress()); + Game::logger->Log("SGCannon", "Sending ActivityPause false"); + + GameMessages::SendActivityPause(self->GetObjectID(), false, player->GetSystemAddress()); + } + } + } else if (name == EndWaveTimer) { + self->SetVar<bool>(WaveStatusVariable, false); + TimerToggle(self); + RecordPlayerScore(self); + + if (self->GetVar<uint32_t>(ThisWaveVariable) >= 2) { + GameMessages::SendActivityPause(self->GetObjectID(), true); + ActivityTimerStart(self, GameOverTimer, 0.1, 0.1); + return; + } + + self->SetVar<uint32_t>(ThisWaveVariable, self->GetVar<uint32_t>(ThisWaveVariable) + 1); + PlaySceneAnimation(self, u"wave" + GeneralUtils::to_u16string(self->GetVar<uint32_t>(ThisWaveVariable)), true, true, 1.7f); + self->SetNetworkVar<uint32_t>(WaveNumVariable, self->GetVar<uint32_t>(ThisWaveVariable) + 1); + self->SetNetworkVar<uint32_t>(WaveStrVariable, self->GetVar<uint32_t>(TimeLimitVariable)); + + Game::logger->Log("SGCannon", "Current wave: %i/%i", self->GetVar<uint32_t>(ThisWaveVariable), m_Waves.size()); + + if (self->GetVar<uint32_t>(ThisWaveVariable) >= m_Waves.size()) { + ActivityTimerStart(self, GameOverTimer, 0.1, 0.1); + } else { + ActivityTimerStart(self, SpawnWaveTimer, constants.inBetweenWavePause, constants.inBetweenWavePause); + } + + Game::logger->Log("SGCannon", "Sending ActivityPause true"); + + GameMessages::SendActivityPause(self->GetObjectID(), true); + if (self->GetVar<bool>(SuperChargeActiveVariable) && !self->GetVar<bool>(SuperChargePausedVariable)) { + PauseChargeCannon(self); + } + } else if (name == GameOverTimer) { + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + Game::logger->Log("SGCannon", "Sending ActivityPause true"); + + GameMessages::SendActivityPause(self->GetObjectID(), true, player->GetSystemAddress()); + + /*const auto leftoverCannonballs = EntityManager::Instance()->GetEntitiesInGroup("cannonball"); + if (leftoverCannonballs.empty()) { + RecordPlayerScore(self); + + } else { + ActivityTimerStart(self, EndGameBufferTimer, 1, leftoverCannonballs.size()); + }*/ + + ActivityTimerStart(self, EndGameBufferTimer, 1, 1); + + TimerToggle(self); + } + } else if (name.rfind(DoSpawnTimer, 0) == 0) { + if (self->GetVar<bool>(GameStartedVariable)) { + const auto spawnNumber = (uint32_t)std::stoi(name.substr(7)); + const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable); + const auto& toSpawn = activeSpawns.at(spawnNumber); + + const auto pathIndex = GeneralUtils::GenerateRandomNumber<float_t>(0, toSpawn.spawnPaths.size() - 1); + + const auto* path = dZoneManager::Instance()->GetZone()->GetPath( + toSpawn.spawnPaths.at(pathIndex) + ); + + if (!path) { + Game::logger->Log("SGCannon", "Path %s at index %i is null", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex); + return; + } + + auto info = EntityInfo{}; + info.lot = toSpawn.lot; + info.spawnerID = self->GetObjectID(); + info.pos = path->pathWaypoints.at(0).position; + + info.settings = { + new LDFData<SGEnemy>(u"SpawnData", toSpawn), + new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"), + new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"), + new LDFData<std::string>(u"attached_path", path->pathName), + new LDFData<uint32_t>(u"attached_path_start", 0), + new LDFData<std::u16string>(u"groupID", u"SGEnemy") + }; + + Game::logger->Log("SGCannon", "Spawning enemy %i on path %s", toSpawn.lot, path->pathName.c_str()); + + auto* enemy = EntityManager::Instance()->CreateEntity(info, nullptr, self); + EntityManager::Instance()->ConstructEntity(enemy); + + auto* movementAI = new MovementAIComponent(enemy, {}); + + enemy->AddComponent(eReplicaComponentType::MOVEMENT_AI, movementAI); + + movementAI->SetSpeed(toSpawn.initialSpeed); + movementAI->SetCurrentSpeed(toSpawn.initialSpeed); + movementAI->SetHaltDistance(0.0f); + + std::vector<NiPoint3> pathWaypoints; + + for (const auto& waypoint : path->pathWaypoints) { + pathWaypoints.push_back(waypoint.position); + } + + if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) { + std::reverse(pathWaypoints.begin(), pathWaypoints.end()); + } + + movementAI->SetPath(pathWaypoints); + + enemy->AddDieCallback([this, self, enemy, name]() { + RegisterHit(self, enemy, name); + }); + + // Save the enemy and tell it to start pathing + if (enemy != nullptr) { + const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).push_back(enemy->GetObjectID()); + GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS); + } + } + } else if (name == EndGameBufferTimer) { + RecordPlayerScore(self); + StopGame(self, false); + } +} + +void +SGCannon::OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) { + ActivityManager::OnActivityTimerUpdate(self, name, timeRemaining, elapsedTime); +} + +void SGCannon::StartGame(Entity* self) { + self->SetNetworkVar<uint32_t>(TimeLimitVariable, self->GetVar<uint32_t>(TimeLimitVariable)); + self->SetNetworkVar<bool>(AudioStartIntroVariable, true); + self->SetVar<LOT>(CurrentRewardVariable, LOT_NULL); + + auto rewardObjects = EntityManager::Instance()->GetEntitiesInGroup(constants.rewardModelGroup); + for (auto* reward : rewardObjects) { + reward->OnFireEventServerSide(self, ModelToBuildEvent); + } + + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self)); + Game::logger->Log("SGCannon", "Sending ActivityStart"); + GameMessages::SendActivityStart(self->GetObjectID(), player->GetSystemAddress()); + + GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"start", ""); + + self->SetNetworkVar<bool>(ClearVariable, true); + DoGameStartup(self); + + if (!self->GetVar<bool>(FirstTimeDoneVariable)) { + TakeActivityCost(self, player->GetObjectID()); + } + + self->SetVar<bool>(FirstTimeDoneVariable, true); + } + + SpawnNewModel(self); +} + +void SGCannon::DoGameStartup(Entity* self) { + ResetVars(self); + self->SetVar<bool>(GameStartedVariable, true); + self->SetNetworkVar<bool>(ClearVariable, true); + self->SetVar<uint32_t>(ThisWaveVariable, 0); + + if (constants.firstWaveStartTime < 1) { + constants.firstWaveStartTime = 1; + } + + ActivityTimerStart(self, SpawnWaveTimer, constants.firstWaveStartTime, + constants.firstWaveStartTime); +} + +void SGCannon::SpawnNewModel(Entity* self) { + + // Add a new reward to the existing rewards + const auto currentReward = self->GetVar<LOT>(CurrentRewardVariable); + if (currentReward != -1) { + auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable); + rewards.push_back(currentReward); + self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward); + } + + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + for (auto* rewardModel : EntityManager::Instance()->GetEntitiesInGroup(constants.rewardModelGroup)) { + uint32_t lootMatrix; + switch (self->GetVar<uint32_t>(MatrixVariable)) { + case 1: + lootMatrix = constants.scoreLootMatrix1; + break; + case 2: + lootMatrix = constants.scoreLootMatrix2; + break; + case 3: + lootMatrix = constants.scoreLootMatrix3; + break; + case 4: + lootMatrix = constants.scoreLootMatrix4; + break; + case 5: + lootMatrix = constants.scoreLootMatrix5; + break; + default: + lootMatrix = 0; + } + + if (lootMatrix != 0) { + std::unordered_map<LOT, int32_t> toDrop = {}; + toDrop = LootGenerator::Instance().RollLootMatrix(player, lootMatrix); + + for (auto drop : toDrop) { + rewardModel->OnFireEventServerSide(self, ModelToBuildEvent, drop.first); + self->SetVar<LOT>(CurrentRewardVariable, drop.first); + } + } + } + } +} + +void SGCannon::RemovePlayer(LWOOBJID playerID) { + auto* player = EntityManager::Instance()->GetEntity(playerID); + if (player == nullptr) + return; + + auto* playerObject = dynamic_cast<Player*>(player); + if (playerObject == nullptr) + return; + + auto* character = playerObject->GetCharacter(); + if (character != nullptr) { + playerObject->SendToZone(character->GetLastNonInstanceZoneID()); + } +} + +void SGCannon::StartChargedCannon(Entity* self, uint32_t optionalTime) { + optionalTime = optionalTime == 0 ? constants.chargedTime : optionalTime; + self->SetVar<bool>(SuperChargePausedVariable, false); + ToggleSuperCharge(self, true); + ActivityTimerStart(self, SuperChargeTimer, 1, optionalTime); + + if (!self->GetVar<bool>(WaveStatusVariable)) { + PauseChargeCannon(self); + } +} + +void SGCannon::TimerToggle(Entity* self, bool start) { + if (start) { + self->SetNetworkVar<uint32_t>(CountVariable, self->GetVar<uint32_t>(TimeLimitVariable)); + self->SetVar<bool>(GameStartedVariable, true); + } else { + self->SetNetworkVar<bool>(StopVariable, true); + } +} + +void SGCannon::SpawnObject(Entity* self, const SGEnemy& toSpawn, bool spawnNow) { + auto activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable); + activeSpawns.push_back(toSpawn); + self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, activeSpawns); + + self->SetVar(SpawnNumberVariable, activeSpawns.size() - 1); + const auto timerName = DoSpawnTimer + std::to_string(activeSpawns.size() - 1); + + if (spawnNow) { + if (toSpawn.minSpawnTime > 0 && toSpawn.maxSpawnTime > 0) { + const auto spawnTime = GeneralUtils::GenerateRandomNumber<float_t>(toSpawn.minSpawnTime, toSpawn.maxSpawnTime); + + ActivityTimerStart(self, timerName, spawnTime, spawnTime); + } else { + ActivityTimerStart(self, timerName, 1, 1); + } + } else if (toSpawn.respawns) { + const auto spawnTime = GeneralUtils::GenerateRandomNumber<float_t>(toSpawn.minRespawnTime, toSpawn.maxRespawnTime); + + ActivityTimerStart(self, timerName, spawnTime, spawnTime); + } +} + +void SGCannon::RecordPlayerScore(Entity* self) { + const auto totalScore = self->GetVar<uint32_t>(TotalScoreVariable); + const auto currentWave = self->GetVar<uint32_t>(ThisWaveVariable); + + if (currentWave > 0) { + auto totalWaveScore = 0; + auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable); + + for (const auto& waveScore : playerScores) { + totalWaveScore += waveScore; + } + + if (currentWave >= playerScores.size()) { + playerScores.push_back(totalWaveScore); + } else { + playerScores[currentWave] = totalWaveScore; + } + } +} + +void SGCannon::PlaySceneAnimation(Entity* self, const std::u16string& animationName, bool onCannon, bool onPlayer, float_t priority) { + for (auto* cannon : EntityManager::Instance()->GetEntitiesInGroup("cannongroup")) { + GameMessages::SendPlayAnimation(cannon, animationName, priority); + } + + if (onCannon) { + GameMessages::SendPlayAnimation(self, animationName, priority); + } + + if (onPlayer) { + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player != nullptr) { + GameMessages::SendPlayAnimation(player, animationName, priority); + } + } +} + +void SGCannon::PauseChargeCannon(Entity* self) { + const auto time = std::max((uint32_t)std::ceil(ActivityTimerGetCurrentTime(self, SuperChargeTimer)), (uint32_t)1); + + self->SetVar<bool>(SuperChargePausedVariable, true); + self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, time); + self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time); + + ActivityTimerStop(self, SuperChargeTimer); +} + +void SGCannon::StopGame(Entity* self, bool cancel) { + self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); + self->SetNetworkVar<bool>(HideSuperChargeVariable, true); + + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player == nullptr) + return; + + ToggleSuperCharge(self, false); + + // The player won, store all the score and send rewards + if (!cancel) { + auto percentage = 0; + auto misses = self->GetVar<uint32_t>(MissesVariable); + auto fired = self->GetVar<uint32_t>(ShotsFiredVariable); + + if (fired > 0) { + percentage = misses / fired; + } + + auto* missionComponent = player->GetComponent<MissionComponent>(); + + if (missionComponent != nullptr) { + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, self->GetVar<uint32_t>(TotalScoreVariable), self->GetObjectID(), "performact_score"); + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, self->GetVar<uint32_t>(MaxStreakVariable), self->GetObjectID(), "performact_streak"); + missionComponent->Progress(eMissionTaskType::ACTIVITY, m_CannonLot, 0, "", self->GetVar<uint32_t>(TotalScoreVariable)); + } + + LootGenerator::Instance().GiveActivityLoot(player, self, GetGameID(self), self->GetVar<uint32_t>(TotalScoreVariable)); + + StopActivity(self, player->GetObjectID(), self->GetVar<uint32_t>(TotalScoreVariable), self->GetVar<uint32_t>(MaxStreakVariable), percentage); + self->SetNetworkVar<bool>(AudioFinalWaveDoneVariable, true); + + // Give the player the model rewards they earned + auto* inventory = player->GetComponent<InventoryComponent>(); + if (inventory != nullptr) { + for (const auto rewardLot : self->GetVar<std::vector<LOT>>(RewardsVariable)) { + inventory->AddItem(rewardLot, 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS); + } + } + + self->SetNetworkVar<std::u16string>(u"UI_Rewards", + GeneralUtils::to_u16string(self->GetVar<uint32_t>(TotalScoreVariable)) + u"_0_0_0_0_0_0" + ); + + GameMessages::SendRequestActivitySummaryLeaderboardData( + player->GetObjectID(), + self->GetObjectID(), + player->GetSystemAddress(), + GetGameID(self), + 1, + 10, + 0, + false + ); + } + + GameMessages::SendActivityStop(self->GetObjectID(), false, cancel, player->GetSystemAddress()); + self->SetVar<bool>(GameStartedVariable, false); + ActivityTimerStopAllTimers(self); + + // Destroy all spawners + for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup("SGEnemy")) { + entity->Kill(); + } + + ResetVars(self); +} + +void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& timerName) { + const auto& spawnInfo = target->GetVar<SGEnemy>(u"SpawnData"); + + if (spawnInfo.respawns) { + const auto respawnTime = GeneralUtils::GenerateRandomNumber<float_t>(spawnInfo.minRespawnTime, spawnInfo.maxRespawnTime); + + ActivityTimerStart(self, timerName, respawnTime, respawnTime); + } + + int score = spawnInfo.score; + + if (score > 0) { + score += score * GetCurrentBonus(self); + + if (!self->GetVar<bool>(SuperChargeActiveVariable)) { + self->SetVar<uint32_t>(u"m_curStreak", self->GetVar<uint32_t>(u"m_curStreak") + 1); + } + } else { + if (!self->GetVar<bool>(SuperChargeActiveVariable)) { + self->SetVar<uint32_t>(u"m_curStreak", 0); + } + + self->SetNetworkVar<bool>(u"hitFriend", true); + } + + auto lastSuperTotal = self->GetVar<uint32_t>(u"LastSuperTotal"); + + auto scScore = self->GetVar<uint32_t>(TotalScoreVariable) - lastSuperTotal; + + Game::logger->Log("SGCannon", "LastSuperTotal: %i, scScore: %i, constants.chargedPoints: %i", + lastSuperTotal, scScore, constants.chargedPoints + ); + + if (!self->GetVar<bool>(SuperChargeActiveVariable) && scScore >= constants.chargedPoints && score >= 0) { + StartChargedCannon(self); + self->SetNetworkVar<float>(u"SuperChargeBar", 100.0f); + self->SetVar<uint32_t>(u"LastSuperTotal", self->GetVar<uint32_t>(TotalScoreVariable)); + } + + UpdateStreak(self); + + GameMessages::SendNotifyClientShootingGalleryScore(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, + 0.0f, + score, + target->GetObjectID(), + target->GetPosition() + ); + + auto newScore = (int)self->GetVar<uint32_t>(TotalScoreVariable) + score; + + if (newScore < 0) { + newScore = 0; + } + + self->SetVar<uint32_t>(TotalScoreVariable, newScore); + + self->SetNetworkVar<uint32_t>(u"updateScore", newScore); + + self->SetNetworkVar<std::u16string>(u"beatHighScore", GeneralUtils::to_u16string(newScore)); + + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + if (player == nullptr) return; + + auto missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) return; + + missionComponent->Progress(eMissionTaskType::SMASH, spawnInfo.lot, self->GetObjectID()); +} + +void SGCannon::UpdateStreak(Entity* self) { + const auto streakBonus = GetCurrentBonus(self); + + const auto curStreak = self->GetVar<uint32_t>(u"m_curStreak"); + + const auto marks = curStreak % 3; + + self->SetNetworkVar<uint32_t>(u"cStreak", curStreak); + + if (curStreak >= 0 && curStreak < 13) { + if (marks == 1) { + self->SetNetworkVar<bool>(u"Mark1", true); + } else if (marks == 2) { + self->SetNetworkVar<bool>(u"Mark2", true); + } else if (marks == 0 && curStreak > 0) { + self->SetVar<float_t>(u"StreakBonus", streakBonus); + self->SetNetworkVar<bool>(u"ShowStreak", streakBonus + 1); + self->SetNetworkVar<bool>(u"Mark3", true); + } else { + self->SetVar<float_t>(u"StreakBonus", streakBonus); + self->SetNetworkVar<bool>(u"UnMarkAll", true); + } + } + auto maxStreak = self->GetVar<uint32_t>(MaxStreakVariable); + if (maxStreak < curStreak) self->SetVar<uint32_t>(MaxStreakVariable, curStreak); +} + +float_t SGCannon::GetCurrentBonus(Entity* self) { + auto streak = self->GetVar<uint32_t>(u"m_curStreak"); + + if (streak > 12) { + streak = 12; + } + + return streak / 3; +} + +void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { + if (enable && self->GetVar<bool>(SuperChargeActiveVariable)) + return; + + auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); + + if (player == nullptr) { + Game::logger->Log("SGCannon", "Player not found in toggle super charge"); + return; + } + + auto* inventoryComponent = player->GetComponent<InventoryComponent>(); + + auto equippedItems = inventoryComponent->GetEquippedItems(); + + Game::logger->Log("SGCannon", "Player has %d equipped items", equippedItems.size()); + + auto skillID = constants.cannonSkill; + auto cooldown = constants.cannonRefireRate; + + auto* selfInventoryComponent = self->GetComponent<InventoryComponent>(); + + if (inventoryComponent == nullptr) { + Game::logger->Log("SGCannon", "Inventory component not found"); + return; + } + + if (enable) { + Game::logger->Log("SGCannon", "Player is activating super charge"); + selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 6505, 1, 0 }); + selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 6506, 1, 0 }); + + // TODO: Equip items + skillID = constants.cannonSuperChargeSkill; + cooldown = 400; + } else { + selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); + selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); + + self->SetNetworkVar<float>(u"SuperChargeBar", 0); + + Game::logger->Log("SGCannon", "Player disables super charge"); + + // TODO: Unequip items + for (const auto& equipped : equippedItems) { + if (equipped.first == "special_r" || equipped.first == "special_l") { + Game::logger->Log("SGCannon", "Trying to unequip a weapon, %i", equipped.second.lot); + + auto* item = inventoryComponent->FindItemById(equipped.second.id); + + if (item != nullptr) { + inventoryComponent->UnEquipItem(item); + } else { + Game::logger->Log("SGCannon", "Item not found, %i", equipped.second.lot); + } + } + } + cooldown = 800; + self->SetVar<uint32_t>(NumberOfChargesVariable, 0); + } + + const auto& constants = GetConstants(); + + auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>(); + + if (shootingGalleryComponent == nullptr) { + return; + } + + DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams(); + + properties.cannonFOV = 58.6f; + properties.cannonVelocity = 129.0; + properties.cannonRefireRate = cooldown; + properties.cannonMinDistance = 30; + properties.cannonTimeout = -1; + + shootingGalleryComponent->SetDynamicParams(properties); + + EntityManager::Instance()->SerializeEntity(self); + EntityManager::Instance()->SerializeEntity(player); + + self->SetNetworkVar<uint64_t>(CannonBallSkillIDVariable, skillID); + self->SetVar<bool>(SuperChargeActiveVariable, enable); +} + +std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { + return { + // Wave 1 + { + // Ship 1 + { + std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, + 6015, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 2 + { + std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, + 6300, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Sub 1 + { + std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 10.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Sub 2 + { + std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Friendly + { + std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, + 2168,0.0,5.0,true, 2.0, 5.0, + 1.0, -1000, false, 0.0, 1.0, + 1.0, false,true + } + }, + + // Wave 2 + { + // Ship 1 + { + std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, + 6015, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 2 + { + std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, + 6300, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 3 + { + std::vector<std::string> { "Wave_2_Ship_1" }, + 6300, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 4 + { + std::vector<std::string> { "Wave_2_Ship_2" }, + 6015, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Sub 1 + { + std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Sub 2 + { + std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Duck + { + std::vector<std::string> { "Wave_1_Duck_1", "Wave_1_Duck_2" }, + 5946, 5.0, 10.0, true, 5.0, 10.0, + 4.0, 5000, false, 0.0, 1.0, + 1.0, false, true + }, + + // Friendly + { + std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, + 2168,0.0,5.0,true, 2.0, 5.0, + 1.0, -1000, false, 0.0, 1.0, + 1.0, false,true + } + }, + + // Wave 3 + { + // Ship 1 + { + std::vector<std::string> { "Wave_1_Ship_1", "Wave_1_Ship_3" }, + 6015, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 2 + { + std::vector<std::string> { "Wave_1_Ship_2", "Wave_1_Ship_4" }, + 6300, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 3 + { + std::vector<std::string> { "Wave_2_Ship_1", "Wave_2_Ship_2" }, + 6015, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ship 4 + { + std::vector<std::string> { "Wave_3_Ship_1", "Wave_3_Ship_2" }, + 6300, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1500, false, 0.0, 1.0, + 1.0, false, true + }, + + // Sub 1 + { + std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Sub 2 + { + std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Sub 3 + { + std::vector<std::string> { "Wave_3_Sub_1", "Wave_3_Sub_2" }, + 6016, 0.0, 2.0, true, 0.0, 2.0, + 2.0, 1000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Duck + { + std::vector<std::string> { "Wave_1_Duck_1", "Wave_1_Duck_2" }, + 5946, 5.0, 10.0, true, 5.0, 10.0, + 4.0, 5000, false, 0.0, 1.0, + 1.0, false, true + }, + + // Ness + { + std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, + 2565, 10.0, 15.0, true, 10.0, 15.0, + 2.0, 10000, false, 0.0, 1.0, + 1.0, true, true + }, + + // Friendly 1 + { + std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, + 2168,0.0,5.0,true, 2.0, 5.0, + 1.0, -1000, false, 0.0, 1.0, + 1.0, false,true + }, + + // Friendly 2 + { + std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, + 2168,0.0,5.0,true, 2.0, 5.0, + 1.0, -1000, false, 0.0, 1.0, + 1.0, false,true + } + } + }; +} + +void SGCannon::ResetVars(Entity* self) { + self->SetVar<uint32_t>(SpawnNumberVariable, 0); + self->SetVar<uint32_t>(CurrentSpawnNumberVariable, 0); + self->SetVar<uint32_t>(ThisWaveVariable, 0); + self->SetVar<uint32_t>(GameScoreVariable, 0); + self->SetVar<uint32_t>(GameTimeVariable, 0); + self->SetVar<bool>(GameStartedVariable, false); + self->SetVar<uint32_t>(ShotsFiredVariable, 0); + self->SetVar<uint32_t>(MaxStreakVariable, 0); + self->SetVar<uint32_t>(MissesVariable, 0); + self->SetVar<uint32_t>(CurrentStreakVariable, 0); + self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, 0); + self->SetVar<std::vector<uint32_t>>(StreakBonusVariable, {}); + self->SetVar<uint32_t>(LastSuperTotalVariable, 0); + self->SetVar<LOT>(CurrentRewardVariable, LOT_NULL); + self->SetVar<std::vector<LOT>>(RewardsVariable, {}); + self->SetVar<uint32_t>(TotalScoreVariable, 0); + + const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear(); + self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {}); + + const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).clear(); + self->SetVar<std::vector<LWOOBJID>>(SpawnedObjects, {}); + + if (self->GetVar<bool>(InitVariable)) { + ToggleSuperCharge(self, false); + } + + self->SetVar<uint32_t>(ImpactSkillVariale, constants.impactSkillID); + self->SetVar<std::vector<int32_t>>(PlayerScoresVariable, {}); + ActivityTimerStopAllTimers(self); +} + +SGConstants SGCannon::GetConstants() { + return { + Vector3 { -908.542480, 229.773178, -908.542480 }, + Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 }, + 1864, + 34, + 1822, + Vector3 { 6.652, -2, 1.5 }, + 157, + 129.0, + 30.0, + 800.0, + Vector3 { 0, 4.3, 9 }, + 6297, + 1822, + 249, + 228, + -1, + 58.6, + true, + 2, + 10, + 25000, + "QBRewardGroup", + 1864, + 50000, + 157, + 100000, + 187, + 200000, + 188, + 400000, + 189, + 800000, + 190, + 4.0, + 7.0 + }; +} diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.h b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.h new file mode 100644 index 00000000..df9831ad --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.h @@ -0,0 +1,153 @@ +#pragma once +#include <regex> +#include "ActivityManager.h" + +struct SGEnemy { + std::vector<std::string> spawnPaths{}; + LOT lot; + float_t minSpawnTime; + float_t maxSpawnTime; + bool respawns; + float_t minRespawnTime; + float_t maxRespawnTime; + float_t initialSpeed; + int32_t score; + bool changeSpeedAtWaypoint; + float_t speedChangeChance; + float_t minSpeed; + float_t maxSpeed; + bool isMovingPlatform; + bool despawnOnLastWaypoint; +}; + +struct SGConstants { + Vector3 playerStartPosition; + Quaternion playerStartRotation; + LOT cannonLot; + uint32_t impactSkillID; + LOT projectileLot; + Vector3 playerOffset; + uint32_t rewardModelMatrix; + float_t cannonVelocity; + float_t cannonMinDistance; + float_t cannonRefireRate; + Vector3 cannonBarrelOffset; + LOT cannonSuperchargedProjectileLot; + LOT cannonProjectileLot; + uint32_t cannonSuperChargeSkill; + uint32_t cannonSkill; + int32_t cannonTimeout; + float_t cannonFOV; + bool useLeaderboards; + uint32_t streakModifier; + uint32_t chargedTime; + uint32_t chargedPoints; + std::string rewardModelGroup; + uint32_t activityID; + uint32_t scoreReward1; + uint32_t scoreLootMatrix1; + uint32_t scoreReward2; + uint32_t scoreLootMatrix2; + uint32_t scoreReward3; + uint32_t scoreLootMatrix3; + uint32_t scoreReward4; + uint32_t scoreLootMatrix4; + uint32_t scoreReward5; + uint32_t scoreLootMatrix5; + float_t firstWaveStartTime; + float_t inBetweenWavePause; +}; + +class SGCannon : public ActivityManager { +public: + void OnStartup(Entity* self) override; + void OnPlayerLoaded(Entity* self, Entity* player) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + void OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int32_t value1, + int32_t value2, const std::u16string& stringValue) override; + void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, + const std::u16string& userData) override; + void OnActivityTimerDone(Entity* self, const std::string& name) override; + void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) override; +private: + static std::vector<std::vector<SGEnemy>> GetWaves(); + static SGConstants GetConstants(); + void ResetVars(Entity* self); + void StartGame(Entity* self); + void DoGameStartup(Entity* self); + void SpawnNewModel(Entity* self); + void TimerToggle(Entity* self, bool start = false); + void SpawnObject(Entity* self, const SGEnemy& toSpawn, bool spawnNow = false); + void StartChargedCannon(Entity* self, uint32_t optionalTime = 0); + void ToggleSuperCharge(Entity* self, bool enable); + void RecordPlayerScore(Entity* self); + void PlaySceneAnimation(Entity* self, const std::u16string& animationName, bool onCannon, bool onPlayer, float_t priority); + static void RemovePlayer(LWOOBJID playerID); + void PauseChargeCannon(Entity* self); + void StopGame(Entity* self, bool cancel = false); + void RegisterHit(Entity* self, Entity* target, const std::string& timerName); + void UpdateStreak(Entity* self); + float_t GetCurrentBonus(Entity* self); + + LOT m_CannonLot = 1864; + std::u16string PlayerIDVariable = u"PlayerID"; + std::u16string HideScoreBoardVariable = u"HideScoreBoard"; + std::u16string ReSetSuperChargeVariable = u"ReSetSuperCharge"; + std::u16string ShowLoadingUI = u"showLoadingUI"; + std::u16string SpawnNumberVariable = u"SpawnNum"; + std::u16string CurrentSpawnNumberVariable = u"CurSpawnNum"; + std::u16string ThisWaveVariable = u"ThisWave"; + std::u16string GameScoreVariable = u"GameScore"; + std::u16string GameTimeVariable = u"GameTime"; + std::u16string GameStartedVariable = u"GameStarted"; + std::u16string ShotsFiredVariable = u"ShotsFired"; + std::u16string MaxStreakVariable = u"MaxStreak"; + std::u16string MissesVariable = u"Misses"; + std::u16string CurrentStreakVariable = u"CurrentStreak"; + std::u16string CurrentSuperChargedTimeVariable = u"CurrentSuperChargedTime"; + std::u16string StreakBonusVariable = u"StreakBonus"; + std::u16string LastSuperTotalVariable = u"LastSuperTotal"; + std::u16string CurrentRewardVariable = u"CurrentReward"; + std::u16string RewardsVariable = u"Rewards"; + std::u16string TotalScoreVariable = u"TotalScore"; + std::u16string InitVariable = u"Init"; + std::u16string ImpactSkillVariale = u"ImpactSkill"; + std::u16string PlayerScoresVariable = u"PlayerScores"; + std::u16string InitialVelocityVariable = u"InitialVelocity"; + std::u16string ValidActorsVariable = u"ValidActors"; + std::u16string ValidEffectsVariable = u"ValidEffects"; + std::u16string SuperChargeActiveVariable = u"SuperChargeActive"; + std::u16string MatrixVariable = u"Matrix"; + std::u16string TimeLimitVariable = u"game_timelimit"; + std::u16string AudioStartIntroVariable = u"Audio_Start_Intro"; + std::u16string ClearVariable = u"Clear"; + std::u16string FirstTimeDoneVariable = u"FirstTimeDone"; + std::u16string RewardAddedVariable = u"rewardAdded"; + std::u16string SuperChargePausedVariable = u"Super_Charge_Paused"; + std::u16string WaveStatusVariable = u"WaveStatus"; + std::u16string CountVariable = u"count"; + std::u16string StopVariable = u"Stop"; + std::u16string ActiveSpawnsVariable = u"ActiveSpawns"; + std::u16string SpawnedObjects = u"SpawnedObjects"; + std::u16string WaveNumVariable = u"wave.waveNum"; + std::u16string WaveStrVariable = u"wave.waveStr"; + std::u16string ChargeCountingVariable = u"charge_counting"; + std::u16string SuperChargeBarVariable = u"SuperChargeBar"; + std::u16string NumberOfChargesVariable = u"NumberOfCharges"; + std::u16string CannonBallSkillIDVariable = u"cbskill"; + std::u16string HideSuperChargeVariable = u"HideSuper"; + std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done"; + + std::string SpawnWaveTimer = "SpawnWave"; + std::string EndWaveTimer = "EndWave"; + std::string GameOverTimer = "GameOver"; + std::string DoSpawnTimer = "DoSpawn"; + std::string EndGameBufferTimer = "endGameBuffer"; + std::string SuperChargeTimer = "SuperChargeTimer"; + + std::string ModelToBuildEvent = "modelToBuild"; + + std::regex DoSpawnRegex = std::regex("\\d*"); + SGConstants constants{}; + std::vector<std::vector<SGEnemy>> m_Waves{}; +}; diff --git a/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.cpp b/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.cpp new file mode 100644 index 00000000..6822abda --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.cpp @@ -0,0 +1,26 @@ +#include "ZoneSGServer.h" +#include "EntityManager.h" + +void ZoneSGServer::OnStartup(Entity* self) { + const auto cannons = EntityManager::Instance()->GetEntitiesByLOT(1864); + for (const auto& cannon : cannons) + self->SetVar<LWOOBJID>(CannonIDVariable, cannon->GetObjectID()); +} + +void ZoneSGServer::OnActivityStateChangeRequest(Entity* self, const LWOOBJID senderID, const int32_t value1, + const int32_t value2, const std::u16string& stringValue) { + + auto* cannon = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(CannonIDVariable)); + if (cannon != nullptr) { + cannon->OnActivityStateChangeRequest(senderID, value1, value2, stringValue); + } +} + +void ZoneSGServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + + auto* cannon = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(CannonIDVariable)); + if (cannon != nullptr) { + cannon->OnFireEventServerSide(sender, args, param1, param2, param3); + } +} diff --git a/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.h b/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.h new file mode 100644 index 00000000..eaa7c909 --- /dev/null +++ b/dScripts/ai/MINIGAME/SG_GF/ZoneSGServer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class ZoneSGServer : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int32_t value1, + int32_t value2, const std::u16string& stringValue) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +private: + std::u16string CannonIDVariable = u"CannonID"; +}; diff --git a/dScripts/ai/NP/CMakeLists.txt b/dScripts/ai/NP/CMakeLists.txt new file mode 100644 index 00000000..39a7301a --- /dev/null +++ b/dScripts/ai/NP/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_NP + "NpcNpSpacemanBob.cpp" + PARENT_SCOPE) diff --git a/dScripts/NpcNpSpacemanBob.cpp b/dScripts/ai/NP/NpcNpSpacemanBob.cpp similarity index 53% rename from dScripts/NpcNpSpacemanBob.cpp rename to dScripts/ai/NP/NpcNpSpacemanBob.cpp index 91fe0f95..2195f4b4 100644 --- a/dScripts/NpcNpSpacemanBob.cpp +++ b/dScripts/ai/NP/NpcNpSpacemanBob.cpp @@ -1,15 +1,15 @@ #include "NpcNpSpacemanBob.h" #include "DestroyableComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" -void NpcNpSpacemanBob::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) -{ - if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE && missionID == 173) - { - DestroyableComponent* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); +void NpcNpSpacemanBob::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionState == eMissionState::READY_TO_COMPLETE && missionID == 173) { + DestroyableComponent* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(eReplicaComponentType::DESTROYABLE)); destroyable->SetImagination(6); - MissionComponent* mission = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); - + MissionComponent* mission = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); + mission->CompleteMission(664); } } diff --git a/dScripts/NpcNpSpacemanBob.h b/dScripts/ai/NP/NpcNpSpacemanBob.h similarity index 82% rename from dScripts/NpcNpSpacemanBob.h rename to dScripts/ai/NP/NpcNpSpacemanBob.h index 08cc850d..84c59deb 100644 --- a/dScripts/NpcNpSpacemanBob.h +++ b/dScripts/ai/NP/NpcNpSpacemanBob.h @@ -4,6 +4,6 @@ class NpcNpSpacemanBob : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); }; diff --git a/dScripts/ai/NS/CMakeLists.txt b/dScripts/ai/NS/CMakeLists.txt new file mode 100644 index 00000000..e8ec84b1 --- /dev/null +++ b/dScripts/ai/NS/CMakeLists.txt @@ -0,0 +1,24 @@ +set(DSCRIPTS_SOURCES_AI_NS + "ClRing.cpp" + "NsConcertChoiceBuild.cpp" + "NsConcertInstrument.cpp" + "NsConcertQuickBuild.cpp" + "NsGetFactionMissionServer.cpp" + "NsJohnnyMissionServer.cpp" + "NsModularBuild.cpp" + "NsQbImaginationStatue.cpp" + "WhFans.cpp") + +add_subdirectory(NS_PP_01) + +foreach(file ${DSCRIPTS_SOURCES_AI_NS_NS_PP_01}) + set(DSCRIPTS_SOURCES_AI_NS ${DSCRIPTS_SOURCES_AI_NS} "NS_PP_01/${file}") +endforeach() + +add_subdirectory(WH) + +foreach(file ${DSCRIPTS_SOURCES_AI_NS_WH}) + set(DSCRIPTS_SOURCES_AI_NS ${DSCRIPTS_SOURCES_AI_NS} "WH/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_NS ${DSCRIPTS_SOURCES_AI_NS} PARENT_SCOPE) diff --git a/dScripts/ai/NS/ClRing.cpp b/dScripts/ai/NS/ClRing.cpp new file mode 100644 index 00000000..37e76d88 --- /dev/null +++ b/dScripts/ai/NS/ClRing.cpp @@ -0,0 +1,5 @@ +#include "ClRing.h" + +void ClRing::OnCollisionPhantom(Entity* self, Entity* target) { + self->Smash(target->GetObjectID()); +} diff --git a/dScripts/ClRing.h b/dScripts/ai/NS/ClRing.h similarity index 100% rename from dScripts/ClRing.h rename to dScripts/ai/NS/ClRing.h diff --git a/dScripts/ai/NS/NS_PP_01/CMakeLists.txt b/dScripts/ai/NS/NS_PP_01/CMakeLists.txt new file mode 100644 index 00000000..3f26c135 --- /dev/null +++ b/dScripts/ai/NS/NS_PP_01/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_NS_NS_PP_01 + "PropertyDeathPlane.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp b/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp new file mode 100644 index 00000000..ab659d8a --- /dev/null +++ b/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp @@ -0,0 +1,16 @@ +#include "PropertyDeathPlane.h" +#include "Entity.h" +#include "GameMessages.h" +#include "EntityManager.h" + +void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) { + const auto teleportGroup = EntityManager::Instance()->GetEntitiesInGroup("Teleport"); + + if (teleportGroup.size() == 0) { + return; + } + + auto* teleport = teleportGroup[0]; + + GameMessages::SendTeleport(target->GetObjectID(), teleport->GetPosition(), teleport->GetRotation(), target->GetSystemAddress()); +} diff --git a/dScripts/PropertyDeathPlane.h b/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.h similarity index 100% rename from dScripts/PropertyDeathPlane.h rename to dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.h diff --git a/dScripts/ai/NS/NsConcertChoiceBuild.cpp b/dScripts/ai/NS/NsConcertChoiceBuild.cpp new file mode 100644 index 00000000..af6389cd --- /dev/null +++ b/dScripts/ai/NS/NsConcertChoiceBuild.cpp @@ -0,0 +1,4 @@ +#include "NsConcertChoiceBuild.h" + +void NsConcertChoiceBuild::OnStartup(Entity* self) { +} diff --git a/dScripts/NsConcertChoiceBuild.h b/dScripts/ai/NS/NsConcertChoiceBuild.h similarity index 69% rename from dScripts/NsConcertChoiceBuild.h rename to dScripts/ai/NS/NsConcertChoiceBuild.h index 310a0677..74fdc9dc 100644 --- a/dScripts/NsConcertChoiceBuild.h +++ b/dScripts/ai/NS/NsConcertChoiceBuild.h @@ -3,5 +3,5 @@ class NsConcertChoiceBuild : public CppScripts::Script { public: - void OnStartup(Entity* self) override; -}; \ No newline at end of file + void OnStartup(Entity* self) override; +}; diff --git a/dScripts/ai/NS/NsConcertInstrument.cpp b/dScripts/ai/NS/NsConcertInstrument.cpp new file mode 100644 index 00000000..7db1ca16 --- /dev/null +++ b/dScripts/ai/NS/NsConcertInstrument.cpp @@ -0,0 +1,365 @@ +#include "NsConcertInstrument.h" +#include "GameMessages.h" +#include "Item.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "RebuildComponent.h" +#include "SoundTriggerComponent.h" +#include "InventoryComponent.h" +#include "MissionComponent.h" +#include "eMissionState.h" +#include "eMissionTaskType.h" + +// Constants are at the bottom + +void NsConcertInstrument::OnStartup(Entity* self) { + self->SetVar<bool>(u"beingPlayed", false); + self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); + self->SetVar<LWOOBJID>(u"oldItemLeft", LWOOBJID_EMPTY); + self->SetVar<LWOOBJID>(u"oldItemRight", LWOOBJID_EMPTY); +} + +void NsConcertInstrument::OnRebuildNotifyState(Entity* self, eRebuildState state) { + if (state == eRebuildState::RESETTING || state == eRebuildState::OPEN) { + self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); + } +} + +void NsConcertInstrument::OnRebuildComplete(Entity* self, Entity* target) { + if (!target->GetIsDead()) { + self->SetVar<LWOOBJID>(u"activePlayer", target->GetObjectID()); + + self->AddCallbackTimer(0.2f, [self, target]() { + RepositionPlayer(self, target); + if (hideInstrumentOnPlay.at(GetInstrumentLot(self))) + self->SetNetworkVar<bool>(u"Hide", true); + }); + + self->AddCallbackTimer(0.1f, [self, target]() { + StartPlayingInstrument(self, target); + }); + } +} + +void NsConcertInstrument::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (args == "stopPlaying") { + const auto activePlayerID = self->GetVar<LWOOBJID>(u"activePlayer"); + if (activePlayerID == LWOOBJID_EMPTY) + return; + + const auto activePlayer = EntityManager::Instance()->GetEntity(activePlayerID); + if (activePlayer == nullptr) + return; + + StopPlayingInstrument(self, activePlayer); + } +} + +void NsConcertInstrument::OnTimerDone(Entity* self, std::string name) { + const auto activePlayerID = self->GetVar<LWOOBJID>(u"activePlayer"); + if (activePlayerID == LWOOBJID_EMPTY) + return; + + // If for some reason the player becomes null (for example an unexpected leave), we need to clean up + const auto activePlayer = EntityManager::Instance()->GetEntity(activePlayerID); + if (activePlayer == nullptr && name != "cleanupAfterStop") { + StopPlayingInstrument(self, nullptr); + return; + } + + if (activePlayer != nullptr && name == "checkPlayer" && self->GetVar<bool>(u"beingPlayed")) { + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"checkMovement", 0, 0, + activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + auto* stats = activePlayer->GetComponent<DestroyableComponent>(); + if (stats) { + if (stats->GetImagination() > 0) { + self->AddTimer("checkPlayer", updateFrequency); + } else { + StopPlayingInstrument(self, activePlayer); + } + } + } else if (activePlayer != nullptr && name == "deductImagination" && self->GetVar<bool>(u"beingPlayed")) { + auto* stats = activePlayer->GetComponent<DestroyableComponent>(); + if (stats) + stats->SetImagination(stats->GetImagination() - instrumentImaginationCost); + + self->AddTimer("deductImagination", instrumentCostFrequency); + } else if (name == "cleanupAfterStop") { + if (activePlayer != nullptr) { + UnEquipInstruments(self, activePlayer); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopPlaying", 0, 0, + activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + } + + auto* rebuildComponent = self->GetComponent<RebuildComponent>(); + if (rebuildComponent != nullptr) + rebuildComponent->ResetRebuild(false); + + self->Smash(self->GetObjectID(), eKillType::VIOLENT); + self->SetVar<LWOOBJID>(u"activePlayer", LWOOBJID_EMPTY); + } else if (activePlayer != nullptr && name == "achievement") { + auto* missionComponent = activePlayer->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->ForceProgress(302, 462, self->GetLOT()); + } + self->AddTimer("achievement2", 10.0f); + } else if (activePlayer != nullptr && name == "achievement2") { + auto* missionComponent = activePlayer->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->ForceProgress(602, achievementTaskID.at(GetInstrumentLot(self)), self->GetLOT()); + } + } +} + +void NsConcertInstrument::StartPlayingInstrument(Entity* self, Entity* player) { + const auto instrumentLot = GetInstrumentLot(self); + self->SetVar<bool>(u"beingPlayed", true); + + // Stuff to notify the player + EquipInstruments(self, player); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"startPlaying", 0, 0, + player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendPlayCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS); + self->AddCallbackTimer(1.0f, [player, instrumentLot]() { + GameMessages::SendPlayAnimation(player, animations.at(instrumentLot), 2.0f); + }); + + for (auto* soundBox : EntityManager::Instance()->GetEntitiesInGroup("Audio-Concert")) { + auto* soundTrigger = soundBox->GetComponent<SoundTriggerComponent>(); + if (soundTrigger != nullptr) { + soundTrigger->ActivateMusicCue(music.at(instrumentLot)); + } + } + + // Add timers for deducting imagination and checking if the instruments can still be played + self->AddTimer("checkPlayer", updateFrequency); + self->AddTimer("deductImagination", instrumentCostFrequency); + self->AddTimer("achievement", 20.0f); +} + +void NsConcertInstrument::StopPlayingInstrument(Entity* self, Entity* player) { + // No use in stopping twice + if (!self->GetVar<bool>(u"beingPlayed")) + return; + + const auto instrumentLot = GetInstrumentLot(self); + + // Player might be null if they left + if (player != nullptr) { + auto* missions = player->GetComponent<MissionComponent>(); + if (missions != nullptr && missions->GetMissionState(176) == eMissionState::ACTIVE) { + missions->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); + } + + GameMessages::SendEndCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS, 1.0f); + GameMessages::SendPlayAnimation(player, smashAnimations.at(instrumentLot), 2.0f); + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopCheckingMovement", 0, 0, + player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + } + + self->SetVar<bool>(u"beingPlayed", false); + + for (auto* soundBox : EntityManager::Instance()->GetEntitiesInGroup("Audio-Concert")) { + auto* soundTrigger = soundBox->GetComponent<SoundTriggerComponent>(); + if (soundTrigger != nullptr) { + soundTrigger->DeactivateMusicCue(music.at(instrumentLot)); + } + } + + self->CancelAllTimers(); + self->AddTimer("cleanupAfterStop", instrumentSmashAnimationTime.at(instrumentLot)); +} + +void NsConcertInstrument::EquipInstruments(Entity* self, Entity* player) { + auto* inventory = player->GetComponent<InventoryComponent>(); + if (inventory != nullptr) { + auto equippedItems = inventory->GetEquippedItems(); + + // Un equip the current left item + const auto equippedLeftItem = equippedItems.find("special_l"); + if (equippedLeftItem != equippedItems.end()) { + auto* leftItem = inventory->FindItemById(equippedLeftItem->second.id); + if (leftItem != nullptr) { + leftItem->UnEquip(); + self->SetVar<LWOOBJID>(u"oldItemLeft", leftItem->GetId()); + } + } + + // Un equip the current right item + const auto equippedRightItem = equippedItems.find("special_r"); + if (equippedRightItem != equippedItems.end()) { + auto* rightItem = inventory->FindItemById(equippedRightItem->second.id); + if (rightItem != nullptr) { + rightItem->UnEquip(); + self->SetVar<LWOOBJID>(u"oldItemRight", rightItem->GetId()); + } + } + + // Equip the left hand instrument + const auto leftInstrumentLot = instrumentLotLeft.find(GetInstrumentLot(self))->second; + if (leftInstrumentLot != LOT_NULL) { + inventory->AddItem(leftInstrumentLot, 1, eLootSourceType::NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false); + auto* leftInstrument = inventory->FindItemByLot(leftInstrumentLot, TEMP_ITEMS); + leftInstrument->Equip(); + } + + // Equip the right hand instrument + const auto rightInstrumentLot = instrumentLotRight.find(GetInstrumentLot(self))->second; + if (rightInstrumentLot != LOT_NULL) { + inventory->AddItem(rightInstrumentLot, 1, eLootSourceType::NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false); + auto* rightInstrument = inventory->FindItemByLot(rightInstrumentLot, TEMP_ITEMS); + rightInstrument->Equip(); + } + } +} + +void NsConcertInstrument::UnEquipInstruments(Entity* self, Entity* player) { + auto* inventory = player->GetComponent<InventoryComponent>(); + if (inventory != nullptr) { + auto equippedItems = inventory->GetEquippedItems(); + + // Un equip the current left instrument + const auto equippedInstrumentLeft = equippedItems.find("special_l"); + if (equippedInstrumentLeft != equippedItems.end()) { + auto* leftItem = inventory->FindItemById(equippedInstrumentLeft->second.id); + if (leftItem != nullptr) { + leftItem->UnEquip(); + inventory->RemoveItem(leftItem->GetLot(), 1, TEMP_ITEMS); + } + } + + // Un equip the current right instrument + const auto equippedInstrumentRight = equippedItems.find("special_r"); + if (equippedInstrumentRight != equippedItems.end()) { + auto* rightItem = inventory->FindItemById(equippedInstrumentRight->second.id); + if (rightItem != nullptr) { + rightItem->UnEquip(); + inventory->RemoveItem(rightItem->GetLot(), 1, TEMP_ITEMS); + } + } + + // Equip the old left hand item + const auto leftItemID = self->GetVar<LWOOBJID>(u"oldItemLeft"); + if (leftItemID != LWOOBJID_EMPTY) { + auto* item = inventory->FindItemById(leftItemID); + if (item != nullptr) + item->Equip(); + self->SetVar<LWOOBJID>(u"oldItemLeft", LWOOBJID_EMPTY); + } + + // Equip the old right hand item + const auto rightItemID = self->GetVar<LWOOBJID>(u"oldItemRight"); + if (rightItemID != LWOOBJID_EMPTY) { + auto* item = inventory->FindItemById(rightItemID); + if (item != nullptr) + item->Equip(); + self->SetVar<LWOOBJID>(u"oldItemRight", LWOOBJID_EMPTY); + } + } +} + +void NsConcertInstrument::RepositionPlayer(Entity* self, Entity* player) { + auto position = self->GetPosition(); + auto rotation = self->GetRotation(); + position.SetY(0.0f); + + switch (GetInstrumentLot(self)) { + case Bass: + case Guitar: + position.SetX(position.GetX() + 5.0f); + break; + case Keyboard: + position.SetX(position.GetX() - 0.45f); + position.SetZ(position.GetZ() + 0.75f); + rotation = NiQuaternion::CreateFromAxisAngle(position, -0.8f); // Slight rotation to make the animation sensible + break; + case Drum: + position.SetZ(position.GetZ() - 0.5f); + break; + } + + GameMessages::SendTeleport(player->GetObjectID(), position, rotation, player->GetSystemAddress()); +} + +InstrumentLot NsConcertInstrument::GetInstrumentLot(Entity* self) { + return static_cast<const InstrumentLot>(self->GetLOT()); +} + +// Static stuff needed for script execution + +const std::map<InstrumentLot, std::u16string> NsConcertInstrument::animations{ + { Guitar, u"guitar"}, + { Bass, u"bass"}, + { Keyboard, u"keyboard"}, + { Drum, u"drums"} +}; + +const std::map<InstrumentLot, std::u16string> NsConcertInstrument::smashAnimations{ + {Guitar, u"guitar-smash"}, + {Bass, u"bass-smash"}, + {Keyboard, u"keyboard-smash"}, + {Drum, u"keyboard-smash"} +}; + +const std::map<InstrumentLot, float> NsConcertInstrument::instrumentSmashAnimationTime{ + {Guitar, 2.167f}, + {Bass, 1.167f}, + {Keyboard, 1.0f}, + {Drum, 1.0f} +}; + +const std::map<InstrumentLot, std::string> NsConcertInstrument::music{ + {Guitar, "Concert_Guitar"}, + {Bass, "Concert_Bass"}, + {Keyboard, "Concert_Keys"}, + {Drum, "Concert_Drums"}, +}; + +const std::map<InstrumentLot, std::u16string> NsConcertInstrument::cinematics{ + {Guitar, u"Concert_Cam_G"}, + {Bass, u"Concert_Cam_B"}, + {Keyboard, u"Concert_Cam_K"}, + {Drum, u"Concert_Cam_D"}, +}; + +const std::map<InstrumentLot, LOT> NsConcertInstrument::instrumentLotLeft{ + {Guitar, 4991}, + {Bass, 4992}, + {Keyboard, LOT_NULL}, + {Drum, 4995}, +}; + +const std::map<InstrumentLot, LOT> NsConcertInstrument::instrumentLotRight{ + {Guitar, LOT_NULL}, + {Bass, LOT_NULL}, + {Keyboard, LOT_NULL}, + {Drum, 4996}, +}; + +const std::map<InstrumentLot, bool> NsConcertInstrument::hideInstrumentOnPlay{ + {Guitar, true}, + {Bass, true}, + {Keyboard, false}, + {Drum, false}, +}; + +const std::map<InstrumentLot, float> NsConcertInstrument::instrumentEquipTime{ + {Guitar, 1.033}, + {Bass, 0.75}, + {Keyboard, -1}, + {Drum, 0}, +}; + +const std::map<InstrumentLot, uint32_t> NsConcertInstrument::achievementTaskID{ + {Guitar, 911}, + {Bass, 912}, + {Keyboard, 913}, + {Drum, 914}, +}; + +const uint32_t NsConcertInstrument::instrumentImaginationCost = 2; + +const float NsConcertInstrument::instrumentCostFrequency = 4.0f; + +const float NsConcertInstrument::updateFrequency = 1.0f; diff --git a/dScripts/ai/NS/NsConcertInstrument.h b/dScripts/ai/NS/NsConcertInstrument.h new file mode 100644 index 00000000..87ccc419 --- /dev/null +++ b/dScripts/ai/NS/NsConcertInstrument.h @@ -0,0 +1,91 @@ +#pragma once +#include "CppScripts.h" + +enum InstrumentLot { + Guitar = 4039, + Bass = 4040, + Keyboard = 4041, + Drum = 4042 +}; + +class NsConcertInstrument : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string name) override; +private: + static void StartPlayingInstrument(Entity* self, Entity* player); + static void StopPlayingInstrument(Entity* self, Entity* player); + static void EquipInstruments(Entity* self, Entity* player); + static void UnEquipInstruments(Entity* self, Entity* player); + static void RepositionPlayer(Entity* self, Entity* player); + static InstrumentLot GetInstrumentLot(Entity* self); + + /** + * Animations played when using an instrument + */ + static const std::map<InstrumentLot, std::u16string> animations; + + /** + * Animation played when an instrument is smashed + */ + static const std::map<InstrumentLot, std::u16string> smashAnimations; + + /** + * Music to play while playing an instrument + */ + static const std::map<InstrumentLot, std::string> music; + + /** + * Cinematics to play while playing an instrument + */ + static const std::map<InstrumentLot, std::u16string> cinematics; + + /** + * Lot to equip in your left hand when playing an instrument + */ + static const std::map<InstrumentLot, LOT> instrumentLotLeft; + + /** + * Lot to play in your right hand when playing an instrument + */ + static const std::map<InstrumentLot, LOT> instrumentLotRight; + + /** + * Whether to hide the instrument or not when someone is playing it + */ + static const std::map<InstrumentLot, bool> hideInstrumentOnPlay; + + /** + * How long to wait before unequipping the instrument if the instrument was smashed + */ + static const std::map<InstrumentLot, float> instrumentEquipTime; + + /** + * How long the smash animation takes for each of the instruments + */ + static const std::map<InstrumentLot, float> instrumentSmashAnimationTime; + + /** + * Task ID of tasks of the Solo Artist 2 achievement + */ + static const std::map<InstrumentLot, uint32_t> achievementTaskID; + + /** + * How much imagination playing an instrument costs per interval + */ + static const uint32_t instrumentImaginationCost; + + /** + * The interval to deduct imagination at when playing an instrument + */ + static const float instrumentCostFrequency; + + /** + * The interval to check if the player still has enough imagination + */ + static const float updateFrequency; +}; diff --git a/dScripts/ai/NS/NsConcertQuickBuild.cpp b/dScripts/ai/NS/NsConcertQuickBuild.cpp new file mode 100644 index 00000000..4589ee6a --- /dev/null +++ b/dScripts/ai/NS/NsConcertQuickBuild.cpp @@ -0,0 +1,224 @@ +#include "NsConcertQuickBuild.h" +#include "EntityManager.h" +#include "NsConcertChoiceBuildManager.h" +#include "DestroyableComponent.h" +#include "GameMessages.h" +#include "MovingPlatformComponent.h" +#include "MissionComponent.h" + +const float NsConcertQuickBuild::resetTime = 40.0f; +const float NsConcertQuickBuild::resetBlinkTime = 6.0f; +const float NsConcertQuickBuild::resetStageTime = 66.5f; +const float NsConcertQuickBuild::resetActivatorTime = 30.0f; +const std::map<LOT, QuickBuildSet> NsConcertQuickBuild::quickBuildSets{ + {5846, QuickBuildSet {"laser", {"discoball", "discofloor", "stagelights", "spotlight"}}}, + {5847, QuickBuildSet {"spotlight", {"spotlight", "stagelights"}}}, + {5848, QuickBuildSet {"rocket", {"flamethrower"}}}, + {5845, QuickBuildSet {"speaker", {"speaker", "speakerHill", "stagelights", "spotlight"}}} +}; + +const std::map<std::string, std::string> NsConcertQuickBuild::quickBuildFX{ + {"discoball", "effectsDiscoball"}, + {"speaker", "effectsShell"}, + {"speakerHill", "effectsHill"}, + {"spotlight", "effectsHill"}, + {"discofloor", "effectsShell"}, + {"flamethrower", "effectsShell"}, + {"stagelights", "effectsShell"} +}; + +std::vector<LWOOBJID> NsConcertQuickBuild::finishedQuickBuilds = {}; + +void NsConcertQuickBuild::OnStartup(Entity* self) { + const auto groups = self->GetGroups(); + if (groups.empty()) + return; + + // Groups are of the form Concert_Laser_QB_1, Concert_Laser_QB_2, etc. + auto group = groups.at(0); + const auto splitGroup = GeneralUtils::SplitString(group, '_'); + if (splitGroup.size() < 4) + return; + + // Get the manager of the crate of this quick build + const auto groupNumber = std::stoi(splitGroup.at(3)); + const auto managerObjects = EntityManager::Instance()->GetEntitiesInGroup("CB_" + std::to_string(groupNumber)); + if (managerObjects.empty()) + return; + + auto* managerObject = managerObjects.at(0); + self->SetVar<LWOOBJID>(u"managerObject", managerObject->GetObjectID()); + self->SetVar<int32_t>(u"groupNumber", groupNumber); + + // Makes the quick build blink after a certain amount of time + self->AddCallbackTimer(GetBlinkTime(resetActivatorTime), [self]() { + self->SetNetworkVar<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); + }); + + // Destroys the quick build after a while if it wasn't built + self->AddCallbackTimer(resetActivatorTime, [self]() { + self->SetNetworkVar<float>(u"startEffect", -1.0f); + self->Smash(self->GetObjectID(), eKillType::SILENT); + }); +} + +float NsConcertQuickBuild::GetBlinkTime(float time) { + return time <= NsConcertQuickBuild::resetBlinkTime ? 1.0f : time - NsConcertQuickBuild::resetBlinkTime; +} + +void NsConcertQuickBuild::OnDie(Entity* self, Entity* killer) { + auto* managerObject = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"managerObject")); + if (managerObject) { + managerObject->CancelAllTimers(); + managerObject->AddCallbackTimer(1.0f, [managerObject]() { + NsConcertChoiceBuildManager::SpawnCrate(managerObject); + }); + } + + auto position = std::find(finishedQuickBuilds.begin(), finishedQuickBuilds.end(), self->GetObjectID()); + if (position != finishedQuickBuilds.end()) + finishedQuickBuilds.erase(position); +} + +void NsConcertQuickBuild::OnRebuildComplete(Entity* self, Entity* target) { + const auto groupNumber = self->GetVar<int32_t>(u"groupNumber"); + finishedQuickBuilds.push_back(self->GetObjectID()); + self->SetNetworkVar<float>(u"startEffect", -1.0f); + + ProgressStageCraft(self, target); + + // Find all the quick build objects of the same lot + auto finishedQuickBuildObjects = std::vector<Entity*>(); + for (auto quickBuildID : finishedQuickBuilds) { + const auto quickBuildObject = EntityManager::Instance()->GetEntity(quickBuildID); + if (quickBuildObject && quickBuildObject->GetLOT() == self->GetLOT()) { + quickBuildObject->SetVar<LWOOBJID>(u"Player_" + (GeneralUtils::to_u16string(groupNumber)), target->GetObjectID()); + finishedQuickBuildObjects.push_back(quickBuildObject); + } + } + + // If all 4 sets were built, do cool stuff + if (finishedQuickBuildObjects.size() >= 4) { + + // Move all the platforms so the user can collect the imagination brick + const auto movingPlatforms = EntityManager::Instance()->GetEntitiesInGroup("ConcertPlatforms"); + for (auto* movingPlatform : movingPlatforms) { + auto* component = movingPlatform->GetComponent<MovingPlatformComponent>(); + if (component) { + component->WarpToWaypoint(component->GetLastWaypointIndex()); + + movingPlatform->AddCallbackTimer(resetStageTime, [movingPlatform, component]() { + component->WarpToWaypoint(0); + }); + } + } + + ProgressLicensedTechnician(self); + + // Reset all timers for the quickbuilds and make them indestructible + for (auto quickBuild : finishedQuickBuildObjects) { + quickBuild->SetNetworkVar<float>(u"startEffect", -1.0f); + quickBuild->CancelAllTimers(); + + // Indicate that the stage will reset + quickBuild->AddCallbackTimer(GetBlinkTime(resetStageTime), [quickBuild]() { + quickBuild->SetNetworkVar<float>(u"startEffect", GetBlinkTime(resetTime)); + }); + + // Reset the stage + quickBuild->AddCallbackTimer(resetStageTime, [quickBuild]() { + CancelEffects(quickBuild); + quickBuild->SetNetworkVar<float>(u"startEffect", -1); + quickBuild->Smash(); + }); + + auto* destroyableComponent = quickBuild->GetComponent<DestroyableComponent>(); + if (destroyableComponent) + destroyableComponent->SetFaction(-1); + } + + UpdateEffects(self); + return; + } + + // If not all 4 sets were built, reset the timers that were set on spawn + self->CancelAllTimers(); + + // Makes the quick build blink after a certain amount of time + self->AddCallbackTimer(GetBlinkTime(resetTime), [self]() { + self->SetNetworkVar<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); + }); + + // Destroys the quick build after a while if it wasn't built + self->AddCallbackTimer(resetTime, [self]() { + self->SetNetworkVar<float>(u"startEffect", -1.0f); + self->Smash(self->GetObjectID()); + }); +} + +void NsConcertQuickBuild::ProgressStageCraft(Entity* self, Entity* player) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent) { + + // Has to be forced as to not accidentally trigger the licensed technician achievement + switch (self->GetLOT()) { + case 5845: + missionComponent->ForceProgress(283, 432, 5845); + break; + case 5846: + missionComponent->ForceProgress(283, 433, 5846); + break; + case 5847: + missionComponent->ForceProgress(283, 434, 5847); + break; + case 5848: + missionComponent->ForceProgress(283, 435, 5848); + break; + default: + break; + } + } +} + +void NsConcertQuickBuild::ProgressLicensedTechnician(Entity* self) { + for (auto i = 1; i < 5; i++) { + const auto playerID = self->GetVar<LWOOBJID>(u"Player_" + (GeneralUtils::to_u16string(i))); + if (playerID != LWOOBJID_EMPTY) { + const auto player = EntityManager::Instance()->GetEntity(playerID); + if (player) { + auto playerMissionComponent = player->GetComponent<MissionComponent>(); + if (playerMissionComponent) + playerMissionComponent->ForceProgress(598, 903, self->GetLOT()); + } + } + } +} + +void NsConcertQuickBuild::UpdateEffects(Entity* self) { + CancelEffects(self); + + auto setIterator = quickBuildSets.find(self->GetLOT()); + if (setIterator == quickBuildSets.end()) + return; + + for (const auto& effectName : setIterator->second.effects) { + const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); + for (auto* effectObject : effectObjects) { + GameMessages::SendPlayFXEffect(effectObject, 0, GeneralUtils::ASCIIToUTF16(effectName), + effectName + "Effect", LWOOBJID_EMPTY, 1, 1, true); + } + } +} + +void NsConcertQuickBuild::CancelEffects(Entity* self) { + auto setIterator = quickBuildSets.find(self->GetLOT()); + if (setIterator == quickBuildSets.end()) + return; + + for (const auto& effectName : setIterator->second.effects) { + const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); + for (auto* effectObject : effectObjects) { + GameMessages::SendStopFXEffect(effectObject, true, effectName + "Effect"); + } + } +} diff --git a/dScripts/ai/NS/NsConcertQuickBuild.h b/dScripts/ai/NS/NsConcertQuickBuild.h new file mode 100644 index 00000000..667580f6 --- /dev/null +++ b/dScripts/ai/NS/NsConcertQuickBuild.h @@ -0,0 +1,27 @@ +#pragma once +#include "CppScripts.h" + +struct QuickBuildSet { + std::string name; + std::vector<std::string> effects; +}; + +class NsConcertQuickBuild : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnDie(Entity* self, Entity* killer) override; +private: + static std::vector<LWOOBJID> finishedQuickBuilds; + static const float resetBlinkTime; + static const float resetStageTime; + static const float resetActivatorTime; + static const float resetTime; + static const std::map<std::string, std::string> quickBuildFX; + static const std::map<LOT, QuickBuildSet> quickBuildSets; + static float GetBlinkTime(float time); + static void ProgressStageCraft(Entity* self, Entity* player); + static void ProgressLicensedTechnician(Entity* self); + static void UpdateEffects(Entity* self); + static void CancelEffects(Entity* self); +}; diff --git a/dScripts/NsGetFactionMissionServer.cpp b/dScripts/ai/NS/NsGetFactionMissionServer.cpp similarity index 76% rename from dScripts/NsGetFactionMissionServer.cpp rename to dScripts/ai/NS/NsGetFactionMissionServer.cpp index d4d03243..185bd344 100644 --- a/dScripts/NsGetFactionMissionServer.cpp +++ b/dScripts/ai/NS/NsGetFactionMissionServer.cpp @@ -2,35 +2,33 @@ #include "GameMessages.h" #include "MissionComponent.h" #include "Character.h" +#include "eReplicaComponentType.h" +#include "ePlayerFlag.h" -void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, Entity* player, int reward) -{ +void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, Entity* player, int reward) { if (missionID != 474) return; if (reward != LOT_NULL) { std::vector<int> factionMissions; int celebrationID = -1; - int flagID = -1; + int32_t flagID = -1; if (reward == 6980) { // Venture League factionMissions = { 555, 556 }; celebrationID = 14; flagID = 46; - } - else if (reward == 6979) { + } else if (reward == 6979) { // Assembly factionMissions = { 544, 545 }; celebrationID = 15; flagID = 47; - } - else if (reward == 6981) { + } else if (reward == 6981) { // Paradox factionMissions = { 577, 578 }; celebrationID = 16; flagID = 48; - } - else if (reward == 6978) { + } else if (reward == 6978) { // Sentinel factionMissions = { 566, 567 }; celebrationID = 17; @@ -44,11 +42,11 @@ void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, } if (flagID != -1) { - player->GetCharacter()->SetPlayerFlag(ePlayerFlags::JOINED_A_FACTION, true); + player->GetCharacter()->SetPlayerFlag(ePlayerFlag::JOINED_A_FACTION, true); player->GetCharacter()->SetPlayerFlag(flagID, true); } - MissionComponent* mis = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mis = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); for (int mission : factionMissions) { mis->AcceptMission(mission); diff --git a/dScripts/NsGetFactionMissionServer.h b/dScripts/ai/NS/NsGetFactionMissionServer.h similarity index 100% rename from dScripts/NsGetFactionMissionServer.h rename to dScripts/ai/NS/NsGetFactionMissionServer.h diff --git a/dScripts/ai/NS/NsJohnnyMissionServer.cpp b/dScripts/ai/NS/NsJohnnyMissionServer.cpp new file mode 100644 index 00000000..107d3c44 --- /dev/null +++ b/dScripts/ai/NS/NsJohnnyMissionServer.cpp @@ -0,0 +1,15 @@ +#include "NsJohnnyMissionServer.h" +#include "MissionComponent.h" +#include "eMissionState.h" + +void NsJohnnyMissionServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 773 && missionState <= eMissionState::ACTIVE) { + auto* missionComponent = target->GetComponent<MissionComponent>(); + if (missionComponent != nullptr) { + missionComponent->AcceptMission(774); + missionComponent->AcceptMission(775); + missionComponent->AcceptMission(776); + missionComponent->AcceptMission(777); + } + } +} diff --git a/dScripts/ai/NS/NsJohnnyMissionServer.h b/dScripts/ai/NS/NsJohnnyMissionServer.h new file mode 100644 index 00000000..c37ea06c --- /dev/null +++ b/dScripts/ai/NS/NsJohnnyMissionServer.h @@ -0,0 +1,6 @@ +#pragma once +#include "CppScripts.h" + +class NsJohnnyMissionServer : public CppScripts::Script { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +}; diff --git a/dScripts/NsModularBuild.cpp b/dScripts/ai/NS/NsModularBuild.cpp similarity index 68% rename from dScripts/NsModularBuild.cpp rename to dScripts/ai/NS/NsModularBuild.cpp index 065d061e..1922eb17 100644 --- a/dScripts/NsModularBuild.cpp +++ b/dScripts/ai/NS/NsModularBuild.cpp @@ -1,11 +1,13 @@ #include "NsModularBuild.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void NsModularBuild::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) { if (bCompleted) { - MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); - if (mission->GetMissionState(m_MissionNum) == MissionState::MISSION_STATE_ACTIVE) { + if (mission->GetMissionState(m_MissionNum) == eMissionState::ACTIVE) { for (LOT mod : modules) { if (mod == 9516 || mod == 9517 || mod == 9518) { mission->ForceProgress(m_MissionNum, 1178, 1); diff --git a/dScripts/NsModularBuild.h b/dScripts/ai/NS/NsModularBuild.h similarity index 100% rename from dScripts/NsModularBuild.h rename to dScripts/ai/NS/NsModularBuild.h diff --git a/dScripts/ai/NS/NsQbImaginationStatue.cpp b/dScripts/ai/NS/NsQbImaginationStatue.cpp new file mode 100644 index 00000000..a2e335b7 --- /dev/null +++ b/dScripts/ai/NS/NsQbImaginationStatue.cpp @@ -0,0 +1,40 @@ +#include "NsQbImaginationStatue.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void NsQbImaginationStatue::OnStartup(Entity* self) { + +} + +void NsQbImaginationStatue::OnRebuildComplete(Entity* self, Entity* target) { + if (target == nullptr) return; + + self->SetVar(u"Player", target->GetObjectID()); + + SpawnLoot(self); + + self->AddTimer("SpawnDelay", 1.5f); + + self->AddTimer("StopSpawner", 10.0f); +} + +void NsQbImaginationStatue::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "SpawnDelay") { + SpawnLoot(self); + + self->AddTimer("SpawnDelay", 1.5f); + } else if (timerName == "StopSpawner") { + self->CancelAllTimers(); + } +} + +void NsQbImaginationStatue::SpawnLoot(Entity* self) { + const auto playerId = self->GetVar<LWOOBJID>(u"Player"); + + auto* player = EntityManager::Instance()->GetEntity(playerId); + + if (player == nullptr) return; + + GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); + GameMessages::SendDropClientLoot(player, self->GetObjectID(), 935, 0); +} diff --git a/dScripts/ai/NS/NsQbImaginationStatue.h b/dScripts/ai/NS/NsQbImaginationStatue.h new file mode 100644 index 00000000..b7a78c32 --- /dev/null +++ b/dScripts/ai/NS/NsQbImaginationStatue.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" + +class NsQbImaginationStatue : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnRebuildComplete(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void SpawnLoot(Entity* self); +}; diff --git a/dScripts/ai/NS/WH/CMakeLists.txt b/dScripts/ai/NS/WH/CMakeLists.txt new file mode 100644 index 00000000..179a417f --- /dev/null +++ b/dScripts/ai/NS/WH/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_AI_NS_WH + "RockHydrantSmashable.cpp" + "RockHydrantBroken.cpp" + PARENT_SCOPE) diff --git a/dScripts/RockHydrantBroken.cpp b/dScripts/ai/NS/WH/RockHydrantBroken.cpp similarity index 84% rename from dScripts/RockHydrantBroken.cpp rename to dScripts/ai/NS/WH/RockHydrantBroken.cpp index 50e3c88d..835d52f6 100644 --- a/dScripts/RockHydrantBroken.cpp +++ b/dScripts/ai/NS/WH/RockHydrantBroken.cpp @@ -2,16 +2,14 @@ #include "EntityManager.h" #include "GameMessages.h" -void RockHydrantBroken::OnStartup(Entity* self) -{ +void RockHydrantBroken::OnStartup(Entity* self) { self->AddTimer("playEffect", 1); const auto hydrant = "hydrant" + self->GetVar<std::string>(u"hydrant"); const auto bouncers = EntityManager::Instance()->GetEntitiesInGroup(hydrant); - for (auto* bouncer : bouncers) - { + for (auto* bouncer : bouncers) { self->SetVar<LWOOBJID>(u"bouncer", bouncer->GetObjectID()); @@ -23,23 +21,18 @@ void RockHydrantBroken::OnStartup(Entity* self) self->AddTimer("KillBroken", 10); } -void RockHydrantBroken::OnTimerDone(Entity* self, std::string timerName) -{ - if (timerName == "KillBroken") - { +void RockHydrantBroken::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "KillBroken") { auto* bouncer = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"bouncer")); - if (bouncer != nullptr) - { + if (bouncer != nullptr) { GameMessages::SendBouncerActiveStatus(bouncer->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision", UNASSIGNED_SYSTEM_ADDRESS); } self->Kill(); - } - else if (timerName == "playEffect") - { + } else if (timerName == "playEffect") { GameMessages::SendPlayFXEffect(self->GetObjectID(), 4737, u"water", "water", LWOOBJID_EMPTY, 1, 1, true); } } diff --git a/dScripts/RockHydrantBroken.h b/dScripts/ai/NS/WH/RockHydrantBroken.h similarity index 100% rename from dScripts/RockHydrantBroken.h rename to dScripts/ai/NS/WH/RockHydrantBroken.h diff --git a/dScripts/RockHydrantSmashable.cpp b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp similarity index 79% rename from dScripts/RockHydrantSmashable.cpp rename to dScripts/ai/NS/WH/RockHydrantSmashable.cpp index 8d5b5861..b3a01567 100644 --- a/dScripts/RockHydrantSmashable.cpp +++ b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp @@ -1,18 +1,18 @@ #include "RockHydrantSmashable.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "GeneralUtils.h" -void RockHydrantSmashable::OnDie(Entity* self, Entity* killer) -{ +void RockHydrantSmashable::OnDie(Entity* self, Entity* killer) { const auto hydrantName = self->GetVar<std::u16string>(u"hydrant"); LDFBaseData* data = new LDFData<std::string>(u"hydrant", GeneralUtils::UTF16ToWTF8(hydrantName)); - EntityInfo info {}; + EntityInfo info{}; info.lot = ROCK_HYDRANT_BROKEN; info.pos = self->GetPosition(); info.rot = self->GetRotation(); - info.settings = {data}; + info.settings = { data }; info.spawnerID = self->GetSpawnerID(); auto* hydrant = EntityManager::Instance()->CreateEntity(info); diff --git a/dScripts/RockHydrantSmashable.h b/dScripts/ai/NS/WH/RockHydrantSmashable.h similarity index 100% rename from dScripts/RockHydrantSmashable.h rename to dScripts/ai/NS/WH/RockHydrantSmashable.h diff --git a/dScripts/WhFans.cpp b/dScripts/ai/NS/WhFans.cpp similarity index 90% rename from dScripts/WhFans.cpp rename to dScripts/ai/NS/WhFans.cpp index f71383cf..44354127 100644 --- a/dScripts/WhFans.cpp +++ b/dScripts/ai/NS/WhFans.cpp @@ -41,8 +41,7 @@ void WhFans::ToggleFX(Entity* self, bool hit) { volumePhys->SetPhysicsEffectActive(false); EntityManager::Instance()->SerializeEntity(volume); } - } - else if (!self->GetVar<bool>(u"on") && self->GetVar<bool>(u"alive")) { + } else if (!self->GetVar<bool>(u"on") && self->GetVar<bool>(u"alive")) { GameMessages::SendPlayAnimation(self, u"fan-on"); self->SetVar<bool>(u"on", true); @@ -56,8 +55,8 @@ void WhFans::ToggleFX(Entity* self, bool hit) { } } -void WhFans::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3) { +void WhFans::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { if (args.length() == 0 || !self->GetVar<bool>(u"alive")) return; if ((args == "turnOn" && self->GetVar<bool>(u"on")) || (args == "turnOff" && !self->GetVar<bool>(u"on"))) return; diff --git a/dScripts/WhFans.h b/dScripts/ai/NS/WhFans.h similarity index 91% rename from dScripts/WhFans.h rename to dScripts/ai/NS/WhFans.h index d41eed5b..0762395b 100644 --- a/dScripts/WhFans.h +++ b/dScripts/ai/NS/WhFans.h @@ -6,8 +6,8 @@ public: void OnStartup(Entity* self) override; void OnDie(Entity* self, Entity* killer) override; void OnFireEventServerSide( - Entity *self, - Entity *sender, + Entity* self, + Entity* sender, std::string args, int32_t param1, int32_t param2, diff --git a/dScripts/ai/PETS/CMakeLists.txt b/dScripts/ai/PETS/CMakeLists.txt new file mode 100644 index 00000000..93a9012d --- /dev/null +++ b/dScripts/ai/PETS/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_PETS + "HydrantSmashable.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/PETS/HydrantSmashable.cpp b/dScripts/ai/PETS/HydrantSmashable.cpp new file mode 100644 index 00000000..1ff082ea --- /dev/null +++ b/dScripts/ai/PETS/HydrantSmashable.cpp @@ -0,0 +1,21 @@ +#include "HydrantSmashable.h" +#include "EntityManager.h" +#include "EntityInfo.h" +#include "GeneralUtils.h" + +void HydrantSmashable::OnDie(Entity* self, Entity* killer) { + const auto hydrantName = self->GetVar<std::u16string>(u"hydrant"); + + LDFBaseData* data = new LDFData<std::string>(u"hydrant", GeneralUtils::UTF16ToWTF8(hydrantName)); + + EntityInfo info{}; + info.lot = HYDRANT_BROKEN; + info.pos = self->GetPosition(); + info.rot = self->GetRotation(); + info.settings = { data }; + info.spawnerID = self->GetSpawnerID(); + + auto* hydrant = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(hydrant); +} diff --git a/dScripts/HydrantSmashable.h b/dScripts/ai/PETS/HydrantSmashable.h similarity index 98% rename from dScripts/HydrantSmashable.h rename to dScripts/ai/PETS/HydrantSmashable.h index 90b0f3a6..156f2e8f 100644 --- a/dScripts/HydrantSmashable.h +++ b/dScripts/ai/PETS/HydrantSmashable.h @@ -7,4 +7,4 @@ public: void OnDie(Entity* self, Entity* killer) override; private: LOT HYDRANT_BROKEN = 7328; -}; \ No newline at end of file +}; diff --git a/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp new file mode 100644 index 00000000..853da92d --- /dev/null +++ b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp @@ -0,0 +1,40 @@ +#include "AgPropGuard.h" +#include "Entity.h" +#include "Character.h" +#include "EntityManager.h" +#include "InventoryComponent.h" +#include "MissionComponent.h" +#include "Item.h" +#include "eMissionState.h" + +void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* character = target->GetCharacter(); + auto* missionComponent = target->GetComponent<MissionComponent>(); + auto* inventoryComponent = target->GetComponent<InventoryComponent>(); + + const auto state = missionComponent->GetMissionState(320); + if (missionID == 768 && missionState == eMissionState::AVAILABLE) { + if (!character->GetPlayerFlag(71)) { + // TODO: Cinematic "MissionCam" + } + } else if (missionID == 768 && missionState >= eMissionState::READY_TO_COMPLETE) { + //remove the inventory items + for (int item : gearSets) { + auto* id = inventoryComponent->FindItemByLot(item); + + if (id) { + inventoryComponent->UnEquipItem(id); + inventoryComponent->RemoveItem(id->GetLot(), id->GetCount()); + } + } + } else if ( + (missionID == 320 && state == eMissionState::AVAILABLE) /*|| + (state == eMissionState::COMPLETE && missionID == 891 && missionState == eMissionState::READY_TO_COMPLETE)*/ + ) { + //GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", target->GetObjectID(), 0, target->GetObjectID(), "", target->GetSystemAddress()); + + target->GetCharacter()->SetPlayerFlag(113, true); + + EntityManager::Instance()->GetZoneControlEntity()->AddTimer("GuardFlyAway", 1.0f); + } +} diff --git a/dScripts/AgPropGuard.h b/dScripts/ai/PROPERTY/AG/AgPropGuard.h similarity index 78% rename from dScripts/AgPropGuard.h rename to dScripts/ai/PROPERTY/AG/AgPropGuard.h index 4f6a96d9..2b41f006 100644 --- a/dScripts/AgPropGuard.h +++ b/dScripts/ai/PROPERTY/AG/AgPropGuard.h @@ -1,10 +1,10 @@ -#pragma once +#pragma once #include "CppScripts.h" class AgPropGuard final : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; private: std::vector<int> gearSets = { 14359,14321,14353,14315 }; diff --git a/dScripts/ai/PROPERTY/AG/CMakeLists.txt b/dScripts/ai/PROPERTY/AG/CMakeLists.txt new file mode 100644 index 00000000..f2139463 --- /dev/null +++ b/dScripts/ai/PROPERTY/AG/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_AI_PROPERTY_AG + "AgPropGuard.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/PROPERTY/AgPropguards.cpp b/dScripts/ai/PROPERTY/AgPropguards.cpp new file mode 100644 index 00000000..7e8e2fd1 --- /dev/null +++ b/dScripts/ai/PROPERTY/AgPropguards.cpp @@ -0,0 +1,57 @@ +#include "AgPropguards.h" +#include "Character.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "dZoneManager.h" +#include "eMissionState.h" + +void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + auto* character = target->GetCharacter(); + if (character == nullptr) + return; + + const auto flag = GetFlagForMission(missionID); + if (flag == 0) + return; + + if ((missionState == eMissionState::AVAILABLE || missionState == eMissionState::ACTIVE) + && !character->GetPlayerFlag(flag)) { + // If the player just started the mission, play a cinematic highlighting the target + GameMessages::SendPlayCinematic(target->GetObjectID(), u"MissionCam", target->GetSystemAddress()); + } else if (missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { + // Makes the guard disappear once the mission has been completed + const auto zoneControlID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); + GameMessages::SendNotifyClientObject(zoneControlID, u"GuardChat", 0, 0, self->GetObjectID(), + "", UNASSIGNED_SYSTEM_ADDRESS); + + self->AddCallbackTimer(5.0f, [self]() { + auto spawnerName = self->GetVar<std::string>(u"spawner_name"); + if (spawnerName.empty()) + spawnerName = "Guard"; + + auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName); + for (auto* spawner : spawners) { + spawner->Deactivate(); + } + + self->Smash(); + }); + } +} + +int32_t AgPropguards::GetFlagForMission(uint32_t missionID) { + switch (missionID) { + case 872: + return 97; + case 873: + return 98; + case 874: + return 99; + case 1293: + return 118; + case 1322: + return 122; + default: + return 0; + } +} diff --git a/dScripts/ai/PROPERTY/AgPropguards.h b/dScripts/ai/PROPERTY/AgPropguards.h new file mode 100644 index 00000000..ed2e3cb0 --- /dev/null +++ b/dScripts/ai/PROPERTY/AgPropguards.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class AgPropguards : public CppScripts::Script { + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; +private: + static int32_t GetFlagForMission(uint32_t missionID); +}; diff --git a/dScripts/ai/PROPERTY/CMakeLists.txt b/dScripts/ai/PROPERTY/CMakeLists.txt new file mode 100644 index 00000000..295137b4 --- /dev/null +++ b/dScripts/ai/PROPERTY/CMakeLists.txt @@ -0,0 +1,11 @@ +set(DSCRIPTS_SOURCES_AI_PROPERTY + "AgPropguards.cpp" + "PropertyFXDamage.cpp") + +add_subdirectory(AG) + +foreach(file ${DSCRIPTS_SOURCES_AI_PROPERTY_AG}) + set(DSCRIPTS_SOURCES_AI_PROPERTY ${DSCRIPTS_SOURCES_AI_PROPERTY} "AG/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_PROPERTY ${DSCRIPTS_SOURCES_AI_PROPERTY} PARENT_SCOPE) diff --git a/dScripts/ai/PROPERTY/PropertyFXDamage.cpp b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp new file mode 100644 index 00000000..56079384 --- /dev/null +++ b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp @@ -0,0 +1,18 @@ +#include "PropertyFXDamage.h" +#include "DestroyableComponent.h" +#include "SkillComponent.h" + +void PropertyFXDamage::OnCollisionPhantom(Entity* self, Entity* target) { + if (target == nullptr) + return; + + auto* skills = self->GetComponent<SkillComponent>(); + auto* targetStats = target->GetComponent<DestroyableComponent>(); + + if (skills != nullptr && targetStats != nullptr) { + auto targetFactions = targetStats->GetFactionIDs(); + if (std::find(targetFactions.begin(), targetFactions.end(), 1) != targetFactions.end()) { + skills->CalculateBehavior(692, 11386, target->GetObjectID()); + } + } +} diff --git a/dScripts/PropertyFXDamage.h b/dScripts/ai/PROPERTY/PropertyFXDamage.h similarity index 58% rename from dScripts/PropertyFXDamage.h rename to dScripts/ai/PROPERTY/PropertyFXDamage.h index b1e67c0a..6973de0c 100644 --- a/dScripts/PropertyFXDamage.h +++ b/dScripts/ai/PROPERTY/PropertyFXDamage.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class PropertyFXDamage : public CppScripts::Script { - void OnCollisionPhantom(Entity *self, Entity *target) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; }; diff --git a/dScripts/ai/RACING/CMakeLists.txt b/dScripts/ai/RACING/CMakeLists.txt new file mode 100644 index 00000000..0c1918de --- /dev/null +++ b/dScripts/ai/RACING/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DSCRIPTS_SOURCES_AI_RACING) + +add_subdirectory(OBJECTS) + +foreach(file ${DSCRIPTS_SOURCES_AI_RACING_OBJECTS}) + set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} "OBJECTS/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} PARENT_SCOPE) diff --git a/dScripts/ai/RACING/OBJECTS/CMakeLists.txt b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt new file mode 100644 index 00000000..4ef427d5 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DSCRIPTS_SOURCES_AI_RACING_OBJECTS + "RaceImagineCrateServer.cpp" + "RaceImaginePowerup.cpp" + "FvRaceSmashEggImagineServer.cpp" + "RaceSmashServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp new file mode 100644 index 00000000..f69a3eb6 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp @@ -0,0 +1,39 @@ +#include "FvRaceSmashEggImagineServer.h" +#include "CharacterComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "PossessableComponent.h" +#include "eRacingTaskParam.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" + +void FvRaceSmashEggImagineServer::OnDie(Entity* self, Entity* killer) { + if (killer != nullptr) { + auto* destroyableComponent = killer->GetComponent<DestroyableComponent>(); + if (destroyableComponent != nullptr) { + destroyableComponent->SetImagination(destroyableComponent->GetImagination() + 10); + EntityManager::Instance()->SerializeEntity(killer); + } + + // get possessor to progress statistics and tasks. + auto* possessableComponent = killer->GetComponent<PossessableComponent>(); + if (possessableComponent != nullptr) { + + auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + if (possessor != nullptr) { + + auto* missionComponent = possessor->GetComponent<MissionComponent>(); + auto* characterComponent = possessor->GetComponent<CharacterComponent>(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(ImaginationPowerUpsCollected); + characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); + } + if (missionComponent == nullptr) return; + // Dragon eggs have their own smash server so we handle mission progression for them here. + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::SMASH_SPECIFIC_SMASHABLE); + } + } + + } +} diff --git a/dScripts/FvRaceSmashEggImagineServer.h b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.h similarity index 65% rename from dScripts/FvRaceSmashEggImagineServer.h rename to dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.h index 7c682c36..dd697440 100644 --- a/dScripts/FvRaceSmashEggImagineServer.h +++ b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class FvRaceSmashEggImagineServer : public CppScripts::Script { - void OnDie(Entity *self, Entity *killer) override; + void OnDie(Entity* self, Entity* killer) override; }; diff --git a/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp new file mode 100644 index 00000000..6a29f9a8 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp @@ -0,0 +1,56 @@ +#include "CharacterComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "PossessableComponent.h" +#include "RaceImagineCrateServer.h" +#include "eRacingTaskParam.h" +#include "MissionComponent.h" +#include "SkillComponent.h" +#include "eMissionTaskType.h" + +void RaceImagineCrateServer::OnDie(Entity* self, Entity* killer) { + if (self->GetVar<bool>(u"bIsDead")) { + return; + } + + self->SetVar<bool>(u"bIsDead", true); + + if (killer == nullptr) { + return; + } + + auto* skillComponent = killer->GetComponent<SkillComponent>(); + + if (skillComponent == nullptr) { + return; + } + + auto* destroyableComponent = killer->GetComponent<DestroyableComponent>(); + + if (destroyableComponent != nullptr) { + destroyableComponent->SetImagination(60); + + EntityManager::Instance()->SerializeEntity(killer); + } + + // Find possessor of race car to progress missions and update stats. + auto* possessableComponent = killer->GetComponent<PossessableComponent>(); + if (possessableComponent != nullptr) { + + auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + if (possessor != nullptr) { + + auto* missionComponent = possessor->GetComponent<MissionComponent>(); + auto* characterComponent = possessor->GetComponent<CharacterComponent>(); + + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingImaginationCratesSmashed); + characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); + } + + // Progress racing smashable missions + if (missionComponent == nullptr) return; + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); + } + } +} diff --git a/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.h b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.h new file mode 100644 index 00000000..92020925 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.h @@ -0,0 +1,14 @@ +#pragma once +#include "CppScripts.h" + +class RaceImagineCrateServer : public CppScripts::Script +{ +public: + /** + * @brief When a boost smashable has been smashed, this function is called + * + * @param self The Entity that called this function. + * @param killer The Entity that killed this Entity. + */ + void OnDie(Entity* self, Entity* killer) override; +}; diff --git a/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp new file mode 100644 index 00000000..92a50873 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp @@ -0,0 +1,37 @@ +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "PossessorComponent.h" +#include "RaceImaginePowerup.h" +#include "eRacingTaskParam.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" + +void RaceImaginePowerup::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, + int32_t param2, int32_t param3) { + if (sender->IsPlayer() && args == "powerup") { + auto* possessorComponent = sender->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) { + return; + } + + auto* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) { + return; + } + + auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>(); + + if (destroyableComponent == nullptr) { + return; + } + + destroyableComponent->Imagine(10); + + auto* missionComponent = sender->GetComponent<MissionComponent>(); + + if (missionComponent == nullptr) return; + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::COLLECT_IMAGINATION); + } +} diff --git a/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.h b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.h new file mode 100644 index 00000000..2df2e060 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class RaceImaginePowerup : public CppScripts::Script +{ +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; diff --git a/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp new file mode 100644 index 00000000..295f38ee --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp @@ -0,0 +1,31 @@ +#include "CharacterComponent.h" +#include "EntityManager.h" +#include "PossessableComponent.h" +#include "RaceSmashServer.h" +#include "eRacingTaskParam.h" +#include "MissionComponent.h" +#include "eMissionTaskType.h" + +void RaceSmashServer::OnDie(Entity* self, Entity* killer) { + // Crate is smashed by the car + auto* possessableComponent = killer->GetComponent<PossessableComponent>(); + if (possessableComponent != nullptr) { + + auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); + if (possessor != nullptr) { + + auto* missionComponent = possessor->GetComponent<MissionComponent>(); + auto* characterComponent = possessor->GetComponent<CharacterComponent>(); + + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingSmashablesSmashed); + } + + // Progress racing smashable missions + if (missionComponent == nullptr) return; + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); + // Progress missions that ask us to smash a specific smashable. + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::SMASH_SPECIFIC_SMASHABLE); + } + } +} diff --git a/dScripts/ai/RACING/OBJECTS/RaceSmashServer.h b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.h new file mode 100644 index 00000000..096092bd --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.h @@ -0,0 +1,12 @@ +#pragma once +#include "CppScripts.h" + +class RaceSmashServer : public CppScripts::Script { + /** + * @brief When a smashable has been destroyed, this function is called. + * + * @param self The Entity that called this function. + * @param killer The Entity that killed this Entity. + */ + void OnDie(Entity* self, Entity* killer) override; +}; diff --git a/dScripts/ai/SPEC/CMakeLists.txt b/dScripts/ai/SPEC/CMakeLists.txt new file mode 100644 index 00000000..42dbf8f8 --- /dev/null +++ b/dScripts/ai/SPEC/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DSCRIPTS_SOURCES_AI_SPEC + "SpecialCoinSpawner.cpp" + "SpecialPowerupSpawner.cpp" + "SpecialSpeedBuffSpawner.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/SPEC/SpecialCoinSpawner.cpp b/dScripts/ai/SPEC/SpecialCoinSpawner.cpp new file mode 100644 index 00000000..ff494845 --- /dev/null +++ b/dScripts/ai/SPEC/SpecialCoinSpawner.cpp @@ -0,0 +1,16 @@ +#include "SpecialCoinSpawner.h" +#include "CharacterComponent.h" + +void SpecialCoinSpawner::OnStartup(Entity* self) { + self->SetProximityRadius(1.5f, "powerupEnter"); +} + +void SpecialCoinSpawner::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) { + if (name != "powerupEnter" && status != "ENTER") return; + if (!entering->IsPlayer()) return; + auto character = entering->GetCharacter(); + if (!character) return; + GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + character->SetCoins(character->GetCoins() + this->m_CurrencyDenomination, eLootSourceType::CURRENCY); + self->Smash(entering->GetObjectID(), eKillType::SILENT); +} diff --git a/dScripts/ai/SPEC/SpecialCoinSpawner.h b/dScripts/ai/SPEC/SpecialCoinSpawner.h new file mode 100644 index 00000000..5af6f24a --- /dev/null +++ b/dScripts/ai/SPEC/SpecialCoinSpawner.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class SpecialCoinSpawner : public CppScripts::Script { +public: + SpecialCoinSpawner(uint32_t CurrencyDenomination) { + m_CurrencyDenomination = CurrencyDenomination; + }; + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) override; +private: + int32_t m_CurrencyDenomination = 0; +}; diff --git a/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp b/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp new file mode 100644 index 00000000..72565923 --- /dev/null +++ b/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp @@ -0,0 +1,26 @@ +#include "SpecialPowerupSpawner.h" + +#include "GameMessages.h" +#include "SkillComponent.h" +#include "EntityManager.h" +#include "eReplicaComponentType.h" + +void SpecialPowerupSpawner::OnStartup(Entity* self) { + self->SetProximityRadius(1.5f, "powerupEnter"); + self->SetVar(u"bIsDead", false); +} + +void SpecialPowerupSpawner::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) { + if (name != "powerupEnter" && status != "ENTER") return; + if (!entering->IsPlayer()) return; + if (self->GetVar<bool>(u"bIsDead")) return; + + GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + + auto skillComponent = self->GetComponent<SkillComponent>(); + if (!skillComponent) return; + skillComponent->CastSkill(this->m_SkillId, entering->GetObjectID()); + + self->SetVar(u"bIsDead", true); + self->Smash(entering->GetObjectID(), eKillType::SILENT); +} diff --git a/dScripts/ai/SPEC/SpecialPowerupSpawner.h b/dScripts/ai/SPEC/SpecialPowerupSpawner.h new file mode 100644 index 00000000..b27e9789 --- /dev/null +++ b/dScripts/ai/SPEC/SpecialPowerupSpawner.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +class SpecialPowerupSpawner : public CppScripts::Script { +public: + SpecialPowerupSpawner(uint32_t skillId) { + m_SkillId = skillId; + }; + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; +private: + uint32_t m_SkillId = 0; +}; diff --git a/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp new file mode 100644 index 00000000..d3109806 --- /dev/null +++ b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp @@ -0,0 +1,26 @@ +#include "SpecialSpeedBuffSpawner.h" + +#include "GameMessages.h" +#include "SkillComponent.h" +#include "EntityManager.h" +#include "eReplicaComponentType.h" + +void SpecialSpeedBuffSpawner::OnStartup(Entity* self) { + self->SetProximityRadius(1.5f, "powerupEnter"); + self->SetVar(u"bIsDead", false); +} + +void SpecialSpeedBuffSpawner::OnProximityUpdate(Entity* self, Entity* entering, const std::string name, const std::string status) { + if (name != "powerupEnter" && status != "ENTER") return; + if (!entering->IsPlayer()) return; + if (self->GetVar<bool>(u"bIsDead")) return; + + GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + + auto skillComponent = entering->GetComponent<SkillComponent>(); + if (!skillComponent) return; + skillComponent->CastSkill(this->m_SkillId, entering->GetObjectID()); + + self->SetVar(u"bIsDead", true); + self->Smash(entering->GetObjectID(), eKillType::SILENT); +} diff --git a/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.h b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.h new file mode 100644 index 00000000..e1741691 --- /dev/null +++ b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class SpecialSpeedBuffSpawner : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; +private: + uint32_t m_SkillId = 500; +}; diff --git a/dScripts/AllCrateChicken.cpp b/dScripts/ai/WILD/AllCrateChicken.cpp similarity index 100% rename from dScripts/AllCrateChicken.cpp rename to dScripts/ai/WILD/AllCrateChicken.cpp diff --git a/dScripts/AllCrateChicken.h b/dScripts/ai/WILD/AllCrateChicken.h similarity index 100% rename from dScripts/AllCrateChicken.h rename to dScripts/ai/WILD/AllCrateChicken.h diff --git a/dScripts/ai/WILD/CMakeLists.txt b/dScripts/ai/WILD/CMakeLists.txt new file mode 100644 index 00000000..446ce0d4 --- /dev/null +++ b/dScripts/ai/WILD/CMakeLists.txt @@ -0,0 +1,11 @@ +set(DSCRIPTS_SOURCES_AI_WILD + "AllCrateChicken.cpp" + "WildAmbients.cpp" + "WildAmbientCrab.cpp" + "WildAndScared.cpp" + "WildGfGlowbug.cpp" + "WildNinjaBricks.cpp" + "WildNinjaStudent.cpp" + "WildNinjaSensei.cpp" + "WildPants.cpp" + PARENT_SCOPE) diff --git a/dScripts/ai/WILD/WildAmbientCrab.cpp b/dScripts/ai/WILD/WildAmbientCrab.cpp new file mode 100644 index 00000000..7b5b3d45 --- /dev/null +++ b/dScripts/ai/WILD/WildAmbientCrab.cpp @@ -0,0 +1,27 @@ +#include "WildAmbientCrab.h" +#include "GameMessages.h" + +void WildAmbientCrab::OnStartup(Entity* self){ + self->SetVar(u"flipped", true); + GameMessages::SendPlayAnimation(self, u"idle"); +} + +void WildAmbientCrab::OnUse(Entity* self, Entity* user) { + auto flipped = self->GetVar<bool>(u"flipped"); + if (flipped) { + self->AddTimer("Flipping", 0.6f); + GameMessages::SendPlayAnimation(self, u"flip-over"); + self->SetVar(u"flipped", false); + } else if (!flipped) { + self->AddTimer("Flipback", 0.8f); + GameMessages::SendPlayAnimation(self, u"flip-back"); + self->SetVar(u"flipped", true); + } +} + +void WildAmbientCrab::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "Flipping") GameMessages::SendPlayAnimation(self, u"over-idle"); + else if (timerName == "Flipback") GameMessages::SendPlayAnimation(self, u"idle"); +} + + diff --git a/dScripts/ai/WILD/WildAmbientCrab.h b/dScripts/ai/WILD/WildAmbientCrab.h new file mode 100644 index 00000000..0e1b3877 --- /dev/null +++ b/dScripts/ai/WILD/WildAmbientCrab.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildAmbientCrab final : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/WildAmbients.cpp b/dScripts/ai/WILD/WildAmbients.cpp similarity index 65% rename from dScripts/WildAmbients.cpp rename to dScripts/ai/WILD/WildAmbients.cpp index f6414ee8..16dfa043 100644 --- a/dScripts/WildAmbients.cpp +++ b/dScripts/ai/WILD/WildAmbients.cpp @@ -1,7 +1,6 @@ #include "WildAmbients.h" #include "GameMessages.h" -void WildAmbients::OnUse(Entity* self, Entity* user) -{ +void WildAmbients::OnUse(Entity* self, Entity* user) { GameMessages::SendPlayAnimation(self, u"interact"); } diff --git a/dScripts/WildAmbients.h b/dScripts/ai/WILD/WildAmbients.h similarity index 100% rename from dScripts/WildAmbients.h rename to dScripts/ai/WILD/WildAmbients.h diff --git a/dScripts/ai/WILD/WildAndScared.cpp b/dScripts/ai/WILD/WildAndScared.cpp new file mode 100644 index 00000000..d2e89c40 --- /dev/null +++ b/dScripts/ai/WILD/WildAndScared.cpp @@ -0,0 +1,6 @@ +#include "WildAndScared.h" +#include "GameMessages.h" + +void WildAndScared::OnUse(Entity* self, Entity* user) { + GameMessages::SendPlayAnimation(self, u"scared"); +} diff --git a/dScripts/ai/WILD/WildAndScared.h b/dScripts/ai/WILD/WildAndScared.h new file mode 100644 index 00000000..c94fb06d --- /dev/null +++ b/dScripts/ai/WILD/WildAndScared.h @@ -0,0 +1,7 @@ +#pragma once +#include "CppScripts.h" + +class WildAndScared : public CppScripts::Script { +public: + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/WILD/WildGfGlowbug.cpp b/dScripts/ai/WILD/WildGfGlowbug.cpp new file mode 100644 index 00000000..d834f5b5 --- /dev/null +++ b/dScripts/ai/WILD/WildGfGlowbug.cpp @@ -0,0 +1,28 @@ +#include "WildGfGlowbug.h" +#include "GameMessages.h" + +void WildGfGlowbug::OnStartup(Entity* self){ + self->SetVar(u"switch", false); +} + +void WildGfGlowbug::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "physicsReady") { + auto switchState = self->GetVar<bool>(u"switch"); + if (!switchState) { + GameMessages::SendStopFXEffect(self, true, "glowlight"); + } else if (switchState) { + GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + } + } +} + +void WildGfGlowbug::OnUse(Entity* self, Entity* user) { + auto switchState = self->GetVar<bool>(u"switch"); + if (switchState) { + GameMessages::SendStopFXEffect(self, true, "glowlight"); + self->SetVar(u"switch", false); + } else if (!switchState) { + GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + self->SetVar(u"switch", true); + } +} diff --git a/dScripts/ai/WILD/WildGfGlowbug.h b/dScripts/ai/WILD/WildGfGlowbug.h new file mode 100644 index 00000000..03242372 --- /dev/null +++ b/dScripts/ai/WILD/WildGfGlowbug.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildGfGlowbug : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/WILD/WildNinjaBricks.cpp b/dScripts/ai/WILD/WildNinjaBricks.cpp new file mode 100644 index 00000000..4fa65b01 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaBricks.cpp @@ -0,0 +1,13 @@ +#include "WildNinjaBricks.h" +#include "Entity.h" + +void WildNinjaBricks::OnStartup(Entity* self) { + self->AddToGroup("Ninjastuff"); +} + +void WildNinjaBricks::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); + else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); + else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); +} + diff --git a/dScripts/ai/WILD/WildNinjaBricks.h b/dScripts/ai/WILD/WildNinjaBricks.h new file mode 100644 index 00000000..9578e37a --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaBricks.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaBricks : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; +}; + diff --git a/dScripts/ai/WILD/WildNinjaSensei.cpp b/dScripts/ai/WILD/WildNinjaSensei.cpp new file mode 100644 index 00000000..42ddfa21 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaSensei.cpp @@ -0,0 +1,36 @@ +#include "WildNinjaSensei.h" +#include "Entity.h" + +void WildNinjaSensei::OnStartup(Entity* self) { + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("CraneStart", 5); +} + +void WildNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "CraneStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Crane"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("TigerStart", 25); + GameMessages::SendPlayAnimation(self, u"crane"); + } else if (timerName == "TigerStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Tiger"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("MantisStart", 25); + GameMessages::SendPlayAnimation(self, u"tiger"); + } else if (timerName == "MantisStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"tiger"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Mantis"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("CraneStart", 25); + GameMessages::SendPlayAnimation(self, u"mantis"); + } else if (timerName == "Bow") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Bow"); + GameMessages::SendPlayAnimation(self, u"bow"); + } +} + diff --git a/dScripts/ai/WILD/WildNinjaSensei.h b/dScripts/ai/WILD/WildNinjaSensei.h new file mode 100644 index 00000000..c14b6f08 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaSensei.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaSensei : public CppScripts::Script { +public: + void OnStartup(Entity* self); + void OnTimerDone(Entity* self, std::string timerName); +}; + diff --git a/dScripts/ai/WILD/WildNinjaStudent.cpp b/dScripts/ai/WILD/WildNinjaStudent.cpp new file mode 100644 index 00000000..b7e2f585 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaStudent.cpp @@ -0,0 +1,14 @@ +#include "WildNinjaStudent.h" +#include "GameMessages.h" + +void WildNinjaStudent::OnStartup(Entity* self) { + self->AddToGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"bow"); +} + +void WildNinjaStudent::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); + else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); + else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); + else if (name == "Bow") GameMessages::SendPlayAnimation(self, u"bow"); +} diff --git a/dScripts/ai/WILD/WildNinjaStudent.h b/dScripts/ai/WILD/WildNinjaStudent.h new file mode 100644 index 00000000..b76e5fa5 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaStudent.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaStudent : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; +}; + diff --git a/dScripts/ai/WILD/WildPants.cpp b/dScripts/ai/WILD/WildPants.cpp new file mode 100644 index 00000000..7c5e1cd2 --- /dev/null +++ b/dScripts/ai/WILD/WildPants.cpp @@ -0,0 +1,10 @@ +#include "WildPants.h" +#include "GameMessages.h" + +void WildPants::OnStartup(Entity* self) { + self->SetProximityRadius(5, "scardyPants"); +} + +void WildPants::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status == "ENTER") GameMessages::SendPlayAnimation(self, u"scared"); +} diff --git a/dScripts/SpecialImaginePowerupSpawner.h b/dScripts/ai/WILD/WildPants.h similarity index 68% rename from dScripts/SpecialImaginePowerupSpawner.h rename to dScripts/ai/WILD/WildPants.h index 6cfe2c6e..c6968045 100644 --- a/dScripts/SpecialImaginePowerupSpawner.h +++ b/dScripts/ai/WILD/WildPants.h @@ -1,7 +1,7 @@ -#pragma once +#pragma once #include "CppScripts.h" -class SpecialImaginePowerupSpawner final : public CppScripts::Script +class WildPants : public CppScripts::Script { public: void OnStartup(Entity* self) override; diff --git a/dScripts/client/CMakeLists.txt b/dScripts/client/CMakeLists.txt new file mode 100644 index 00000000..c2777508 --- /dev/null +++ b/dScripts/client/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DSCRIPTS_SOURCES_CLIENT) + +add_subdirectory(ai) + +foreach(file ${DSCRIPTS_SOURCES_CLIENT_AI}) + set(DSCRIPTS_SOURCES_CLIENT ${DSCRIPTS_SOURCES_CLIENT} "ai/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_CLIENT ${DSCRIPTS_SOURCES_CLIENT} PARENT_SCOPE) diff --git a/dScripts/client/ai/CMakeLists.txt b/dScripts/client/ai/CMakeLists.txt new file mode 100644 index 00000000..c1358c57 --- /dev/null +++ b/dScripts/client/ai/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DSCRIPTS_SOURCES_CLIENT_AI) + +add_subdirectory(PR) + +foreach(file ${DSCRIPTS_SOURCES_CLIENT_AI_PR}) + set(DSCRIPTS_SOURCES_CLIENT_AI ${DSCRIPTS_SOURCES_CLIENT_AI} "PR/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_CLIENT_AI ${DSCRIPTS_SOURCES_CLIENT_AI} PARENT_SCOPE) diff --git a/dScripts/client/ai/PR/CMakeLists.txt b/dScripts/client/ai/PR/CMakeLists.txt new file mode 100644 index 00000000..ef7d5d6a --- /dev/null +++ b/dScripts/client/ai/PR/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DSCRIPTS_SOURCES_CLIENT_AI_PR + "PrWhistle.cpp" + "CrabServer.cpp" + PARENT_SCOPE) diff --git a/dScripts/client/ai/PR/CrabServer.cpp b/dScripts/client/ai/PR/CrabServer.cpp new file mode 100644 index 00000000..f30142ba --- /dev/null +++ b/dScripts/client/ai/PR/CrabServer.cpp @@ -0,0 +1,44 @@ +#include "CrabServer.h" +#include "PetComponent.h" +#include "ePetTamingNotifyType.h" + +void CrabServer::OnStartup(Entity* self) { + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + return; + + // Triggers the local crab script for taming etc. + auto tamer = self->GetVar<LWOOBJID>(u"tamer"); + // Client compares this with player:GetID() which is a string, so we'll have to give it a string + self->SetNetworkVar(u"crabtamer", std::to_string(tamer)); + + // Kill if the player decides that the crab is not worthy + self->AddTimer("killself", 45.0f); +} + +void CrabServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "killself") { + + // Don't accidentally kill a pet that is already owned + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr || petComponent->GetOwner() != nullptr) + return; + + self->Smash(self->GetObjectID(), eKillType::SILENT); + } +} + +void CrabServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) { + if (type == ePetTamingNotifyType::BEGIN) { + self->CancelTimer("killself"); + } else if (type == ePetTamingNotifyType::QUIT || type == ePetTamingNotifyType::FAILED) { + self->Smash(self->GetObjectID(), eKillType::SILENT); + } else if (type == ePetTamingNotifyType::SUCCESS) { + auto* petComponent = self->GetComponent<PetComponent>(); + if (petComponent == nullptr) + return; + // TODO: Remove custom group? + // Command the pet to the player as it may otherwise go to its spawn point which is non existant + // petComponent->Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 6, 202, true); + } +} diff --git a/dScripts/client/ai/PR/CrabServer.h b/dScripts/client/ai/PR/CrabServer.h new file mode 100644 index 00000000..8c689dbd --- /dev/null +++ b/dScripts/client/ai/PR/CrabServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class CrabServer : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, ePetTamingNotifyType type) override; +}; diff --git a/dScripts/client/ai/PR/PrWhistle.cpp b/dScripts/client/ai/PR/PrWhistle.cpp new file mode 100644 index 00000000..888e1c65 --- /dev/null +++ b/dScripts/client/ai/PR/PrWhistle.cpp @@ -0,0 +1,14 @@ +#include "PrWhistle.h" +#include "Character.h" +#include "Entity.h" + +void PrWhistle::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) { + if (args == "unlockEmote") { + auto* character = sender->GetCharacter(); + + if (character != nullptr) { + character->UnlockEmote(115); + } + } +} diff --git a/dScripts/client/ai/PR/PrWhistle.h b/dScripts/client/ai/PR/PrWhistle.h new file mode 100644 index 00000000..1209ba0d --- /dev/null +++ b/dScripts/client/ai/PR/PrWhistle.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class PrWhistle : public CppScripts::Script +{ +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, + int32_t param3) override; +}; + diff --git a/dScripts/zone/AG/CMakeLists.txt b/dScripts/zone/AG/CMakeLists.txt new file mode 100644 index 00000000..14426a46 --- /dev/null +++ b/dScripts/zone/AG/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_AG + "ZoneAgSurvival.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/AG/ZoneAgSurvival.cpp b/dScripts/zone/AG/ZoneAgSurvival.cpp new file mode 100644 index 00000000..79f54c06 --- /dev/null +++ b/dScripts/zone/AG/ZoneAgSurvival.cpp @@ -0,0 +1,127 @@ +#include "ZoneAgSurvival.h" + +Constants ZoneAgSurvival::GetConstants() { + return Constants{ + 60, + 2, + 7, + 5, + 10, + 5, + 15, + 10, + 0, + true, + std::vector<uint32_t> {8, 13, 18, 23, 28, 32}, + std::vector<uint32_t> {2, 10, 15, 20, 25, 30} + }; +} + +MobSets ZoneAgSurvival::GetMobSets() { + return MobSets{ + std::map<std::string, std::vector<LOT>> { + {"MobA", {6351, 8088, 8089} }, + {"MobB", {6668, 8090, 8091} }, + {"MobC", {6454, 8096, 8097} }, + }, + std::map<std::string, std::vector<std::vector<std::vector<uint32_t>>>> { + { BaseMobSet, { + { {3, 0, 0}, }, + { {2, 1, 0}, }, + { {4, 1, 0}, }, + { {1, 2, 0}, }, + { {0, 1, 1}, }, + { {0, 2, 2}, } + }}, + { RandMobSet, { + { {4, 0, 0}, {4, 0, 0}, {4, 0, 0}, {4, 0, 0}, {3, 1, 0} }, + { {4, 1, 0}, {4, 1, 0}, {4, 1, 0}, {4, 1, 0}, {2, 1, 1} }, + { {1, 2, 0}, {1, 2, 0}, {1, 2, 0}, {1, 2, 0}, {0, 1, 1} }, + { {1, 2, 1}, {1, 2, 1}, {1, 2, 1}, {0, 2, 1}, {0, 2, 2} }, + { {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 3}, {0, 1, 3} }, + { {0, 2, 3}, {0, 2, 3}, {0, 2, 3}, {0, 2, 3}, {0, 2, 3} }, + }} + } + }; +} + +SpawnerNetworks ZoneAgSurvival::GetSpawnerNetworks() { + return SpawnerNetworks{ + SpawnerNetworkCollection { + BaseMobSet, + { + SpawnerNetwork { + std::vector<std::string> { "Base_MobA", "Base_MobB", "Base_MobC" }, + "", + false, + false + }, + } + }, + SpawnerNetworkCollection { + RandMobSet, + { + SpawnerNetwork { + std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, + "01", + false, + false + }, + SpawnerNetwork { + std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, + "02", + false, + false + }, + SpawnerNetwork { + std::vector<std::string> {"MobA_", "MobB_", "MobC_"}, + "03", + true, + false + }, + } + }, + SpawnerNetworkCollection { + "", + { + SpawnerNetwork { + std::vector<std::string> { "Rewards_" }, + "01", + false, + false + }, + } + }, + SpawnerNetworkCollection { + "", + { + SpawnerNetwork { + std::vector<std::string> { "Smash_" }, + "01", + false, + false + }, + } + } + }; +} + +std::map<uint32_t, uint32_t> ZoneAgSurvival::GetMissionsToUpdate() { + return std::map<uint32_t, uint32_t> { + { 479, 60 }, + { 1153, 180 }, + { 1618, 420 }, + { 1628, 420 }, + { 1638, 420 }, + { 1648, 420 }, + { 1412, 120 }, + { 1510, 120 }, + { 1547, 120 }, + { 1584, 120 }, + { 1426, 300 }, + { 1524, 300 }, + { 1561, 300 }, + { 1598, 300 }, + { 1865, 180 } + }; +} diff --git a/dScripts/zone/AG/ZoneAgSurvival.h b/dScripts/zone/AG/ZoneAgSurvival.h new file mode 100644 index 00000000..4447b6b8 --- /dev/null +++ b/dScripts/zone/AG/ZoneAgSurvival.h @@ -0,0 +1,11 @@ +#pragma once +#include "CppScripts.h" +#include "BaseSurvivalServer.h" +#include <map> + +class ZoneAgSurvival : public BaseSurvivalServer { + Constants GetConstants() override; + SpawnerNetworks GetSpawnerNetworks() override; + MobSets GetMobSets() override; + std::map<uint32_t, uint32_t> GetMissionsToUpdate() override; +}; diff --git a/dScripts/zone/CMakeLists.txt b/dScripts/zone/CMakeLists.txt new file mode 100644 index 00000000..5d800031 --- /dev/null +++ b/dScripts/zone/CMakeLists.txt @@ -0,0 +1,21 @@ +set(DSCRIPTS_SOURCES_ZONE) + +add_subdirectory(AG) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_AG}) + set(DSCRIPTS_SOURCES_ZONE ${DSCRIPTS_SOURCES_ZONE} "AG/${file}") +endforeach() + +add_subdirectory(LUPs) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_LUPS}) + set(DSCRIPTS_SOURCES_ZONE ${DSCRIPTS_SOURCES_ZONE} "LUPs/${file}") +endforeach() + +add_subdirectory(PROPERTY) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_PROPERTY}) + set(DSCRIPTS_SOURCES_ZONE ${DSCRIPTS_SOURCES_ZONE} "PROPERTY/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_ZONE ${DSCRIPTS_SOURCES_ZONE} PARENT_SCOPE) diff --git a/dScripts/zone/LUPs/CMakeLists.txt b/dScripts/zone/LUPs/CMakeLists.txt new file mode 100644 index 00000000..b3b55ad6 --- /dev/null +++ b/dScripts/zone/LUPs/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_LUPS + "WblGenericZone.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/LUPs/WblGenericZone.cpp b/dScripts/zone/LUPs/WblGenericZone.cpp new file mode 100644 index 00000000..5a670d8e --- /dev/null +++ b/dScripts/zone/LUPs/WblGenericZone.cpp @@ -0,0 +1,10 @@ +#include "WblGenericZone.h" +#include "Player.h" + +void WblGenericZone::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == m_WblAbortMsg) { + if (!sender) return; + auto player = dynamic_cast<Player*>(sender); + if (player) player->SendToZone(m_WblMainZone); + } +} diff --git a/dScripts/zone/LUPs/WblGenericZone.h b/dScripts/zone/LUPs/WblGenericZone.h new file mode 100644 index 00000000..55b66e81 --- /dev/null +++ b/dScripts/zone/LUPs/WblGenericZone.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" +class WblGenericZone : public CppScripts::Script +{ +public: + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +private: + const LWOMAPID m_WblMainZone = 1600; + const std::string m_WblAbortMsg = "AbortWBLZone"; +}; diff --git a/dScripts/zone/PROPERTY/CMakeLists.txt b/dScripts/zone/PROPERTY/CMakeLists.txt new file mode 100644 index 00000000..b0588181 --- /dev/null +++ b/dScripts/zone/PROPERTY/CMakeLists.txt @@ -0,0 +1,21 @@ +set(DSCRIPTS_SOURCES_ZONE_PROPERTY) + +add_subdirectory(FV) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_PROPERTY_FV}) + set(DSCRIPTS_SOURCES_ZONE_PROPERTY ${DSCRIPTS_SOURCES_ZONE_PROPERTY} "FV/${file}") +endforeach() + +add_subdirectory(GF) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_PROPERTY_GF}) + set(DSCRIPTS_SOURCES_ZONE_PROPERTY ${DSCRIPTS_SOURCES_ZONE_PROPERTY} "GF/${file}") +endforeach() + +add_subdirectory(NS) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_PROPERTY_NS}) + set(DSCRIPTS_SOURCES_ZONE_PROPERTY ${DSCRIPTS_SOURCES_ZONE_PROPERTY} "NS/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_ZONE_PROPERTY ${DSCRIPTS_SOURCES_ZONE_PROPERTY} PARENT_SCOPE) diff --git a/dScripts/zone/PROPERTY/FV/CMakeLists.txt b/dScripts/zone/PROPERTY/FV/CMakeLists.txt new file mode 100644 index 00000000..60da048d --- /dev/null +++ b/dScripts/zone/PROPERTY/FV/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_PROPERTY_FV + "ZoneFvProperty.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/PROPERTY/FV/ZoneFvProperty.cpp b/dScripts/zone/PROPERTY/FV/ZoneFvProperty.cpp new file mode 100644 index 00000000..8b8072ad --- /dev/null +++ b/dScripts/zone/PROPERTY/FV/ZoneFvProperty.cpp @@ -0,0 +1,40 @@ +#include "ZoneFvProperty.h" +#include "Entity.h" + +void ZoneFvProperty::SetGameVariables(Entity* self) { + self->SetVar<std::string>(ClaimMarkerGroup, "Platform"); + self->SetVar<std::string>(GeneratorGroup, "Generator"); + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(SpotsGroup, "Spots"); + self->SetVar<std::string>(MSCloudsGroup, "Clouds"); + self->SetVar<std::string>(EnemiesGroup, "Enemies"); + self->SetVar<std::string>(FXManagerGroup, "FXManager"); + self->SetVar<std::string>(ImagOrbGroup, "Orb"); + self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); + + self->SetVar<std::vector<std::string>>(EnemiesSpawner, + { "RoninWander", "RoninGen", "HorsemenGen" }); + self->SetVar<std::string>(ClaimMarkerSpawner, "Platform"); + self->SetVar<std::string>(GeneratorSpawner, "Generator"); + self->SetVar<std::string>(DamageFXSpawner, "Clouds"); + self->SetVar<std::string>(FXSpotsSpawner, "Spots"); + self->SetVar<std::string>(PropertyMGSpawner, "Guard"); + self->SetVar<std::string>(ImageOrbSpawner, "Orb"); + self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); + self->SetVar<std::string>(SmashablesSpawner, "Smashables"); + self->SetVar<std::string>(FXManagerSpawner, "FXManager"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Ash", "FX", "Fog" }); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, {}); + + self->SetVar<int32_t>(defeatedProperyFlag, 99); + self->SetVar<int32_t>(placedModelFlag, 107); + self->SetVar<uint32_t>(guardMissionFlag, 874); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 950); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 11023); + self->SetVar<LOT>(orbIDFlag, 10226); + self->SetVar<LOT>(behaviorQBID, 11011); +} diff --git a/dScripts/ZoneFvProperty.h b/dScripts/zone/PROPERTY/FV/ZoneFvProperty.h similarity index 66% rename from dScripts/ZoneFvProperty.h rename to dScripts/zone/PROPERTY/FV/ZoneFvProperty.h index 44ec9f85..d456ef11 100644 --- a/dScripts/ZoneFvProperty.h +++ b/dScripts/zone/PROPERTY/FV/ZoneFvProperty.h @@ -2,5 +2,5 @@ #include "BasePropertyServer.h" class ZoneFvProperty : public BasePropertyServer { - void SetGameVariables(Entity *self) override; + void SetGameVariables(Entity* self) override; }; diff --git a/dScripts/zone/PROPERTY/GF/CMakeLists.txt b/dScripts/zone/PROPERTY/GF/CMakeLists.txt new file mode 100644 index 00000000..fed6033b --- /dev/null +++ b/dScripts/zone/PROPERTY/GF/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_PROPERTY_GF + "ZoneGfProperty.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/PROPERTY/GF/ZoneGfProperty.cpp b/dScripts/zone/PROPERTY/GF/ZoneGfProperty.cpp new file mode 100644 index 00000000..87b2345d --- /dev/null +++ b/dScripts/zone/PROPERTY/GF/ZoneGfProperty.cpp @@ -0,0 +1,40 @@ +#include "ZoneGfProperty.h" +#include "Entity.h" + +void ZoneGfProperty::SetGameVariables(Entity* self) { + self->SetVar<std::string>(ClaimMarkerGroup, "BehavQB"); + self->SetVar<std::string>(GeneratorGroup, "Generator"); + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(SpotsGroup, "Spots"); + self->SetVar<std::string>(MSCloudsGroup, "Clouds"); + self->SetVar<std::string>(EnemiesGroup, "Enemies"); + self->SetVar<std::string>(FXManagerGroup, "FXManager"); + self->SetVar<std::string>(ImagOrbGroup, "Orb"); + self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); + + self->SetVar<std::vector<std::string>>(EnemiesSpawner, + { "PiratesWander", "PiratesGen", "AdmiralsWander", "AdmiralsGen" }); + self->SetVar<std::string>(ClaimMarkerSpawner, "BehavPlat"); + self->SetVar<std::string>(GeneratorSpawner, "Generator"); + self->SetVar<std::string>(DamageFXSpawner, "Clouds"); + self->SetVar<std::string>(FXSpotsSpawner, "Spots"); + self->SetVar<std::string>(PropertyMGSpawner, "Guard"); + self->SetVar<std::string>(ImageOrbSpawner, "Orb"); + self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); + self->SetVar<std::string>(SmashablesSpawner, "Smashables"); + self->SetVar<std::string>(FXManagerSpawner, "FXManager"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Birds", "Falls", "Sunbeam" }); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, { "TrappedPlatform", "IceBarrier", "FireBeast" }); + + self->SetVar<int32_t>(defeatedProperyFlag, 98); + self->SetVar<int32_t>(placedModelFlag, 106); + self->SetVar<uint32_t>(guardMissionFlag, 873); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 949); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 11109); + self->SetVar<LOT>(orbIDFlag, 10226); + self->SetVar<LOT>(behaviorQBID, 11001); +} diff --git a/dScripts/ZoneGfProperty.h b/dScripts/zone/PROPERTY/GF/ZoneGfProperty.h similarity index 66% rename from dScripts/ZoneGfProperty.h rename to dScripts/zone/PROPERTY/GF/ZoneGfProperty.h index 9b3a8a30..74ffd3b6 100644 --- a/dScripts/ZoneGfProperty.h +++ b/dScripts/zone/PROPERTY/GF/ZoneGfProperty.h @@ -2,5 +2,5 @@ #include "BasePropertyServer.h" class ZoneGfProperty : public BasePropertyServer { - void SetGameVariables(Entity *self) override; + void SetGameVariables(Entity* self) override; }; diff --git a/dScripts/zone/PROPERTY/NS/CMakeLists.txt b/dScripts/zone/PROPERTY/NS/CMakeLists.txt new file mode 100644 index 00000000..0e1f392c --- /dev/null +++ b/dScripts/zone/PROPERTY/NS/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_PROPERTY_NS + "ZoneNsProperty.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/PROPERTY/NS/ZoneNsProperty.cpp b/dScripts/zone/PROPERTY/NS/ZoneNsProperty.cpp new file mode 100644 index 00000000..52bb02e2 --- /dev/null +++ b/dScripts/zone/PROPERTY/NS/ZoneNsProperty.cpp @@ -0,0 +1,41 @@ +#include "ZoneNsProperty.h" +#include "Entity.h" + +void ZoneNsProperty::SetGameVariables(Entity* self) { + self->SetVar<std::string>(ClaimMarkerGroup, "Rhino"); + self->SetVar<std::string>(GeneratorGroup, "Generator"); + self->SetVar<std::string>(GuardGroup, "Guard"); + self->SetVar<std::string>(PropertyPlaqueGroup, "PropertyPlaque"); + self->SetVar<std::string>(PropertyVendorGroup, "PropertyVendor"); + self->SetVar<std::string>(SpotsGroup, "Spots"); + self->SetVar<std::string>(MSCloudsGroup, "Clouds"); + self->SetVar<std::string>(EnemiesGroup, "Enemies"); + self->SetVar<std::string>(FXManagerGroup, "FXManager"); + self->SetVar<std::string>(ImagOrbGroup, "Orb"); + self->SetVar<std::string>(GeneratorFXGroup, "GeneratorFX"); + + self->SetVar<std::vector<std::string>>(EnemiesSpawner, { + "StrombieWander", "StrombieGen", "PirateWander", "PirateGen", "RoninGen" + }); + self->SetVar<std::string>(ClaimMarkerSpawner, "ClaimMarker"); + self->SetVar<std::string>(GeneratorSpawner, "Generator"); + self->SetVar<std::string>(DamageFXSpawner, "MSClouds"); + self->SetVar<std::string>(FXSpotsSpawner, "Spots"); + self->SetVar<std::string>(PropertyMGSpawner, "Guard"); + self->SetVar<std::string>(ImageOrbSpawner, "Orb"); + self->SetVar<std::string>(GeneratorFXSpawner, "GeneratorFX"); + self->SetVar<std::string>(SmashablesSpawner, "Smashables"); + self->SetVar<std::string>(FXManagerSpawner, "FXManager"); + self->SetVar<std::string>(PropObjsSpawner, "BankObj"); + self->SetVar<std::vector<std::string>>(AmbientFXSpawner, { "Rockets" }); + self->SetVar<std::vector<std::string>>(BehaviorObjsSpawner, { "Cage", "Platform", "Door" }); + + self->SetVar<int32_t>(defeatedProperyFlag, 97); + self->SetVar<int32_t>(placedModelFlag, 105); + self->SetVar<uint32_t>(guardMissionFlag, 872); + self->SetVar<uint32_t>(brickLinkMissionIDFlag, 948); + self->SetVar<std::string>(passwordFlag, "s3kratK1ttN"); + self->SetVar<LOT>(generatorIdFlag, 11031); + self->SetVar<LOT>(orbIDFlag, 10226); + self->SetVar<LOT>(behaviorQBID, 11009); +} diff --git a/dScripts/ZoneNsProperty.h b/dScripts/zone/PROPERTY/NS/ZoneNsProperty.h similarity index 66% rename from dScripts/ZoneNsProperty.h rename to dScripts/zone/PROPERTY/NS/ZoneNsProperty.h index 353f4d72..bee8fd4c 100644 --- a/dScripts/ZoneNsProperty.h +++ b/dScripts/zone/PROPERTY/NS/ZoneNsProperty.h @@ -2,5 +2,5 @@ #include "BasePropertyServer.h" class ZoneNsProperty : public BasePropertyServer { - void SetGameVariables(Entity *self) override; + void SetGameVariables(Entity* self) override; }; diff --git a/dWorldServer/CMakeLists.txt b/dWorldServer/CMakeLists.txt new file mode 100644 index 00000000..c616da87 --- /dev/null +++ b/dWorldServer/CMakeLists.txt @@ -0,0 +1,11 @@ +set(DWORLDSERVER_SOURCES + "ObjectIDManager.cpp" + "PerformanceManager.cpp" +) + +add_library(dWorldServer ${DWORLDSERVER_SOURCES}) +add_executable(WorldServer "WorldServer.cpp") + +target_link_libraries(dWorldServer ${COMMON_LIBRARIES}) +target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation) + diff --git a/dWorldServer/ObjectIDManager.cpp b/dWorldServer/ObjectIDManager.cpp index bf8f770f..ef5fb9a5 100644 --- a/dWorldServer/ObjectIDManager.cpp +++ b/dWorldServer/ObjectIDManager.cpp @@ -10,54 +10,53 @@ #include "Game.h" // Static Variables -ObjectIDManager * ObjectIDManager::m_Address = nullptr; +ObjectIDManager* ObjectIDManager::m_Address = nullptr; static std::uniform_int_distribution<int> uni(10000000, INT32_MAX); //! Initializes the manager void ObjectIDManager::Initialize(void) { - //this->currentRequestID = 0; - this->currentObjectID = uint32_t(1152921508165007067); //Initial value for this server's objectIDs + //this->currentRequestID = 0; + this->currentObjectID = uint32_t(1152921508165007067); //Initial value for this server's objectIDs } //! Requests a persistent ID void ObjectIDManager::RequestPersistentID(std::function<void(uint32_t)> callback) { - PersistentIDRequest * request = new PersistentIDRequest(); - request->requestID = ++this->currentRequestID; - request->callback = callback; + PersistentIDRequest* request = new PersistentIDRequest(); + request->requestID = ++this->currentRequestID; + request->callback = callback; - this->requests.push_back(request); + this->requests.push_back(request); - MasterPackets::SendPersistentIDRequest(Game::server, request->requestID); + MasterPackets::SendPersistentIDRequest(Game::server, request->requestID); } //! Handles a persistent ID response void ObjectIDManager::HandleRequestPersistentIDResponse(uint64_t requestID, uint32_t persistentID) { - for (uint32_t i = 0; i < this->requests.size(); ++i) { - if (this->requests[i]->requestID == requestID) { + for (uint32_t i = 0; i < this->requests.size(); ++i) { + if (this->requests[i]->requestID == requestID) { - // Call the callback function - this->requests[i]->callback(persistentID); + // Call the callback function + this->requests[i]->callback(persistentID); - // Then delete the request - delete this->requests[i]; - this->requests.erase(this->requests.begin() + i); - return; - } - } + // Then delete the request + delete this->requests[i]; + this->requests.erase(this->requests.begin() + i); + return; + } + } } //! Handles cases where we have to get a unique object ID synchronously -uint32_t ObjectIDManager::GenerateRandomObjectID() -{ - std::random_device rd; - - std::mt19937 rng(rd()); +uint32_t ObjectIDManager::GenerateRandomObjectID() { + std::random_device rd; - return uni(rng); + std::mt19937 rng(rd()); + + return uni(rng); } //! Generates an object ID server-sided (used for regular entities like smashables) uint32_t ObjectIDManager::GenerateObjectID(void) { - return ++this->currentObjectID; + return ++this->currentObjectID; } diff --git a/dWorldServer/ObjectIDManager.h b/dWorldServer/ObjectIDManager.h index 7bfc1d27..deef89fd 100644 --- a/dWorldServer/ObjectIDManager.h +++ b/dWorldServer/ObjectIDManager.h @@ -10,66 +10,66 @@ \brief A manager for handling object ID generation */ -//! The persistent ID request + //! The persistent ID request struct PersistentIDRequest { - uint64_t requestID; + uint64_t requestID; - std::function<void(uint32_t)> callback; + std::function<void(uint32_t)> callback; }; //! The Object ID Manager class ObjectIDManager { private: - static ObjectIDManager * m_Address; //!< The singleton instance + static ObjectIDManager* m_Address; //!< The singleton instance - std::vector<PersistentIDRequest*> requests; //!< All outstanding persistent ID requests - uint64_t currentRequestID; //!< The current request ID + std::vector<PersistentIDRequest*> requests; //!< All outstanding persistent ID requests + uint64_t currentRequestID; //!< The current request ID - uint32_t currentObjectID; //!< The current object ID + uint32_t currentObjectID; //!< The current object ID public: - //! The singleton instance - static ObjectIDManager * Instance() { - if (m_Address == 0) { - m_Address = new ObjectIDManager; - } + //! The singleton instance + static ObjectIDManager* Instance() { + if (m_Address == 0) { + m_Address = new ObjectIDManager; + } - return m_Address; - } + return m_Address; + } - //! Initializes the manager - void Initialize(void); + //! Initializes the manager + void Initialize(void); - //! Requests a persistent ID - /*! - \param callback The callback function - */ - void RequestPersistentID(std::function<void(uint32_t)> callback); + //! Requests a persistent ID + /*! + \param callback The callback function + */ + void RequestPersistentID(std::function<void(uint32_t)> callback); - //! Handles a persistent ID response - /*! - \param requestID The request ID - \param persistentID The persistent ID - */ - void HandleRequestPersistentIDResponse(uint64_t requestID, uint32_t persistentID); + //! Handles a persistent ID response + /*! + \param requestID The request ID + \param persistentID The persistent ID + */ + void HandleRequestPersistentIDResponse(uint64_t requestID, uint32_t persistentID); - //! Generates an object ID server-sided - /*! - \return A generated object ID - */ - uint32_t GenerateObjectID(void); + //! Generates an object ID server-sided + /*! + \return A generated object ID + */ + uint32_t GenerateObjectID(void); //! Generates a random object ID server-sided /*! \return A generated object ID */ - static uint32_t GenerateRandomObjectID(); + static uint32_t GenerateRandomObjectID(); - //! Generates a persistent object ID server-sided - /*! - \return A generated object ID - */ - uint32_t GeneratePersistentObjectID(void); + //! Generates a persistent object ID server-sided + /*! + \return A generated object ID + */ + uint32_t GeneratePersistentObjectID(void); }; diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 6809fec0..19f38d00 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -2,23 +2,18 @@ #include "UserManager.h" -//Times are 1 / fps, in ms -#define HIGH 16 //60 fps -#define MEDIUM 33 //30 fps -#define LOW 66 //15 fps - -#define SOCIAL { LOW } -#define SOCIAL_HUB { MEDIUM } //Added to compensate for the large playercounts in NS and NT -#define BATTLE { HIGH } -#define BATTLE_INSTANCE { MEDIUM } -#define RACE { HIGH } -#define PROPERTY { LOW } +#define SOCIAL { lowFrameDelta } +#define SOCIAL_HUB { mediumFrameDelta } //Added to compensate for the large playercounts in NS and NT +#define BATTLE { highFrameDelta } +#define BATTLE_INSTANCE { mediumFrameDelta } +#define RACE { highFrameDelta } +#define PROPERTY { lowFrameDelta } PerformanceProfile PerformanceManager::m_CurrentProfile = SOCIAL; PerformanceProfile PerformanceManager::m_DefaultProfile = SOCIAL; -PerformanceProfile PerformanceManager::m_InactiveProfile = { LOW }; +PerformanceProfile PerformanceManager::m_InactiveProfile = { lowFrameDelta }; std::map<LWOMAPID, PerformanceProfile> PerformanceManager::m_Profiles = { // VE @@ -72,13 +67,6 @@ std::map<LWOMAPID, PerformanceProfile> PerformanceManager::m_Profiles = { { 2001, BATTLE_INSTANCE }, }; - -PerformanceManager::PerformanceManager() { -} - -PerformanceManager::~PerformanceManager() { -} - void PerformanceManager::SelectProfile(LWOMAPID mapID) { const auto pair = m_Profiles.find(mapID); @@ -91,10 +79,10 @@ void PerformanceManager::SelectProfile(LWOMAPID mapID) { m_CurrentProfile = pair->second; } -uint32_t PerformanceManager::GetServerFramerate() { +uint32_t PerformanceManager::GetServerFrameDelta() { if (UserManager::Instance()->GetUserCount() == 0) { - return m_InactiveProfile.serverFramerate; + return m_InactiveProfile.serverFrameDelta; } - return m_CurrentProfile.serverFramerate; -} \ No newline at end of file + return m_CurrentProfile.serverFrameDelta; +} diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index b8a090e0..c584d4ac 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -5,21 +5,16 @@ #include "dCommonVars.h" struct PerformanceProfile { - uint32_t serverFramerate; + uint32_t serverFrameDelta; }; - class PerformanceManager { public: - ~PerformanceManager(); - static void SelectProfile(LWOMAPID mapID); - static uint32_t GetServerFramerate(); + static uint32_t GetServerFrameDelta(); private: - PerformanceManager(); - static PerformanceProfile m_CurrentProfile; static PerformanceProfile m_DefaultProfile; static PerformanceProfile m_InactiveProfile; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 4f1ec400..5dabce1c 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -17,6 +17,7 @@ #include "Metrics.hpp" #include "PerformanceManager.h" #include "Diagnostics.h" +#include "BinaryPathFinder.h" //RakNet includes: #include "RakNetDefines.h" @@ -30,7 +31,6 @@ #include "PacketUtils.h" #include "WorldPackets.h" #include "UserManager.h" -#include "dMessageIdentifiers.h" #include "CDClientManager.h" #include "CDClientDatabase.h" #include "GeneralUtils.h" @@ -41,13 +41,15 @@ #include "CharacterComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" +#include "User.h" +#include "Loot.h" #include "Entity.h" #include "Character.h" #include "ChatPackets.h" #include "GameMessageHandler.h" #include "GameMessages.h" #include "Mail.h" -#include "dLocale.h" #include "TeamManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" @@ -55,33 +57,43 @@ #include "MasterPackets.h" #include "Player.h" #include "PropertyManagementComponent.h" - +#include "AssetManager.h" +#include "LevelProgressionComponent.h" +#include "eBlueprintSaveResponseType.h" +#include "AMFFormat.h" +#include "NiPoint3.h" +#include "eServerDisconnectIdentifiers.h" +#include "eObjectBits.h" +#include "eConnectionType.h" +#include "eServerMessageType.h" +#include "eChatInternalMessageType.h" +#include "eWorldMessageType.h" +#include "eMasterMessageType.h" +#include "eGameMessageType.h" #include "ZCompression.h" namespace Game { - dLogger* logger; - dServer* server; - dZoneManager* zoneManager; - dpWorld* physicsWorld; - dChatFilter* chatFilter; - dConfig* config; - dLocale* locale; + dLogger* logger = nullptr; + dServer* server = nullptr; + dpWorld* physicsWorld = nullptr; + dChatFilter* chatFilter = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + RakPeerInterface* chatServer = nullptr; std::mt19937 randomEngine; - - RakPeerInterface* chatServer; SystemAddress chatSysAddr; -} + bool shouldShutdown = false; +} // namespace Game bool chatDisabled = false; bool chatConnected = false; -bool worldShutdownSequenceStarted = false; bool worldShutdownSequenceComplete = false; void WorldShutdownSequence(); void WorldShutdownProcess(uint32_t zoneId); void FinalizeShutdown(); void SendShutdownMessageToMaster(); -dLogger* SetupLogger(int zoneID, int instanceID); +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID); void HandlePacketChat(Packet* packet); void HandlePacket(Packet* packet); @@ -91,8 +103,8 @@ struct tempSessionInfo { }; std::map<std::string, tempSessionInfo> m_PendingUsers; -int instanceID = 0; -int g_CloneID = 0; +uint32_t instanceID = 0; +uint32_t g_CloneID = 0; std::string databaseChecksum = ""; int main(int argc, char** argv) { @@ -103,16 +115,16 @@ int main(int argc, char** argv) { // Triggers the shutdown sequence at application exit std::atexit(WorldShutdownSequence); - signal(SIGINT, [](int){ WorldShutdownSequence(); }); - signal(SIGTERM, [](int){ WorldShutdownSequence(); }); + signal(SIGINT, [](int) { WorldShutdownSequence(); }); + signal(SIGTERM, [](int) { WorldShutdownSequence(); }); - int zoneID = 1000; - int cloneID = 0; - int maxClients = 8; - int ourPort = 2007; + uint32_t zoneID = 1000; + uint32_t cloneID = 0; + uint32_t maxClients = 8; + uint32_t ourPort = 2007; //Check our arguments: - for (int i = 0; i < argc; ++i) { + for (int32_t i = 0; i < argc; ++i) { std::string argument(argv[i]); if (argument == "-zone") zoneID = atoi(argv[i + 1]); @@ -124,59 +136,67 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); - if (!Game::logger) return 0; - - Game::logger->SetLogToConsole(true); //We want this info to always be logged. - Game::logger->Log("WorldServer", "Starting World server...\n"); - Game::logger->Log("WorldServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); - Game::logger->Log("WorldServer", "Compiled on: %s\n", __TIMESTAMP__); - -#ifndef _DEBUG - Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug. -#endif + if (!Game::logger) return EXIT_FAILURE; //Read our config: - dConfig config("worldconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - if (config.GetValue("disable_chat") == "1") chatDisabled = true; + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + + Game::logger->Log("WorldServer", "Starting World server..."); + Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); + Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); + + if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; + + try { + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + Game::assetManager = new AssetManager(clientPath); + } catch (std::runtime_error& ex) { + Game::logger->Log("WorldServer", "Got an error while setting up assets: %s", ex.what()); + + return EXIT_FAILURE; + } // Connect to CDClient - try { - CDClientDatabase::Connect("./res/CDServer.sqlite"); - } catch (CppSQLite3Exception& e) { - Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database\n"); - Game::logger->Log("WorldServer", "Error: %s\n", e.errorMessage()); - Game::logger->Log("WorldServer", "Error Code: %i\n", e.errorCode()); - return -1; - } + try { + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); + Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); + Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); + return EXIT_FAILURE; + } - CDClientManager::Instance()->Initialize(); + CDClientManager::Instance(); //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); - Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1"); + Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); - if (!config.GetValue("dump_folder").empty()) - { - Diagnostics::SetOutDirectory(config.GetValue("dump_folder")); + if (!Game::config->GetValue("dump_folder").empty()) { + Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); } try { - Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); - } catch (sql::SQLException& ex) { - Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s\n", ex.what()); - return 0; - } + Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); + } catch (sql::SQLException& ex) { + Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); + return EXIT_FAILURE; + } //Find out the master's IP: std::string masterIP = "localhost"; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -190,13 +210,13 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(); UserManager::Instance()->Initialize(); LootGenerator::Instance(); - Game::chatFilter = new dChatFilter("./res/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); - Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, zoneID); + Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID); //Connect to the chat server: - int chatPort = 1501; - if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); + uint32_t chatPort = 1501; + if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); @@ -205,29 +225,28 @@ int main(int argc, char** argv) { //Set up other things: Game::randomEngine = std::mt19937(time(0)); - Game::locale = new dLocale(); //Run it until server gets a kill message from Master: auto lastTime = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceChatDisconnect = 0; - int framesSinceLastUsersSave = 0; - int framesSinceLastSQLPing = 0; - int framesSinceLastUser = 0; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceChatDisconnect = 0; + uint32_t framesSinceLastUsersSave = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceLastUser = 0; const float maxPacketProcessingTime = 1.5f; //0.015f; - const int maxPacketsToProcess = 1024; + const uint32_t maxPacketsToProcess = 1024; bool ready = false; - int framesSinceMasterStatus = 0; - int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameRate; + uint32_t framesSinceMasterStatus = 0; + uint32_t framesSinceShutdownSequence = 0; + uint32_t currentFramerate = highFramerate; - int ghostingStepCount = 0; + uint32_t ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); PerformanceManager::SelectProfile(zoneID); @@ -235,52 +254,60 @@ int main(int argc, char** argv) { //Load our level: if (zoneID != 0) { dpWorld::Instance().Initialize(zoneID); - Game::physicsWorld = &dpWorld::Instance(); //just in case some old code references it dZoneManager::Instance()->Initialize(LWOZONEID(zoneID, instanceID, cloneID)); g_CloneID = cloneID; // pre calculate the FDB checksum if (Game::config->GetValue("check_fdb") == "1") { - std::ifstream fileStream; + std::ifstream fileStream; - static const std::vector<std::string> aliases = { - "res/CDServers.fdb", - "res/cdserver.fdb", - "res/CDClient.fdb", - "res/cdclient.fdb", - }; + static const std::vector<std::string> aliases = { + "CDServers.fdb", + "cdserver.fdb", + "CDClient.fdb", + "cdclient.fdb", + }; - for (const auto& file : aliases) { - fileStream.open(file, std::ios::binary | std::ios::in); - if (fileStream.is_open()) { - break; - } + for (const auto& file : aliases) { + fileStream.open(Game::assetManager->GetResPath() / file, std::ios::binary | std::ios::in); + if (fileStream.is_open()) { + break; } - - const int bufferSize = 1024; - MD5* md5 = new MD5(); - - char fileStreamBuffer[1024] = {}; - - while (!fileStream.eof()) { - memset(fileStreamBuffer, 0, bufferSize); - fileStream.read(fileStreamBuffer, bufferSize); - md5->update(fileStreamBuffer, fileStream.gcount()); - } - - fileStream.close(); - - const char* nullTerminateBuffer = "\0"; - md5->update(nullTerminateBuffer, 1); // null terminate the data - md5->finalize(); - databaseChecksum = md5->hexdigest(); - - delete md5; - - Game::logger->Log("WorldServer", "FDB Checksum calculated as: %s\n", databaseChecksum.c_str()); } + + const int32_t bufferSize = 1024; + MD5* md5 = new MD5(); + + char fileStreamBuffer[1024] = {}; + + while (!fileStream.eof()) { + memset(fileStreamBuffer, 0, bufferSize); + fileStream.read(fileStreamBuffer, bufferSize); + md5->update(fileStreamBuffer, fileStream.gcount()); + } + + fileStream.close(); + + const char* nullTerminateBuffer = "\0"; + md5->update(nullTerminateBuffer, 1); // null terminate the data + md5->finalize(); + databaseChecksum = md5->hexdigest(); + + delete md5; + + Game::logger->Log("WorldServer", "FDB Checksum calculated as: %s", databaseChecksum.c_str()); + } } + uint32_t currentFrameDelta = highFrameDelta; + // These values are adjust them selves to the current framerate should it update. + uint32_t logFlushTime = 15 * currentFramerate; // 15 seconds in frames + uint32_t shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + uint32_t chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + uint32_t saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. while (true) { Metrics::StartMeasurement(MetricVariable::Frame); Metrics::StartMeasurement(MetricVariable::GameLoop); @@ -293,44 +320,60 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; - if (!ready) - { - currentFramerate = highFrameRate; + uint32_t newFrameDelta = currentFrameDelta; + if (!ready) { + newFrameDelta = highFrameDelta; + } else { + newFrameDelta = PerformanceManager::GetServerFrameDelta(); } - else - { - currentFramerate = PerformanceManager::GetServerFramerate(); + + // Update to the new framerate and scale all timings to said new framerate + if (newFrameDelta != currentFrameDelta) { + float_t ratioBeforeToAfter = (float)currentFrameDelta / (float)newFrameDelta; + currentFrameDelta = newFrameDelta; + currentFramerate = MS_TO_FRAMES(newFrameDelta); + Game::logger->LogDebug("WorldServer", "Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); + logFlushTime = 15 * currentFramerate; // 15 seconds in frames + framesSinceLastFlush *= ratioBeforeToAfter; + shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUser *= ratioBeforeToAfter; + noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + framesSinceMasterDisconnect *= ratioBeforeToAfter; + chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + framesSinceChatDisconnect *= ratioBeforeToAfter; + saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUsersSave *= ratioBeforeToAfter; + sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastSQLPing *= ratioBeforeToAfter; + emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. + framesSinceLastUser *= ratioBeforeToAfter; } //Warning if we ran slow - if (deltaTime > currentFramerate) { - Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate)\n", deltaTime, currentFramerate); + if (deltaTime > currentFrameDelta) { + Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); } //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - int framesToWaitForMaster = ready ? 10 : 200; - if (framesSinceMasterDisconnect >= framesToWaitForMaster && !worldShutdownSequenceStarted) { - Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down\n", framesToWaitForMaster); - worldShutdownSequenceStarted = true; + if (framesSinceMasterDisconnect >= noMasterConnectionTimeout && !Game::shouldShutdown) { + Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", noMasterConnectionTimeout); + Game::shouldShutdown = true; } - } - else framesSinceMasterDisconnect = 0; + } else framesSinceMasterDisconnect = 0; // Check if we're still connected to chat: if (!chatConnected) { framesSinceChatDisconnect++; - // Attempt to reconnect every 30 seconds. - if (framesSinceChatDisconnect >= 2000) { + if (framesSinceChatDisconnect >= chatReconnectionTime) { framesSinceChatDisconnect = 0; Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8); } - } - else framesSinceChatDisconnect = 0; + } else framesSinceChatDisconnect = 0; //In world we'd update our other systems here. @@ -377,18 +420,17 @@ int main(int argc, char** argv) { UserManager::Instance()->DeletePendingRemovals(); auto t1 = std::chrono::high_resolution_clock::now(); - for (int curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { + for (uint32_t curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { packet = Game::server->Receive(); if (packet) { auto t1 = std::chrono::high_resolution_clock::now(); HandlePacket(packet); auto t2 = std::chrono::high_resolution_clock::now(); - timeSpent += std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); + timeSpent += std::chrono::duration_cast<std::chrono::duration<float>>(t2 - t1).count(); Game::server->DeallocatePacket(packet); packet = nullptr; - } - else { + } else { break; } } @@ -403,42 +445,37 @@ int main(int argc, char** argv) { Metrics::EndMeasurement(MetricVariable::UpdateReplica); //Push our log every 15s: - if (framesSinceLastFlush >= 1000) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; - if (zoneID != 0 && !occupied) - { + if (zoneID != 0 && !occupied) { framesSinceLastUser++; //If we haven't had any players for a while, time out and shut down: - if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) - { - worldShutdownSequenceStarted = true; + if (framesSinceLastUser >= emptyShutdownTime) { + Game::shouldShutdown = true; } - } - else - { + } else { framesSinceLastUser = 0; } //Save all connected users every 10 minutes: - if (framesSinceLastUsersSave >= 40000 && zoneID != 0) { + if (framesSinceLastUsersSave >= saveTime && zoneID != 0) { UserManager::Instance()->SaveAllActiveCharacters(); framesSinceLastUsersSave = 0; if (PropertyManagementComponent::Instance() != nullptr) { PropertyManagementComponent::Instance()->Save(); } - } - else framesSinceLastUsersSave++; + } else framesSinceLastUsersSave++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -450,27 +487,24 @@ int main(int argc, char** argv) { delete stmt; framesSinceLastSQLPing = 0; - } - else framesSinceLastSQLPing++; + } else framesSinceLastSQLPing++; Metrics::EndMeasurement(MetricVariable::GameLoop); Metrics::StartMeasurement(MetricVariable::Sleep); - t += std::chrono::milliseconds(currentFramerate); + t += std::chrono::milliseconds(currentFrameDelta); std::this_thread::sleep_until(t); Metrics::EndMeasurement(MetricVariable::Sleep); - if (!ready && Game::server->GetIsConnectedToMaster()) - { + if (!ready && Game::server->GetIsConnectedToMaster()) { // Some delay is required here or else we crash the client? framesSinceMasterStatus++; - if (framesSinceMasterStatus >= 200) - { - Game::logger->Log("WorldServer", "Finished loading world with zone (%i), ready up!\n", Game::server->GetZoneID()); + if (framesSinceMasterStatus >= 200) { + Game::logger->Log("WorldServer", "Finished loading world with zone (%i), ready up!", Game::server->GetZoneID()); MasterPackets::SendWorldReady(Game::server, Game::server->GetZoneID(), Game::server->GetInstanceID()); @@ -478,7 +512,7 @@ int main(int argc, char** argv) { } } - if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) { + if (Game::shouldShutdown && !worldShutdownSequenceComplete) { WorldShutdownProcess(zoneID); break; } @@ -490,8 +524,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } -dLogger * SetupLogger(int zoneID, int instanceID) { - std::string logPath = "./logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log"; +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID) { + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -504,26 +538,25 @@ dLogger * SetupLogger(int zoneID, int instanceID) { void HandlePacketChat(Packet* packet) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { - Game::logger->Log("WorldServer", "Lost our connection to chat, zone(%i), instance(%i)\n", Game::server->GetZoneID(), Game::server->GetInstanceID()); + Game::logger->Log("WorldServer", "Lost our connection to chat, zone(%i), instance(%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); chatConnected = false; } if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) { - Game::logger->Log("WorldServer", "Established connection to chat, zone(%i), instance (%i)\n",Game::server -> GetZoneID(), Game::server -> GetInstanceID()); + Game::logger->Log("WorldServer", "Established connection to chat, zone(%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); Game::chatSysAddr = packet->systemAddress; chatConnected = true; } if (packet->data[0] == ID_USER_PACKET_ENUM) { - if (packet->data[1] == CHAT_INTERNAL) { - switch (packet->data[3]) { - case MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER: { - CINSTREAM; + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { + switch (static_cast<eChatInternalMessageType>(packet->data[3])) { + case eChatInternalMessageType::ROUTE_TO_PLAYER: { + CINSTREAM_SKIP_HEADER; LWOOBJID playerID; inStream.Read(playerID); - inStream.Read(playerID); auto player = EntityManager::Instance()->GetEntity(playerID); if (!player) return; @@ -532,7 +565,7 @@ void HandlePacketChat(Packet* packet) { //Write our stream outwards: CBITSTREAM; - for (int i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { + for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip } @@ -541,49 +574,53 @@ void HandlePacketChat(Packet* packet) { break; } - case MSG_CHAT_INTERNAL_ANNOUNCEMENT: { - CINSTREAM; - LWOOBJID header; - inStream.Read(header); + case eChatInternalMessageType::ANNOUNCEMENT: { + CINSTREAM_SKIP_HEADER; - RakNet::RakString title; - RakNet::RakString msg; + std::string title; + std::string msg; - inStream.Read(title); - inStream.Read(msg); + uint32_t len; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + title += character; + } + + len = 0; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + msg += character; + } //Send to our clients: AMFArrayValue args; auto* titleValue = new AMFStringValue(); - titleValue->SetStringValue(title.C_String()); + titleValue->SetStringValue(title.c_str()); auto* messageValue = new AMFStringValue(); - messageValue->SetStringValue(msg.C_String()); + messageValue->SetStringValue(msg.c_str()); args.InsertValue("title", titleValue); args.InsertValue("message", messageValue); GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", &args); - delete titleValue; - delete messageValue; - titleValue = nullptr; - messageValue = nullptr; - break; } - case MSG_CHAT_INTERNAL_MUTE_UPDATE: { - CINSTREAM; + case eChatInternalMessageType::MUTE_UPDATE: { + CINSTREAM_SKIP_HEADER; LWOOBJID playerId; time_t expire = 0; inStream.Read(playerId); - inStream.Read(playerId); inStream.Read(expire); auto* entity = EntityManager::Instance()->GetEntity(playerId); - if (entity != nullptr) - { + if (entity != nullptr) { entity->GetParentUser()->SetMuteExpire(expire); entity->GetCharacter()->SendMuteNotice(); @@ -592,10 +629,8 @@ void HandlePacketChat(Packet* packet) { break; } - case MSG_CHAT_INTERNAL_TEAM_UPDATE: { - CINSTREAM; - LWOOBJID header; - inStream.Read(header); + case eChatInternalMessageType::TEAM_UPDATE: { + CINSTREAM_SKIP_HEADER; LWOOBJID teamID = 0; char lootOption = 0; @@ -605,25 +640,23 @@ void HandlePacketChat(Packet* packet) { inStream.Read(teamID); bool deleteTeam = inStream.ReadBit(); - if (deleteTeam) - { + if (deleteTeam) { TeamManager::Instance()->DeleteTeam(teamID); - Game::logger->Log("WorldServer", "Deleting team (%llu)\n", teamID); + Game::logger->Log("WorldServer", "Deleting team (%llu)", teamID); break; } inStream.Read(lootOption); inStream.Read(memberCount); - Game::logger->Log("WorldServer", "Updating team (%llu), (%i), (%i)\n", teamID, lootOption, memberCount); - for (char i = 0; i < memberCount; i++) - { + Game::logger->Log("WorldServer", "Updating team (%llu), (%i), (%i)", teamID, lootOption, memberCount); + for (char i = 0; i < memberCount; i++) { LWOOBJID member = LWOOBJID_EMPTY; inStream.Read(member); members.push_back(member); - Game::logger->Log("WorldServer", "Updating team member (%llu)\n", member); + Game::logger->Log("WorldServer", "Updating team member (%llu)", member); } TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); @@ -632,7 +665,7 @@ void HandlePacketChat(Packet* packet) { } default: - Game::logger->Log("WorldServer", "Received an unknown chat internal: %i\n", int(packet->data[3])); + Game::logger->Log("WorldServer", "Received an unknown chat internal: %i", int(packet->data[3])); } } } @@ -651,28 +684,28 @@ void HandlePacket(Packet* packet) { auto* entity = EntityManager::Instance()->GetEntity(c->GetObjectID()); - if (!entity) - { + if (!entity) { entity = Player::GetPlayer(packet->systemAddress); } if (entity) { auto* skillComponent = entity->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) - { + if (skillComponent != nullptr) { skillComponent->Reset(); } entity->GetCharacter()->SaveXMLToDatabase(); - Game::logger->Log("WorldServer", "Deleting player %llu\n", entity->GetObjectID()); + Game::logger->Log("WorldServer", "Deleting player %llu", entity->GetObjectID()); EntityManager::Instance()->DestroyEntity(entity); + } + { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); - bitStream.Write(c->GetObjectID()); + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + bitStream.Write(user->GetLoggedInChar()); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -683,607 +716,624 @@ void HandlePacket(Packet* packet) { } CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_PLAYER_REMOVED); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_REMOVED); bitStream.Write((LWOMAPID)Game::server->GetZoneID()); bitStream.Write((LWOINSTANCEID)instanceID); Game::server->SendToMaster(&bitStream); } - if (packet->data[0] != ID_USER_PACKET_ENUM) return; - if (packet->data[1] == SERVER) { - if (packet->data[3] == MSG_SERVER_VERSION_CONFIRM) { + if (packet->data[0] != ID_USER_PACKET_ENUM || packet->length < 4) return; + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) { + if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { AuthPackets::HandleHandshake(Game::server, packet); } } - if (packet->data[1] == MASTER) { - switch (packet->data[3]) { - case MSG_MASTER_REQUEST_PERSISTENT_ID_RESPONSE: { - uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); - uint32_t objectID = PacketUtils::ReadPacketU32(16, packet); - ObjectIDManager::Instance()->HandleRequestPersistentIDResponse(requestID, objectID); - break; - } + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) { + switch (static_cast<eMasterMessageType>(packet->data[3])) { + case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: { + uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); + uint32_t objectID = PacketUtils::ReadPacketU32(16, packet); + ObjectIDManager::Instance()->HandleRequestPersistentIDResponse(requestID, objectID); + break; + } - case MSG_MASTER_REQUEST_ZONE_TRANSFER_RESPONSE: { - uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); - ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); - break; - } + case eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE: { + uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); + ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); + break; + } - case MSG_MASTER_SESSION_KEY_RESPONSE: { - //Read our session key and to which user it belongs: - RakNet::BitStream inStream(packet->data, packet->length, false); - uint64_t header = inStream.Read(header); - uint32_t sessionKey = 0; - std::string username; + case eMasterMessageType::SESSION_KEY_RESPONSE: { + //Read our session key and to which user it belongs: + RakNet::BitStream inStream(packet->data, packet->length, false); + uint64_t header = inStream.Read(header); + uint32_t sessionKey = 0; + std::string username; - inStream.Read(sessionKey); - username = PacketUtils::ReadString(12, packet, false); + inStream.Read(sessionKey); + username = PacketUtils::ReadString(12, packet, false); - //Find them: - auto it = m_PendingUsers.find(username); - if (it == m_PendingUsers.end()) return; + //Find them: + auto it = m_PendingUsers.find(username); + if (it == m_PendingUsers.end()) return; - //Convert our key: - std::string userHash = std::to_string(sessionKey); - userHash = md5(userHash); + //Convert our key: + std::string userHash = std::to_string(sessionKey); + userHash = md5(userHash); - //Verify it: - if (userHash != it->second.hash) { - Game::logger->Log("WorldServer", "SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s\n", userHash.c_str(), it->second.hash.c_str()); - Game::server->Disconnect(it->second.sysAddr, SERVER_DISCON_INVALID_SESSION_KEY); - return; - } - else { - Game::logger->Log("WorldServer", "User %s authenticated with correct key.\n", username.c_str()); + //Verify it: + if (userHash != it->second.hash) { + Game::logger->Log("WorldServer", "SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str()); + Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY); + return; + } else { + Game::logger->Log("WorldServer", "User %s authenticated with correct key.", username.c_str()); - UserManager::Instance()->DeleteUser(packet->systemAddress); + UserManager::Instance()->DeleteUser(packet->systemAddress); - //Create our user and send them in: - UserManager::Instance()->CreateUser(it->second.sysAddr, username, userHash); + //Create our user and send them in: + UserManager::Instance()->CreateUser(it->second.sysAddr, username, userHash); - auto zone = dZoneManager::Instance()->GetZone(); - if (zone) { - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; + auto zone = dZoneManager::Instance()->GetZone(); + if (zone) { + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; - if (zone->GetZoneID().GetMapID() == 1100) { - auto pos = zone->GetSpawnPos(); - x = pos.x; - y = pos.y; - z = pos.z; - } - - WorldPackets::SendLoadStaticZone(it->second.sysAddr, x, y, z, zone->GetChecksum()); + if (zone->GetZoneID().GetMapID() == 1100) { + auto pos = zone->GetSpawnPos(); + x = pos.x; + y = pos.y; + z = pos.z; } - if (Game::server->GetZoneID() == 0) { - //Since doing this reroute breaks the client's request, we have to call this manually. - UserManager::Instance()->RequestCharacterList(it->second.sysAddr); - } - - m_PendingUsers.erase(username); - - //Notify master: - { - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_PLAYER_ADDED); - bitStream.Write((LWOMAPID)Game::server->GetZoneID()); - bitStream.Write((LWOINSTANCEID)instanceID); - Game::server->SendToMaster(&bitStream); - } + WorldPackets::SendLoadStaticZone(it->second.sysAddr, x, y, z, zone->GetChecksum()); } - break; - } - case MSG_MASTER_AFFIRM_TRANSFER_REQUEST: { - const uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); - - Game::logger->Log("MasterServer", "Got affirmation request of transfer %llu\n", requestID); - - CBITSTREAM - - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_AFFIRM_TRANSFER_RESPONSE); - bitStream.Write(requestID); - Game::server->SendToMaster(&bitStream); - - break; - } - - case MSG_MASTER_SHUTDOWN: { - worldShutdownSequenceStarted = true; - Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)\n", Game::server->GetZoneID(), Game::server->GetInstanceID()); - break; - } - - case MSG_MASTER_NEW_SESSION_ALERT: { - RakNet::BitStream inStream(packet->data, packet->length, false); - uint64_t header = inStream.Read(header); - uint32_t sessionKey = inStream.Read(sessionKey); - RakNet::RakString username; - inStream.Read(username); - - //Find them: - User* user = UserManager::Instance()->GetUser(username.C_String()); - if (!user) { - Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.\n", username.C_String()); - return; + if (Game::server->GetZoneID() == 0) { + //Since doing this reroute breaks the client's request, we have to call this manually. + UserManager::Instance()->RequestCharacterList(it->second.sysAddr); } - //Check the key: - if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { - Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.\n", username.C_String()); - Game::server->Disconnect(user->GetSystemAddress(), SERVER_DISCON_INVALID_SESSION_KEY); - return; + m_PendingUsers.erase(username); + + //Notify master: + { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_ADDED); + bitStream.Write((LWOMAPID)Game::server->GetZoneID()); + bitStream.Write((LWOINSTANCEID)instanceID); + Game::server->SendToMaster(&bitStream); } - break; } - default: - Game::logger->Log("WorldServer", "Unknown packet ID from master %i\n", int(packet->data[3])); + break; + } + case eMasterMessageType::AFFIRM_TRANSFER_REQUEST: { + const uint64_t requestID = PacketUtils::ReadPacketU64(8, packet); + + Game::logger->Log("MasterServer", "Got affirmation request of transfer %llu", requestID); + + CBITSTREAM; + + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_RESPONSE); + bitStream.Write(requestID); + Game::server->SendToMaster(&bitStream); + + break; + } + + case eMasterMessageType::SHUTDOWN: { + Game::shouldShutdown = true; + Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); + break; + } + + case eMasterMessageType::NEW_SESSION_ALERT: { + RakNet::BitStream inStream(packet->data, packet->length, false); + uint64_t header = inStream.Read(header); + uint32_t sessionKey = inStream.Read(sessionKey); + + std::string username; + + uint32_t len; + inStream.Read(len); + + for (uint32_t i = 0; i < len; i++) { + char character; inStream.Read<char>(character); + username += character; + } + + //Find them: + User* user = UserManager::Instance()->GetUser(username.c_str()); + if (!user) { + Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.", username.c_str()); + return; + } + + //Check the key: + if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { + Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.", username.c_str()); + Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY); + return; + } + break; + } + + default: + Game::logger->Log("WorldServer", "Unknown packet ID from master %i", int(packet->data[3])); } return; } - if (packet->data[1] != WORLD) return; + if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::WORLD) return; - switch (packet->data[3]) { - case MSG_WORLD_CLIENT_VALIDATION: { - std::string username = PacketUtils::ReadString(0x08, packet, true); - std::string sessionKey = PacketUtils::ReadString(74, packet, true); - std::string clientDatabaseChecksum = PacketUtils::ReadString(packet->length - 33, packet, false); + switch (static_cast<eWorldMessageType>(packet->data[3])) { + case eWorldMessageType::VALIDATION: { + std::string username = PacketUtils::ReadString(0x08, packet, true); + std::string sessionKey = PacketUtils::ReadString(74, packet, true); + std::string clientDatabaseChecksum = PacketUtils::ReadString(packet->length - 33, packet, false); - // sometimes client puts a null terminator at the end of the checksum and sometimes doesn't, weird - clientDatabaseChecksum = clientDatabaseChecksum.substr(0, 32); + // sometimes client puts a null terminator at the end of the checksum and sometimes doesn't, weird + clientDatabaseChecksum = clientDatabaseChecksum.substr(0, 32); - // If the check is turned on, validate the client's database checksum. - if (Game::config->GetValue("check_fdb") == "1" && !databaseChecksum.empty()) { - uint32_t gmLevel = 0; - auto* stmt = Database::CreatePreppedStmt("SELECT gm_level FROM accounts WHERE name=? LIMIT 1;"); - stmt->setString(1, username.c_str()); + // If the check is turned on, validate the client's database checksum. + if (Game::config->GetValue("check_fdb") == "1" && !databaseChecksum.empty()) { + uint32_t gmLevel = 0; + auto* stmt = Database::CreatePreppedStmt("SELECT gm_level FROM accounts WHERE name=? LIMIT 1;"); + stmt->setString(1, username.c_str()); - auto* res = stmt->executeQuery(); - while (res->next()) { - gmLevel = res->getInt(1); - } + auto* res = stmt->executeQuery(); + while (res->next()) { + gmLevel = res->getInt(1); + } - delete stmt; - delete res; + delete stmt; + delete res; - // Developers may skip this check - if (gmLevel < 8 && clientDatabaseChecksum != databaseChecksum) { - Game::logger->Log("WorldServer", "Client's database checksum does not match the server's, aborting connection.\n"); - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_KICK); + // Developers may skip this check + if (gmLevel < 8 && clientDatabaseChecksum != databaseChecksum) { + Game::logger->Log("WorldServer", "Client's database checksum does not match the server's, aborting connection."); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::WRONG_GAME_VERSION); + return; + } + } + + //Request the session info from Master: + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_SESSION_KEY); + PacketUtils::WriteString(bitStream, username, 64); + Game::server->SendToMaster(&bitStream); + + //Insert info into our pending list + tempSessionInfo info; + info.sysAddr = SystemAddress(packet->systemAddress); + info.hash = sessionKey; + m_PendingUsers.insert(std::make_pair(username, info)); + + break; + } + + case eWorldMessageType::CHARACTER_LIST_REQUEST: { + //We need to delete the entity first, otherwise the char list could delete it while it exists in the world! + if (Game::server->GetZoneID() != 0) { + auto user = UserManager::Instance()->GetUser(packet->systemAddress); + if (!user) return; + EntityManager::Instance()->DestroyEntity(user->GetLastUsedChar()->GetEntity()); + } + + //This loops prevents users who aren't authenticated to double-request the char list, which + //would make the login screen freeze sometimes. + if (m_PendingUsers.size() > 0) { + for (auto it : m_PendingUsers) { + if (it.second.sysAddr == packet->systemAddress) { return; } } - - //Request the session info from Master: - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_SESSION_KEY); - PacketUtils::WriteString(bitStream, username, 64); - Game::server->SendToMaster(&bitStream); - - //Insert info into our pending list - tempSessionInfo info; - info.sysAddr = SystemAddress(packet->systemAddress); - info.hash = sessionKey; - m_PendingUsers.insert(std::make_pair(username, info)); - - break; } - case MSG_WORLD_CLIENT_CHARACTER_LIST_REQUEST: { - //We need to delete the entity first, otherwise the char list could delete it while it exists in the world! - if (Game::server->GetZoneID() != 0) { - auto user = UserManager::Instance()->GetUser(packet->systemAddress); - if (!user) return; - EntityManager::Instance()->DestroyEntity(user->GetLastUsedChar()->GetEntity()); - } + UserManager::Instance()->RequestCharacterList(packet->systemAddress); + break; + } - //This loops prevents users who aren't authenticated to double-request the char list, which - //would make the login screen freeze sometimes. - if (m_PendingUsers.size() > 0) { - for (auto it : m_PendingUsers) { - if (it.second.sysAddr == packet->systemAddress) { - return; - } + case eWorldMessageType::GAME_MSG: { + RakNet::BitStream bitStream(packet->data, packet->length, false); + + uint64_t header; + LWOOBJID objectID; + eGameMessageType messageID; + + bitStream.Read(header); + bitStream.Read(objectID); + bitStream.Read(messageID); + + RakNet::BitStream dataStream; + bitStream.Read(dataStream, bitStream.GetNumberOfUnreadBits()); + + GameMessageHandler::HandleMessage(&dataStream, packet->systemAddress, objectID, messageID); + break; + } + + case eWorldMessageType::CHARACTER_CREATE_REQUEST: { + UserManager::Instance()->CreateCharacter(packet->systemAddress, packet); + break; + } + + case eWorldMessageType::LOGIN_REQUEST: { + RakNet::BitStream inStream(packet->data, packet->length, false); + uint64_t header = inStream.Read(header); + + LWOOBJID playerID = 0; + inStream.Read(playerID); + GeneralUtils::ClearBit(playerID, eObjectBits::CHARACTER); + GeneralUtils::ClearBit(playerID, eObjectBits::PERSISTENT); + + auto user = UserManager::Instance()->GetUser(packet->systemAddress); + + if (user) { + auto lastCharacter = user->GetLoggedInChar(); + // This means we swapped characters and we need to remove the previous player from the container. + if (static_cast<uint32_t>(lastCharacter) != playerID) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + bitStream.Write(lastCharacter); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } + } + + UserManager::Instance()->LoginCharacter(packet->systemAddress, static_cast<uint32_t>(playerID)); + break; + } + + case eWorldMessageType::CHARACTER_DELETE_REQUEST: { + UserManager::Instance()->DeleteCharacter(packet->systemAddress, packet); + UserManager::Instance()->RequestCharacterList(packet->systemAddress); + break; + } + + case eWorldMessageType::CHARACTER_RENAME_REQUEST: { + UserManager::Instance()->RenameCharacter(packet->systemAddress, packet); + break; + } + + case eWorldMessageType::LEVEL_LOAD_COMPLETE: { + Game::logger->Log("WorldServer", "Received level load complete from user."); + User* user = UserManager::Instance()->GetUser(packet->systemAddress); + if (user) { + Character* c = user->GetLastUsedChar(); + if (c != nullptr) { + std::u16string username = GeneralUtils::ASCIIToUTF16(c->GetName()); + Game::server->GetReplicaManager()->AddParticipant(packet->systemAddress); + + EntityInfo info{}; + info.lot = 1; + Entity* player = EntityManager::Instance()->CreateEntity(info, UserManager::Instance()->GetUser(packet->systemAddress)); + + WorldPackets::SendCreateCharacter(packet->systemAddress, player, c->GetXMLData(), username, c->GetGMLevel()); + WorldPackets::SendServerState(packet->systemAddress); + + const auto respawnPoint = player->GetCharacter()->GetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID()); + + EntityManager::Instance()->ConstructEntity(player, UNASSIGNED_SYSTEM_ADDRESS, true); + + if (respawnPoint != NiPoint3::ZERO) { + GameMessages::SendPlayerReachedRespawnCheckpoint(player, respawnPoint, NiQuaternion::IDENTITY); } - } - UserManager::Instance()->RequestCharacterList(packet->systemAddress); - break; - } + EntityManager::Instance()->ConstructAllEntities(packet->systemAddress); - case MSG_WORLD_CLIENT_GAME_MSG: { - RakNet::BitStream bitStream(packet->data, packet->length, false); + auto* characterComponent = player->GetComponent<CharacterComponent>(); + if (characterComponent) { + player->GetComponent<CharacterComponent>()->RocketUnEquip(player); + } - uint64_t header; - LWOOBJID objectID; - uint16_t messageID; + // Do charxml fixes here + auto* levelComponent = player->GetComponent<LevelProgressionComponent>(); + if (!levelComponent) return; - bitStream.Read(header); - bitStream.Read(objectID); - bitStream.Read(messageID); + auto version = levelComponent->GetCharacterVersion(); + switch(version) { + case eCharacterVersion::RELEASE: + // TODO: Implement, super low priority + case eCharacterVersion::LIVE: + Game::logger->Log("WorldServer", "Updating Character Flags"); + c->SetRetroactiveFlags(); + levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); + case eCharacterVersion::PLAYER_FACTION_FLAGS: + Game::logger->Log("WorldServer", "Updating Vault Size"); + player->RetroactiveVaultSize(); + levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); + case eCharacterVersion::VAULT_SIZE: + Game::logger->Log("WorldServer", "Updaing Speedbase"); + levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + case eCharacterVersion::UP_TO_DATE: + break; + } - RakNet::BitStream dataStream; - bitStream.Read(dataStream, bitStream.GetNumberOfUnreadBits()); + player->GetCharacter()->SetTargetScene(""); - GameMessageHandler::HandleMessage(&dataStream, packet->systemAddress, objectID, GAME_MSG(messageID)); - break; - } + // Fix the destroyable component + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); - case MSG_WORLD_CLIENT_CHARACTER_CREATE_REQUEST: { - UserManager::Instance()->CreateCharacter(packet->systemAddress, packet); - break; - } + if (destroyableComponent != nullptr) { + destroyableComponent->FixStats(); + } - case MSG_WORLD_CLIENT_LOGIN_REQUEST: { - RakNet::BitStream inStream(packet->data, packet->length, false); - uint64_t header = inStream.Read(header); + //Tell the player to generate BBB models, if any: + if (g_CloneID != 0) { + const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); - LWOOBJID playerID = 0; - inStream.Read(playerID); - playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_CHARACTER); - playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_PERSISTENT); + const auto zoneId = Game::server->GetZoneID(); + const auto cloneId = g_CloneID; - UserManager::Instance()->LoginCharacter(packet->systemAddress, static_cast<uint32_t>(playerID)); - break; - } + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); + query.bind(1, (int)zoneId); - case MSG_WORLD_CLIENT_CHARACTER_DELETE_REQUEST: { - UserManager::Instance()->DeleteCharacter(packet->systemAddress, packet); - UserManager::Instance()->RequestCharacterList(packet->systemAddress); - break; - } + auto result = query.execQuery(); - case MSG_WORLD_CLIENT_CHARACTER_RENAME_REQUEST: { - UserManager::Instance()->RenameCharacter(packet->systemAddress, packet); - break; - } - - case MSG_WORLD_CLIENT_LEVEL_LOAD_COMPLETE: { - Game::logger->Log("WorldServer", "Received level load complete from user.\n"); - User* user = UserManager::Instance()->GetUser(packet->systemAddress); - if (user) { - Character* c = user->GetLastUsedChar(); - if (c != nullptr) { - std::u16string username = GeneralUtils::ASCIIToUTF16(c->GetName()); - Game::server->GetReplicaManager()->AddParticipant(packet->systemAddress); - - EntityInfo info {}; - info.lot = 1; - Entity* player = EntityManager::Instance()->CreateEntity(info, UserManager::Instance()->GetUser(packet->systemAddress)); - - WorldPackets::SendCreateCharacter(packet->systemAddress, player, c->GetXMLData(), username, c->GetGMLevel()); - WorldPackets::SendServerState(packet->systemAddress); - - const auto respawnPoint = player->GetCharacter()->GetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID()); - - EntityManager::Instance()->ConstructEntity(player, UNASSIGNED_SYSTEM_ADDRESS, true); - - if (respawnPoint != NiPoint3::ZERO) - { - GameMessages::SendPlayerReachedRespawnCheckpoint(player, respawnPoint, NiQuaternion::IDENTITY); + if (result.eof() || result.fieldIsNull(0)) { + Game::logger->Log("WorldServer", "No property templates found for zone %d, not sending BBB", zoneId); + goto noBBB; } - EntityManager::Instance()->ConstructAllEntities(packet->systemAddress); + //Check for BBB models: + auto stmt = Database::CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - auto* characterComponent = player->GetComponent<CharacterComponent>(); - if (characterComponent) { - player->GetComponent<CharacterComponent>()->RocketUnEquip(player); + int32_t templateId = result.getIntField(0); + + result.finalize(); + + auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;"); + + propertyLookup->setInt(1, templateId); + propertyLookup->setInt64(2, g_CloneID); + + auto* propertyEntry = propertyLookup->executeQuery(); + uint64_t propertyId = 0; + + if (propertyEntry->next()) { + propertyId = propertyEntry->getUInt64(1); } - c->SetRetroactiveFlags(); + delete propertyLookup; - player->RetroactiveVaultSize(); + stmt->setUInt64(1, propertyId); + auto res = stmt->executeQuery(); + while (res->next()) { + Game::logger->Log("UGC", "Getting lxfml ugcID: %u", res->getUInt(1)); - player->GetCharacter()->SetTargetScene(""); + //Get lxfml: + auto stmtL = Database::CreatePreppedStmt("SELECT lxfml from ugc where id=?"); + stmtL->setUInt(1, res->getUInt(1)); - // Fix the destroyable component - auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + auto lxres = stmtL->executeQuery(); - if (destroyableComponent != nullptr) - { - destroyableComponent->FixStats(); - } + while (lxres->next()) { + auto lxfml = lxres->getBlob(1); - //Tell the player to generate BBB models, if any: - if (g_CloneID != 0) { - const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); + lxfml->seekg(0, std::ios::end); + size_t lxfmlSize = lxfml->tellg(); + lxfml->seekg(0); - const auto zoneId = Game::server->GetZoneID(); - const auto cloneId = g_CloneID; + //Send message: + { + LWOOBJID blueprintID = res->getUInt(1); + GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int) zoneId); + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + bitStream.Write<LWOOBJID>(LWOOBJID_EMPTY); //always zero so that a check on the client passes + bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); + bitStream.Write<uint32_t>(1); + bitStream.Write(blueprintID); - auto result = query.execQuery(); + bitStream.Write<uint32_t>(lxfmlSize); - if (result.eof() || result.fieldIsNull(0)) { - Game::logger->Log("WorldServer", "No property templates found for zone %d, not sending BBB\n", zoneId); - goto noBBB; - } + for (size_t i = 0; i < lxfmlSize; ++i) + bitStream.Write<uint8_t>(lxfml->get()); - //Check for BBB models: - auto stmt = Database::CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - - int templateId = result.getIntField(0); - - result.finalize(); - - auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;"); - - propertyLookup->setInt(1, templateId); - propertyLookup->setInt64(2, g_CloneID); - - auto* propertyEntry = propertyLookup->executeQuery(); - uint64_t propertyId = 0; - - if (propertyEntry->next()) { - propertyId = propertyEntry->getUInt64(1); - } - - delete propertyLookup; - - stmt->setUInt64(1, propertyId); - auto res = stmt->executeQuery(); - while (res->next()) { - Game::logger->Log("UGC", "Getting lxfml ugcID: " + std::to_string(res->getUInt(1)) + "\n"); - - //Get lxfml: - auto stmtL = Database::CreatePreppedStmt("SELECT lxfml from ugc where id=?"); - stmtL->setUInt(1, res->getUInt(1)); - - auto lxres = stmtL->executeQuery(); - - while (lxres->next()) { - auto lxfml = lxres->getBlob(1); - - lxfml->seekg(0, std::ios::end); - size_t lxfmlSize = lxfml->tellg(); - lxfml->seekg(0); - - //Send message: - { - LWOOBJID blueprintID = res->getUInt(1); - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_CHARACTER); - blueprintID = GeneralUtils::SetBit(blueprintID, OBJECT_BIT_PERSISTENT); - - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE); - bitStream.Write<LWOOBJID>(0); //always zero so that a check on the client passes - bitStream.Write<unsigned int>(0); - bitStream.Write<unsigned int>(1); - bitStream.Write(blueprintID); - - bitStream.Write<uint32_t>(lxfmlSize + 9); - - //Write a fake sd0 header: - bitStream.Write<unsigned char>(0x73); //s - bitStream.Write<unsigned char>(0x64); //d - bitStream.Write<unsigned char>(0x30); //0 - bitStream.Write<unsigned char>(0x01); //1 - bitStream.Write<unsigned char>(0xFF); //end magic - - bitStream.Write<uint32_t>(lxfmlSize); - - for (size_t i = 0; i < lxfmlSize; ++i) - bitStream.Write<uint8_t>(lxfml->get()); - - SystemAddress sysAddr = packet->systemAddress; - SEND_PACKET; - PacketUtils::SavePacket("lxfml packet " + std::to_string(res->getUInt(1)) + ".bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); - } + SystemAddress sysAddr = packet->systemAddress; + SEND_PACKET; + PacketUtils::SavePacket("lxfml packet " + std::to_string(res->getUInt(1)) + ".bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); } - - delete stmtL; - delete lxres; } - delete stmt; - delete res; + delete stmtL; + delete lxres; } - noBBB: - - // Tell the client it's done loading: - GameMessages::SendInvalidZoneTransferList(player, packet->systemAddress, GeneralUtils::ASCIIToUTF16(Game::config->GetValue("source")), u"", false, false); - GameMessages::SendServerDoneLoadingAllObjects(player, packet->systemAddress); - - //Send the player it's mail count: - //update: this might not be needed so im going to try disabling this here. - //Mail::HandleNotificationRequest(packet->systemAddress, player->GetObjectID()); - - //Notify chat that a player has loaded: - { - const auto& playerName = player->GetCharacter()->GetName(); - //RakNet::RakString playerName(player->GetCharacter()->GetName().c_str()); - - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION); - bitStream.Write(player->GetObjectID()); - bitStream.Write<uint16_t>(playerName.size()); - for (size_t i = 0; i < playerName.size(); i++) - { - bitStream.Write(playerName[i]); - } - - //bitStream.Write(playerName); - - auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); - bitStream.Write(zone.GetMapID()); - bitStream.Write(zone.GetInstanceID()); - bitStream.Write(zone.GetCloneID()); - bitStream.Write(player->GetParentUser()->GetMuteExpire()); - - Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); - } - } - else { - Game::logger->Log("WorldServer", "Couldn't find character to log in with for user %s (%i)!\n", user->GetUsername().c_str(), user->GetAccountID()); - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_CHARACTER_NOT_FOUND); + delete stmt; + delete res; } - } else { - Game::logger->Log("WorldServer", "Couldn't get user for level load complete!\n"); - } - break; - } - case MSG_WORLD_CLIENT_POSITION_UPDATE: { - ClientPackets::HandleClientPositionUpdate(packet->systemAddress, packet); - break; + noBBB: + + // Tell the client it's done loading: + GameMessages::SendInvalidZoneTransferList(player, packet->systemAddress, GeneralUtils::ASCIIToUTF16(Game::config->GetValue("source")), u"", false, false); + GameMessages::SendServerDoneLoadingAllObjects(player, packet->systemAddress); + + //Send the player it's mail count: + //update: this might not be needed so im going to try disabling this here. + //Mail::HandleNotificationRequest(packet->systemAddress, player->GetObjectID()); + + //Notify chat that a player has loaded: + { + const auto& playerName = player->GetCharacter()->GetName(); + //RakNet::RakString playerName(player->GetCharacter()->GetName().c_str()); + + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION); + bitStream.Write(player->GetObjectID()); + bitStream.Write<uint32_t>(playerName.size()); + for (size_t i = 0; i < playerName.size(); i++) { + bitStream.Write(playerName[i]); + } + + auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); + bitStream.Write(zone.GetMapID()); + bitStream.Write(zone.GetInstanceID()); + bitStream.Write(zone.GetCloneID()); + bitStream.Write(player->GetParentUser()->GetMuteExpire()); + + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } + } else { + Game::logger->Log("WorldServer", "Couldn't find character to log in with for user %s (%i)!", user->GetUsername().c_str(), user->GetAccountID()); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); + } + } else { + Game::logger->Log("WorldServer", "Couldn't get user for level load complete!"); + } + break; + } + + case eWorldMessageType::POSITION_UPDATE: { + ClientPackets::HandleClientPositionUpdate(packet->systemAddress, packet); + break; + } + + case eWorldMessageType::MAIL: { + RakNet::BitStream bitStream(packet->data, packet->length, false); + LWOOBJID space; + bitStream.Read(space); + Mail::HandleMailStuff(&bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); + break; + } + + case eWorldMessageType::ROUTE_PACKET: { + //Yeet to chat + CINSTREAM_SKIP_HEADER; + uint32_t size = 0; + inStream.Read(size); + + if (size > 20000) { + Game::logger->Log("WorldServer", "Tried to route a packet with a read size > 20000, so likely a false packet."); + return; } - case MSG_WORLD_CLIENT_MAIL: { - RakNet::BitStream bitStream(packet->data, packet->length, false); - LWOOBJID space; - bitStream.Read(space); - Mail::HandleMailStuff(&bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); - break; + CBITSTREAM; + + PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, packet->data[14]); + + //We need to insert the player's objectID so the chat server can find who originated this request: + LWOOBJID objectID = 0; + auto user = UserManager::Instance()->GetUser(packet->systemAddress); + if (user) { + objectID = user->GetLastUsedChar()->GetObjectID(); } - case MSG_WORLD_CLIENT_ROUTE_PACKET: { - //Yeet to chat - CINSTREAM; - uint64_t header = 0; - uint32_t size = 0; - inStream.Read(header); - inStream.Read(size); + bitStream.Write(objectID); - if (size > 20000) { - Game::logger->Log("WorldServer", "Tried to route a packet with a read size > 20000, so likely a false packet.\n"); - return; - } - - CBITSTREAM; - - PacketUtils::WriteHeader(bitStream, CHAT, packet->data[14]); - - //We need to insert the player's objectID so the chat server can find who originated this request: - LWOOBJID objectID = 0; - auto user = UserManager::Instance()->GetUser(packet->systemAddress); - if (user) { - objectID = user->GetLastUsedChar()->GetObjectID(); - } - - bitStream.Write(objectID); - - //Now write the rest of the data: - auto data = inStream.GetData(); - for (uint32_t i = 0; i < size; ++i) { - bitStream.Write(data[i+23]); - } - - Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, Game::chatSysAddr, false); - break; + //Now write the rest of the data: + auto data = inStream.GetData(); + for (uint32_t i = 0; i < size; ++i) { + bitStream.Write(data[i + 23]); } - case MSG_WORLD_CLIENT_STRING_CHECK: { - ClientPackets::HandleChatModerationRequest(packet->systemAddress, packet); - break; + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, Game::chatSysAddr, false); + break; + } + + case eWorldMessageType::STRING_CHECK: { + ClientPackets::HandleChatModerationRequest(packet->systemAddress, packet); + break; + } + + case eWorldMessageType::GENERAL_CHAT_MESSAGE: { + if (chatDisabled) { + ChatPackets::SendMessageFail(packet->systemAddress); + } else { + ClientPackets::HandleChatMessage(packet->systemAddress, packet); } - case MSG_WORLD_CLIENT_GENERAL_CHAT_MESSAGE: { - if (chatDisabled) { - ChatPackets::SendMessageFail(packet->systemAddress); - } - else { - ClientPackets::HandleChatMessage(packet->systemAddress, packet); - } + break; + } - break; + case eWorldMessageType::HANDLE_FUNNESS: { + //This means the client is running slower or faster than it should. + //Could be insane lag, but I'mma just YEET them as it's usually speedhacking. + //This is updated to now count the amount of times we've been caught "speedhacking" to kick with a delay + //This is hopefully going to fix the random disconnects people face sometimes. + if (Game::config->GetValue("disable_anti_speedhack") == "1") { + return; } - case MSG_WORLD_CLIENT_HANDLE_FUNNESS: { - //This means the client is running slower or faster than it should. - //Could be insane lag, but I'mma just YEET them as it's usually speedhacking. - //This is updated to now count the amount of times we've been caught "speedhacking" to kick with a delay - //This is hopefully going to fix the random disconnects people face sometimes. - if (Game::config->GetValue("disable_anti_speedhack") == "1") { - return; - } - - User* user = UserManager::Instance()->GetUser(packet->systemAddress); - if (user) { - user->UserOutOfSync(); - } - else { - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_KICK); - } - break; + User* user = UserManager::Instance()->GetUser(packet->systemAddress); + if (user) { + user->UserOutOfSync(); + } else { + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK); } + break; + } default: - Game::server->GetLogger()->Log("HandlePacket", "Unknown world packet received: %i\n", int(packet->data[3])); + Game::server->GetLogger()->Log("HandlePacket", "Unknown world packet received: %i", int(packet->data[3])); } } void WorldShutdownProcess(uint32_t zoneId) { - Game::logger->Log("WorldServer", "Saving map %i instance %i\n", zoneId, instanceID); - for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) { - const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i); + Game::logger->Log("WorldServer", "Saving map %i instance %i", zoneId, instanceID); + for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) { + const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i); - auto* entity = Player::GetPlayer(player); - Game::logger->Log("WorldServer", "Saving data!\n"); - if (entity != nullptr && entity->GetCharacter() != nullptr) { - auto* skillComponent = entity->GetComponent<SkillComponent>(); + auto* entity = Player::GetPlayer(player); + Game::logger->Log("WorldServer", "Saving data!"); + if (entity != nullptr && entity->GetCharacter() != nullptr) { + auto* skillComponent = entity->GetComponent<SkillComponent>(); - if (skillComponent != nullptr) { - skillComponent->Reset(); - } - std::string message = "Saving character " + entity->GetCharacter()->GetName() + "...\n"; - Game::logger->Log("WorldServer", message); - entity->GetCharacter()->SaveXMLToDatabase(); - message = "Character data for " + entity->GetCharacter()->GetName() + " was saved!\n"; - Game::logger->Log("WorldServer", message); - } - } + if (skillComponent != nullptr) { + skillComponent->Reset(); + } + Game::logger->Log("WorldServer", "Saving character %s...", entity->GetCharacter()->GetName().c_str()); + entity->GetCharacter()->SaveXMLToDatabase(); + Game::logger->Log("WorldServer", "Character data for %s was saved!", entity->GetCharacter()->GetName().c_str()); + } + } - if (PropertyManagementComponent::Instance() != nullptr) { - Game::logger->Log("WorldServer", "Saving ALL property data for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); - PropertyManagementComponent::Instance()->Save(); - Game::logger->Log("WorldServer", "ALL property data saved for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); - } + if (PropertyManagementComponent::Instance() != nullptr) { + Game::logger->Log("WorldServer", "Saving ALL property data for zone %i clone %i!", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); + PropertyManagementComponent::Instance()->Save(); + Game::logger->Log("WorldServer", "ALL property data saved for zone %i clone %i!", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); + } - Game::logger->Log("WorldServer", "ALL DATA HAS BEEN SAVED FOR ZONE %i INSTANCE %i!\n", zoneId, instanceID); + Game::logger->Log("WorldServer", "ALL DATA HAS BEEN SAVED FOR ZONE %i INSTANCE %i!", zoneId, instanceID); - while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { - const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); + while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { + const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); - Game::server->Disconnect(player, SERVER_DISCON_KICK); - } + Game::server->Disconnect(player, eServerDisconnectIdentifiers::SERVER_SHUTDOWN); + } SendShutdownMessageToMaster(); } void WorldShutdownSequence() { - if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) { - return; - } + if (Game::shouldShutdown || worldShutdownSequenceComplete) { + return; + } - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; - Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!\n", Game::server->GetZoneID(), instanceID); - WorldShutdownProcess(Game::server->GetZoneID()); + Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!", Game::server->GetZoneID(), instanceID); + WorldShutdownProcess(Game::server->GetZoneID()); FinalizeShutdown(); } void FinalizeShutdown() { + Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); + //Delete our objects here: - if (Game::physicsWorld) Game::physicsWorld = nullptr; - if (Game::zoneManager) delete Game::zoneManager; - - Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)\n", Game::server->GetZoneID(), instanceID); - Metrics::Clear(); Database::Destroy("WorldServer"); - delete Game::chatFilter; - delete Game::server; - delete Game::logger; + if (Game::chatFilter) delete Game::chatFilter; + if (Game::server) delete Game::server; + if (Game::logger) delete Game::logger; + if (Game::config) delete Game::config; worldShutdownSequenceComplete = true; @@ -1292,6 +1342,6 @@ void FinalizeShutdown() { void SendShutdownMessageToMaster() { CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_RESPONSE); + PacketUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_RESPONSE); Game::server->SendToMaster(&bitStream); -} \ No newline at end of file +} diff --git a/dZoneManager/CMakeLists.txt b/dZoneManager/CMakeLists.txt new file mode 100644 index 00000000..1dd3841b --- /dev/null +++ b/dZoneManager/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DZONEMANAGER_SOURCES "dZoneManager.cpp" + "Level.cpp" + "Spawner.cpp" + "Zone.cpp") + +add_library(dZoneManager STATIC ${DZONEMANAGER_SOURCES}) diff --git a/dZoneManager/LUTriggers.h b/dZoneManager/LUTriggers.h new file mode 100644 index 00000000..a93cd67d --- /dev/null +++ b/dZoneManager/LUTriggers.h @@ -0,0 +1,33 @@ +#ifndef __LUTRIGGERS__H__ +#define __LUTRIGGERS__H__ + +#include <string> +#include <vector> + +class Command; +class Event; +enum class eTriggerCommandType; +enum class eTriggerEventType; + + +namespace LUTriggers { + struct Command { + eTriggerCommandType id; + std::string target; + std::string targetName; + std::string args; + }; + + struct Event { + eTriggerEventType id; + std::vector<Command*> commands; + }; + + struct Trigger { + uint32_t id; + bool enabled; + std::vector<Event*> events; + }; +}; + +#endif //!__LUTRIGGERS__H__ diff --git a/dZoneManager/Level.cpp b/dZoneManager/Level.cpp index b678ed95..55790592 100644 --- a/dZoneManager/Level.cpp +++ b/dZoneManager/Level.cpp @@ -13,19 +13,22 @@ #include "EntityManager.h" #include "CDFeatureGatingTable.h" #include "CDClientManager.h" +#include "AssetManager.h" Level::Level(Zone* parentZone, const std::string& filepath) { - m_ParentZone = parentZone; - std::ifstream file(filepath, std::ios_base::in | std::ios_base::binary); - if (file) { - //printf("Opened %s\n", filepath.c_str()); - ReadChunks(file); - } - else { - Game::logger->Log("Level", "Failed to load %s\n", filepath.c_str()); + m_ParentZone = parentZone; + + auto buffer = Game::assetManager->GetFileAsBuffer(filepath.c_str()); + + if (!buffer.m_Success) { + Game::logger->Log("Level", "Failed to load %s", filepath.c_str()); + return; } - file.close(); + std::istream file(&buffer); + ReadChunks(file); + + buffer.close(); } Level::~Level() { @@ -43,7 +46,7 @@ const void Level::PrintAllObjects() { } } -void Level::ReadChunks(std::ifstream & file) { +void Level::ReadChunks(std::istream& file) { const uint32_t CHNK_HEADER = ('C' + ('H' << 8) + ('N' << 16) + ('K' << 24)); while (!file.eof()) { @@ -64,15 +67,13 @@ void Level::ReadChunks(std::ifstream & file) { //We're currently not loading env or particle data if (header.id == ChunkTypeID::FileInfo) { ReadFileInfoChunk(file, header); - } - else if (header.id == ChunkTypeID::SceneObjectData) { + } else if (header.id == ChunkTypeID::SceneObjectData) { ReadSceneObjectDataChunk(file, header); } m_ChunkHeaders.insert(std::make_pair(header.id, header)); file.seekg(target); - } - else { + } else { if (initPos == std::streamoff(0)) { //Really old chunk version file.seekg(0); Header header; @@ -96,11 +97,10 @@ void Level::ReadChunks(std::ifstream & file) { for (uint32_t i = 0; i < s; ++i) { file.ignore(4); //a uint file.ignore(4); //two floats - file.ignore(4); + file.ignore(4); } } - } - else { + } else { file.ignore(8); } @@ -110,7 +110,7 @@ void Level::ReadChunks(std::ifstream & file) { if (header.chunkVersion >= 36) { file.ignore(3 * 4); } - + if (header.chunkVersion < 42) { file.ignore(3 * 4); @@ -144,7 +144,7 @@ void Level::ReadChunks(std::ifstream & file) { } } -void Level::ReadFileInfoChunk(std::ifstream & file, Header & header) { +void Level::ReadFileInfoChunk(std::istream& file, Header& header) { FileInfoChunk* fi = new FileInfoChunk; BinaryIO::BinaryRead(file, fi->version); BinaryIO::BinaryRead(file, fi->revision); @@ -157,12 +157,12 @@ void Level::ReadFileInfoChunk(std::ifstream & file, Header & header) { if (header.fileInfo->revision == 3452816845 && m_ParentZone->GetZoneID().GetMapID() == 1100) header.fileInfo->revision = 26; } -void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { +void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { SceneObjectDataChunk* chunk = new SceneObjectDataChunk; uint32_t objectsCount = 0; BinaryIO::BinaryRead(file, objectsCount); - CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance()->GetTable<CDFeatureGatingTable>("FeatureGating"); + CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance().GetTable<CDFeatureGatingTable>(); for (uint32_t i = 0; i < objectsCount; ++i) { SceneObject obj; @@ -176,32 +176,32 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { BinaryIO::BinaryRead(file, obj.rotation); BinaryIO::BinaryRead(file, obj.scale); - //This is a little bit of a bodge, but because the alpha client (HF) doesn't store the + //This is a little bit of a bodge, but because the alpha client (HF) doesn't store the //spawn position / rotation like the later versions do, we need to check the LOT for the spawn pos & set it. if (obj.lot == LOT_MARKER_PLAYER_START) { dZoneManager::Instance()->GetZone()->SetSpawnPos(obj.position); dZoneManager::Instance()->GetZone()->SetSpawnRot(obj.rotation); } - std::u16string ldfString = u""; - uint32_t length = 0; - BinaryIO::BinaryRead(file, length); - - for (uint32_t i = 0; i < length; ++i) { - uint16_t data; - BinaryIO::BinaryRead(file, data); - ldfString.push_back(data); - } - - std::string sData = GeneralUtils::UTF16ToWTF8(ldfString); - std::stringstream ssData(sData); - std::string token; - char deliminator = '\n'; - - while (std::getline(ssData, token, deliminator)) { - LDFBaseData * ldfData = LDFBaseData::DataFromString(token); - obj.settings.push_back(ldfData); - } + std::u16string ldfString = u""; + uint32_t length = 0; + BinaryIO::BinaryRead(file, length); + + for (uint32_t i = 0; i < length; ++i) { + uint16_t data; + BinaryIO::BinaryRead(file, data); + ldfString.push_back(data); + } + + std::string sData = GeneralUtils::UTF16ToWTF8(ldfString); + std::stringstream ssData(sData); + std::string token; + char deliminator = '\n'; + + while (std::getline(ssData, token, deliminator)) { + LDFBaseData* ldfData = LDFBaseData::DataFromString(token); + obj.settings.push_back(ldfData); + } BinaryIO::BinaryRead(file, obj.value3); @@ -229,7 +229,7 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { continue; } - if (obj.lot == 176) { //Spawner + if (obj.lot == 176) { //Spawner SpawnerInfo spawnInfo = SpawnerInfo(); SpawnerNode* node = new SpawnerNode(); spawnInfo.templateID = obj.lot; @@ -260,19 +260,18 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { if (data->GetKey() == u"spawner_active_on_load") { spawnInfo.activeOnLoad = std::stoi(data->GetValueAsString()); } - + if (data->GetKey() == u"active_on_load") { spawnInfo.activeOnLoad = std::stoi(data->GetValueAsString()); } - + if (data->GetKey() == u"respawn") { if (data->GetValueType() == eLDFType::LDF_TYPE_FLOAT) // Floats are in seconds { spawnInfo.respawnTime = std::stof(data->GetValueAsString()); - } - else if (data->GetValueType() == eLDFType::LDF_TYPE_U32) // Ints are in ms? + } else if (data->GetValueType() == eLDFType::LDF_TYPE_U32) // Ints are in ms? { - spawnInfo.respawnTime = std::stoi(data->GetValueAsString()) / 1000; + spawnInfo.respawnTime = std::stoul(data->GetValueAsString()) / 1000; } } if (data->GetKey() == u"spawnsGroupOnSmash") { @@ -297,9 +296,9 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { } } } - Spawner* spawner = new Spawner(spawnInfo); - dZoneManager::Instance()->AddSpawner(obj.id, spawner); - } else { //Regular object + Spawner* spawner = new Spawner(spawnInfo); + dZoneManager::Instance()->AddSpawner(obj.id, spawner); + } else { //Regular object EntityInfo info; info.spawnerID = 0; info.id = obj.id; @@ -328,16 +327,14 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { if (!clientOnly) { - // We should never have more than 1 zone control object - const auto zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); + // We should never have more than 1 zone control object + const auto zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); if (zoneControlObject != nullptr && info.lot == zoneControlObject->GetLOT()) goto deleteSettings; - EntityManager::Instance()->CreateEntity(info, nullptr); - } - else - { - deleteSettings: + EntityManager::Instance()->CreateEntity(info, nullptr); + } else { + deleteSettings: for (auto* setting : info.settings) { delete setting; @@ -350,6 +347,5 @@ void Level::ReadSceneObjectDataChunk(std::ifstream & file, Header & header) { } } - //printf("Loaded %u objects!\n", objectsCount); header.sceneObjects = chunk; } diff --git a/dZoneManager/Level.h b/dZoneManager/Level.h index 05839759..83daeedb 100644 --- a/dZoneManager/Level.h +++ b/dZoneManager/Level.h @@ -29,7 +29,7 @@ public: struct SceneObjectDataChunk { std::map<LWOOBJID, SceneObject> objects; - + SceneObject& GetObject(LWOOBJID id) { for (std::map<LWOOBJID, SceneObject>::iterator it = objects.begin(); it != objects.end(); ++it) { if (it->first == id) return it->second; @@ -67,7 +67,7 @@ private: Zone* m_ParentZone; //private functions: - void ReadChunks(std::ifstream& file); - void ReadFileInfoChunk(std::ifstream& file, Header& header); - void ReadSceneObjectDataChunk(std::ifstream& file, Header& header); + void ReadChunks(std::istream& file); + void ReadFileInfoChunk(std::istream& file, Header& header); + void ReadSceneObjectDataChunk(std::istream& file, Header& header); }; diff --git a/dZoneManager/Spawner.cpp b/dZoneManager/Spawner.cpp index 3e69d785..28f77fea 100644 --- a/dZoneManager/Spawner.cpp +++ b/dZoneManager/Spawner.cpp @@ -15,8 +15,7 @@ Spawner::Spawner(const SpawnerInfo info) { if (!m_Info.emulated) { m_EntityInfo.spawnerID = m_Info.spawnerID; - } - else { + } else { m_EntityInfo.spawnerID = m_Info.emulator; m_Info.isNetwork = false; } @@ -46,8 +45,7 @@ Spawner::Spawner(const SpawnerInfo info) { m_WaitTimes.push_back(m_Info.respawnTime); } - if (m_Info.spawnOnSmashGroupName != "") - { + if (m_Info.spawnOnSmashGroupName != "") { std::vector<Entity*> spawnSmashEntities = EntityManager::Instance()->GetEntitiesInGroup(m_Info.spawnOnSmashGroupName); std::vector<Spawner*> spawnSmashSpawners = dZoneManager::Instance()->GetSpawnersInGroup(m_Info.spawnOnSmashGroupName); std::vector<Spawner*> spawnSmashSpawnersN = dZoneManager::Instance()->GetSpawnersByName(m_Info.spawnOnSmashGroupName); @@ -55,20 +53,20 @@ Spawner::Spawner(const SpawnerInfo info) { m_SpawnSmashFoundGroup = true; ssEntity->AddDieCallback([=]() { Spawn(); - }); + }); } for (Spawner* ssSpawner : spawnSmashSpawners) { m_SpawnSmashFoundGroup = true; ssSpawner->AddSpawnedEntityDieCallback([=]() { Spawn(); - }); + }); } for (Spawner* ssSpawner : spawnSmashSpawnersN) { m_SpawnSmashFoundGroup = true; m_SpawnOnSmash = ssSpawner; ssSpawner->AddSpawnedEntityDieCallback([=]() { Spawn(); - }); + }); } } } @@ -77,8 +75,7 @@ Spawner::~Spawner() { } -Entity* Spawner::Spawn() -{ +Entity* Spawner::Spawn() { std::vector<SpawnerNode*> freeNodes; for (SpawnerNode* node : m_Info.nodes) { if (node->entities.size() < node->nodeMax) { @@ -131,37 +128,33 @@ void Spawner::AddSpawnedEntityDieCallback(std::function<void()> callback) { m_SpawnedEntityDieCallbacks.push_back(callback); } -void Spawner::AddEntitySpawnedCallback(std::function<void(Entity *)> callback) { +void Spawner::AddEntitySpawnedCallback(std::function<void(Entity*)> callback) { m_EntitySpawnedCallbacks.push_back(callback); } -void Spawner::Reset() -{ +void Spawner::Reset() { m_Start = true; - - for (auto* node : m_Info.nodes) - { - for (const auto& spawned : node->entities) - { - auto* entity = EntityManager::Instance()->GetEntity(spawned); - - if (entity == nullptr) continue; - - entity->Kill(); - } - - node->entities.clear(); - } - + DestroyAllEntities(); m_Entities.clear(); m_AmountSpawned = 0; m_NeedsUpdate = true; } +void Spawner::DestroyAllEntities(){ + for (auto* node : m_Info.nodes) { + for (const auto& element : node->entities) { + auto* entity = EntityManager::Instance()->GetEntity(element); + if (entity == nullptr) continue; + entity->Kill(); + } + node->entities.clear(); + } +} + void Spawner::SoftReset() { - m_Start = true; - m_AmountSpawned = 0; - m_NeedsUpdate = true; + m_Start = true; + m_AmountSpawned = 0; + m_NeedsUpdate = true; } void Spawner::SetRespawnTime(float time) { @@ -171,8 +164,8 @@ void Spawner::SetRespawnTime(float time) { m_WaitTimes[i] = 0; }; - m_Start = true; - m_NeedsUpdate = true; + m_Start = true; + m_NeedsUpdate = true; } void Spawner::SetNumToMaintain(int32_t value) { @@ -180,21 +173,19 @@ void Spawner::SetNumToMaintain(int32_t value) { } void Spawner::Update(const float deltaTime) { - if (m_Start && m_Active) - { + if (m_Start && m_Active) { m_Start = false; const auto toSpawn = m_Info.amountMaintained - m_AmountSpawned; - for (auto i = 0; i < toSpawn; ++i) - { + for (auto i = 0; i < toSpawn; ++i) { Spawn(); } - + m_WaitTimes.clear(); - + return; } - + if (!m_NeedsUpdate) return; if (!m_Active) return; //if (m_Info.noTimedSpawn) return; @@ -223,7 +214,7 @@ void Spawner::NotifyOfEntityDeath(const LWOOBJID& objectID) { //m_RespawnTime = 10.0f; m_WaitTimes.push_back(0.0f); SpawnerNode* node; - + auto it = m_Entities.find(objectID); if (it != m_Entities.end()) node = it->second; else return; @@ -233,29 +224,26 @@ void Spawner::NotifyOfEntityDeath(const LWOOBJID& objectID) { } for (size_t i = 0; i < node->entities.size(); ++i) { - if (node->entities[i] && node->entities[i] == objectID) + if (node->entities[i] && node->entities[i] == objectID) node->entities.erase(node->entities.begin() + i); } m_Entities.erase(objectID); - if (m_SpawnOnSmash != nullptr) - { + if (m_SpawnOnSmash != nullptr) { m_SpawnOnSmash->Reset(); } } -void Spawner::Activate() -{ +void Spawner::Activate() { m_Active = true; m_NeedsUpdate = true; - for (auto& time : m_WaitTimes) - { + for (auto& time : m_WaitTimes) { time = 0; } } void Spawner::SetSpawnLot(LOT lot) { - m_EntityInfo.lot = lot; + m_EntityInfo.lot = lot; } diff --git a/dZoneManager/Spawner.h b/dZoneManager/Spawner.h index 17e2e126..1f610b71 100644 --- a/dZoneManager/Spawner.h +++ b/dZoneManager/Spawner.h @@ -9,6 +9,7 @@ #include <string> #include <functional> #include "LDFFormat.h" +#include "EntityInfo.h" struct SpawnerNode { NiPoint3 position = NiPoint3::ZERO; @@ -37,15 +38,15 @@ struct SpawnerInfo { bool noTimedSpawn = false; std::string grpNameQBShowBricks = ""; bool spawnActivator = true; - + bool emulated = false; LWOOBJID emulator = LWOOBJID_EMPTY; }; class Spawner { public: - Spawner(SpawnerInfo info); - ~Spawner(); + Spawner(SpawnerInfo info); + ~Spawner(); Entity* Spawn(); Entity* Spawn(std::vector<SpawnerNode*> freeNodes, bool force = false); @@ -60,6 +61,7 @@ public: void AddEntitySpawnedCallback(std::function<void(Entity*)> callback); void SetSpawnLot(LOT lot); void Reset(); + void DestroyAllEntities(); void SoftReset(); void SetRespawnTime(float time); void SetNumToMaintain(int32_t value); @@ -69,7 +71,7 @@ public: bool m_Active = true; private: std::vector<std::function<void()>> m_SpawnedEntityDieCallbacks = {}; - std::vector<std::function<void(Entity*)>> m_EntitySpawnedCallbacks = {}; + std::vector<std::function<void(Entity*)>> m_EntitySpawnedCallbacks = {}; bool m_SpawnSmashFoundGroup = false; diff --git a/dZoneManager/WorldConfig.h b/dZoneManager/WorldConfig.h new file mode 100644 index 00000000..a98433a1 --- /dev/null +++ b/dZoneManager/WorldConfig.h @@ -0,0 +1,67 @@ +#ifndef __WORLDCONFIG__H__ +#define __WORLDCONFIG__H__ + +#include <cstdint> +#include <string> + +struct WorldConfig { + int32_t worldConfigID{}; //! Primary key for WorlcConfig table + float peGravityValue{}; //! Unknown + float peBroadphaseWorldSize{}; //! Unknown + float peGameObjScaleFactor{}; //! Unknown + float characterRotationSpeed{}; //! The players' rotation speed + float characterWalkForwardSpeed{}; //! The players' walk forward speed + float characterWalkBackwardSpeed{}; //! The players' walk backwards speed + float characterWalkStrafeSpeed{}; //! The players' strafe speed + float characterWalkStrafeForwardSpeed{}; //! The players' walk strafe forward speed + float characterWalkStrafeBackwardSpeed{}; //! The players' walk strage backwards speed + float characterRunBackwardSpeed{}; //! The players' run backwards speed + float characterRunStrafeSpeed{}; //! The players' run strafe speed + float characterRunStrafeForwardSpeed{}; //! The players' run strafe forward speed + float characterRunStrafeBackwardSpeed{}; //! The players' run strage backwards speed + float globalCooldown{}; //! The global ability cooldown + float characterGroundedTime{}; //! Unknown + float characterGroundedSpeed{}; //! Unknown + float globalImmunityTime{}; //! Unknown + float characterMaxSlope{}; //! Unknown + float defaultRespawnTime{}; //! Unknown + float missionTooltipTimeout{}; + float vendorBuyMultiplier{}; //! The buy scalar for buying from vendors + float petFollowRadius{}; //! The players' pet follow radius + float characterEyeHeight{}; //! The players' eye height + float flightVerticalVelocity{}; //! Unknown + float flightAirspeed{}; //! Unknown + float flightFuelRatio{}; //! Unknown + float flightMaxAirspeed{}; //! Unknown + float fReputationPerVote{}; //! Unknown + int32_t propertyCloneLimit{}; //! Unknown + int32_t defaultHomespaceTemplate{}; //! Unknown + float coinsLostOnDeathPercent{}; //! The percentage of coins to lose on a player death + int32_t coinsLostOnDeathMin{}; //! The minimum number of coins to lose on a player death + int32_t coinsLostOnDeathMax{}; //! The maximum number of coins to lose on a player death + int32_t characterVotesPerDay{}; //! Unknown + int32_t propertyModerationRequestApprovalCost{};//! Unknown + int32_t propertyModerationRequestReviewCost{}; //! Unknown + int32_t propertyModRequestsAllowedSpike{}; //! Unknown + int32_t propertyModRequestsAllowedInterval{}; //! Unknown + int32_t propertyModRequestsAllowedTotal{}; //! Unknown + int32_t propertyModRequestsSpikeDuration{}; //! Unknown + int32_t propertyModRequestsIntervalDuration{}; //! Unknown + bool modelModerateOnCreate{}; //! Unknown + float defaultPropertyMaxHeight{}; //! Unknown + float reputationPerVoteCast{}; //! Unknown + float reputationPerVoteReceived{}; //! Unknown + int32_t showcaseTopModelConsiderationBattles{}; //! Unknown + float reputationPerBattlePromotion{}; //! Unknown + float coinsLostOnDeathMinTimeout{}; //! Unknown + float coinsLostOnDeathMaxTimeout{}; //! Unknown + int32_t mailBaseFee{}; //! The base fee to take when a player sends mail + float mailPercentAttachmentFee{}; //! The scalar multiplied by an items base cost to determine how much that item costs to be mailed + int32_t propertyReputationDelay{}; //! Unknown + int32_t levelCap{}; //! The maximum player level + std::string levelUpBehaviorEffect{}; //! Unknown + int32_t characterVersion{}; //! Unknown + int32_t levelCapCurrencyConversion{}; //! The ratio of UScore (LEGO Score) to coins +}; + +#endif //! __WORLDCONFIG__H__ diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index 68adb943..28d3f0c8 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -6,15 +6,19 @@ #include "dLogger.h" #include "GeneralUtils.h" #include "BinaryIO.h" +#include "LUTriggers.h" +#include "AssetManager.h" #include "CDClientManager.h" #include "CDZoneTableTable.h" #include "Spawner.h" #include "dZoneManager.h" -Zone::Zone(const LWOMAPID & mapID, const LWOINSTANCEID & instanceID, const LWOCLONEID & cloneID) : - m_ZoneID(mapID, instanceID, cloneID) -{ +#include "eTriggerCommandType.h" +#include "eTriggerEventType.h" + +Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) : + m_ZoneID(mapID, instanceID, cloneID) { m_NumberOfScenesLoaded = 0; m_NumberOfObjectsLoaded = 0; m_NumberOfSceneTransitionsLoaded = 0; @@ -24,14 +28,13 @@ Zone::Zone(const LWOMAPID & mapID, const LWOINSTANCEID & instanceID, const LWOCL } Zone::~Zone() { - Game::logger->Log("Zone", "Destroying zone %i\n", m_ZoneID.GetMapID()); + Game::logger->Log("Zone", "Destroying zone %i", m_ZoneID.GetMapID()); for (std::map<LWOSCENEID, SceneRef>::iterator it = m_Scenes.begin(); it != m_Scenes.end(); ++it) { if (it->second.level != nullptr) delete it->second.level; } } -void Zone::Initalize() -{ +void Zone::Initalize() { LoadZoneIntoMemory(); LoadLevelsIntoMemory(); m_CheckSum = CalculateChecksum(); @@ -42,15 +45,22 @@ void Zone::LoadZoneIntoMemory() { m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1); if (m_ZoneFilePath == "ERR") return; - std::ifstream file(m_ZoneFilePath, std::ios::binary); + AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer(m_ZoneFilePath.c_str()); + + if (!buffer.m_Success) { + Game::logger->Log("Zone", "Failed to load %s", m_ZoneFilePath.c_str()); + throw std::runtime_error("Aborting Zone loading due to no Zone File."); + } + + std::istream file(&buffer); if (file) { BinaryIO::BinaryRead(file, m_ZoneFileFormatVersion); - + uint32_t mapRevision = 0; if (m_ZoneFileFormatVersion >= Zone::ZoneFileFormatVersion::Alpha) BinaryIO::BinaryRead(file, mapRevision); - + BinaryIO::BinaryRead(file, m_WorldID); - if ((uint16_t)m_WorldID != m_ZoneID.GetMapID()) Game::logger->Log("Zone", "WorldID: %i doesn't match MapID %i! Is this intended?\n", m_WorldID, m_ZoneID.GetMapID()); + if ((uint16_t)m_WorldID != m_ZoneID.GetMapID()) Game::logger->Log("Zone", "WorldID: %i doesn't match MapID %i! Is this intended?", m_WorldID, m_ZoneID.GetMapID()); AddRevision(LWOSCENEID_INVALID, mapRevision); @@ -58,13 +68,12 @@ void Zone::LoadZoneIntoMemory() { BinaryIO::BinaryRead(file, m_Spawnpoint); BinaryIO::BinaryRead(file, m_SpawnpointRotation); } - + if (m_ZoneFileFormatVersion <= Zone::ZoneFileFormatVersion::LateAlpha) { uint8_t sceneCount; BinaryIO::BinaryRead(file, sceneCount); m_SceneCount = sceneCount; - } - else BinaryIO::BinaryRead(file, m_SceneCount); + } else BinaryIO::BinaryRead(file, m_SceneCount); for (uint32_t i = 0; i < m_SceneCount; ++i) { LoadScene(file); @@ -93,16 +102,13 @@ void Zone::LoadZoneIntoMemory() { if (m_ZoneFileFormatVersion >= Zone::ZoneFileFormatVersion::EarlyAlpha) { BinaryIO::BinaryRead(file, m_PathDataLength); - uint32_t unknown; - uint32_t pathCount; + BinaryIO::BinaryRead(file, m_PathChunkVersion); // always should be 1 - BinaryIO::BinaryRead(file, unknown); + uint32_t pathCount; BinaryIO::BinaryRead(file, pathCount); - for (uint32_t i = 0; i < pathCount; ++i) { - LoadPath(file); - } - + for (uint32_t i = 0; i < pathCount; ++i) LoadPath(file); + for (Path path : m_Paths) { if (path.pathType == PathType::Spawner) { SpawnerInfo info = SpawnerInfo(); @@ -117,23 +123,18 @@ void Zone::LoadZoneIntoMemory() { if (data) { if (data->GetKey() == u"spawner_node_id") { node->nodeID = std::stoi(data->GetValueAsString()); - } - else if (data->GetKey() == u"spawner_max_per_node") { + } else if (data->GetKey() == u"spawner_max_per_node") { node->nodeMax = std::stoi(data->GetValueAsString()); - } - else if (data->GetKey() == u"groupID") { // Load object group + } else if (data->GetKey() == u"groupID") { // Load object group std::string groupStr = data->GetValueAsString(); info.groups = GeneralUtils::SplitString(groupStr, ';'); info.groups.erase(info.groups.end() - 1); - } - else if (data->GetKey() == u"grpNameQBShowBricks") { + } else if (data->GetKey() == u"grpNameQBShowBricks") { if (data->GetValueAsString() == "") continue; /*std::string groupStr = data->GetValueAsString(); info.groups.push_back(groupStr);*/ info.grpNameQBShowBricks = data->GetValueAsString(); - } - else if (data->GetKey() == u"spawner_name") - { + } else if (data->GetKey() == u"spawner_name") { info.name = data->GetValueAsString(); } } @@ -150,29 +151,24 @@ void Zone::LoadZoneIntoMemory() { Spawner* spawner = new Spawner(info); dZoneManager::Instance()->AddSpawner(info.spawnerID, spawner); } - - } - - //m_PathData.resize(m_PathDataLength); - //file.read((char*)&m_PathData[0], m_PathDataLength); + } } - } - else { - Game::logger->Log("Zone", "Failed to open: %s\n", m_ZoneFilePath.c_str()); + } else { + Game::logger->Log("Zone", "Failed to open: %s", m_ZoneFilePath.c_str()); } m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1); - file.close(); + buffer.close(); } std::string Zone::GetFilePathForZoneID() { //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable * zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); const CDZoneTable* zone = zoneTable->Query(this->GetZoneID().GetMapID()); if (zone != nullptr) { - std::string toReturn = "./res/maps/" + zone->zoneName; - std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower); + std::string toReturn = "maps/" + zone->zoneName; + std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower); return toReturn; } @@ -226,12 +222,12 @@ void Zone::AddRevision(LWOSCENEID sceneID, uint32_t revision) { const void Zone::PrintAllGameObjects() { for (std::pair<LWOSCENEID, SceneRef> scene : m_Scenes) { - Game::logger->Log("Zone", "\nIn sceneID: %i\n\n", scene.first.GetSceneID()); + Game::logger->Log("Zone", "In sceneID: %i", scene.first.GetSceneID()); scene.second.level->PrintAllObjects(); } } -void Zone::LoadScene(std::ifstream & file) { +void Zone::LoadScene(std::istream& file) { SceneRef scene; scene.level = nullptr; LWOSCENEID lwoSceneID(LWOZONEID_INVALID, 0); @@ -241,8 +237,9 @@ void Zone::LoadScene(std::ifstream & file) { scene.filename = BinaryIO::ReadString(file, sceneFilenameLength); std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers"; - std::vector<LUTriggers::Trigger*> triggers = LoadLUTriggers(luTriggersPath, scene.id); - + std::vector<LUTriggers::Trigger*> triggers; + if(Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) triggers = LoadLUTriggers(luTriggersPath, scene.id); + for (LUTriggers::Trigger* trigger : triggers) { scene.triggers.insert({ trigger->id, trigger }); } @@ -256,15 +253,6 @@ void Zone::LoadScene(std::ifstream & file) { scene.name = BinaryIO::ReadString(file, sceneNameLength); file.ignore(3); - /* - if (m_Scenes.find(scene.id) != m_Scenes.end()) { - //Extract the layer id from the filename (bad I know, but it's reliable at least): - std::string layer = scene.filename.substr(scene.filename.rfind('x') + 1); - layer = layer.substr(0, layer.find('_')); - lwoSceneID.SetLayerID(std::atoi(layer.c_str())); - } - */ - lwoSceneID.SetLayerID(scene.sceneType); m_Scenes.insert(std::make_pair(lwoSceneID, scene)); @@ -273,40 +261,49 @@ void Zone::LoadScene(std::ifstream & file) { std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, LWOSCENEID sceneID) { std::vector<LUTriggers::Trigger*> lvlTriggers; - std::ifstream file(m_ZonePath + triggerFile); + + auto buffer = Game::assetManager->GetFileAsBuffer((m_ZonePath + triggerFile).c_str()); + + if (!buffer.m_Success) { + Game::logger->Log("Zone", "Failed to load %s from disk. Skipping loading triggers", (m_ZonePath + triggerFile).c_str()); + return lvlTriggers; + } + + std::istream file(&buffer); std::stringstream data; data << file.rdbuf(); + buffer.close(); + if (data.str().size() == 0) return lvlTriggers; tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(); if (!doc) return lvlTriggers; if (doc->Parse(data.str().c_str(), data.str().size()) == 0) { - //Game::logger->Log("Zone", "Loaded LUTriggers from file %s!\n", triggerFile.c_str()); - } - else { - Game::logger->Log("Zone", "Failed to load LUTriggers from file %s\n", triggerFile.c_str()); + //Game::logger->Log("Zone", "Loaded LUTriggers from file %s!", triggerFile.c_str()); + } else { + Game::logger->Log("Zone", "Failed to load LUTriggers from file %s", triggerFile.c_str()); return lvlTriggers; } - + tinyxml2::XMLElement* triggers = doc->FirstChildElement("triggers"); if (!triggers) return lvlTriggers; auto currentTrigger = triggers->FirstChildElement("trigger"); while (currentTrigger) { - LUTriggers::Trigger *newTrigger = new LUTriggers::Trigger(); + LUTriggers::Trigger* newTrigger = new LUTriggers::Trigger(); currentTrigger->QueryAttribute("enabled", &newTrigger->enabled); currentTrigger->QueryAttribute("id", &newTrigger->id); auto currentEvent = currentTrigger->FirstChildElement("event"); while (currentEvent) { LUTriggers::Event* newEvent = new LUTriggers::Event(); - newEvent->eventID = currentEvent->Attribute("id"); + newEvent->id = TriggerEventType::StringToTriggerEventType(currentEvent->Attribute("id")); auto currentCommand = currentEvent->FirstChildElement("command"); while (currentCommand) { LUTriggers::Command* newCommand = new LUTriggers::Command(); - newCommand->id = currentCommand->Attribute("id"); + newCommand->id = TriggerCommandType::StringToTriggerCommandType(currentCommand->Attribute("id")); newCommand->target = currentCommand->Attribute("target"); if (currentCommand->Attribute("targetName") != NULL) { newCommand->targetName = currentCommand->Attribute("targetName"); @@ -323,7 +320,7 @@ std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, currentTrigger = currentTrigger->NextSiblingElement("trigger"); lvlTriggers.push_back(newTrigger); } - + delete doc; return lvlTriggers; @@ -336,12 +333,9 @@ LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) { return m_Scenes[sceneID].triggers[triggerID]; } -const Path* Zone::GetPath(std::string name) const -{ - for (const auto& path : m_Paths) - { - if (name == path.pathName) - { +const Path* Zone::GetPath(std::string name) const { + for (const auto& path : m_Paths) { + if (name == path.pathName) { return &path; } } @@ -349,12 +343,13 @@ const Path* Zone::GetPath(std::string name) const return nullptr; } -void Zone::LoadSceneTransition(std::ifstream & file) { +void Zone::LoadSceneTransition(std::istream& file) { SceneTransition sceneTrans; - if (m_ZoneFileFormatVersion < Zone::ZoneFileFormatVersion::LateAlpha) { + if (m_ZoneFileFormatVersion < Zone::ZoneFileFormatVersion::Auramar) { uint8_t length; BinaryIO::BinaryRead(file, length); sceneTrans.name = BinaryIO::ReadString(file, length); + file.ignore(4); } //BR�THER MAY I HAVE SOME L��PS? @@ -367,22 +362,18 @@ void Zone::LoadSceneTransition(std::ifstream & file) { m_SceneTransitions.push_back(sceneTrans); } -SceneTransitionInfo Zone::LoadSceneTransitionInfo(std::ifstream & file) { +SceneTransitionInfo Zone::LoadSceneTransitionInfo(std::istream& file) { SceneTransitionInfo info; BinaryIO::BinaryRead(file, info.sceneID); BinaryIO::BinaryRead(file, info.position); return info; } -void Zone::LoadPath(std::ifstream & file) { - // Currently only spawner (type 4) paths are supported +void Zone::LoadPath(std::istream& file) { Path path = Path(); - uint32_t unknown1; - uint32_t pathType; - uint32_t pathBehavior; - BinaryIO::BinaryRead(file, path.pathVersion); + uint8_t stringLength; BinaryIO::BinaryRead(file, stringLength); for (uint8_t i = 0; i < stringLength; ++i) { @@ -390,18 +381,15 @@ void Zone::LoadPath(std::ifstream & file) { BinaryIO::BinaryRead(file, character); path.pathName.push_back(character); } - BinaryIO::BinaryRead(file, pathType); - path.pathType = PathType(pathType); - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, pathBehavior); - path.pathType = PathType(pathType); + + BinaryIO::BinaryRead(file, path.pathType); + BinaryIO::BinaryRead(file, path.flags); + BinaryIO::BinaryRead(file, path.pathBehavior); if (path.pathType == PathType::MovingPlatform) { if (path.pathVersion >= 18) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); - } - else if (path.pathVersion >= 13) { + BinaryIO::BinaryRead(file, path.movingPlatform.timeBasedMovement); + } else if (path.pathVersion >= 13) { uint8_t count; BinaryIO::BinaryRead(file, count); for (uint8_t i = 0; i < count; ++i) { @@ -410,39 +398,45 @@ void Zone::LoadPath(std::ifstream & file) { path.movingPlatform.platformTravelSound.push_back(character); } } - } - else if (path.pathType == PathType::Property) { - int32_t unknown; - BinaryIO::BinaryRead(file, unknown); + } else if (path.pathType == PathType::Property) { + BinaryIO::BinaryRead(file, path.property.pathType); BinaryIO::BinaryRead(file, path.property.price); - BinaryIO::BinaryRead(file, path.property.rentalTime); - BinaryIO::BinaryRead(file, path.property.associatedZone); - uint8_t count1; - BinaryIO::BinaryRead(file, count1); - for (uint8_t i = 0; i < count1; ++i) { - uint16_t character; - BinaryIO::BinaryRead(file, character); - path.property.displayName.push_back(character); - } - uint32_t count2; - BinaryIO::BinaryRead(file, count2); - for (uint8_t i = 0; i < count2; ++i) { - uint16_t character; - BinaryIO::BinaryRead(file, character); - path.property.displayDesc.push_back(character); - } - int32_t unknown1; - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, path.property.cloneLimit); - BinaryIO::BinaryRead(file, path.property.repMultiplier); BinaryIO::BinaryRead(file, path.property.rentalTimeUnit); - BinaryIO::BinaryRead(file, path.property.achievementRequired); - BinaryIO::BinaryRead(file, path.property.playerZoneCoords.x); - BinaryIO::BinaryRead(file, path.property.playerZoneCoords.y); - BinaryIO::BinaryRead(file, path.property.playerZoneCoords.z); - BinaryIO::BinaryRead(file, path.property.maxBuildHeight); - } - else if (path.pathType == PathType::Camera) { + BinaryIO::BinaryRead(file, path.property.associatedZone); + + if (path.pathVersion >= 5) { + uint8_t count1; + BinaryIO::BinaryRead(file, count1); + for (uint8_t i = 0; i < count1; ++i) { + uint16_t character; + BinaryIO::BinaryRead(file, character); + path.property.displayName.push_back(character); + } + uint32_t count2; + BinaryIO::BinaryRead(file, count2); + for (uint8_t i = 0; i < count2; ++i) { + uint16_t character; + BinaryIO::BinaryRead(file, character); + path.property.displayDesc.push_back(character); + } + } + + if (path.pathVersion >= 6) BinaryIO::BinaryRead(file, path.property.type); + + if (path.pathVersion >= 7) { + BinaryIO::BinaryRead(file, path.property.cloneLimit); + BinaryIO::BinaryRead(file, path.property.repMultiplier); + BinaryIO::BinaryRead(file, path.property.rentalTimeUnit); + } + + if (path.pathVersion >= 8) { + BinaryIO::BinaryRead(file, path.property.achievementRequired); + BinaryIO::BinaryRead(file, path.property.playerZoneCoords.x); + BinaryIO::BinaryRead(file, path.property.playerZoneCoords.y); + BinaryIO::BinaryRead(file, path.property.playerZoneCoords.z); + BinaryIO::BinaryRead(file, path.property.maxBuildHeight); + } + } else if (path.pathType == PathType::Camera) { uint8_t count; BinaryIO::BinaryRead(file, count); for (uint8_t i = 0; i < count; ++i) { @@ -451,11 +445,10 @@ void Zone::LoadPath(std::ifstream & file) { path.camera.nextPath.push_back(character); } if (path.pathVersion >= 14) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, path.camera.rotatePlayer); + } } else if (path.pathType == PathType::Spawner) { - //SpawnerPath* path = static_cast<SpawnerPath*>(path); // Convert to a spawner path BinaryIO::BinaryRead(file, path.spawner.spawnedLOT); BinaryIO::BinaryRead(file, path.spawner.respawnTime); BinaryIO::BinaryRead(file, path.spawner.maxToSpawn); @@ -474,9 +467,9 @@ void Zone::LoadPath(std::ifstream & file) { BinaryIO::BinaryRead(file, waypoint.position.x); BinaryIO::BinaryRead(file, waypoint.position.y); BinaryIO::BinaryRead(file, waypoint.position.z); - - - if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race) { + + + if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race || path.pathType == PathType::Camera || path.pathType == PathType::Rail) { BinaryIO::BinaryRead(file, waypoint.rotation.w); BinaryIO::BinaryRead(file, waypoint.rotation.x); BinaryIO::BinaryRead(file, waypoint.rotation.y); @@ -503,37 +496,20 @@ void Zone::LoadPath(std::ifstream & file) { waypoint.movingPlatform.arriveSound.push_back(character); } } - } - else if (path.pathType == PathType::Camera) { - float unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); + } else if (path.pathType == PathType::Camera) { BinaryIO::BinaryRead(file, waypoint.camera.time); - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, waypoint.camera.fov); BinaryIO::BinaryRead(file, waypoint.camera.tension); BinaryIO::BinaryRead(file, waypoint.camera.continuity); BinaryIO::BinaryRead(file, waypoint.camera.bias); - } - else if (path.pathType == PathType::Race) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - float unknown1; - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, unknown1); - } - else if (path.pathType == PathType::Rail) { - float unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - if (path.pathVersion >= 17) { - BinaryIO::BinaryRead(file, unknown); - } + } else if (path.pathType == PathType::Race) { + BinaryIO::BinaryRead(file, waypoint.racing.isResetNode); + BinaryIO::BinaryRead(file, waypoint.racing.isNonHorizontalCamera); + BinaryIO::BinaryRead(file, waypoint.racing.planeWidth); + BinaryIO::BinaryRead(file, waypoint.racing.planeHeight); + BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd); + } else if (path.pathType == PathType::Rail) { + if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.rail.speed); } // object LDF configs @@ -557,15 +533,21 @@ void Zone::LoadPath(std::ifstream & file) { BinaryIO::BinaryRead(file, character); value.push_back(character); } - LDFBaseData* ldfConfig = LDFBaseData::DataFromString(parameter + "=" + value); - waypoint.config.push_back(ldfConfig); + + LDFBaseData* ldfConfig = nullptr; + if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) { + ldfConfig = LDFBaseData::DataFromString(parameter + "=0:" + value); + } else { + ldfConfig = LDFBaseData::DataFromString(parameter + "=" + value); + } + if (ldfConfig) waypoint.config.push_back(ldfConfig); } } path.pathWaypoints.push_back(waypoint); } - + m_Paths.push_back(path); } diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index 0d30415d..9c5322a1 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -1,35 +1,18 @@ #pragma once + #include "dZMCommon.h" #include "LDFFormat.h" -#include "../thirdparty/tinyxml2/tinyxml2.h" +#include "tinyxml2.h" #include <string> #include <vector> #include <map> -class Level; - -class LUTriggers { - public: - - struct Command { - std::string id; - std::string target; - std::string targetName; - std::string args; - }; - - struct Event { - std::string eventID; - std::vector<Command*> commands; - }; - - struct Trigger { - uint32_t id; - bool enabled; - std::vector<Event*> events; - }; +namespace LUTriggers { + struct Trigger; }; +class Level; + struct SceneRef { std::string filename; uint32_t id; @@ -59,16 +42,31 @@ struct MovingPlatformPathWaypoint { struct CameraPathWaypoint { float time; + float fov; float tension; float continuity; float bias; }; +struct RacingPathWaypoint { + uint8_t isResetNode; + uint8_t isNonHorizontalCamera; + float planeWidth; + float planeHeight; + float shortestDistanceToEnd; +}; + +struct RailPathWaypoint { + float speed; +}; + struct PathWaypoint { NiPoint3 position; NiQuaternion rotation; // not included in all, but it's more convenient here MovingPlatformPathWaypoint movingPlatform; CameraPathWaypoint camera; + RacingPathWaypoint racing; + RailPathWaypoint rail; std::vector<LDFBaseData*> config; }; @@ -89,7 +87,20 @@ enum class PathBehavior : uint32_t { Once = 2 }; -enum class PropertyRentalTimeUnit : int32_t{ +enum class PropertyPathType : int32_t { + Path = 0, + EntireZone = 1, + GenetatedRectangle = 2 +}; + +enum class PropertyType : int32_t { + Premiere = 0, + Prize = 1, + LUP = 2, + Headspace = 3 +}; + +enum class PropertyRentalTimeUnit : int32_t { Forever = 0, Seconds = 1, Minutes = 2, @@ -116,17 +127,19 @@ enum class PropertyAchievmentRequired : int32_t { struct MovingPlatformPath { std::string platformTravelSound; + uint8_t timeBasedMovement; }; struct PropertyPath { + PropertyPathType pathType; int32_t price; - int32_t rentalTime; + PropertyRentalTimeUnit rentalTimeUnit; uint64_t associatedZone; std::string displayName; std::string displayDesc; + PropertyType type; int32_t cloneLimit; float repMultiplier; - PropertyRentalTimeUnit rentalTimeUnit; PropertyAchievmentRequired achievementRequired; NiPoint3 playerZoneCoords; float maxBuildHeight; @@ -134,6 +147,7 @@ struct PropertyPath { struct CameraPath { std::string nextPath; + uint8_t rotatePlayer; }; struct SpawnerPath { @@ -150,6 +164,7 @@ struct Path { uint32_t pathVersion; PathType pathType; std::string pathName; + uint32_t flags; PathBehavior pathBehavior; uint32_t waypointCount; std::vector<PathWaypoint> pathWaypoints; @@ -190,6 +205,8 @@ public: uint32_t GetWorldID() const { return m_WorldID; } [[nodiscard]] std::string GetZoneName() const { return m_ZoneName; } + std::string GetZoneRawPath() const { return m_ZoneRawPath; } + std::string GetZonePath() const { return m_ZonePath; } const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; } const NiQuaternion& GetSpawnRot() const { return m_SpawnpointRotation; } @@ -217,15 +234,17 @@ private: std::map<LWOSCENEID, SceneRef, mapCompareLwoSceneIDs> m_Scenes; std::vector<SceneTransition> m_SceneTransitions; + uint32_t m_PathDataLength; - //std::vector<char> m_PathData; //Binary path data + uint32_t m_PathChunkVersion; std::vector<Path> m_Paths; + std::map<LWOSCENEID, uint32_t, mapCompareLwoSceneIDs> m_MapRevisions; //rhs is the revision! //private ("helper") functions: - void LoadScene(std::ifstream& file); + void LoadScene(std::istream& file); std::vector<LUTriggers::Trigger*> LoadLUTriggers(std::string triggerFile, LWOSCENEID sceneID); - void LoadSceneTransition(std::ifstream& file); - SceneTransitionInfo LoadSceneTransitionInfo(std::ifstream& file); - void LoadPath(std::ifstream& file); + void LoadSceneTransition(std::istream& file); + SceneTransitionInfo LoadSceneTransitionInfo(std::istream& file); + void LoadPath(std::istream& file); }; diff --git a/dZoneManager/dZMCommon.h b/dZoneManager/dZMCommon.h index 6ee23a61..635faaae 100644 --- a/dZoneManager/dZMCommon.h +++ b/dZoneManager/dZMCommon.h @@ -19,8 +19,8 @@ struct SceneObject { float scale = 1.0f; //std::string settings; uint32_t value3; - std::vector<LDFBaseData*> settings; + std::vector<LDFBaseData*> settings; }; #define LOT_MARKER_PLAYER_START 1931 -#define LOT_MARKET_CAMERA_TARGET 2182 \ No newline at end of file +#define LOT_MARKET_CAMERA_TARGET 2182 diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index 12215378..a26e912f 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -8,26 +8,31 @@ #include "DestroyableComponent.h" #include "GameMessages.h" #include "VanityUtilities.h" +#include "WorldConfig.h" +#include "CDZoneTableTable.h" #include <chrono> +#include "eObjectBits.h" +#include "CDZoneTableTable.h" +#include "AssetManager.h" #include "../dWorldServer/ObjectIDManager.h" dZoneManager* dZoneManager::m_Address = nullptr; void dZoneManager::Initialize(const LWOZONEID& zoneID) { - Game::logger->Log("dZoneManager", "Preparing zone: %i/%i/%i\n", zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID()); + Game::logger->Log("dZoneManager", "Preparing zone: %i/%i/%i", zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID()); - int64_t startTime = 0; - int64_t endTime = 0; + int64_t startTime = 0; + int64_t endTime = 0; - startTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); + startTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); - LoadZone(zoneID); + LoadZone(zoneID); LOT zoneControlTemplate = 2365; - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); - if (zoneTable != nullptr){ + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); + if (zoneTable != nullptr) { const CDZoneTable* zone = zoneTable->Query(zoneID.GetMapID()); if (zone != nullptr) { @@ -37,10 +42,10 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { EntityManager::Instance()->SetGhostDistanceMax(max + min); EntityManager::Instance()->SetGhostDistanceMin(max); m_PlayerLoseCoinsOnDeath = zone->PlayerLoseCoinsOnDeath; - } + } } - Game::logger->Log("dZoneManager", "Creating zone control object %i\n", zoneControlTemplate); + Game::logger->Log("dZoneManager", "Creating zone control object %i", zoneControlTemplate); // Create ZoneControl object EntityInfo info; @@ -51,9 +56,11 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { m_pZone->Initalize(); - endTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); + endTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); - Game::logger->Log("dZoneManager", "Zone prepared in: %llu ms\n", (endTime - startTime)); + LoadWorldConfig(); + + Game::logger->Log("dZoneManager", "Zone prepared in: %llu ms", (endTime - startTime)); VanityUtilities::SpawnVanity(); } @@ -61,17 +68,18 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { dZoneManager::~dZoneManager() { if (m_pZone) delete m_pZone; - for (std::pair<LWOOBJID, Spawner*> p : m_Spawners) { - if (p.second) { - delete p.second; - p.second = nullptr; - } + for (std::pair<LWOOBJID, Spawner*> p : m_Spawners) { + if (p.second) { + delete p.second; + p.second = nullptr; + } - m_Spawners.erase(p.first); - } + m_Spawners.erase(p.first); + } + if (m_WorldConfig) delete m_WorldConfig; } -Zone * dZoneManager::GetZone() { +Zone* dZoneManager::GetZone() { return m_pZone; } @@ -82,14 +90,14 @@ void dZoneManager::LoadZone(const LWOZONEID& zoneID) { m_pZone = new Zone(zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID()); } -void dZoneManager::NotifyZone(const dZoneNotifier & notifier, const LWOOBJID& objectID) { +void dZoneManager::NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID) { switch (notifier) { case dZoneNotifier::SpawnedObjectDestroyed: break; case dZoneNotifier::SpawnedChildObjectDestroyed: break; case dZoneNotifier::ReloadZone: - Game::logger->Log("dZoneManager", "Forcing reload of zone %i\n", m_ZoneID.GetMapID()); + Game::logger->Log("dZoneManager", "Forcing reload of zone %i", m_ZoneID.GetMapID()); LoadZone(m_ZoneID); m_pZone->Initalize(); @@ -102,56 +110,33 @@ void dZoneManager::NotifyZone(const dZoneNotifier & notifier, const LWOOBJID& ob m_pZone->PrintAllGameObjects(); break; case dZoneNotifier::InvalidNotifier: - Game::logger->Log("dZoneManager", "Got an invalid zone notifier.\n"); + Game::logger->Log("dZoneManager", "Got an invalid zone notifier."); break; default: - Game::logger->Log("dZoneManager", "Unknown zone notifier: %i\n", int(notifier)); + Game::logger->Log("dZoneManager", "Unknown zone notifier: %i", int(notifier)); } } -void dZoneManager::AddSpawner(LWOOBJID id, Spawner* spawner) -{ +void dZoneManager::AddSpawner(LWOOBJID id, Spawner* spawner) { m_Spawners.insert_or_assign(id, spawner); } -LWOZONEID dZoneManager::GetZoneID() const -{ +LWOZONEID dZoneManager::GetZoneID() const { return m_ZoneID; } -uint32_t dZoneManager::GetMaxLevel() { - if (m_MaxLevel == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCap FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_MaxLevel = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_MaxLevel; -} - -int32_t dZoneManager::GetLevelCapCurrencyConversion() { - if (m_CurrencyConversionRate == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCapCurrencyConversion FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_CurrencyConversionRate = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_CurrencyConversionRate; -} - void dZoneManager::Update(float deltaTime) { for (auto spawner : m_Spawners) { spawner.second->Update(deltaTime); } } -LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) -{ +LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) { auto objectId = info.spawnerID; - if (objectId == LWOOBJID_EMPTY) - { + if (objectId == LWOOBJID_EMPTY) { objectId = ObjectIDManager::Instance()->GenerateObjectID(); - - objectId = GeneralUtils::SetBit(objectId, OBJECT_BIT_CLIENT); + GeneralUtils::SetBit(objectId, eObjectBits::CLIENT); info.spawnerID = objectId; } @@ -172,8 +157,7 @@ LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) return objectId; } -Spawner* dZoneManager::GetSpawner(const LWOOBJID id) -{ +Spawner* dZoneManager::GetSpawner(const LWOOBJID id) { const auto& index = m_Spawners.find(id); if (index == m_Spawners.end()) { @@ -183,12 +167,11 @@ Spawner* dZoneManager::GetSpawner(const LWOOBJID id) return index->second; } -void dZoneManager::RemoveSpawner(const LWOOBJID id) -{ +void dZoneManager::RemoveSpawner(const LWOOBJID id) { auto* spawner = GetSpawner(id); if (spawner == nullptr) { - Game::logger->Log("dZoneManager", "Failed to find spawner (%llu)\n", id); + Game::logger->Log("dZoneManager", "Failed to find spawner (%llu)", id); return; } @@ -196,29 +179,16 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) if (entity != nullptr) { entity->Kill(); - } - else { + } else { - Game::logger->Log("dZoneManager", "Failed to find spawner entity (%llu)\n", id); + Game::logger->Log("dZoneManager", "Failed to find spawner entity (%llu)", id); } - for (auto* node : spawner->m_Info.nodes) - { - for (const auto& element : node->entities) - { - auto* nodeEntity = EntityManager::Instance()->GetEntity(element); - - if (nodeEntity == nullptr) continue; - - nodeEntity->Kill(); - } - - node->entities.clear(); - } + spawner->DestroyAllEntities(); spawner->Deactivate(); - Game::logger->Log("dZoneManager", "Destroying spawner (%llu)\n", id); + Game::logger->Log("dZoneManager", "Destroying spawner (%llu)", id); m_Spawners.erase(id); @@ -249,3 +219,97 @@ std::vector<Spawner*> dZoneManager::GetSpawnersInGroup(std::string group) { return spawnersInGroup; } + +uint32_t dZoneManager::GetUniqueMissionIdStartingValue() { + if (m_UniqueMissionIdStart == 0) { + auto tableData = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Missions WHERE isMission = 0 GROUP BY isMission;"); + m_UniqueMissionIdStart = tableData.getIntField(0, -1); + tableData.finalize(); + } + return m_UniqueMissionIdStart; +} + +bool dZoneManager::CheckIfAccessibleZone(LWOMAPID zoneID) { + //We're gonna go ahead and presume we've got the db loaded already: + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); + const CDZoneTable* zone = zoneTable->Query(zoneID); + if (zone != nullptr) { + return Game::assetManager->HasFile(("maps/" + zone->zoneName).c_str()); + } else { + return false; + } +} + +void dZoneManager::LoadWorldConfig() { + Game::logger->Log("dZoneManager", "Loading WorldConfig into memory"); + + auto worldConfig = CDClientDatabase::ExecuteQuery("SELECT * FROM WorldConfig;"); + + if (!m_WorldConfig) m_WorldConfig = new WorldConfig(); + + if (worldConfig.eof()) { + Game::logger->Log("dZoneManager", "WorldConfig table is empty. Is this intended?"); + return; + } + + // Now read in the giant table + m_WorldConfig->worldConfigID = worldConfig.getIntField("WorldConfigID"); + m_WorldConfig->peGravityValue = worldConfig.getFloatField("pegravityvalue"); + m_WorldConfig->peBroadphaseWorldSize = worldConfig.getFloatField("pebroadphaseworldsize"); + m_WorldConfig->peGameObjScaleFactor = worldConfig.getFloatField("pegameobjscalefactor"); + m_WorldConfig->characterRotationSpeed = worldConfig.getFloatField("character_rotation_speed"); + m_WorldConfig->characterWalkForwardSpeed = worldConfig.getFloatField("character_walk_forward_speed"); + m_WorldConfig->characterWalkBackwardSpeed = worldConfig.getFloatField("character_walk_backward_speed"); + m_WorldConfig->characterWalkStrafeSpeed = worldConfig.getFloatField("character_walk_strafe_speed"); + m_WorldConfig->characterWalkStrafeForwardSpeed = worldConfig.getFloatField("character_walk_strafe_forward_speed"); + m_WorldConfig->characterWalkStrafeBackwardSpeed = worldConfig.getFloatField("character_walk_strafe_backward_speed"); + m_WorldConfig->characterRunBackwardSpeed = worldConfig.getFloatField("character_run_backward_speed"); + m_WorldConfig->characterRunStrafeSpeed = worldConfig.getFloatField("character_run_strafe_speed"); + m_WorldConfig->characterRunStrafeForwardSpeed = worldConfig.getFloatField("character_run_strafe_forward_speed"); + m_WorldConfig->characterRunStrafeBackwardSpeed = worldConfig.getFloatField("character_run_strafe_backward_speed"); + m_WorldConfig->globalCooldown = worldConfig.getFloatField("global_cooldown"); + m_WorldConfig->characterGroundedTime = worldConfig.getFloatField("characterGroundedTime"); + m_WorldConfig->characterGroundedSpeed = worldConfig.getFloatField("characterGroundedSpeed"); + m_WorldConfig->globalImmunityTime = worldConfig.getFloatField("globalImmunityTime"); + m_WorldConfig->characterMaxSlope = worldConfig.getFloatField("character_max_slope"); + m_WorldConfig->defaultRespawnTime = worldConfig.getFloatField("defaultrespawntime"); + m_WorldConfig->missionTooltipTimeout = worldConfig.getFloatField("mission_tooltip_timeout"); + m_WorldConfig->vendorBuyMultiplier = worldConfig.getFloatField("vendor_buy_multiplier"); + m_WorldConfig->petFollowRadius = worldConfig.getFloatField("pet_follow_radius"); + m_WorldConfig->characterEyeHeight = worldConfig.getFloatField("character_eye_height"); + m_WorldConfig->flightVerticalVelocity = worldConfig.getFloatField("flight_vertical_velocity"); + m_WorldConfig->flightAirspeed = worldConfig.getFloatField("flight_airspeed"); + m_WorldConfig->flightFuelRatio = worldConfig.getFloatField("flight_fuel_ratio"); + m_WorldConfig->flightMaxAirspeed = worldConfig.getFloatField("flight_max_airspeed"); + m_WorldConfig->fReputationPerVote = worldConfig.getFloatField("fReputationPerVote"); + m_WorldConfig->propertyCloneLimit = worldConfig.getIntField("nPropertyCloneLimit"); + m_WorldConfig->defaultHomespaceTemplate = worldConfig.getIntField("defaultHomespaceTemplate"); + m_WorldConfig->coinsLostOnDeathPercent = worldConfig.getFloatField("coins_lost_on_death_percent"); + m_WorldConfig->coinsLostOnDeathMin = worldConfig.getIntField("coins_lost_on_death_min"); + m_WorldConfig->coinsLostOnDeathMax = worldConfig.getIntField("coins_lost_on_death_max"); + m_WorldConfig->characterVotesPerDay = worldConfig.getIntField("character_votes_per_day"); + m_WorldConfig->propertyModerationRequestApprovalCost = worldConfig.getIntField("property_moderation_request_approval_cost"); + m_WorldConfig->propertyModerationRequestReviewCost = worldConfig.getIntField("property_moderation_request_review_cost"); + m_WorldConfig->propertyModRequestsAllowedSpike = worldConfig.getIntField("propertyModRequestsAllowedSpike"); + m_WorldConfig->propertyModRequestsAllowedInterval = worldConfig.getIntField("propertyModRequestsAllowedInterval"); + m_WorldConfig->propertyModRequestsAllowedTotal = worldConfig.getIntField("propertyModRequestsAllowedTotal"); + m_WorldConfig->propertyModRequestsSpikeDuration = worldConfig.getIntField("propertyModRequestsSpikeDuration"); + m_WorldConfig->propertyModRequestsIntervalDuration = worldConfig.getIntField("propertyModRequestsIntervalDuration"); + m_WorldConfig->modelModerateOnCreate = worldConfig.getIntField("modelModerateOnCreate") != 0; + m_WorldConfig->defaultPropertyMaxHeight = worldConfig.getFloatField("defaultPropertyMaxHeight"); + m_WorldConfig->reputationPerVoteCast = worldConfig.getFloatField("reputationPerVoteCast"); + m_WorldConfig->reputationPerVoteReceived = worldConfig.getFloatField("reputationPerVoteReceived"); + m_WorldConfig->showcaseTopModelConsiderationBattles = worldConfig.getIntField("showcaseTopModelConsiderationBattles"); + m_WorldConfig->reputationPerBattlePromotion = worldConfig.getFloatField("reputationPerBattlePromotion"); + m_WorldConfig->coinsLostOnDeathMinTimeout = worldConfig.getFloatField("coins_lost_on_death_min_timeout"); + m_WorldConfig->coinsLostOnDeathMaxTimeout = worldConfig.getFloatField("coins_lost_on_death_max_timeout"); + m_WorldConfig->mailBaseFee = worldConfig.getIntField("mail_base_fee"); + m_WorldConfig->mailPercentAttachmentFee = worldConfig.getFloatField("mail_percent_attachment_fee"); + m_WorldConfig->propertyReputationDelay = worldConfig.getIntField("propertyReputationDelay"); + m_WorldConfig->levelCap = worldConfig.getIntField("LevelCap"); + m_WorldConfig->levelUpBehaviorEffect = worldConfig.getStringField("LevelUpBehaviorEffect"); + m_WorldConfig->characterVersion = worldConfig.getIntField("CharacterVersion"); + m_WorldConfig->levelCapCurrencyConversion = worldConfig.getIntField("LevelCapCurrencyConversion"); + worldConfig.finalize(); + Game::logger->Log("dZoneManager", "Loaded WorldConfig into memory"); +} diff --git a/dZoneManager/dZoneManager.h b/dZoneManager/dZoneManager.h index 3171c81f..3086e6d7 100644 --- a/dZoneManager/dZoneManager.h +++ b/dZoneManager/dZoneManager.h @@ -4,6 +4,8 @@ #include "Spawner.h" #include <map> +class WorldConfig; + class dZoneManager { public: enum class dZoneNotifier { @@ -16,15 +18,21 @@ public: InvalidNotifier }; +private: + /** + * Reads the WorldConfig from the CDClientDatabase into memory + */ + void LoadWorldConfig(); + public: - static dZoneManager* Instance() { + static dZoneManager* Instance() { if (!m_Address) { m_Address = new dZoneManager(); } - + return m_Address; } - + void Initialize(const LWOZONEID& zoneID); ~dZoneManager(); @@ -33,8 +41,6 @@ public: void NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID); //Notifies the zone of a certain event or command. void AddSpawner(LWOOBJID id, Spawner* spawner); LWOZONEID GetZoneID() const; - uint32_t GetMaxLevel(); - int32_t GetLevelCapCurrencyConversion(); LWOOBJID MakeSpawner(SpawnerInfo info); Spawner* GetSpawner(LWOOBJID id); void RemoveSpawner(LWOOBJID id); @@ -43,23 +49,27 @@ public: void Update(float deltaTime); Entity* GetZoneControlObject() { return m_ZoneControlObject; } bool GetPlayerLoseCoinOnDeath() { return m_PlayerLoseCoinsOnDeath; } + uint32_t GetUniqueMissionIdStartingValue(); + bool CheckIfAccessibleZone(LWOMAPID zoneID); + + // The world config should not be modified by a caller. + const WorldConfig* GetWorldConfig() { + if (!m_WorldConfig) LoadWorldConfig(); + return m_WorldConfig; + }; private: /** - * The maximum level of the world. + * The starting unique mission ID. */ - uint32_t m_MaxLevel = 0; + uint32_t m_UniqueMissionIdStart = 0; - /** - * The ratio of LEGO Score to currency when the character has hit the max level. - */ - int32_t m_CurrencyConversionRate = 0; - - static dZoneManager* m_Address; //Singleton - Zone* m_pZone; + static dZoneManager* m_Address; //Singleton + Zone* m_pZone = nullptr; LWOZONEID m_ZoneID; - bool m_PlayerLoseCoinsOnDeath; //Do players drop coins in this zone when smashed - std::map<LWOOBJID, Spawner*> m_Spawners; + bool m_PlayerLoseCoinsOnDeath; //Do players drop coins in this zone when smashed + std::map<LWOOBJID, Spawner*> m_Spawners; + WorldConfig* m_WorldConfig = nullptr; - Entity* m_ZoneControlObject; + Entity* m_ZoneControlObject = nullptr; }; diff --git a/docker/Dockerfile b/docker/Dockerfile index 27387e22..a7d91855 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \ echo "Install build dependencies" && \ apt update && \ apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \ - apt install cmake zlib1g zlib1g-dev unzip -yqq --no-install-recommends && \ + apt install cmake zlib1g zlib1g-dev -yqq --no-install-recommends && \ rm -rf /var/lib/apt/lists/* COPY dAuthServer/ /build/dAuthServer @@ -21,6 +21,7 @@ COPY dPhysics/ /build/dPhysics COPY dScripts/ /build/dScripts COPY dWorldServer/ /build/dWorldServer COPY dZoneManager/ /build/dZoneManager +COPY dNavigation/ /build/dNavigation COPY migrations/ /build/migrations COPY resources/ /build/resources COPY thirdparty/ /build/thirdparty @@ -34,12 +35,11 @@ ARG BUILD_VERSION=171022 RUN echo "Build server" && \ mkdir -p cmake_build && \ cd cmake_build && \ - sed -i -e "s/171022/${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/NET_VERSION=.*/NET_VERSION=${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/__maria_db_connector_compile_jobs__=.*/__maria_db_connector_compile_jobs__=${BUILD_THREADS}/g" ../CMakeVariables.txt && \ cmake .. -DCMAKE_BUILD_RPATH_USE_ORIGIN=TRUE && \ make -j $BUILD_THREADS -RUN unzip /build/resources/navmeshes.zip -d /build/cmake_build/res/maps - FROM gcc:11 as runtime RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \ diff --git a/docker/setup.Dockerfile b/docker/setup.Dockerfile index 2664e2fa..18bb2d06 100644 --- a/docker/setup.Dockerfile +++ b/docker/setup.Dockerfile @@ -1,23 +1,12 @@ -FROM rust:alpine3.14 as LUnpack - -WORKDIR /build_LUnpack - -COPY ./thirdparty/LUnpack . - -RUN apk add musl-dev --no-cache && cargo build --release - FROM python:3.10-alpine3.14 as prep -RUN apk add sqlite bash --no-cache +RUN apk add bash --no-cache WORKDIR /setup # copy needed files from repo COPY resources/ resources/ -COPY migrations/cdserver/ migrations/cdserver -COPY --from=LUnpack /build_LUnpack/target/release/lunpack /usr/local/bin/lunpack -ADD thirdparty/docker-utils/utils/*.py utils/ COPY docker/setup.sh /setup.sh -CMD [ "/setup.sh" ] \ No newline at end of file +CMD [ "/setup.sh" ] diff --git a/docker/setup.sh b/docker/setup.sh index 1a95f4de..ade67d2e 100755 --- a/docker/setup.sh +++ b/docker/setup.sh @@ -7,7 +7,7 @@ function update_ini() { FILE="/docker/configs/$1" KEY=$2 NEW_VALUE=$3 - sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $FILE + sed -i "s~$2=.*~$2=$3~" $FILE } function update_database_ini_values_for() { @@ -30,66 +30,13 @@ function update_ini_values() { cp resources/authconfig.ini /docker/configs/ cp resources/chatconfig.ini /docker/configs/ cp resources/worldconfig.ini /docker/configs/ - - update_ini worldconfig.ini chat_server_port $CHAT_SERVER_PORT - update_ini worldconfig.ini max_clients $MAX_CLIENTS + cp resources/sharedconfig.ini /docker/configs/ # always use the internal docker hostname update_ini masterconfig.ini master_ip "darkflame" + update_ini sharedconfig.ini client_location "/client" - update_database_ini_values_for masterconfig.ini - update_database_ini_values_for authconfig.ini - update_database_ini_values_for chatconfig.ini - update_database_ini_values_for worldconfig.ini -} - -function fdb_to_sqlite() { - echo "Run fdb_to_sqlite" - python3 utils/fdb_to_sqlite.py /client/client/res/cdclient.fdb --sqlite_path /client/client/res/CDServer.sqlite - - ( - cd migrations/cdserver - readarray -d '' entries < <(printf '%s\0' *.sql | sort -zV) - for entry in "${entries[@]}"; do - echo "Execute $entry" - sqlite3 /client/client/res/CDServer.sqlite < $entry - done - ) + update_database_ini_values_for sharedconfig.ini } update_ini_values - -if [[ ! -d "/client" ]]; then - echo "Client not found." - echo "Did you forget to mount the client into the \"/client\" directory?" - exit 1 -fi - -if [[ ! -f "/client/extracted" ]]; then - echo "Start client resource extraction" - - touch globs.txt - - echo "client/res/macros/**" >> globs.txt - echo "client/res/BrickModels/**" >> globs.txt - echo "client/res/maps/**" >> globs.txt - echo "*.fdb" >> globs.txt - - lunpack -g ./globs.txt /client/ - - touch /client/extracted -else - echo "Client already extracted. Skip this step..." - echo "If you want to force a re-extract, just delete the file called \"extracted\" in the client directory" -fi - -if [[ ! -f "/client/migrated" ]]; then - echo "Start client db migration" - - fdb_to_sqlite - - touch /client/migrated -else - echo "Client db already migrated. Skip this step..." - echo "If you want to force a re-migrate, just delete the file called \"migrated\" in the client directory" -fi diff --git a/docker/start_server.sh b/docker/start_server.sh index feb61361..2e2e8c28 100755 --- a/docker/start_server.sh +++ b/docker/start_server.sh @@ -1,23 +1,5 @@ #!/bin/bash -function symlink_client_files() { - echo "Creating symlinks for client files" - ln -s /client/client/res/macros/ /app/res/macros - ln -s /client/client/res/BrickModels/ /app/res/BrickModels - ln -s /client/client/res/chatplus_en_us.txt /app/res/chatplus_en_us.txt - ln -s /client/client/res/names/ /app/res/names - ln -s /client/client/res/CDServer.sqlite /app/res/CDServer.sqlite - ln -s /client/client/locale/locale.xml /app/locale/locale.xml - # need to iterate over entries in maps due to maps already being a directory with navmeshes/ in it - ( - cd /client/client/res/maps - readarray -d '' entries < <(printf '%s\0' * | sort -zV) - for entry in "${entries[@]}"; do - ln -s /client/client/res/maps/$entry /app/res/maps/ - done - ) -} - function symlink_config_files() { echo "Creating symlinks for config files" rm /app/*.ini @@ -25,17 +7,11 @@ function symlink_config_files() { ln -s /shared_configs/configs/chatconfig.ini /app/chatconfig.ini ln -s /shared_configs/configs/masterconfig.ini /app/masterconfig.ini ln -s /shared_configs/configs/worldconfig.ini /app/worldconfig.ini + ln -s /shared_configs/configs/sharedconfig.ini /app/sharedconfig.ini } -# check to make sure the setup has completed -while [ ! -f "/client/extracted" ] || [ ! -f "/client/migrated" ]; do - echo "Client setup not finished. Waiting for setup container to complete..." - sleep 5 -done - if [[ ! -f "/app/initialized" ]]; then # setup symlinks for volume files - symlink_client_files symlink_config_files # do not run symlinks more than once touch /app/initialized @@ -46,4 +22,4 @@ fi # start the server echo "Starting MasterServer" ./MasterServer -tail -f /dev/null \ No newline at end of file +tail -f /dev/null diff --git a/docs/Commands.md b/docs/Commands.md index b5588f68..c997c3c4 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -1,6 +1,5 @@ # In-game commands - -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](../dGame/dUtilities/SlashCommandHandler.cpp). +* All commands are prefixed by `/` and typed in the in-game chat window. Some commands require elevated gmlevel privileges. Operands within `<>` are required, operands within `()` are not. ## General Commands @@ -14,8 +13,6 @@ Here is a summary of the commands available in-game. All commands are prefixed b |pvp|`/pvp`|Toggle your PVP flag.|| |resurrect|`/resurrect`|Resurrects the player.|| |requestmailcount|`/requestmailcount`|Sends notification with number of unread messages in the player's mailbox.|| -|skip-ags|`/skip-ags`|Skips the Avant Gardens Survival minigame mission, "Impress the Sentinel Faction".|| -|skip-sg|`/skip-sg`|Skips the Shooting Gallery minigame mission, "Monarch of the Sea".|| |who|`/who`|Displays in chat all players on the instance.|| ## Moderation Commands @@ -32,14 +29,13 @@ Here is a summary of the commands available in-game. All commands are prefixed b |gminvis|`/gminvis`|Toggles invisibility for the character, though it's currently a bit buggy. Requires nonzero GM Level for the character, but the account must have a GM level of 8.|8| |setname|`/setname <name>`|Sets a temporary name for your player. The name resets when you log out.|8| |title|`/title <title>`|Temporarily appends your player's name with " - <title>". This resets when you log out.|8| +|fly|`/fly <speed>`|This toggles your flying state with an optional parameter for the speed scale.|4| ## Server Operation Commands |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | |announce|`/announce`|Sends a announcement. `/setanntitle` and `/setannmsg` must be called first to configure the announcement.|8| -|config-set|`/config-set <key> <value>`|Set configuration item.|8| -|config-get|`/config-get <key>`|Get current value of a configuration item.|8| |kill|`/kill <username>`|Smashes the character whom the given user is playing.|8| |metrics|`/metrics`|Prints some information about the server's performance.|8| |setannmsg|`/setannmsg <title>`|Sets the message of an announcement.|8| @@ -52,6 +48,7 @@ These commands are primarily for development and testing. The usage of many of t |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | +|togglenameplate|`/togglenameplate`|Turns the nameplate above your head that is visible to other players off and on.|8 or if `allow_nameplate_off` is set to exactly `1` in the settings| |fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.|| |join|`/join <password>`|Joins a private zone with given password.|| |leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.|| @@ -62,7 +59,8 @@ These commands are primarily for development and testing. The usage of many of t |teleport|`/teleport <x> (y) <z>`|Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z). Alias: `/tele`.|6| |activatespawner|`/activatespawner <spawner name>`|Activates spawner by name.|8| |addmission|`/addmission <mission id>`|Accepts the mission, adding it to your journal.|8| -|boost|`/boost`|Adds a passive boost action if you are in a vehicle.|8| +|boost|`/boost (time)`|Adds a passive boost action if you are in a vehicle. If time is given it will end after that amount of time|8| +|unboost|`/unboost`|Removes a passive vehicle boost|8| |buff|`/buff <id> <duration>`|Applies the buff with the given id for the given number of seconds.|8| |buffme|`/buffme`|Sets health, armor, and imagination to 999.|8| |buffmed|`/buffmed`|Sets health, armor, and imagination to 9.|8| @@ -70,7 +68,8 @@ These commands are primarily for development and testing. The usage of many of t |completemission|`/completemission <mission id>`|Completes the mission, removing it from your journal.|8| |createprivate|`/createprivate <zone id> <clone id> <password>`|Creates a private zone with password.|8| |debugui|`/debugui`|Toggle Debug UI.|8| -|dismount|`/dismount`|Dismounts you from the vehicle.|8| +|dismount|`/dismount`|Dismounts you from the vehicle or mount.|8| +|reloadconfig|`/reloadconfig`|Reloads the server with the new config values.|8| |force-save|`/force-save`|While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database.|8| |freecam|`/freecam`|Toggles freecam mode.|8| |freemoney|`/freemoney <coins>`|Gives coins.|8| @@ -80,7 +79,7 @@ These commands are primarily for development and testing. The usage of many of t |inspect|`/inspect <component> (-m <waypoint> \| -a <animation> \| -s \| -p \| -f (faction) \| -t)`|Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See [Detailed `/inspect` Usage](#detailed-inspect-usage) below.|8| |list-spawns|`/list-spawns`|Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.|8| |locrow|`/locrow`|Prints the your current position and rotation information to the console.|8| -|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query.|8| +|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query. Query can be multiple words delimited by spaces.|8| |playanimation|`/playanimation <id>`|Plays animation with given ID. Alias: `/playanim`.|8| |playeffect|`/playeffect <effect id> <effect type> <effect name>`|Plays an effect.|8| |playlvlfx|`/playlvlfx`|Plays the level up animation on your character.|8| @@ -94,7 +93,7 @@ These commands are primarily for development and testing. The usage of many of t |setcontrolscheme|`/setcontrolscheme <scheme number>`|Sets the character control scheme to the specified number.|8| |setcurrency|`/setcurrency <coins>`|Sets your coins.|8| |setflag|`/setflag (value) <flag id>`|Sets the given inventory or health flag to the given value, where value can be one of "on" or "off". If no value is given, by default this adds the flag to your character (equivalent of calling `/setflag on <flag id>`).|8| -|setinventorysize|`/setinventorysize <size>`|Sets your inventory size to the given size. Alias: `/setinvsize`|8| +|setinventorysize|`/setinventorysize <size> (inventory)`|Sets your inventory size to the given size. If `inventory` is provided, the number or string will be used to set that inventory to the requested size. Alias: `/setinvsize`|8| |setuistate|`/setuistate <ui state>`|Changes UI state.|8| |spawn|`/spawn <id>`|Spawns an object at your location by id.|8| |speedboost|`/speedboost <amount>`|Sets the speed multiplier to the given amount. `/speedboost 1.5` will set the speed multiplier to 1.5x the normal speed.|8| @@ -129,13 +128,13 @@ There are 9 Game master levels |Level|Variable Name|Description| |--- |--- |--- | -|0|GAME_MASTER_LEVEL_CIVILIAN|Normal player| -|1|GAME_MASTER_LEVEL_FORUM_MODERATOR|Forum moderator. No permissions on live servers.| -|2|GAME_MASTER_LEVEL_JUNIOR_MODERATOR|Can kick/mute and pull chat logs| -|3|GAME_MASTER_LEVEL_MODERATOR|Can return lost items| -|4|GAME_MASTER_LEVEL_SENIOR_MODERATOR|Can ban| -|5|GAME_MASTER_LEVEL_LEAD_MODERATOR|Can approve properties| -|6|GAME_MASTER_LEVEL_JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| -|7|GAME_MASTER_LEVEL_INACTIVE_DEVELOPER|Inactive developer, limited permissions.| -|8|GAME_MASTER_LEVEL_DEVELOPER|Active developer, full permissions on live.| -|9|GAME_MASTER_LEVEL_OPERATOR|Can shutdown server for restarts & updates.| +|0|CIVILIAN|Normal player| +|1|FORUM_MODERATOR|Forum moderator. No permissions on live servers.| +|2|JUNIOR_MODERATOR|Can kick/mute and pull chat logs| +|3|MODERATOR|Can return lost items| +|4|SENIOR_MODERATOR|Can ban| +|5|LEAD_MODERATOR|Can approve properties| +|6|JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| +|7|INACTIVE_DEVELOPER|Inactive developer, limited permissions.| +|8|DEVELOPER|Active developer, full permissions on live.| +|9|OPERATOR|Can shutdown server for restarts & updates.| diff --git a/migrations/cdserver/0_nt_footrace.sql b/migrations/cdserver/0_nt_footrace.sql index fd37599e..0a40cfef 100644 --- a/migrations/cdserver/0_nt_footrace.sql +++ b/migrations/cdserver/0_nt_footrace.sql @@ -1,6 +1,2 @@ -BEGIN TRANSACTION; - UPDATE ComponentsRegistry SET component_id = 1901 WHERE id = 12916 AND component_type = 39; INSERT INTO ActivityRewards (objectTemplate, ActivityRewardIndex, activityRating, LootMatrixIndex, CurrencyIndex, ChallengeRating, description) VALUES (1901, 166, -1, 598, 1, 4, 'NT Foot Race'); - -COMMIT; diff --git a/migrations/cdserver/3_plunger_gun_fix.sql b/migrations/cdserver/3_plunger_gun_fix.sql index 35654e8b..3d33592e 100644 --- a/migrations/cdserver/3_plunger_gun_fix.sql +++ b/migrations/cdserver/3_plunger_gun_fix.sql @@ -1,2 +1 @@ --- File added April 9th, 2022 UPDATE ItemComponent SET itemType = 5 where id = 7082; diff --git a/migrations/cdserver/5_serratorizer_chargeup_fix.sql b/migrations/cdserver/5_serratorizer_chargeup_fix.sql new file mode 100644 index 00000000..a61da2c2 --- /dev/null +++ b/migrations/cdserver/5_serratorizer_chargeup_fix.sql @@ -0,0 +1 @@ +UPDATE behaviorParameter SET value = 20 WHERE behaviorID = 21001 AND parameterID = "value 2"; diff --git a/migrations/cdserver/6_ninja_sensei.sql b/migrations/cdserver/6_ninja_sensei.sql new file mode 100644 index 00000000..f3828b07 --- /dev/null +++ b/migrations/cdserver/6_ninja_sensei.sql @@ -0,0 +1,2 @@ +INSERT INTO ScriptComponent (id, script_name, client_script_name) VALUES (228, 'scripts\ai\FV\L_ACT_NINJA_SENSEI.lua', null); +UPDATE ComponentsRegistry SET component_id = 228 WHERE id = 2489 AND component_type = 5; diff --git a/migrations/dlu/4_friends_list_objectids.sql b/migrations/dlu/4_friends_list_objectids.sql new file mode 100644 index 00000000..efb3a7ae --- /dev/null +++ b/migrations/dlu/4_friends_list_objectids.sql @@ -0,0 +1 @@ +UPDATE friends SET player_id = player_id % 0x100000000, friend_id = friend_id % 0x100000000; \ No newline at end of file diff --git a/migrations/dlu/5_brick_model_sd0.sql b/migrations/dlu/5_brick_model_sd0.sql new file mode 100644 index 00000000..895f8b34 --- /dev/null +++ b/migrations/dlu/5_brick_model_sd0.sql @@ -0,0 +1 @@ +# This file is here as a mock. The real migration is located in BrickByBrickFix.cpp diff --git a/migrations/dlu/6_property_behaviors.sql b/migrations/dlu/6_property_behaviors.sql new file mode 100644 index 00000000..b858db67 --- /dev/null +++ b/migrations/dlu/6_property_behaviors.sql @@ -0,0 +1,11 @@ +ALTER TABLE properties_contents + ADD COLUMN model_name TEXT NOT NULL DEFAULT "", + ADD COLUMN model_description TEXT NOT NULL DEFAULT "", + ADD COLUMN behavior_1 INT NOT NULL DEFAULT 0, + ADD COLUMN behavior_2 INT NOT NULL DEFAULT 0, + ADD COLUMN behavior_3 INT NOT NULL DEFAULT 0, + ADD COLUMN behavior_4 INT NOT NULL DEFAULT 0, + ADD COLUMN behavior_5 INT NOT NULL DEFAULT 0; + +UPDATE properties_contents SET model_name = CONCAT("Objects_", lot, "_name") WHERE model_name = ""; +CREATE TABLE IF NOT EXISTS behaviors (id INT NOT NULL, behavior_info TEXT NOT NULL); diff --git a/migrations/dlu/7_make_play_key_id_nullable.sql b/migrations/dlu/7_make_play_key_id_nullable.sql new file mode 100644 index 00000000..11239967 --- /dev/null +++ b/migrations/dlu/7_make_play_key_id_nullable.sql @@ -0,0 +1 @@ +ALTER TABLE accounts MODIFY play_key_id INT DEFAULT 0; diff --git a/migrations/dlu/8_foreign_play_key.sql b/migrations/dlu/8_foreign_play_key.sql new file mode 100644 index 00000000..6f171bb5 --- /dev/null +++ b/migrations/dlu/8_foreign_play_key.sql @@ -0,0 +1 @@ +ALTER TABLE accounts MODIFY play_key_id INT DEFAULT NULL; diff --git a/resources/authconfig.ini b/resources/authconfig.ini index 40ca146e..ec414bc0 100644 --- a/resources/authconfig.ini +++ b/resources/authconfig.ini @@ -1,27 +1,6 @@ -# MySQL connection info: -mysql_host= -mysql_database= -mysql_username= -mysql_password= - -# The public facing IP address. Can be 'localhost' for locally hosted servers -external_ip=localhost - # Port number. The client has the authserver port hardcoded to 1001 port=1001 -# Where to put crashlogs -dump_folder= - -# How many clients can be connected to the server at once -max_clients=999 - -# 0 or 1, should log to console -log_to_console=1 - -# 0 or 1, should log debug (developer only) statements to console for debugging, not needed for normal operation -log_debug_statements=0 - # 0 or 1, should ignore playkeys # If 1 everyone with an account will be able to login, regardless of if they have a key or not dont_use_keys=0 diff --git a/resources/blacklist.dcf b/resources/blacklist.dcf new file mode 100644 index 00000000..ca4db242 Binary files /dev/null and b/resources/blacklist.dcf differ diff --git a/resources/chatconfig.ini b/resources/chatconfig.ini index f30fb8f9..26b26cc7 100644 --- a/resources/chatconfig.ini +++ b/resources/chatconfig.ini @@ -1,26 +1,2 @@ -# MySQL connection info: -mysql_host= -mysql_database= -mysql_username= -mysql_password= - -# The public facing IP address. Can be 'localhost' for locally hosted servers -external_ip=localhost - # Port number port=2005 - -# Where to put crashlogs -dump_folder= - -# How many clients can be connected to the server at once -max_clients=999 - -# 0 or 1, should log to console -log_to_console=1 - -# 0 or 1, should log debug (developer only) statements to console for debugging, not needed for normal operation -log_debug_statements=0 - -# 0 or 1, should not compile chat hash map to file -dont_generate_dcf=0 diff --git a/resources/masterconfig.ini b/resources/masterconfig.ini index c2d884a5..4864d8cb 100644 --- a/resources/masterconfig.ini +++ b/resources/masterconfig.ini @@ -1,12 +1,3 @@ -# MySQL connection info: -mysql_host= -mysql_database= -mysql_username= -mysql_password= - -# The public facing IP address. Can be 'localhost' for locally hosted servers -external_ip=localhost - # The internal ip of the master server master_ip=localhost @@ -26,17 +17,5 @@ use_sudo_chat=0 # Use sudo when launching world servers use_sudo_world=0 -# Where to put crashlogs -dump_folder= - -# How many clients can be connected to the server at once -max_clients=999 - -# 0 or 1, should log to console -log_to_console=1 - -# 0 or 1, should log debug (developer only) statements to console for debugging, not needed for normal operation -log_debug_statements=0 - # 0 or 1, should autostart auth, chat, and char servers prestart_servers=1 diff --git a/resources/sharedconfig.ini b/resources/sharedconfig.ini new file mode 100644 index 00000000..d2c43d11 --- /dev/null +++ b/resources/sharedconfig.ini @@ -0,0 +1,38 @@ +# MySQL connection info: +mysql_host= +mysql_database= +mysql_username= +mysql_password= + +# 0 or 1, should log to console +log_to_console=1 + +# 0 or 1, should log debug (developer only) statements to console for debugging, not needed for normal operation +log_debug_statements=0 + +# The public facing IP address. Can be 'localhost' for locally hosted servers +external_ip=localhost + +# 0 or 1, should not compile chat hash map to file +dont_generate_dcf=0 + +# How many clients can be connected to the server at once +max_clients=999 + +# Where to put crashlogs +dump_folder= + +# The location of the client +# Either the folder with /res or with /client and /versions +client_location= + +# The maximum outgoing bandwidth in bits. If your clients are having +# issues with enemies taking a while to catch up to them, increse this value. +maximum_outgoing_bandwidth=80000 + +# The Maximum Translation Unit (MTU) size for packets. If players are +# getting stuck at 55% on the loading screen, lower this number to +# reduce the chances of packet loss. This value only has an effect +# from 512 <= maximum_mtu_size <= 1492 so make sure to keep this +# value within that range. +maximum_mtu_size=1228 diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index a665f059..b05614b4 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -1,9 +1,3 @@ -# MySQL connection info: -mysql_host= -mysql_database= -mysql_username= -mysql_password= - # URL to the code repository for the hosted server # If you fork this repository and/or make changes to the code, reflect that here to comply with AGPLv3 source=https://github.com/DarkflameUniverse/DarkflameServer @@ -11,21 +5,6 @@ source=https://github.com/DarkflameUniverse/DarkflameServer # Port to the chat server, same as in chatconfig.ini chat_server_port=2005 -# Where to put crashlogs -dump_folder= - -# How many clients can be connected to the server at once -max_clients=999 - -# 0 or 1, should log to console -log_to_console=1 - -# 0 or 1, should log debug (developer only) statements to console for debugging, not needed for normal operation -log_debug_statements=0 - -# 0 or 1, should not compile chat hash map to file -dont_generate_dcf=0 - # 0 or 1, should disable chat disable_chat=0 @@ -60,3 +39,25 @@ classic_survival_scoring=0 # If this value is 1, pets will consume imagination as they did in live. if 0 they will not consume imagination at all. pets_take_imagination=1 + +# If you would like to increase the maximum number of best friends a player can have on the server +# Change the value below to what you would like this to be (5 is live accurate) +max_number_of_best_friends=5 + +# Disables loot drops +disable_drops=0 + +# Hardcore mode settings +hardcore_mode=0 + +# Drop your entire inventory on death + coins (drops on the ground, so can be retrieved) +hardcore_dropinventory_on_death=1 + +# Enemies drop their max hp * this value. 0 will effectively disable it. +hardcore_uscore_enemies_multiplier=2 + +# Percentage of u-score to lose on player death +hardcore_lose_uscore_on_death_percent=10 + +# Allow civilian players the ability to turn the nameplate above their head off. Must be exactly 1 to be enabled for civilians. +allow_nameplate_off=0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 85f4bda4..9ba75a2f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,25 +1,21 @@ -# create the testing file and list of tests -create_test_sourcelist (Tests - CommonCxxTests.cpp - TestNiPoint3.cpp - TestLDFFormat.cpp +message (STATUS "Testing is enabled. Fetching gtest...") +enable_testing() + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 ) - -# add the executable -add_executable (CommonCxxTests ${Tests}) -target_link_libraries(CommonCxxTests dCommon raknet) -if(WIN32) - target_link_libraries(CommonCxxTests ws2_32) -endif(WIN32) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# remove the test driver source file -set (TestsToRun ${Tests}) -remove (TestsToRun CommonCxxTests.cpp) +FetchContent_MakeAvailable(GoogleTest) +include(GoogleTest) -# Add all the ADD_TEST for each test -foreach (test ${TestsToRun}) - get_filename_component (TName ${test} NAME_WE) - add_test (NAME ${TName} COMMAND CommonCxxTests ${TName}) - set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1) -endforeach () +message(STATUS "gtest fetched and is now ready.") + +# Add the subdirectories +add_subdirectory(dCommonTests) +add_subdirectory(dGameTests) diff --git a/tests/CommonCxxTests.cpp b/tests/CommonCxxTests.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/CommonCxxTests.h b/tests/CommonCxxTests.h deleted file mode 100644 index f1894927..00000000 --- a/tests/CommonCxxTests.h +++ /dev/null @@ -1,4 +0,0 @@ -#include <cstdio> - -#define ASSERT_EQ(a,b) { if (!(a == b)) { printf("Failed assertion: " #a " == " #b " \n in %s:%d\n", __FILE__, __LINE__); return 1; }} -#define ASSERT_NE(a,b) { if (!(a != b)) { printf("Failed assertion: " #a " != " #b " \n in %s:%d\n", __FILE__, __LINE__); return 1; }} diff --git a/tests/TestLDFFormat.cpp b/tests/TestLDFFormat.cpp deleted file mode 100644 index 7ba31420..00000000 --- a/tests/TestLDFFormat.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "LDFFormat.h" -#include "CommonCxxTests.h" - -/** - * @brief Test parsing an LDF value - * - * @param argc Number of command line arguments for this test - * @param argv Command line arguments - * @return 0 on success, non-zero on failure - */ -int TestLDFFormat(int argc, char* *const argv) { - // Create - auto* data = LDFBaseData::DataFromString("KEY=0:VALUE"); - - // Check that the data type is correct - ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); - - // Check that the key is correct - ASSERT_EQ(data->GetKey(), u"KEY"); - - // Check that the value is correct - ASSERT_EQ(((LDFData<std::u16string>* )data)->GetValue(), u"VALUE"); - - // Check that the serialization is correct - ASSERT_EQ(data->GetString(), "KEY=0:VALUE"); - - // Cleanup the object - delete data; - - return 0; -} diff --git a/tests/TestNiPoint3.cpp b/tests/TestNiPoint3.cpp deleted file mode 100644 index 076b186d..00000000 --- a/tests/TestNiPoint3.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include <stdexcept> - -#include "NiPoint3.h" -#include "CommonCxxTests.h" - -int TestNiPoint3(int argc, char* *const argv) { - // Check that Unitize works - ASSERT_EQ(NiPoint3(3,0,0).Unitize(), NiPoint3::UNIT_X); - // Check what unitize does to a vector of length 0 - ASSERT_EQ(NiPoint3::ZERO.Unitize(), NiPoint3::ZERO); - // If we get here, all was successful - return 0; -} diff --git a/tests/dCommonTests/AMFDeserializeTests.cpp b/tests/dCommonTests/AMFDeserializeTests.cpp new file mode 100644 index 00000000..b679ea78 --- /dev/null +++ b/tests/dCommonTests/AMFDeserializeTests.cpp @@ -0,0 +1,444 @@ +#include <fstream> +#include <memory> +#include <gtest/gtest.h> + +#include "AMFDeserialize.h" +#include "AMFFormat.h" + +/** + * Helper method that all tests use to get their respective AMF. + */ +std::unique_ptr<AMFValue> ReadFromBitStream(RakNet::BitStream* bitStream) { + AMFDeserialize deserializer; + std::unique_ptr<AMFValue> returnValue(deserializer.Read(bitStream)); + return returnValue; +} + +/** + * @brief Test reading an AMFUndefined value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFUndefinedTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x00); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFUndefined); +} + +/** + * @brief Test reading an AMFNull value from a BitStream. + * + */ +TEST(dCommonTests, AMFDeserializeAMFNullTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x01); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFNull); +} + +/** + * @brief Test reading an AMFFalse value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFFalseTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x02); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFFalse); +} + +/** + * @brief Test reading an AMFTrue value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFTrueTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x03); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFTrue); +} + +/** + * @brief Test reading an AMFInteger value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { + CBITSTREAM + { + bitStream.Write<uint8_t>(0x04); + // 127 == 01111111 + bitStream.Write<uint8_t>(127); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFInteger); + // Check that the max value of a byte can be read correctly + ASSERT_EQ(static_cast<AMFIntegerValue*>(res.get())->GetIntegerValue(), 127); + } + bitStream.Reset(); + { + bitStream.Write<uint8_t>(0x04); + bitStream.Write<uint32_t>(UINT32_MAX); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFInteger); + // Check that we can read the maximum value correctly + ASSERT_EQ(static_cast<AMFIntegerValue*>(res.get())->GetIntegerValue(), 536870911); + } + bitStream.Reset(); + { + bitStream.Write<uint8_t>(0x04); + // 131 == 10000011 + bitStream.Write<uint8_t>(131); + // 255 == 11111111 + bitStream.Write<uint8_t>(255); + // 127 == 01111111 + bitStream.Write<uint8_t>(127); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFInteger); + // Check that short max can be read correctly + ASSERT_EQ(static_cast<AMFIntegerValue*>(res.get())->GetIntegerValue(), UINT16_MAX); + } + bitStream.Reset(); + { + bitStream.Write<uint8_t>(0x04); + // 255 == 11111111 + bitStream.Write<uint8_t>(255); + // 127 == 01111111 + bitStream.Write<uint8_t>(127); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFInteger); + // Check that 2 byte max can be read correctly + ASSERT_EQ(static_cast<AMFIntegerValue*>(res.get())->GetIntegerValue(), 16383); + } +} + +/** + * @brief Test reading an AMFDouble value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFDoubleTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x05); + bitStream.Write<double>(25346.4f); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFDouble); + ASSERT_EQ(static_cast<AMFDoubleValue*>(res.get())->GetDoubleValue(), 25346.4f); +} + +/** + * @brief Test reading an AMFString value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFStringTest) { + CBITSTREAM + bitStream.Write<uint8_t>(0x06); + bitStream.Write<uint8_t>(0x0F); + std::string toWrite = "stateID"; + for (auto e : toWrite) bitStream.Write<char>(e); + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFString); + ASSERT_EQ(static_cast<AMFStringValue*>(res.get())->GetStringValue(), "stateID"); +} + +/** + * @brief Test reading an AMFArray value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFArrayTest) { + CBITSTREAM + // Test empty AMFArray + bitStream.Write<uint8_t>(0x09); + bitStream.Write<uint8_t>(0x01); + bitStream.Write<uint8_t>(0x01); + { + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFArray); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociativeMap().size(), 0); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDenseArray().size(), 0); + } + bitStream.Reset(); + // Test a key'd value and dense value + bitStream.Write<uint8_t>(0x09); + bitStream.Write<uint8_t>(0x03); + bitStream.Write<uint8_t>(0x15); + for (auto e : "BehaviorID") if (e != '\0') bitStream.Write<char>(e); + bitStream.Write<uint8_t>(0x06); + bitStream.Write<uint8_t>(0x0B); + for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e); + bitStream.Write<uint8_t>(0x01); + bitStream.Write<uint8_t>(0x06); + bitStream.Write<uint8_t>(0x0B); + for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e); + { + std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); + ASSERT_EQ(res->GetValueType(), AMFValueType::AMFArray); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociativeMap().size(), 1); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDenseArray().size(), 1); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->FindValue<AMFStringValue>("BehaviorID")->GetStringValue(), "10447"); + ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetValueAt<AMFStringValue>(0)->GetStringValue(), "10447"); + } +} + +/** + * @brief This test checks that if we recieve an unimplemented AMFValueType + * we correctly throw an error and can actch it. + * Yes this leaks memory. + */ +TEST(dCommonTests, AMFDeserializeUnimplementedValuesTest) { + std::vector<AMFValueType> unimplementedValues = { + AMFValueType::AMFXMLDoc, + AMFValueType::AMFDate, + AMFValueType::AMFObject, + AMFValueType::AMFXML, + AMFValueType::AMFByteArray, + AMFValueType::AMFVectorInt, + AMFValueType::AMFVectorUInt, + AMFValueType::AMFVectorDouble, + AMFValueType::AMFVectorObject, + AMFValueType::AMFDictionary + }; + // Run unimplemented tests to check that errors are thrown if + // unimplemented AMF values are attempted to be parsed. + std::ifstream fileStream; + fileStream.open("AMFBitStreamUnimplementedTest.bin", std::ios::binary); + + // Read a test BitStream from a file + std::vector<char> baseBitStream; + char byte = 0; + while (fileStream.get(byte)) { + baseBitStream.push_back(byte); + } + + fileStream.close(); + + for (auto amfValueType : unimplementedValues) { + RakNet::BitStream testBitStream; + for (auto element : baseBitStream) { + testBitStream.Write(element); + } + testBitStream.Write(amfValueType); + bool caughtException = false; + try { + ReadFromBitStream(&testBitStream); + } catch (AMFValueType unimplementedValueType) { + caughtException = true; + } + + ASSERT_EQ(caughtException, true); + } +} + +/** + * @brief Test reading a packet capture from live from a BitStream + */ +TEST(dCommonTests, AMFDeserializeLivePacketTest) { + std::ifstream testFileStream; + testFileStream.open("AMFBitStreamTest.bin", std::ios::binary); + + // Read a test BitStream from a file + RakNet::BitStream testBitStream; + char byte = 0; + while (testFileStream.get(byte)) { + testBitStream.Write<char>(byte); + } + + testFileStream.close(); + + auto resultFromFn = ReadFromBitStream(&testBitStream); + auto result = static_cast<AMFArrayValue*>(resultFromFn.get()); + // Test the outermost array + + ASSERT_EQ(result->FindValue<AMFStringValue>("BehaviorID")->GetStringValue(), "10447"); + ASSERT_EQ(result->FindValue<AMFStringValue>("objectID")->GetStringValue(), "288300744895913279"); + + // Test the execution state array + auto executionState = result->FindValue<AMFArrayValue>("executionState"); + + ASSERT_NE(executionState, nullptr); + + auto strips = executionState->FindValue<AMFArrayValue>("strips")->GetDenseArray(); + + ASSERT_EQ(strips.size(), 1); + + auto stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0]); + + auto actionIndex = stripsPosition0->FindValue<AMFDoubleValue>("actionIndex"); + + ASSERT_EQ(actionIndex->GetDoubleValue(), 0.0f); + + auto stripIdExecution = stripsPosition0->FindValue<AMFDoubleValue>("id"); + + ASSERT_EQ(stripIdExecution->GetDoubleValue(), 0.0f); + + auto stateIDExecution = executionState->FindValue<AMFDoubleValue>("stateID"); + + ASSERT_EQ(stateIDExecution->GetDoubleValue(), 0.0f); + + auto states = result->FindValue<AMFArrayValue>("states")->GetDenseArray(); + + ASSERT_EQ(states.size(), 1); + + auto firstState = dynamic_cast<AMFArrayValue*>(states[0]); + + auto stateID = firstState->FindValue<AMFDoubleValue>("id"); + + ASSERT_EQ(stateID->GetDoubleValue(), 0.0f); + + auto stripsInState = firstState->FindValue<AMFArrayValue>("strips")->GetDenseArray(); + + ASSERT_EQ(stripsInState.size(), 1); + + auto firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0]); + + auto actionsInFirstStrip = firstStrip->FindValue<AMFArrayValue>("actions")->GetDenseArray(); + + ASSERT_EQ(actionsInFirstStrip.size(), 3); + + auto actionID = firstStrip->FindValue<AMFDoubleValue>("id"); + + ASSERT_EQ(actionID->GetDoubleValue(), 0.0f); + + auto uiArray = firstStrip->FindValue<AMFArrayValue>("ui"); + + auto xPos = uiArray->FindValue<AMFDoubleValue>("x"); + auto yPos = uiArray->FindValue<AMFDoubleValue>("y"); + + ASSERT_EQ(xPos->GetDoubleValue(), 103.0f); + ASSERT_EQ(yPos->GetDoubleValue(), 82.0f); + + auto stripId = firstStrip->FindValue<AMFDoubleValue>("id"); + + ASSERT_EQ(stripId->GetDoubleValue(), 0.0f); + + auto firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]); + + auto firstType = firstAction->FindValue<AMFStringValue>("Type"); + + ASSERT_EQ(firstType->GetStringValue(), "OnInteract"); + + auto firstCallback = firstAction->FindValue<AMFStringValue>("__callbackID__"); + + ASSERT_EQ(firstCallback->GetStringValue(), ""); + + auto secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1]); + + auto secondType = secondAction->FindValue<AMFStringValue>("Type"); + + ASSERT_EQ(secondType->GetStringValue(), "FlyUp"); + + auto secondCallback = secondAction->FindValue<AMFStringValue>("__callbackID__"); + + ASSERT_EQ(secondCallback->GetStringValue(), ""); + + auto secondDistance = secondAction->FindValue<AMFDoubleValue>("Distance"); + + ASSERT_EQ(secondDistance->GetDoubleValue(), 25.0f); + + auto thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2]); + + auto thirdType = thirdAction->FindValue<AMFStringValue>("Type"); + + ASSERT_EQ(thirdType->GetStringValue(), "FlyDown"); + + auto thirdCallback = thirdAction->FindValue<AMFStringValue>("__callbackID__"); + + ASSERT_EQ(thirdCallback->GetStringValue(), ""); + + auto thirdDistance = thirdAction->FindValue<AMFDoubleValue>("Distance"); + + ASSERT_EQ(thirdDistance->GetDoubleValue(), 25.0f); +} + +/** + * @brief Tests that having no BitStream returns a nullptr. + */ +TEST(dCommonTests, AMFDeserializeNullTest) { + auto result = ReadFromBitStream(nullptr); + ASSERT_EQ(result.get(), nullptr); +} + +TEST(dCommonTests, AMFBadConversionTest) { + std::ifstream testFileStream; + testFileStream.open("AMFBitStreamTest.bin", std::ios::binary); + + // Read a test BitStream from a file + RakNet::BitStream testBitStream; + char byte = 0; + while (testFileStream.get(byte)) { + testBitStream.Write<char>(byte); + } + + testFileStream.close(); + + auto resultFromFn = ReadFromBitStream(&testBitStream); + auto result = static_cast<AMFArrayValue*>(resultFromFn.get()); + + // Actually a string value. + ASSERT_EQ(result->FindValue<AMFDoubleValue>("BehaviorID"), nullptr); + + // Does not exist in the associative portion + ASSERT_EQ(result->FindValue<AMFNullValue>("DOES_NOT_EXIST"), nullptr); + + result->PushBackValue(new AMFTrueValue()); + + // Exists and is correct type + ASSERT_NE(result->GetValueAt<AMFTrueValue>(0), nullptr); + + // Value exists but is wrong typing + ASSERT_EQ(result->GetValueAt<AMFFalseValue>(0), nullptr); + + // Value is out of bounds + ASSERT_EQ(result->GetValueAt<AMFTrueValue>(1), nullptr); +} + +/** + * Below is the AMF that is in the AMFBitStreamTest.bin file that we are reading in + * from a bitstream to test. +args: amf3! +{ + "objectID": "288300744895913279", + "BehaviorID": "10447", + "executionState": amf3! + { + "strips": amf3! + [ + amf3! + { + "actionIndex": 0.0, + "id": 0.0, + }, + ], + "stateID": 0.0, + }, + "states": amf3! + [ + amf3! + { + "id": 0.0, + "strips": amf3! + [ + amf3! + { + "actions": amf3! + [ + amf3! + { + "Type": "OnInteract", + "__callbackID__": "", + }, + amf3! + { + "Distance": 25.0, + "Type": "FlyUp", + "__callbackID__": "", + }, + amf3! + { + "Distance": 25.0, + "Type": "FlyDown", + "__callbackID__": "", + }, + ], + "id": 0.0, + "ui": amf3! + { + "x": 103.0, + "y": 82.0, + }, + }, + ], + }, + ], +} + */ diff --git a/tests/dCommonTests/CMakeLists.txt b/tests/dCommonTests/CMakeLists.txt new file mode 100644 index 00000000..444afbdd --- /dev/null +++ b/tests/dCommonTests/CMakeLists.txt @@ -0,0 +1,21 @@ +set(DCOMMONTEST_SOURCES + "AMFDeserializeTests.cpp" + "HeaderSkipTest.cpp" + "TestLDFFormat.cpp" + "TestNiPoint3.cpp" + "TestEncoding.cpp" + "dCommonDependencies.cpp" +) + +# Set our executable +add_executable(dCommonTests ${DCOMMONTEST_SOURCES}) + +# Link needed libraries +target_link_libraries(dCommonTests ${COMMON_LIBRARIES} GTest::gtest_main) + +# Copy test files to testing directory +add_subdirectory(TestBitStreams) +file(COPY ${TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Discover the tests +gtest_discover_tests(dCommonTests) diff --git a/tests/dCommonTests/HeaderSkipTest.cpp b/tests/dCommonTests/HeaderSkipTest.cpp new file mode 100644 index 00000000..a8f78078 --- /dev/null +++ b/tests/dCommonTests/HeaderSkipTest.cpp @@ -0,0 +1,37 @@ +#include <gtest/gtest.h> + +#include "dCommonDependencies.h" +#include "dCommonVars.h" +#include "BitStream.h" + +#define PacketUniquePtr std::unique_ptr<Packet> + +TEST(dCommonTests, HeaderSkipExcessTest) { + PacketUniquePtr packet = std::make_unique<Packet>(); + unsigned char headerAndData[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 }; // positive + packet->data = headerAndData; + packet->length = sizeof(headerAndData); + CINSTREAM_SKIP_HEADER; + ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 64); + ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 128); +} + +TEST(dCommonTests, HeaderSkipExactDataTest) { + PacketUniquePtr packet = std::make_unique<Packet>(); + unsigned char header[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00 }; // positive + packet->data = header; + packet->length = sizeof(header); + CINSTREAM_SKIP_HEADER; + ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 0); + ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 64); +} + +TEST(dCommonTests, HeaderSkipNotEnoughDataTest) { + PacketUniquePtr packet = std::make_unique<Packet>(); + unsigned char notEnoughData[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00 }; // negative + packet->data = notEnoughData; + packet->length = sizeof(notEnoughData); + CINSTREAM_SKIP_HEADER; + ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 0); + ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 48); +} diff --git a/tests/dCommonTests/TestBitStreams/AMFBitStreamTest.bin b/tests/dCommonTests/TestBitStreams/AMFBitStreamTest.bin new file mode 100644 index 00000000..05241f35 Binary files /dev/null and b/tests/dCommonTests/TestBitStreams/AMFBitStreamTest.bin differ diff --git a/tests/dCommonTests/TestBitStreams/AMFBitStreamUnimplementedTest.bin b/tests/dCommonTests/TestBitStreams/AMFBitStreamUnimplementedTest.bin new file mode 100644 index 00000000..624bc5c3 --- /dev/null +++ b/tests/dCommonTests/TestBitStreams/AMFBitStreamUnimplementedTest.bin @@ -0,0 +1 @@ + BehaviorID \ No newline at end of file diff --git a/tests/dCommonTests/TestBitStreams/CMakeLists.txt b/tests/dCommonTests/TestBitStreams/CMakeLists.txt new file mode 100644 index 00000000..93606df6 --- /dev/null +++ b/tests/dCommonTests/TestBitStreams/CMakeLists.txt @@ -0,0 +1,11 @@ +set(TESTBITSTREAMS + "AMFBitStreamTest.bin" + "AMFBitStreamUnimplementedTest.bin" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM TESTBITSTREAMS PREPEND "${thisFolderName}/") + +# Export our list of files +set(TESTBITSTREAMS ${TESTBITSTREAMS} PARENT_SCOPE) diff --git a/tests/dCommonTests/TestEncoding.cpp b/tests/dCommonTests/TestEncoding.cpp new file mode 100644 index 00000000..c103ccbf --- /dev/null +++ b/tests/dCommonTests/TestEncoding.cpp @@ -0,0 +1,68 @@ +#include <string> +#include <gtest/gtest.h> +#include <string_view> + +#include "GeneralUtils.h" + +class EncodingTest : public ::testing::Test { +protected: + std::string originalWord; + std::string_view originalWordSv; + uint32_t out; +}; + +TEST_F(EncodingTest, TestEncodingHello) { + originalWord = "Hello World!"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), true); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!"); +}; + +TEST_F(EncodingTest, TestEncodingUmlaut) { + originalWord = u8"Frühling"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling"); +}; + +TEST_F(EncodingTest, TestEncodingChinese) { + originalWord = "中文字"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字"); +}; + +TEST_F(EncodingTest, TestEncodingEmoji) { + originalWord = "👨‍⚖️"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("👨‍⚖️"), u"👨‍⚖️"); +}; diff --git a/tests/dCommonTests/TestLDFFormat.cpp b/tests/dCommonTests/TestLDFFormat.cpp new file mode 100644 index 00000000..36326e38 --- /dev/null +++ b/tests/dCommonTests/TestLDFFormat.cpp @@ -0,0 +1,252 @@ +#include "LDFFormat.h" + +#include <gtest/gtest.h> + +#include "Game.h" +#include "dCommonDependencies.h" +#include "dLogger.h" + +class LDFTests : public dCommonDependenciesTest { +protected: + void SetUp() override { + SetUpDependencies(); + } + + void TearDown() override { + TearDownDependencies(); + } +}; + +#define LdfUniquePtr std::unique_ptr<LDFBaseData> + +// Suite of tests for parsing LDF values + +TEST_F(LDFTests, LDFUTF16Test) { + std::string testWord = "KEY=0:IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFUTF16EmptyTest) { + std::string testWord = "KEY=0:"; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u""); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFUTF16ColonTest) { + std::string testWord = "KEY=0:::"; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"::"); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFUTF16EqualsTest) { + std::string testWord = "KEY=0:=="; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"=="); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFS32Test) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=1:-15")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_S32); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<int32_t>*)data.get())->GetValue(), -15); + ASSERT_EQ(data->GetString(), "KEY=1:-15"); +} +TEST_F(LDFTests, LDFU32Test) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=5:15")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(data->GetString(), "KEY=5:15"); +} + +TEST_F(LDFTests, LDFU32TrueTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=5:true")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 1); + ASSERT_EQ(data->GetString(), "KEY=5:1"); +} + +TEST_F(LDFTests, LDFU32FalseTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=5:false")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 0); + ASSERT_EQ(data->GetString(), "KEY=5:0"); +} + + +// Use find since floats and doubles generally have appended 0s +TEST_F(LDFTests, LDFFloatTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=3:15.5")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_FLOAT); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<float>*)data.get())->GetValue(), 15.5f); + ASSERT_EQ(data->GetString().find("KEY=3:15.5"), 0); +} + +TEST_F(LDFTests, LDFDoubleTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=4:15.5")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_DOUBLE); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<double>*)data.get())->GetValue(), 15.5); + ASSERT_EQ(data->GetString().find("KEY=4:15.5"), 0); +} + + +TEST_F(LDFTests, LDFBoolTrueTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=7:true")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), true); + ASSERT_EQ(data->GetString(), "KEY=7:1"); +} + +TEST_F(LDFTests, LDFBoolFalseTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=7:false")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), false); + ASSERT_EQ(data->GetString(), "KEY=7:0"); +} + +TEST_F(LDFTests, LDFBoolIntTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=7:3")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), true); + ASSERT_EQ(data->GetString(), "KEY=7:1"); +} + +TEST_F(LDFTests, LDFU64Test) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=8:15")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U64); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<uint64_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(data->GetString(), "KEY=8:15"); +} + +TEST_F(LDFTests, LDFLWOOBJIDTest) { + LdfUniquePtr data(LDFBaseData::DataFromString("KEY=9:15")); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_OBJID); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<uint64_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(data->GetString(), "KEY=9:15"); +} + +TEST_F(LDFTests, LDFUTF8Test) { + std::string testWord = "KEY=13:IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFUTF8EmptyTest) { + std::string testWord = "KEY=13:"; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), ""); + ASSERT_EQ(data->GetString(), testWord); +} + +TEST_F(LDFTests, LDFUTF8ColonsTest) { + std::string testWord = "KEY=13:::"; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "::"); + ASSERT_EQ(data->GetString(), testWord); +} +TEST_F(LDFTests, LDFUTF8EqualsTest) { + std::string testWord = "KEY=13:=="; + LdfUniquePtr data(LDFBaseData::DataFromString(testWord)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); + ASSERT_EQ(data->GetKey(), u"KEY"); + ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "=="); + ASSERT_EQ(data->GetString(), testWord); +} + + +TEST_F(LDFTests, LDFParseEdgeCaseTest) { + std::vector<std::string> tests = { + // Test undefined data + "", // Empty + "=", // Only equals sign + ":", // Only colon + "=:", // Only colon and equals sign + + // Test no LDFType + "KEY=:", // No LDF Type + "KEY=:44", // No LDF Type, but has value + + // Test invalid values, but valid types + "key=1:", // no value for int32 + "key=1:banana", // invalid value for int32 + "key=3:", // No value for float + "key=3:banana", // invalid for float + "key=4:", // No value for double + "key=4:banana", // invalid for double + "key=5:", // No value for U32 + "key=5:banana", // invalid for U32 + "key=7:", // No value for bool + "key=7:banana", // invalid for bool + "key=8:", // No value for U64 + "key=8:banana", // invalid for U64 + "key=9:", // No value for LWOOBJID + "key=9:banana", // invalid for LWOOBJID + + // Test invalid LDF types + "key=14:value", // invalid LDF type + "key=-1:value", // invalid LDF type + "key=-2:value", // invalid LDF type (no enum definition) + "key=Garbage:value", // invalid LDF type + }; + for (auto testString : tests) { + Game::logger->Log("LDFTests", "Testing LDF Parsing of invalid string (%s)", testString.c_str()); + EXPECT_NO_THROW(LDFBaseData::DataFromString(testString)); + } +} + +#ifdef PERF_TEST + +TEST_F(LDFTests, LDFSpeedTest) { + std::string keyToTest = "KEY=0:IAmA weird string with :::: and s"; + for (int i = 0; i < 10000; i++) LDFBaseData::DataFromString(keyToTest); +} + +#endif //PERF diff --git a/tests/dCommonTests/TestNiPoint3.cpp b/tests/dCommonTests/TestNiPoint3.cpp new file mode 100644 index 00000000..33cd51d2 --- /dev/null +++ b/tests/dCommonTests/TestNiPoint3.cpp @@ -0,0 +1,14 @@ +#include <gtest/gtest.h> + +#include "NiPoint3.h" + +/** + * @brief Basic test for NiPoint3 functionality + * + */ +TEST(dCommonTests, NiPoint3Test) { + // Check that Unitize works + ASSERT_EQ(NiPoint3(3, 0, 0).Unitize(), NiPoint3::UNIT_X); + // Check what unitize does to a vector of length 0 + ASSERT_EQ(NiPoint3::ZERO.Unitize(), NiPoint3::ZERO); +} diff --git a/tests/dCommonTests/dCommonDependencies.cpp b/tests/dCommonTests/dCommonDependencies.cpp new file mode 100644 index 00000000..5b25fd47 --- /dev/null +++ b/tests/dCommonTests/dCommonDependencies.cpp @@ -0,0 +1,7 @@ +#include "Game.h" + +class dLogger; +namespace Game +{ + dLogger* logger; +} // namespace Game diff --git a/tests/dCommonTests/dCommonDependencies.h b/tests/dCommonTests/dCommonDependencies.h new file mode 100644 index 00000000..12aeb938 --- /dev/null +++ b/tests/dCommonTests/dCommonDependencies.h @@ -0,0 +1,26 @@ +#ifndef __DCOMMONDEPENDENCIES__H__ +#define __DCOMMONDEPENDENCIES__H__ + +#include "Game.h" +#include "dLogger.h" +#include "dServer.h" +#include "EntityInfo.h" +#include "EntityManager.h" +#include "dConfig.h" +#include <gtest/gtest.h> + +class dCommonDependenciesTest : public ::testing::Test { +protected: + void SetUpDependencies() { + Game::logger = new dLogger("./testing.log", true, true); + } + + void TearDownDependencies() { + if (Game::logger) { + Game::logger->Flush(); + delete Game::logger; + } + } +}; + +#endif //!__DCOMMONDEPENDENCIES__H__ diff --git a/tests/dGameTests/CMakeLists.txt b/tests/dGameTests/CMakeLists.txt new file mode 100644 index 00000000..b1fdaa07 --- /dev/null +++ b/tests/dGameTests/CMakeLists.txt @@ -0,0 +1,19 @@ +set(DGAMETEST_SOURCES + "GameDependencies.cpp" +) + +add_subdirectory(dComponentsTests) +list(APPEND DGAMETEST_SOURCES ${DCOMPONENTS_TESTS}) + +add_subdirectory(dGameMessagesTests) +list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS}) + +file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Add the executable. Remember to add all tests above this! +add_executable(dGameTests ${DGAMETEST_SOURCES}) + +target_link_libraries(dGameTests ${COMMON_LIBRARIES} GTest::gtest_main dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dChatFilter dNavigation) + +# Discover the tests +gtest_discover_tests(dGameTests) diff --git a/tests/dGameTests/GameDependencies.cpp b/tests/dGameTests/GameDependencies.cpp new file mode 100644 index 00000000..7b0a8412 --- /dev/null +++ b/tests/dGameTests/GameDependencies.cpp @@ -0,0 +1,13 @@ +#include "GameDependencies.h" + +namespace Game { + dLogger* logger; + dServer* server; + dZoneManager* zoneManager; + dChatFilter* chatFilter; + dConfig* config; + std::mt19937 randomEngine; + RakPeerInterface* chatServer; + AssetManager* assetManager; + SystemAddress chatSysAddr; +} diff --git a/tests/dGameTests/GameDependencies.h b/tests/dGameTests/GameDependencies.h new file mode 100644 index 00000000..353b53b8 --- /dev/null +++ b/tests/dGameTests/GameDependencies.h @@ -0,0 +1,50 @@ +#ifndef __GAMEDEPENDENCIES__H__ +#define __GAMEDEPENDENCIES__H__ + +#include "Game.h" +#include "dLogger.h" +#include "dServer.h" +#include "EntityInfo.h" +#include "EntityManager.h" +#include "dConfig.h" +#include <gtest/gtest.h> + +class dZoneManager; +class AssetManager; + +class dServerMock : public dServer { + RakNet::BitStream* sentBitStream = nullptr; +public: + dServerMock() {}; + ~dServerMock() {}; + RakNet::BitStream* GetMostRecentBitStream() { return sentBitStream; }; + void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast) override { sentBitStream = bitStream; }; +}; + +class GameDependenciesTest : public ::testing::Test { +protected: + void SetUpDependencies() { + info.pos = NiPoint3::ZERO; + info.rot = NiQuaternion::IDENTITY; + info.scale = 1.0f; + info.spawner = nullptr; + info.lot = 999; + Game::logger = new dLogger("./testing.log", true, true); + Game::server = new dServerMock(); + Game::config = new dConfig("worldconfig.ini"); + } + + void TearDownDependencies() { + if (Game::server) delete Game::server; + delete EntityManager::Instance(); + if (Game::logger) { + Game::logger->Flush(); + delete Game::logger; + } + if (Game::config) delete Game::config; + } + + EntityInfo info; +}; + +#endif //!__GAMEDEPENDENCIES__H__ diff --git a/tests/dGameTests/dComponentsTests/CMakeLists.txt b/tests/dGameTests/dComponentsTests/CMakeLists.txt new file mode 100644 index 00000000..17e69a2f --- /dev/null +++ b/tests/dGameTests/dComponentsTests/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DCOMPONENTS_TESTS + "DestroyableComponentTests.cpp" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM DCOMPONENTS_TESTS PREPEND "${thisFolderName}/") + +# Export to parent scope +set(DCOMPONENTS_TESTS ${DCOMPONENTS_TESTS} PARENT_SCOPE) diff --git a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp new file mode 100644 index 00000000..db9c033a --- /dev/null +++ b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp @@ -0,0 +1,533 @@ +#include "GameDependencies.h" +#include <gtest/gtest.h> + +#include "BitStream.h" +#include "DestroyableComponent.h" +#include "Entity.h" +#include "eReplicaComponentType.h" +#include "eStateChangeType.h" + +class DestroyableTest : public GameDependenciesTest { +protected: + Entity* baseEntity; + DestroyableComponent* destroyableComponent; + CBITSTREAM + uint32_t flags = 0; + void SetUp() override { + SetUpDependencies(); + baseEntity = new Entity(15, GameDependenciesTest::info); + destroyableComponent = new DestroyableComponent(baseEntity); + baseEntity->AddComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent); + // Initialize some values to be not default + destroyableComponent->SetMaxHealth(12345.0f); + destroyableComponent->SetHealth(23); + destroyableComponent->SetMaxArmor(14.0f); + destroyableComponent->SetArmor(7); + destroyableComponent->SetMaxImagination(14000.0f); + destroyableComponent->SetImagination(6000); + destroyableComponent->SetIsSmashable(true); + destroyableComponent->SetExplodeFactor(1.1f); + destroyableComponent->AddFactionNoLookup(-1); + destroyableComponent->AddFactionNoLookup(6); + } + + void TearDown() override { + delete baseEntity; + TearDownDependencies(); + } +}; + +/** + * Test Construction of a DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { + destroyableComponent->Serialize(&bitStream, true, flags); + // Assert that the full number of bits are present + ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 748); + { + // Now read in the full serialized construction BitStream + bool optionStatusImmunityInfo{}; + uint32_t ImmuneToBasicAttackCount{}; + uint32_t ImmuneToDamageOverTimeCount{}; + uint32_t ImmuneToKnockbackCount{}; + uint32_t ImmuneToInterruptCount{}; + uint32_t ImmuneToSpeedCount{}; + uint32_t ImmuneToImaginationGainCount{}; + uint32_t ImmuneToImaginationLossCount{}; + uint32_t ImmuneToQuickbuildInterruptCount{}; + uint32_t ImmuneToPullToPointCount{}; + bool optionStatsInfo{}; + uint32_t currentHealth{}; + float maxHealth{}; + uint32_t currentArmor{}; + float maxArmor{}; + uint32_t currentImagination{}; + float maxImagination{}; + uint32_t damageAbsorptionPoints{}; + bool hasImmunity{}; + bool isGmImmune{}; + bool isShielded{}; + float actualMaxHealth{}; + float actualMaxArmor{}; + float actualMaxImagination{}; + uint32_t factionsSize{}; + std::vector<int32_t> factions{}; + bool isSmashable{}; + bool isDead{}; + bool isSmashed{}; + bool isModuleAssembly{}; + bool optionExplodeFactor{}; + float explodeFactor{}; + bool optionIsOnThreatList{}; + bool isThreatened{}; + bitStream.Read(optionStatusImmunityInfo); + bitStream.Read(ImmuneToBasicAttackCount); + bitStream.Read(ImmuneToDamageOverTimeCount); + bitStream.Read(ImmuneToKnockbackCount); + bitStream.Read(ImmuneToInterruptCount); + bitStream.Read(ImmuneToSpeedCount); + bitStream.Read(ImmuneToImaginationGainCount); + bitStream.Read(ImmuneToImaginationLossCount); + bitStream.Read(ImmuneToQuickbuildInterruptCount); + bitStream.Read(ImmuneToPullToPointCount); + bitStream.Read(optionStatsInfo); + bitStream.Read(currentHealth); + bitStream.Read(maxHealth); + bitStream.Read(currentArmor); + bitStream.Read(maxArmor); + bitStream.Read(currentImagination); + bitStream.Read(maxImagination); + bitStream.Read(damageAbsorptionPoints); + bitStream.Read(hasImmunity); + bitStream.Read(isGmImmune); + bitStream.Read(isShielded); + bitStream.Read(actualMaxHealth); + bitStream.Read(actualMaxArmor); + bitStream.Read(actualMaxImagination); + bitStream.Read(factionsSize); + for (uint32_t i = 0; i < factionsSize; i++) { + int32_t factionID{}; + bitStream.Read(factionID); + factions.push_back(factionID); + } + bitStream.Read(isSmashable); // This is an option later and also a flag at this spot + bitStream.Read(isDead); + bitStream.Read(isSmashed); + // if IsSmashable is true, read the next bits. + bitStream.Read(isModuleAssembly); + bitStream.Read(optionExplodeFactor); + bitStream.Read(explodeFactor); + + bitStream.Read(optionIsOnThreatList); + bitStream.Read(isThreatened); + EXPECT_EQ(optionStatusImmunityInfo, true); + EXPECT_EQ(ImmuneToBasicAttackCount, 0); + EXPECT_EQ(ImmuneToDamageOverTimeCount, 0); + EXPECT_EQ(ImmuneToKnockbackCount, 0); + EXPECT_EQ(ImmuneToInterruptCount, 0); + EXPECT_EQ(ImmuneToSpeedCount, 0); + EXPECT_EQ(ImmuneToImaginationGainCount, 0); + EXPECT_EQ(ImmuneToImaginationLossCount, 0); + EXPECT_EQ(ImmuneToQuickbuildInterruptCount, 0); + EXPECT_EQ(ImmuneToPullToPointCount, 0); + + EXPECT_EQ(optionStatsInfo, true); + EXPECT_EQ(currentHealth, 23); + EXPECT_EQ(maxHealth, 12345.0f); + EXPECT_EQ(currentArmor, 7); + EXPECT_EQ(maxArmor, 14.0f); + EXPECT_EQ(currentImagination, 6000); + EXPECT_EQ(maxImagination, 14000.0f); + EXPECT_EQ(damageAbsorptionPoints, 0.0f); + EXPECT_EQ(hasImmunity, false); + EXPECT_EQ(isGmImmune, false); + EXPECT_EQ(isShielded, false); + EXPECT_EQ(actualMaxHealth, 12345.0f); + EXPECT_EQ(actualMaxArmor, 14.0f); + EXPECT_EQ(actualMaxImagination, 14000.0f); + EXPECT_EQ(factionsSize, 2); + EXPECT_NE(std::find(factions.begin(), factions.end(), -1), factions.end()); + EXPECT_NE(std::find(factions.begin(), factions.end(), 6), factions.end()); + EXPECT_EQ(isSmashable, true); + EXPECT_EQ(isDead, false); + EXPECT_EQ(isSmashed, false); + EXPECT_EQ(isSmashable, true); // For the sake of readability with the struct viewers, we will test this twice since its used as an option here, but as a bool above. + EXPECT_EQ(isModuleAssembly, false); + EXPECT_EQ(optionExplodeFactor, true); + EXPECT_EQ(explodeFactor, 1.1f); + + EXPECT_EQ(optionIsOnThreatList, true); + EXPECT_EQ(isThreatened, false); + } + bitStream.Reset(); +} + +/** + * Test serialization of a DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentSerializeTest) { + bitStream.Reset(); + // Initialize some values to be not default so we can test a full serialization + destroyableComponent->SetMaxHealth(1233.0f); + + // Now we test a serialization for correctness. + destroyableComponent->Serialize(&bitStream, false, flags); + ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 422); + { + // Now read in the full serialized BitStream + bool optionStatsInfo{}; + uint32_t currentHealth{}; + float maxHealth{}; + uint32_t currentArmor{}; + float maxArmor{}; + uint32_t currentImagination{}; + float maxImagination{}; + uint32_t damageAbsorptionPoints{}; + bool hasImmunity{}; + bool isGmImmune{}; + bool isShielded{}; + float actualMaxHealth{}; + float actualMaxArmor{}; + float actualMaxImagination{}; + uint32_t factionsSize{}; + std::vector<int32_t> factions{}; + bool isSmashable{}; + bool optionIsOnThreatList{}; + bitStream.Read(optionStatsInfo); + bitStream.Read(currentHealth); + bitStream.Read(maxHealth); + bitStream.Read(currentArmor); + bitStream.Read(maxArmor); + bitStream.Read(currentImagination); + bitStream.Read(maxImagination); + bitStream.Read(damageAbsorptionPoints); + bitStream.Read(hasImmunity); + bitStream.Read(isGmImmune); + bitStream.Read(isShielded); + bitStream.Read(actualMaxHealth); + bitStream.Read(actualMaxArmor); + bitStream.Read(actualMaxImagination); + bitStream.Read(factionsSize); + for (uint32_t i = 0; i < factionsSize; i++) { + int32_t factionID{}; + bitStream.Read(factionID); + factions.push_back(factionID); + } + bitStream.Read(isSmashable); + + bitStream.Read(optionIsOnThreatList); + + EXPECT_EQ(optionStatsInfo, true); + EXPECT_EQ(currentHealth, 23); + EXPECT_EQ(maxHealth, 1233.0f); + EXPECT_EQ(currentArmor, 7); + EXPECT_EQ(maxArmor, 14.0f); + EXPECT_EQ(currentImagination, 6000); + EXPECT_EQ(maxImagination, 14000.0f); + EXPECT_EQ(damageAbsorptionPoints, 0.0f); + EXPECT_EQ(hasImmunity, false); + EXPECT_EQ(isGmImmune, false); + EXPECT_EQ(isShielded, false); + EXPECT_EQ(actualMaxHealth, 1233.0f); + EXPECT_EQ(actualMaxArmor, 14.0f); + EXPECT_EQ(actualMaxImagination, 14000.0f); + EXPECT_EQ(factionsSize, 2); + EXPECT_NE(std::find(factions.begin(), factions.end(), -1), factions.end()); + EXPECT_NE(std::find(factions.begin(), factions.end(), 6), factions.end()); + EXPECT_EQ(isSmashable, true); + + EXPECT_EQ(optionIsOnThreatList, false); // Always zero for now on serialization + } +} + +/** + * Test the Damage method of DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentDamageTest) { + // Do some actions + destroyableComponent->SetMaxHealth(100.0f); + destroyableComponent->SetHealth(100); + destroyableComponent->SetMaxArmor(0.0f); + destroyableComponent->Damage(10, LWOOBJID_EMPTY); + // Check that we take damage + ASSERT_EQ(destroyableComponent->GetHealth(), 90); + // Check that if we have armor, we take the correct amount of damage + destroyableComponent->SetMaxArmor(10.0f); + destroyableComponent->SetArmor(5); + destroyableComponent->Damage(10, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 85); + // Check that if we have damage absorption we take the correct damage + destroyableComponent->SetDamageToAbsorb(10); + destroyableComponent->Damage(9, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 85); + ASSERT_EQ(destroyableComponent->GetDamageToAbsorb(), 1); + destroyableComponent->Damage(6, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 80); + // Check that we take the correct reduced damage if we take reduced damage + destroyableComponent->SetDamageReduction(2); + destroyableComponent->Damage(7, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 75); + destroyableComponent->Damage(2, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 74); + ASSERT_EQ(destroyableComponent->GetDamageReduction(), 2); + destroyableComponent->SetDamageReduction(0); + // Check that blocking works + destroyableComponent->SetAttacksToBlock(1); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 74); + destroyableComponent->Damage(4, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + // Check that immunity works + destroyableComponent->SetIsImmune(true); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + ASSERT_TRUE(destroyableComponent->IsImmune()); + destroyableComponent->SetIsImmune(false); + destroyableComponent->SetIsGMImmune(true); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + ASSERT_TRUE(destroyableComponent->IsImmune()); + destroyableComponent->SetIsGMImmune(false); + // Check knockback immunity + destroyableComponent->SetIsShielded(true); + ASSERT_TRUE(destroyableComponent->IsKnockbackImmune()); + // Finally deal enough damage to kill the Entity + destroyableComponent->Damage(71, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 0); + // Now lets heal some stats + destroyableComponent->Heal(15); + ASSERT_EQ(destroyableComponent->GetHealth(), 15); + destroyableComponent->Heal(15000); + ASSERT_EQ(destroyableComponent->GetHealth(), 100); + destroyableComponent->Repair(10); + ASSERT_EQ(destroyableComponent->GetArmor(), 10); + destroyableComponent->Repair(15000); + ASSERT_EQ(destroyableComponent->GetArmor(), 10); + destroyableComponent->SetMaxImagination(100.0f); + destroyableComponent->SetImagination(0); + destroyableComponent->Imagine(99); + ASSERT_EQ(destroyableComponent->GetImagination(), 99); + destroyableComponent->Imagine(4); + ASSERT_EQ(destroyableComponent->GetImagination(), 100); +} + +TEST_F(DestroyableTest, DestroyableComponentFactionTest) { + ASSERT_TRUE(destroyableComponent->HasFaction(-1)); + ASSERT_TRUE(destroyableComponent->HasFaction(6)); +} + +TEST_F(DestroyableTest, DestroyableComponentValiditiyTest) { + auto* enemyEntity = new Entity(19, info); + auto* enemyDestroyableComponent = new DestroyableComponent(enemyEntity); + enemyEntity->AddComponent(eReplicaComponentType::DESTROYABLE, enemyDestroyableComponent); + enemyDestroyableComponent->AddFactionNoLookup(16); + destroyableComponent->AddEnemyFaction(16); + EXPECT_TRUE(destroyableComponent->IsEnemy(enemyEntity)); + EXPECT_FALSE(destroyableComponent->IsFriend(enemyEntity)); + delete enemyEntity; +} + +TEST_F(DestroyableTest, DestroyableComponentImmunityTest) { + // assert to show that they are empty + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // set them all to true (count 1) and check + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, true, true, true, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + + // remove them to check that they get removed properly + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // should not crash to remove them again + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // just do one + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // now stack it to 2 on basic attack + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // remove one and still shoudl be true + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // go back to 0 + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // check individual ones now + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, false, false, false, false, false, false, false, false); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, false, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, true, false, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, true, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, true, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, true, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, true, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, true, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, true, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, true, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, true, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, true, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, true, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, true, false, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, true, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, true, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, false, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, false, true); + +} + diff --git a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt new file mode 100644 index 00000000..54c43777 --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt @@ -0,0 +1,14 @@ +SET(DGAMEMESSAGES_TESTS + "GameMessageTests.cpp") + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM DGAMEMESSAGES_TESTS PREPEND "${thisFolderName}/") + +# Copy test files to testing directory +add_subdirectory(TestBitStreams) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) + +# Export to parent scope +set(DGAMEMESSAGES_TESTS ${DGAMEMESSAGES_TESTS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp new file mode 100644 index 00000000..631f0d2d --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp @@ -0,0 +1,226 @@ +#include "Action.h" +#include "AMFFormat.h" +#include "AMFDeserialize.h" +#include "GameMessages.h" +#include "GameDependencies.h" + +#include <gtest/gtest.h> + +// Message includes +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" + +class GameMessageTests: public GameDependenciesTest { +protected: + void SetUp() override { + SetUpDependencies(); + } + void TearDown() override { + TearDownDependencies(); + } + std::string ReadFromFile(std::string filename) { + std::ifstream file(filename, std::ios::binary); + std::string readFile; + while (file.good()) { + char readCharacter = file.get(); + readFile.push_back(readCharacter); + } + return readFile; + } + AMFArrayValue* ReadArrayFromBitStream(RakNet::BitStream* inStream) { + AMFDeserialize des; + AMFValue* readArray = des.Read(inStream); + EXPECT_EQ(readArray->GetValueType(), AMFValueType::AMFArray); + return static_cast<AMFArrayValue*>(readArray); + } +}; + +/** + * @brief Tests that the serialization struct BlueprintLoadItemResponse is serialized correctly + * + */ +TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) { + GameMessages::SendBlueprintLoadItemResponse(UNASSIGNED_SYSTEM_ADDRESS, true, 515, 990); + auto* bitStream = static_cast<dServerMock*>(Game::server)->GetMostRecentBitStream(); + ASSERT_NE(bitStream, nullptr); + ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 200); + // First read in the packets' header + uint8_t rakNetPacketId{}; + uint16_t remoteConnectionType{}; + uint32_t packetId{}; + uint8_t always0{}; + + bitStream->Read(rakNetPacketId); + bitStream->Read(remoteConnectionType); + bitStream->Read(packetId); + bitStream->Read(always0); + ASSERT_EQ(rakNetPacketId, 0x53); + ASSERT_EQ(remoteConnectionType, 0x05); + ASSERT_EQ(packetId, 0x17); + ASSERT_EQ(always0, 0x00); + + // Next read in packet data + + uint8_t bSuccess{}; // unsigned bool + LWOOBJID previousId{}; + LWOOBJID newId{}; + bitStream->Read(bSuccess); + bitStream->Read(previousId); + bitStream->Read(newId); + ASSERT_EQ(bSuccess, static_cast<uint8_t>(true)); + ASSERT_EQ(previousId, 515); + ASSERT_EQ(newId, 990); + + ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorAddStrip) { + auto data = ReadFromFile("addStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddStripMessage addStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(addStrip.GetPosition().GetX(), 50.65); + ASSERT_FLOAT_EQ(addStrip.GetPosition().GetY(), 178.05); + ASSERT_EQ(addStrip.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(addStrip.GetActionContext().GetStateId()), 0); + ASSERT_EQ(addStrip.GetBehaviorId(), -1); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetType(), "DropImagination"); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterName(), "Amount"); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterString(), ""); + ASSERT_FLOAT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterDouble(), 1.0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { + auto data = ReadFromFile("removeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveStripMessage removeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStripId()), 1); + ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStateId()), 0); + ASSERT_EQ(removeStrip.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { + auto data = ReadFromFile("mergeStrips"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MergeStripsMessage mergeStrips(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(mergeStrips.GetSourceActionContext().GetStripId(), 2); + ASSERT_EQ(mergeStrips.GetDestinationActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(mergeStrips.GetDstActionIndex(), 0); + ASSERT_EQ(mergeStrips.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { + auto data = ReadFromFile("splitStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + SplitStripMessage splitStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(splitStrip.GetBehaviorId(), -1); + + ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetX(), 275.65); + ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetY(), 28.7); + ASSERT_EQ(splitStrip.GetSourceActionContext().GetStripId(), 0); + ASSERT_EQ(splitStrip.GetDestinationActionContext().GetStripId(), 2); + ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(splitStrip.GetSrcActionIndex(), 1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { + auto data = ReadFromFile("updateStripUI"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetX(), 116.65); + ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetY(), 35.35); + ASSERT_EQ(updateStripUi.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(updateStripUi.GetActionContext().GetStateId()), 0); + ASSERT_EQ(updateStripUi.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorAddAction) { + auto data = ReadFromFile("addAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddActionMessage addAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(addAction.GetActionIndex(), 3); + ASSERT_EQ(addAction.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(addAction.GetActionContext().GetStateId()), 0); + ASSERT_EQ(addAction.GetAction().GetType(), "DoDamage"); + ASSERT_EQ(addAction.GetAction().GetValueParameterName(), ""); + ASSERT_EQ(addAction.GetAction().GetValueParameterString(), ""); + ASSERT_EQ(addAction.GetAction().GetValueParameterDouble(), 0.0); + ASSERT_EQ(addAction.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { + auto data = ReadFromFile("migrateActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MigrateActionsMessage migrateActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1); + ASSERT_EQ(migrateActions.GetDstActionIndex(), 2); + ASSERT_EQ(migrateActions.GetSourceActionContext().GetStripId(), 1); + ASSERT_EQ(migrateActions.GetDestinationActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(migrateActions.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { + auto data = ReadFromFile("rearrangeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2); + ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1); + ASSERT_EQ(rearrangeStrip.GetActionContext().GetStripId(), 0); + ASSERT_EQ(rearrangeStrip.GetBehaviorId(), -1); + ASSERT_EQ(static_cast<uint32_t>(rearrangeStrip.GetActionContext().GetStateId()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorAdd) { + auto data = ReadFromFile("add"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddMessage add(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(add.GetBehaviorId(), 10446); + ASSERT_EQ(add.GetBehaviorIndex(), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { + auto data = ReadFromFile("removeActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveActionsMessage removeActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(removeActions.GetBehaviorId(), -1); + ASSERT_EQ(removeActions.GetActionIndex(), 1); + ASSERT_EQ(removeActions.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(removeActions.GetActionContext().GetStateId()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRename) { + auto data = ReadFromFile("rename"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RenameMessage rename(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rename.GetName(), "test"); + ASSERT_EQ(rename.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateAction) { + auto data = ReadFromFile("updateAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateActionMessage updateAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(updateAction.GetAction().GetType(), "FlyDown"); + ASSERT_EQ(updateAction.GetAction().GetValueParameterName(), "Distance"); + ASSERT_EQ(updateAction.GetAction().GetValueParameterString(), ""); + ASSERT_EQ(updateAction.GetAction().GetValueParameterDouble(), 50.0); + ASSERT_EQ(updateAction.GetBehaviorId(), -1); + ASSERT_EQ(updateAction.GetActionIndex(), 1); + ASSERT_EQ(updateAction.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(updateAction.GetActionContext().GetStateId()), 0); +} diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt new file mode 100644 index 00000000..e32ed3ef --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt @@ -0,0 +1,24 @@ +set(GAMEMESSAGE_TESTBITSTREAMS +"sendBehaviorListToClient" +"modelTypeChanged" +"toggleExecutionUpdates" +"addStrip" +"removeStrip" +"mergeStrips" +"splitStrip" +"updateStripUI" +"addAction" +"migrateActions" +"rearrangeStrip" +"add" +"removeActions" +"rename" +"updateAction" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") + +# Export our list of files +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/add b/tests/dGameTests/dGameMessagesTests/TestBitStreams/add new file mode 100644 index 00000000..13c0dd92 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/add differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction new file mode 100644 index 00000000..d91d0ee4 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip new file mode 100644 index 00000000..60ba6521 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips b/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips new file mode 100644 index 00000000..062fd10b Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions b/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions new file mode 100644 index 00000000..217f44d9 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged b/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged new file mode 100644 index 00000000..ef282ce2 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip new file mode 100644 index 00000000..06dda90b Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions new file mode 100644 index 00000000..56e158e5 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip new file mode 100644 index 00000000..46ca0640 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename new file mode 100644 index 00000000..bc8827dc Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient b/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient new file mode 100644 index 00000000..fcca696d Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip new file mode 100644 index 00000000..a23c1682 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates b/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates new file mode 100644 index 00000000..02a72181 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction new file mode 100644 index 00000000..e007d5e6 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI new file mode 100644 index 00000000..7d0eed92 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI differ diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index ce24ecd3..978c5532 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,206 +1,50 @@ -# Source Code for raknet -file( -GLOB SOURCES_RAKNET -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/raknet/Source/*.cpp -) - # Source Code for recast -file( -GLOB SOURCES_RECAST -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Recast/Source/*.cpp -) - -# Source Code for detour -file( -GLOB SOURCES_DETOUR -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Detour/Source/*.cpp -) +add_subdirectory(recastnavigation) +# Turn off tinyxml2 testing +set(tinyxml2_BUILD_TESTING OFF) # Source Code for tinyxml2 +add_subdirectory(tinyxml2) + +# Source Code for libbcrypt. Uses a file glob instead to get around Windows build issues. file( -GLOB SOURCES_TINYXML2 -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/tinyxml2/tinyxml2.cpp + GLOB SOURCES_LIBBCRYPT + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c ) +add_library(bcrypt ${SOURCES_LIBBCRYPT}) -# Source Code for libbcrypt -file( -GLOB SOURCES_LIBBCRYPT -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c -${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c -) +# Source code for sqlite +add_subdirectory(SQLite) -file( -GLOB SOURCES_SQLITE3 -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.cpp -${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.c -) +# MariaDB C++ Connector +include(CMakeMariaDBLists.txt) -# mariadb connector cpp -# On Windows ClangCL can't compile the connector from source but can link to an msvc compiled one, -# so prefer the prebuilt binaries unless MARIADB_BUILD_SOURCE is specified -if(WIN32 AND NOT MARIADB_BUILD_SOURCE) - set(MARIADB_MSI_DIR "${PROJECT_BINARY_DIR}/msi") - set(MARIADB_CONNECTOR_DIR "${PROJECT_BINARY_DIR}/mariadbcpp") - set(MARIADB_C_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB Connector C 64-bit") - set(MARIADB_CPP_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB C++ Connector 64-bit") +# Create our third party library objects +add_subdirectory(raknet) - file(MAKE_DIRECTORY "${MARIADB_MSI_DIR}") - file(MAKE_DIRECTORY "${MARIADB_CONNECTOR_DIR}") +# Download Backtrace if configured +if(UNIX AND NOT APPLE) + include(FetchContent) + if (__include_backtrace__ AND __compile_backtrace__) + FetchContent_Declare( + backtrace + GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git + ) - if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" ) - message("Downloading mariadb connector/c") - file(DOWNLOAD https://dlm.mariadb.com/1936366/connectors/c/connector-c-3.2.5/mariadb-connector-c-3.2.5-win64.msi - "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" - EXPECTED_HASH MD5=09d418c290109068a5bea136dafca36b) + FetchContent_MakeAvailable(backtrace) + + if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs) + set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind") + + execute_process( + COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}" + ) + endif() + + link_directories(${backtrace_SOURCE_DIR}/.libs/) + include_directories(${backtrace_SOURCE_DIR}) endif() - - if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" ) - message("Downloading mariadb connector/c++") - file(DOWNLOAD https://dlm.mariadb.com/1683453/connectors/cpp/connector-cpp-1.0.1/mariadb-connector-cpp-1.0.1-win64.msi - "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" - EXPECTED_HASH MD5=548e743fbf067d21d42b81d958bf4ed7) - endif() - - - file(TO_NATIVE_PATH "${MARIADB_CONNECTOR_DIR}" MSIEXEC_TARGETDIR) - # extract msi files without installing to users system - if(NOT EXISTS "${MARIADB_C_CONNECTOR_DIR}") - file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" MSI_DIR) - execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) - endif() - - if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}") - file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" MSI_DIR) - execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) - endif() - - set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll") - set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib") - set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb") - - add_custom_target(mariadb_connector_cpp) - add_custom_command(TARGET mariadb_connector_cpp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll" - "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll" - "${PROJECT_BINARY_DIR}") - - # MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories, - # so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory. - # Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable - add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION}) - add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin") -else() # Build from source - - include(ExternalProject) - if(WIN32) - set(MARIADB_EXTRA_COMPILE_FLAGS /EHsc) - set(MARIADB_EXTRA_CMAKE_ARGS -DWITH_MSI=OFF) - elseif(APPLE) - set(MARIADB_EXTRA_COMPILE_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0) - set(MARIADB_EXTRA_CMAKE_ARGS -DWITH_EXTERNAL_ZLIB=ON -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}) - else() - set(MARIADB_EXTRA_COMPILE_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0) - endif() - - ExternalProject_Add(mariadb_connector_cpp - SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp - CMAKE_ARGS "-DCMAKE_CXX_FLAGS:STRING= ${MARIADB_EXTRA_COMPILE_FLAGS}" - -DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN} - -DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory - -DINSTALL_PLUGINDIR=plugin - ${MARIADB_EXTRA_CMAKE_ARGS} - PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp" - BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${__maria_db_connector_compile_jobs__} - INSTALL_COMMAND "") - - ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR) - - if(WIN32) - set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll) - set(MARIADB_PLUGIN_SUFFIX .dll) - set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib") - - # When built from source windows only seems to check same folder as exe instead specified folder, so use - # environment variable to force it - add_link_options(/DELAYLOAD:mariadbcpp.dll) - add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin") - else() - set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(MARIADB_PLUGIN_SUFFIX .so) - endif() - - get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - if(isMultiConfig) - set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}") - set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>") - set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo") - message(STATUS "1 ${CMAKE_SOURCE_DIR}") - else() - set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}") - set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}") - set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb") - endif() - - set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/") - - add_custom_command(TARGET mariadb_connector_cpp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - ${BINARY_DIR}/mariadbcpp/plugin - ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} - - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${MARIADB_SHARED_LIBRARY_LOCATION} - ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} - - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX} - ${BINARY_DIR}/mariadbcpp/plugin) endif() - -# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests. -if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") - file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") -endif() - -add_library(mariadbConnCpp SHARED IMPORTED GLOBAL) -set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION}) -if(WIN32) - set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION}) -endif() -target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR}) -add_dependencies(mariadbConnCpp mariadb_connector_cpp) - -# 3rdparty static libraries: -#add_library(zlib ${SOURCES_ZLIB}) -add_library(raknet ${SOURCES_RAKNET}) -add_library(tinyxml2 ${SOURCES_TINYXML2}) -add_library(detour ${SOURCES_DETOUR}) -add_library(recast ${SOURCES_RECAST}) -add_library(libbcrypt ${SOURCES_LIBBCRYPT}) -add_library(sqlite3 ${SOURCES_SQLITE3}) - -if(UNIX) -target_link_libraries(sqlite3 pthread dl m) - -# -Wno-unused-result -Wno-unknown-pragmas -fpermissive -target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized") -target_compile_options(raknet PRIVATE "-Wno-write-strings" "-Wformat-overflow=0" "-Wformat=0") -target_compile_options(libbcrypt PRIVATE "-Wno-implicit-function-declaration" "-Wno-int-conversion") -endif(UNIX) \ No newline at end of file diff --git a/thirdparty/CMakeMariaDBLists.txt b/thirdparty/CMakeMariaDBLists.txt new file mode 100644 index 00000000..cb1e28e7 --- /dev/null +++ b/thirdparty/CMakeMariaDBLists.txt @@ -0,0 +1,149 @@ +# mariadb connector cpp +# On Windows ClangCL can't compile the connector from source but can link to an msvc compiled one, +# so prefer the prebuilt binaries unless MARIADB_BUILD_SOURCE is specified +if(WIN32 AND NOT MARIADB_BUILD_SOURCE) + set(MARIADB_MSI_DIR "${PROJECT_BINARY_DIR}/msi") + set(MARIADB_CONNECTOR_DIR "${PROJECT_BINARY_DIR}/mariadbcpp") + set(MARIADB_C_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB Connector C 64-bit") + set(MARIADB_CPP_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB C++ Connector 64-bit") + + file(MAKE_DIRECTORY "${MARIADB_MSI_DIR}") + file(MAKE_DIRECTORY "${MARIADB_CONNECTOR_DIR}") + + if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" ) + message("Downloading mariadb connector/c") + file(DOWNLOAD https://dlm.mariadb.com/1936366/connectors/c/connector-c-3.2.5/mariadb-connector-c-3.2.5-win64.msi + "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" + EXPECTED_HASH MD5=09d418c290109068a5bea136dafca36b) + endif() + + if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" ) + message("Downloading mariadb connector/c++") + file(DOWNLOAD https://dlm.mariadb.com/1683453/connectors/cpp/connector-cpp-1.0.1/mariadb-connector-cpp-1.0.1-win64.msi + "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" + EXPECTED_HASH MD5=548e743fbf067d21d42b81d958bf4ed7) + endif() + + + file(TO_NATIVE_PATH "${MARIADB_CONNECTOR_DIR}" MSIEXEC_TARGETDIR) + # extract msi files without installing to users system + if(NOT EXISTS "${MARIADB_C_CONNECTOR_DIR}") + file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" MSI_DIR) + execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) + endif() + + if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}") + file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" MSI_DIR) + execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) + endif() + + set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll") + set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib") + set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb") + + add_custom_target(mariadb_connector_cpp) + add_custom_command(TARGET mariadb_connector_cpp POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll" + "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll" + "${PROJECT_BINARY_DIR}") + + # MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories, + # so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory. + # Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable + add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION}) + add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin") +else() # Build from source + + include(ExternalProject) + if(WIN32) + set(MARIADB_EXTRA_CMAKE_ARGS + -DCMAKE_C_FLAGS=/w # disable zlib warnings + -DCMAKE_CXX_FLAGS=/EHsc + -DWITH_MSI=OFF) + elseif(APPLE) + set(MARIADB_EXTRA_CMAKE_ARGS + -DWITH_EXTERNAL_ZLIB=ON + -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} + -DCMAKE_C_FLAGS=-w # disable zlib warnings + -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0) + else() + set(MARIADB_EXTRA_CMAKE_ARGS + -DCMAKE_C_FLAGS=-w # disable zlib warnings + -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0) + endif() + + ExternalProject_Add(mariadb_connector_cpp + SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp + CMAKE_ARGS -Wno-dev + -DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN} + -DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory + -DINSTALL_PLUGINDIR=plugin + ${MARIADB_EXTRA_CMAKE_ARGS} + PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp" + BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${__maria_db_connector_compile_jobs__} + INSTALL_COMMAND "") + + ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR) + + if(WIN32) + set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll) + set(MARIADB_PLUGIN_SUFFIX .dll) + set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib") + + # When built from source windows only seems to check same folder as exe instead specified folder, so use + # environment variable to force it + add_link_options(/DELAYLOAD:mariadbcpp.dll) + add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin") + else() + set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(MARIADB_PLUGIN_SUFFIX .so) + endif() + + get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(isMultiConfig) + set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}") + set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>") + set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo") + else() + set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}") + set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}") + set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb") + endif() + + set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/") + + add_custom_command(TARGET mariadb_connector_cpp POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + ${BINARY_DIR}/mariadbcpp/plugin + ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} + + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${MARIADB_SHARED_LIBRARY_LOCATION} + ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} + + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX} + ${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX} + ${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX} + ${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX} + ${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX} + ${BINARY_DIR}/mariadbcpp/plugin) +endif() + +# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests. +if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") + file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") +endif() + +# Create mariadb connector library object +add_library(mariadbConnCpp SHARED IMPORTED GLOBAL) +set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION}) + +if(WIN32) + set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION}) +endif() + +# Add directories to include lists +target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR}) +add_dependencies(mariadbConnCpp mariadb_connector_cpp) diff --git a/thirdparty/LUnpack b/thirdparty/LUnpack deleted file mode 160000 index f8d7e442..00000000 --- a/thirdparty/LUnpack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f8d7e442a78910b298fe1cd5780f07c9c9285b8c diff --git a/thirdparty/SQLite/CMakeLists.txt b/thirdparty/SQLite/CMakeLists.txt new file mode 100644 index 00000000..aa7a6423 --- /dev/null +++ b/thirdparty/SQLite/CMakeLists.txt @@ -0,0 +1,14 @@ +set (SQLITE3_SOURCES + "CppSQLite3.cpp" + "sqlite3.c" +) + +add_library (sqlite3 ${SQLITE3_SOURCES}) + +if(UNIX) + # Add warning disable flags and link Unix libraries to sqlite3 + target_link_libraries(sqlite3 pthread dl m) + + # -Wno-unused-result -Wno-unknown-pragmas -fpermissive + target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized") +endif() diff --git a/thirdparty/cpplinq/cpplinq.hpp b/thirdparty/cpplinq/cpplinq.hpp index d25cde85..ae9169d9 100644 --- a/thirdparty/cpplinq/cpplinq.hpp +++ b/thirdparty/cpplinq/cpplinq.hpp @@ -14,6 +14,8 @@ #ifndef CPPLINQ__HEADER_GUARD # define CPPLINQ__HEADER_GUARD +#undef min +#undef max #define NOMINMAX // ---------------------------------------------------------------------------- diff --git a/thirdparty/docker-utils b/thirdparty/docker-utils deleted file mode 160000 index 3f0129e0..00000000 --- a/thirdparty/docker-utils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3f0129e0939ce5ccf41f0808dcbbe71a6243e37f diff --git a/thirdparty/raknet/CMakeLists.txt b/thirdparty/raknet/CMakeLists.txt index 8d90f329..417e24dd 100644 --- a/thirdparty/raknet/CMakeLists.txt +++ b/thirdparty/raknet/CMakeLists.txt @@ -1,6 +1,4 @@ - - -PROJECT(RakNetStaticLib) +project(RakNetStaticLib) SET(RAKNET_SOURCES @@ -27,7 +25,7 @@ Source/FileList.cpp Source/RakMemoryOverride.cpp Source/ Source/FileListTransfer.cpp Source/RakNetCommandParser.cpp Source/TCPInterface.cpp Source/FileOperations.cpp Source/RakNetStatistics.cpp Source/TelnetTransport.cpp Source/_FindFirst.cpp Source/RakNetTransport.cpp Source/ThreadsafePacketLogger.cpp -Source/RakThread.cpp Source/SuperFastHash.cpp Source/Itoa.cpp +Source/RakThread.cpp Source/SuperFastHash.cpp Source/Itoa.cpp Source/HTTPConnection.cpp ) @@ -70,18 +68,25 @@ Source/DS_Tree.h Source/RakNetCommandParser.h S Source/DS_WeightedGraph.h Source/RakNetDefines.h Source/ThreadsafePacketLogger.h Source/EmailSender.h Source/RakNetStatistics.h Source/TransportInterface.h Source/EpochTimeToString.h Source/RakNetTransport.h Source/Types.h -Source/RakThread.h Source/SuperFastHash.h Source/Itoa.h -Source/HTTPConnection.h Kbhit.h\ +Source/RakThread.h Source/SuperFastHash.h Source/Itoa.h +Source/HTTPConnection.h Kbhit.h ) -ADD_LIBRARY(RakNet STATIC ${RAKNET_SOURCES}) +add_library(raknet STATIC ${RAKNET_SOURCES}) +target_compile_options(raknet PRIVATE + $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: + -w> + $<$<CXX_COMPILER_ID:MSVC>: + /w>) +if(WIN32) + # Link Win Sockets 2 to RakNet + target_link_libraries(raknet ws2_32) +endif() -INSTALL(TARGETS RakNet +install(TARGETS raknet DESTINATION lib) -INSTALL(FILES ${RAKNET_HEADERS} +install(FILES ${RAKNET_HEADERS} DESTINATION include/raknet) - - diff --git a/thirdparty/raknet/Source/SocketLayer.cpp b/thirdparty/raknet/Source/SocketLayer.cpp index b6af8751..6cb4f7c6 100644 --- a/thirdparty/raknet/Source/SocketLayer.cpp +++ b/thirdparty/raknet/Source/SocketLayer.cpp @@ -417,8 +417,14 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns assert( 0 ); #endif - *errorCode = -1; - return -1; + //*errorCode = -1; +#ifdef __linux__ + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: empty datagram from %s", str); +#endif + //return -1; + return 0; } if ( len > 0 ) @@ -479,6 +485,47 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns } #endif } +#elif defined(__linux__) + if (len < -1) + { + printf("[RakNet] SocketLayer::RecvFrom: Unexpected return value."); + return -1; + } + + int local_errno = errno; + if (local_errno == EAGAIN || local_errno == EWOULDBLOCK) + { + return 0; // no data + } + + if (local_errno == EINTR) + { + printf("[RakNet] SocketLayer::RecvFrom: The receive was interrupted by delivery of a signal before any data were available."); + return 0; // log, but ignore + } + + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: Error receiving data from %s", str); + + switch (local_errno) { + case EINVAL: + printf("[RakNet] SocketLayer::RecvFrom: Invalid argument passed."); break; + case ENOMEM: + case ENOBUFS: + printf("[RakNet] SocketLayer::RecvFrom: Could not allocate memory for recvmsg()."); break; + case EFAULT: + printf("[RakNet] SocketLayer::RecvFrom: The receive buffer pointer(s) point outside the process's address space."); break; + case EBADF: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd is an invalid descriptor."); break; + case ENOTSOCK: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd does not refer to a socket."); break; + case EPIPE: + printf("[RakNet] SocketLayer::RecvFrom: The connection was unexpectedly closed or shut down by the other end. "); break; + default: + printf("[RakNet] SocketLayer::RecvFrom: Unknown Error %d", local_errno); break; + } + return -1; #endif } diff --git a/vanity/CREDITS.md b/vanity/CREDITS.md index e130cfb3..6780cff7 100644 --- a/vanity/CREDITS.md +++ b/vanity/CREDITS.md @@ -1,18 +1,17 @@ # CREDITS -## Developers +## DLU Team DarwinAnim8or (Max) Wincent01 Mick averysumner (codeshaunted) Jon002 Jonny -EmosewaMC -Jettford - -## Research & Tooling Xiphoseer lcdr - -## Community Management +Aaron K. Neal + +## Active Contributors +EmosewaMC +Jettford \ No newline at end of file diff --git a/vanity/NPC.xml b/vanity/NPC.xml index 3bb5ae9f..2311ab46 100644 --- a/vanity/NPC.xml +++ b/vanity/NPC.xml @@ -17,6 +17,19 @@ </locations> </zone> </npc> + <npc name="EmosewaMC - Quickbuilder" lot="6738"> + <equipment>12947, 12949, 12962, 12963</equipment> + <phrases> + <phrase>I hope quickbulds are still working!</phrase> + <phrase>Be careful crossing the gap!</phrase> + <phrase>Have The Maelstrom stopped going invisible?</phrase> + </phrases> + <zone id="1800"> + <locations> + <location x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" /> + </locations> + </zone> + </npc> <npc name="Neal - Paradox Scout" lot="6738"> <equipment>9950, 9944, 14102, 14092</equipment> <phrases>