mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-30 08:07:46 +00:00
Merge https://github.com/SapphireMordred/Sapphire into SQL_REWRITE_OWN
This commit is contained in:
commit
14c8d674cc
49 changed files with 652 additions and 238 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -97,3 +97,5 @@ src/libraries/external/boost_*
|
||||||
*.iobj
|
*.iobj
|
||||||
*.filters
|
*.filters
|
||||||
|
|
||||||
|
# sapphire version
|
||||||
|
src/servers/Server_Common/Version\.cpp
|
||||||
|
|
|
@ -31,6 +31,14 @@ include( "cmake/boost.cmake" )
|
||||||
include( "cmake/mysql.cmake" )
|
include( "cmake/mysql.cmake" )
|
||||||
include( "cmake/compiler.cmake" )
|
include( "cmake/compiler.cmake" )
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# Git #
|
||||||
|
##############################
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||||
|
git_describe(VERSION --tags --dirty=-d)
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp" @ONLY)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Common include folders
|
# Common include folders
|
||||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/external/ChaiScript-6.0.0/include/")
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/external/ChaiScript-6.0.0/include/")
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,40 +1,42 @@
|
||||||
# Sapphire - FINAL FANTASY XIV Server Emulator
|
# Sapphire - FINAL FANTASY XIV Server Emulator
|
||||||
[](https://discord.gg/KfrZCkx)
|
[](https://discord.gg/KfrZCkx)
|
||||||
[](https://travis-ci.org/SapphireMordred/Sapphire)
|
[](https://travis-ci.org/SapphireMordred/Sapphire)
|
||||||
|
[](https://ci.appveyor.com/project/SapphireMordred/Sapphire)
|
||||||

|

|
||||||
|
|
||||||
Sapphire is a FINAL FANTASY XIV 4.0+ Server Emulator currently in development.
|
Sapphire is a FINAL FANTASY XIV 4.0+ Server Emulator currently in development.
|
||||||
|
|
||||||
## Features
|
Sapphire is a **research project** to learn how retail servers work and currently not production code; at this time it is **insecure** (use throwaway passwords for accounts) and you should expect a lot of things unimplemented or broken (of course contributions are always welcome).
|
||||||
|
|
||||||
* Fully working base world servers, including character creation, chat, player interaction, etc.
|
|
||||||
* Basic action/battle system
|
|
||||||
* Teleports, discovery
|
|
||||||
* NPCs, enemies
|
|
||||||
* Support for most Quest types(instanced content planned, to be added later)
|
|
||||||
* Content scripting via ChaiScript
|
|
||||||
* Retail GM commands working
|
|
||||||
|
|
||||||
## Dependencies + Compiling
|
## Dependencies + Compiling
|
||||||
Sapphire requires the following software:
|
Sapphire requires the following software:
|
||||||
|
|
||||||
| *Name* | *Windows* | *Linux* |
|
| *Name* | *Windows* | *Linux* |
|
||||||
| ------ | --------- | ------- |
|
| ------ | --------- | ------- |
|
||||||
| CMake 2.6+ and C++14 capable compiler | [Visual Studio 2017](https://www.visualstudio.com/) | Your favorite C++14 capable compiler |
|
| CMake 2.6+ and C++14 capable compiler | [Visual Studio 2017](https://www.visualstudio.com/) | `gcc 4.9` and `g++ 4.9` or newer |
|
||||||
| Boost 1.63.0 | [Win32 precompiled binaries](https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/boost_1_63_0-msvc-14.0-32.exe/download) | Boost libraries from your distribution's package manager |
|
| Boost 1.63.0 | [Win32 precompiled binaries](https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/boost_1_63_0-msvc-14.0-32.exe/download) | Boost libraries from your distribution's package manager |
|
||||||
| MySQL Server 5.7 | [Official Site](https://dev.mysql.com/downloads/mysql/) | MySQL server from your distribution's package manager |
|
| MySQL Server 5.7 | [Official Site](https://dev.mysql.com/downloads/mysql/) | MySQL server from your distribution's package manager |
|
||||||
| C# Compiler(used for various tools) | [Visual Studio 2017](https://www.visualstudio.com/) \| [Mono](http://www.mono-project.com/) | [Mono](http://www.mono-project.com/) from your distribution's package manager |
|
| C# Compiler(used for various tools) | [Visual Studio 2017](https://www.visualstudio.com/) \| [Mono](http://www.mono-project.com/) | [Mono](http://www.mono-project.com/) from your distribution's package manager |
|
||||||
|
|
||||||
**Windows**
|
**Windows**
|
||||||
Set the environment variables ``BOOST_ROOT_DIR`` and ``BOOST_LIB_DIR`` to ``[boost main folder]`` and ``[boost main folder]/lib32-msvc-14.0`` respectively **or** copy your boost installation into the project's ``src/lib`` folder.
|
Set the environment variables ``BOOST_ROOT_DIR`` and ``BOOST_LIB_DIR`` to ``[boost main folder]`` and ``[boost main folder]/lib32-msvc-14.0`` respectively **or** copy your boost installation into the project's ``src/lib`` folder.
|
||||||
|
|
||||||
|
Visual Studio 2017 users: open `Visual Studio Installer` and ensure `Individual Components > SDKs, libraries, and frameworks > Windows Universal C Runtime` is installed. You may also need to install `Individual Components > Compilers, build tools, and runtimes > VC++ 2015.3 v140 toolset for desktop (x86, 64)`.
|
||||||
|
|
||||||
|
To enable [Edit and Continue](https://msdn.microsoft.com/en-us/library/esaeyddf.aspx) ensure you define `-DCMAKE_BUILD_TYPE="Debug"` when generating with CMake.
|
||||||
|
|
||||||
|
If you installed CMake outside of Visual Studio and have it in your `PATH` environment variable, navigate to Sapphire folder and `cmake -DCMAKE_BUILD_TYPE="Debug" && cmake --build .`.
|
||||||
|
|
||||||
|
Otherwise:
|
||||||
* In *Visual Studio 2017*: Open the project via ``File`` > ``Open`` > ``Folder`` and wait, till CMake automatically finishes cache generation. Right click any CMakeLists.txt and select build to build a application.
|
* In *Visual Studio 2017*: Open the project via ``File`` > ``Open`` > ``Folder`` and wait, till CMake automatically finishes cache generation. Right click any CMakeLists.txt and select build to build a application.
|
||||||
To configure debug startup parameters, select ``Debug and Launch settings``, the application you want to set up parameters for, and add a ``args`` json array containing your launch parameters in ``configurations``.
|
To configure debug startup parameters, select ``Debug and Launch settings``, the application you want to set up parameters for, and add a ``args`` json array containing your launch parameters in ``configurations``.
|
||||||
If Visual Studio fails to generate a CMake Cache or does not show options to build, make sure that the newest version of it is installed and all environment variables are set correctly. Keep in mind that generating a cache can take a while on some machines.
|
If Visual Studio fails to generate a CMake Cache or does not show options to build, make sure that the newest version of it is installed and all environment variables are set correctly. Keep in mind that generating a cache can take a while on some machines.
|
||||||
* In *Visual Studio 2015*: Generate a Visual Studio project via CMake: ``cmake -G "Visual Studio 14 2015"`` and open it as a normal solution in Visual Studio.
|
|
||||||
|
The solution `Sapphire.sln` is also generated in the main Sapphire folder.
|
||||||
|
|
||||||
**Linux**
|
**Linux**
|
||||||
Generate a cache with CMake and use your favorite C++14 capable compiler to compile those wonderful lines of code into binaries with ``make``.
|
`cmake . -DSAPPHIRE_BOOST_VER="your.boost.ver" && make -j JOBS` where `JOBS` is number of cores on your system.
|
||||||
Sapphire is **not** currently configured to compile in 64bit. Make sure that all libraries have their ``:i386`` versions installed.
|
`-j JOBS` can be omitted if your system lacks resources (spoiler: your system probably lacks resources if running on 1GB RAM or lower, or if the build fails due to being out of memory)
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
|
168
cmake/GetGitRevisionDescription.cmake
Normal file
168
cmake/GetGitRevisionDescription.cmake
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright Iowa State University 2009-2010.
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||||
|
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||||
|
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||||
|
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||||
|
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||||
|
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||||
|
endwhile()
|
||||||
|
# check if this is a submodule
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake"
|
||||||
|
@ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||||
|
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(COMMAND
|
||||||
|
"${GIT_EXECUTABLE}"
|
||||||
|
describe
|
||||||
|
${hash}
|
||||||
|
${ARGN}
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE
|
||||||
|
res
|
||||||
|
OUTPUT_VARIABLE
|
||||||
|
out
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var} "${out}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var} "${out}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(COMMAND
|
||||||
|
"${GIT_EXECUTABLE}"
|
||||||
|
diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE
|
||||||
|
res
|
||||||
|
OUTPUT_VARIABLE
|
||||||
|
out
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var} "CLEAN" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var} "DIRTY" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
41
cmake/GetGitRevisionDescription.cmake.in
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright Iowa State University 2009-2010.
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
|
@ -11,7 +11,7 @@ class skillDef_121Def
|
||||||
def onFinish( player, target )
|
def onFinish( player, target )
|
||||||
{
|
{
|
||||||
player.handleScriptSkill( STD_DAMAGE, 121, 50, 0, target );
|
player.handleScriptSkill( STD_DAMAGE, 121, 50, 0, target );
|
||||||
target.addStatusEffectByIdIfNotExist(143, 20000, 0);
|
target.addStatusEffectByIdIfNotExist(143, 20000, player, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
18
scripts/chai/skill/cnj/skillDef_124.chai
Normal file
18
scripts/chai/skill/cnj/skillDef_124.chai
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Skill Name: Medica
|
||||||
|
// Skill ID: 124
|
||||||
|
|
||||||
|
class skillDef_124Def
|
||||||
|
{
|
||||||
|
def skillDef_124Def()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def onFinish( player, target )
|
||||||
|
{
|
||||||
|
player.handleScriptSkill( STD_HEAL, 124, 300, 0, player );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
GLOBAL skillDef_124 = skillDef_124Def();
|
|
@ -10,7 +10,7 @@ class skillDef_125Def
|
||||||
|
|
||||||
def onFinish( player, target )
|
def onFinish( player, target )
|
||||||
{
|
{
|
||||||
target.addStatusEffectByIdIfNotExist( 148, 60000, 0 );
|
target.addStatusEffectByIdIfNotExist( 148, 60000, player, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ class skillDef_128Def
|
||||||
|
|
||||||
def onFinish( player, target )
|
def onFinish( player, target )
|
||||||
{
|
{
|
||||||
target.addStatusEffectByIdIfNotExist(3, 30000, 0);
|
target.addStatusEffectByIdIfNotExist( 3, 30000, player, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ class skillDef_132Def
|
||||||
def onFinish( player, target )
|
def onFinish( player, target )
|
||||||
{
|
{
|
||||||
player.handleScriptSkill( STD_DAMAGE, 132, 50, 0, target );
|
player.handleScriptSkill( STD_DAMAGE, 132, 50, 0, target );
|
||||||
target.addStatusEffectByIdIfNotExist( 143, 20000, 0 );
|
target.addStatusEffectByIdIfNotExist( 143, 20000, player, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
19
scripts/chai/skill/cnj/skillDef_133.chai
Normal file
19
scripts/chai/skill/cnj/skillDef_133.chai
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Skill Name: Medica II
|
||||||
|
// Skill ID: 133
|
||||||
|
|
||||||
|
class skillDef_133Def
|
||||||
|
{
|
||||||
|
def skillDef_133Def()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def onFinish( player, target )
|
||||||
|
{
|
||||||
|
player.handleScriptSkill( STD_HEAL, 133, 200, 0, player );
|
||||||
|
target.addStatusEffectByIdIfNotExist( 150, 30000, player, 50 );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
GLOBAL skillDef_133 = skillDef_133Def();
|
|
@ -10,7 +10,7 @@ class skillDef_3Def
|
||||||
|
|
||||||
def onFinish( player, target )
|
def onFinish( player, target )
|
||||||
{
|
{
|
||||||
player.addStatusEffectById(50, 20000, 30);
|
player.addStatusEffectById(50, 20000, player, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS `zonepositions` (
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
|
||||||
|
|
||||||
-- Dumping data for table sapphire.zonepositions: 157 rows
|
-- Dumping data for table sapphire.zonepositions: 186 rows
|
||||||
DELETE FROM `zonepositions`;
|
DELETE FROM `zonepositions`;
|
||||||
/*!40000 ALTER TABLE `zonepositions` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `zonepositions` DISABLE KEYS */;
|
||||||
INSERT INTO `zonepositions` (`id`, `target_zone_id`, `pos_x`, `pos_y`, `pos_z`, `pos_o`, `radius`) VALUES
|
INSERT INTO `zonepositions` (`id`, `target_zone_id`, `pos_x`, `pos_y`, `pos_z`, `pos_o`, `radius`) VALUES
|
||||||
|
@ -192,7 +192,27 @@ INSERT INTO `zonepositions` (`id`, `target_zone_id`, `pos_x`, `pos_y`, `pos_z`,
|
||||||
(4203092, 129, -213.582, 16, 48.801, -0.006, 2),
|
(4203092, 129, -213.582, 16, 48.801, -0.006, 2),
|
||||||
(6390356, 128, -11.685, 91.499, -13.191, -0.377, 2),
|
(6390356, 128, -11.685, 91.499, -13.191, -0.377, 2),
|
||||||
(4170499, 134, -39.562, 36.039, 152.972, 2.041, 2),
|
(4170499, 134, -39.562, 36.039, 152.972, 2.041, 2),
|
||||||
(4170784, 135, -39.271, 71.504, 116.516, 1.587, 2);
|
(4170784, 135, -39.271, 71.504, 116.516, 1.587, 2),
|
||||||
|
(6100648, 478, -74.827, 209.524, -23.346, 2.854, 2),
|
||||||
|
(5865600, 478, 135.482, 207, 114.076, -2.166, 2),
|
||||||
|
(5865605, 478, 79.813, 203.98, 132.018, 2.558, 2),
|
||||||
|
(5865668, 399, -221.2, 104.271, -599.535, 0.268, 2),
|
||||||
|
(5865672, 399, -221.2, 155.809, -516.036, 0.295, 2),
|
||||||
|
(5865598, 399, -221.2, 104.271, -599.535, 0.268, 2),
|
||||||
|
(5865604, 399, -533.153, 153.074, -487.968, 0.18, 2),
|
||||||
|
(5916706, 418, -111.521, 15.14, -29.188, 0.0077, 2),
|
||||||
|
(5916705, 418, 47.713, 23.979, 1.144, 1.457, 2),
|
||||||
|
(5916704, 418, 47.701, -12.02, 67.738, 2.057, 2),
|
||||||
|
(5916727, 155, -161.481, 304.153, -321.403, 0.795, 2),
|
||||||
|
(5916708, 419, 0.000456, 16.015, -35.806, -0.0296, 2),
|
||||||
|
(5916724, 419, 80.156, 10.054, -123.9, -2.445, 2),
|
||||||
|
(5916722, 419, -80.517, 10.054, -123.315, 2.468, 2),
|
||||||
|
(5916717, 419, -136.889, -12.634, -16.757, 0.978, 2),
|
||||||
|
(5916716, 419, 136.079, -9.234, -66.426, -0.989, 2),
|
||||||
|
(6905273, 612, 475.811, 61.576, -555.551, -1.274, 2),
|
||||||
|
(6905297, 620, -653.588, 51.867, -790.168, 1.1366, 2),
|
||||||
|
(6906489, 635, -82.295, 0, 8.925, 1.77, 2),
|
||||||
|
(6906492, 635, 100.312, 2.731, -113.366, -0.481, 2);
|
||||||
/*!40000 ALTER TABLE `zonepositions` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `zonepositions` ENABLE KEYS */;
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||||
|
|
|
@ -424,15 +424,6 @@ namespace Core {
|
||||||
Land = 0x200,
|
Land = 0x200,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UserLevel : uint8_t
|
|
||||||
{
|
|
||||||
all = 0xff,
|
|
||||||
player = 0x01,
|
|
||||||
gm = 0x02,
|
|
||||||
dev = 0x04,
|
|
||||||
admin = 0x08
|
|
||||||
};
|
|
||||||
|
|
||||||
struct QuestActive
|
struct QuestActive
|
||||||
{
|
{
|
||||||
QuestActive()
|
QuestActive()
|
||||||
|
@ -571,6 +562,35 @@ namespace Core {
|
||||||
LimitBreak = 8,
|
LimitBreak = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ActionEffectType : uint8_t
|
||||||
|
{
|
||||||
|
Nothing = 0,
|
||||||
|
Miss = 1,
|
||||||
|
FullResist = 2,
|
||||||
|
Damage = 3,
|
||||||
|
Heal = 4,
|
||||||
|
BlockedDamage = 5,
|
||||||
|
ParriedDamage = 6,
|
||||||
|
Invulnerable = 7,
|
||||||
|
NoEffectText = 8,
|
||||||
|
Unknown_0 = 9,
|
||||||
|
MpLoss = 10,
|
||||||
|
MpGain = 11,
|
||||||
|
TpLoss = 12,
|
||||||
|
TpGain = 13,
|
||||||
|
GpGain = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ActionHitSeverityType : uint8_t
|
||||||
|
{
|
||||||
|
NormalDamage = 0,
|
||||||
|
CritHeal = 0,
|
||||||
|
CritDamage = 1,
|
||||||
|
NormalHeal = 1,
|
||||||
|
DirectHitDamage = 2,
|
||||||
|
CritDirectHitDamage = 3
|
||||||
|
};
|
||||||
|
|
||||||
enum HandleActionType : uint8_t
|
enum HandleActionType : uint8_t
|
||||||
{
|
{
|
||||||
Event,
|
Event,
|
||||||
|
@ -743,7 +763,7 @@ namespace Core {
|
||||||
|
|
||||||
Flee = 0x1B,
|
Flee = 0x1B,
|
||||||
|
|
||||||
Unk3 = 0x20,
|
Unk3 = 0x20, // Animation related?
|
||||||
|
|
||||||
CombatIndicationShow = 0x22,
|
CombatIndicationShow = 0x22,
|
||||||
|
|
||||||
|
@ -769,7 +789,7 @@ namespace Core {
|
||||||
ItemRepairMsg = 0x5C,
|
ItemRepairMsg = 0x5C,
|
||||||
|
|
||||||
LeveStartAnim = 0x66,
|
LeveStartAnim = 0x66,
|
||||||
Unk4 = 0x67,
|
LeveStartError = 0x67,
|
||||||
PlayerNameGrayout = 0x6A,
|
PlayerNameGrayout = 0x6A,
|
||||||
|
|
||||||
ItemObtainMsg = 0x75,
|
ItemObtainMsg = 0x75,
|
||||||
|
@ -869,7 +889,7 @@ namespace Core {
|
||||||
|
|
||||||
AchievementPopup = 0x203,
|
AchievementPopup = 0x203,
|
||||||
|
|
||||||
Unk7 = 0x205,
|
Unk7 = 0x205, // LogMessage?
|
||||||
AchievementMsg = 0x206,
|
AchievementMsg = 0x206,
|
||||||
|
|
||||||
SetItemLevel = 0x209,
|
SetItemLevel = 0x209,
|
||||||
|
|
|
@ -33,7 +33,26 @@ namespace Db {
|
||||||
|
|
||||||
return static_cast< T >( atol( m_pValue ) );
|
return static_cast< T >( atol( m_pValue ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t getUInt64()
|
||||||
|
{
|
||||||
|
if( m_pValue )
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
uint64_t value;
|
||||||
|
sscanf( m_pValue, "%I64d", &value );
|
||||||
|
return value;
|
||||||
|
#else
|
||||||
|
uint64_t value;
|
||||||
|
sscanf( m_pValue, "%Lu", &value );
|
||||||
|
return value;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t getLength() const;
|
uint32_t getLength() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -315,8 +315,7 @@ bool Core::Data::ExdData::loadActionInfo()
|
||||||
for( auto row : rows )
|
for( auto row : rows )
|
||||||
{
|
{
|
||||||
auto& fields = row.second;
|
auto& fields = row.second;
|
||||||
|
auto info = boost::make_shared< ActionInfo >();
|
||||||
ActionInfo info{ 0 };
|
|
||||||
|
|
||||||
uint32_t id = row.first;
|
uint32_t id = row.first;
|
||||||
if( id == 0 )
|
if( id == 0 )
|
||||||
|
@ -350,7 +349,7 @@ bool Core::Data::ExdData::loadActionInfo()
|
||||||
uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
|
uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
|
||||||
|
|
||||||
int8_t model = getField< int8_t >( fields, 39 ); // 39: Action model
|
int8_t model = getField< int8_t >( fields, 39 ); // 39: Action model
|
||||||
uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40: Action aspect
|
uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40: Action aspect
|
||||||
|
|
||||||
uint8_t typeshift = 0x6;
|
uint8_t typeshift = 0x6;
|
||||||
uint8_t mask = 1 << typeshift;
|
uint8_t mask = 1 << typeshift;
|
||||||
|
@ -360,36 +359,36 @@ bool Core::Data::ExdData::loadActionInfo()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
info.id = id;
|
info->id = id;
|
||||||
info.name = name;
|
info->name = name;
|
||||||
info.category = category;
|
info->category = category;
|
||||||
|
|
||||||
info.class_job = class_job;
|
info->class_job = class_job;
|
||||||
info.unlock_level = unlock_level;
|
info->unlock_level = unlock_level;
|
||||||
info.range = range;
|
info->range = range;
|
||||||
info.can_target_self = can_target_self;
|
info->can_target_self = can_target_self;
|
||||||
info.can_target_party = can_target_party;
|
info->can_target_party = can_target_party;
|
||||||
info.can_target_friendly = can_target_friendly;
|
info->can_target_friendly = can_target_friendly;
|
||||||
info.can_target_enemy = can_target_enemy;
|
info->can_target_enemy = can_target_enemy;
|
||||||
|
|
||||||
info.can_target_ko = can_target_ko;
|
info->can_target_ko = can_target_ko;
|
||||||
|
|
||||||
info.is_aoe = is_aoe;
|
info->is_aoe = is_aoe;
|
||||||
|
|
||||||
info.aoe_type = aoe_type;
|
info->aoe_type = aoe_type;
|
||||||
info.radius = radius;
|
info->radius = radius;
|
||||||
|
|
||||||
info.points_type = points_type;
|
info->points_type = points_type;
|
||||||
info.points_cost = points_cost;
|
info->points_cost = points_cost;
|
||||||
|
|
||||||
info.is_instant = is_instant;
|
info->is_instant = is_instant;
|
||||||
info.cast_time = cast_time * 100;
|
info->cast_time = cast_time * 100;
|
||||||
info.recast_time = recast_time * 100;
|
info->recast_time = recast_time * 100;
|
||||||
|
|
||||||
info.model = model;
|
info->model = model;
|
||||||
info.aspect = aspect;
|
info->aspect = aspect;
|
||||||
|
|
||||||
m_actionInfoMap[id] = info;
|
m_actionInfoMap.emplace( std::make_pair( info->id, info ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,6 +463,22 @@ boost::shared_ptr< Core::Data::AetheryteInfo >
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr< Core::Data::ActionInfo >
|
||||||
|
Core::Data::ExdData::getActionInfo( uint32_t actionId )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return m_actionInfoMap[actionId];
|
||||||
|
}
|
||||||
|
catch ( ... )
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
boost::shared_ptr< Core::Data::CustomTalkInfo >
|
boost::shared_ptr< Core::Data::CustomTalkInfo >
|
||||||
Core::Data::ExdData::getCustomTalkInfo( uint32_t customTalkId )
|
Core::Data::ExdData::getCustomTalkInfo( uint32_t customTalkId )
|
||||||
{
|
{
|
||||||
|
|
|
@ -299,7 +299,7 @@ namespace Core {
|
||||||
std::map<uint8_t, ClassJobInfo> m_classJobInfoMap;
|
std::map<uint8_t, ClassJobInfo> m_classJobInfoMap;
|
||||||
std::map<uint32_t, ParamGrowthInfo> m_paramGrowthInfoMap;
|
std::map<uint32_t, ParamGrowthInfo> m_paramGrowthInfoMap;
|
||||||
std::map<uint16_t, EventActionInfo> m_EventActionInfoMap;
|
std::map<uint16_t, EventActionInfo> m_EventActionInfoMap;
|
||||||
std::map<uint16_t, ActionInfo> m_actionInfoMap;
|
std::map<uint16_t, boost::shared_ptr< ActionInfo > > m_actionInfoMap;
|
||||||
std::map<uint16_t, StatusEffectInfo> m_statusEffectInfoMap;
|
std::map<uint16_t, StatusEffectInfo> m_statusEffectInfoMap;
|
||||||
std::map<uint32_t, boost::shared_ptr< AetheryteInfo > > m_aetheryteInfoMap;
|
std::map<uint32_t, boost::shared_ptr< AetheryteInfo > > m_aetheryteInfoMap;
|
||||||
std::map<uint32_t, TribeInfo > m_tribeInfoMap;
|
std::map<uint32_t, TribeInfo > m_tribeInfoMap;
|
||||||
|
@ -317,6 +317,7 @@ namespace Core {
|
||||||
boost::shared_ptr< OpeningInfo > getOpeningInfo( uint32_t openingId );
|
boost::shared_ptr< OpeningInfo > getOpeningInfo( uint32_t openingId );
|
||||||
boost::shared_ptr< CustomTalkInfo > getCustomTalkInfo( uint32_t customTalkId );
|
boost::shared_ptr< CustomTalkInfo > getCustomTalkInfo( uint32_t customTalkId );
|
||||||
boost::shared_ptr< AetheryteInfo > getAetheryteInfo( uint32_t aetheryteId );
|
boost::shared_ptr< AetheryteInfo > getAetheryteInfo( uint32_t aetheryteId );
|
||||||
|
boost::shared_ptr< ActionInfo > getActionInfo( uint32_t actionId );
|
||||||
boost::shared_ptr< PlaceNameInfo > getPlaceNameInfo( uint32_t placeNameId );
|
boost::shared_ptr< PlaceNameInfo > getPlaceNameInfo( uint32_t placeNameId );
|
||||||
boost::shared_ptr< ItemInfo > getItemInfo( uint32_t catalogId );
|
boost::shared_ptr< ItemInfo > getItemInfo( uint32_t catalogId );
|
||||||
boost::shared_ptr< RaceInfo > getRaceInfo( uint32_t raceId );
|
boost::shared_ptr< RaceInfo > getRaceInfo( uint32_t raceId );
|
||||||
|
|
|
@ -116,6 +116,7 @@ namespace Packets {
|
||||||
WeatherChange = 0x01AF, // updated for sb
|
WeatherChange = 0x01AF, // updated for sb
|
||||||
Discovery = 0x01B2, // updated for sb
|
Discovery = 0x01B2, // updated for sb
|
||||||
|
|
||||||
|
EorzeaTimeOffset = 0x01B4,
|
||||||
|
|
||||||
CFAvailableContents = 0x01CF,
|
CFAvailableContents = 0x01CF,
|
||||||
|
|
||||||
|
|
|
@ -301,12 +301,12 @@ struct FFXIVIpcUpdateHpMpTp : FFXIVIpcBasePacket<UpdateHpMpTp>
|
||||||
*/
|
*/
|
||||||
struct effectEntry
|
struct effectEntry
|
||||||
{
|
{
|
||||||
uint8_t unknown_1;
|
Common::ActionEffectType effectType;
|
||||||
uint8_t unknown_2;
|
Common::ActionHitSeverityType hitSeverity;
|
||||||
uint8_t unknown_3;
|
uint8_t unknown_3;
|
||||||
int8_t bonusPercent;
|
int8_t bonusPercent;
|
||||||
int16_t param1;
|
int16_t value;
|
||||||
uint8_t unknown_5;
|
uint8_t valueMultiplier; // This multiplies whatever value is in the 'value' param by 10. Possibly a workaround for big numbers
|
||||||
uint8_t unknown_6;
|
uint8_t unknown_6;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1281,6 +1281,11 @@ struct FFXIVIpcCFMemberStatus : FFXIVIpcBasePacket<CFMemberStatus>
|
||||||
uint32_t unknown3;
|
uint32_t unknown3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcEorzeaTimeOffset : FFXIVIpcBasePacket<EorzeaTimeOffset>
|
||||||
|
{
|
||||||
|
uint64_t timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} /* Server */
|
} /* Server */
|
||||||
|
|
10
src/servers/Server_Common/Version.cpp.in
Normal file
10
src/servers/Server_Common/Version.cpp.in
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace Version {
|
||||||
|
|
||||||
|
const std::string GIT_HASH = "@GIT_SHA1@";
|
||||||
|
const std::string VERSION = "@VERSION@";
|
||||||
|
|
||||||
|
} /* Version */
|
||||||
|
} /* Core */
|
15
src/servers/Server_Common/Version.h
Normal file
15
src/servers/Server_Common/Version.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _VERSION_H
|
||||||
|
#define _VERSION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace Version {
|
||||||
|
|
||||||
|
extern const std::string GIT_HASH;
|
||||||
|
extern const std::string VERSION;
|
||||||
|
|
||||||
|
} /* Version */
|
||||||
|
} /* Core */
|
||||||
|
|
||||||
|
#endif
|
|
@ -70,7 +70,7 @@ namespace Core {
|
||||||
setBirthDay( field[2].get< int8_t >(), field[3].get< int8_t >() );
|
setBirthDay( field[2].get< int8_t >(), field[3].get< int8_t >() );
|
||||||
m_guardianDeity = field[4].get< int8_t >();
|
m_guardianDeity = field[4].get< int8_t >();
|
||||||
m_class = field[5].get< int8_t >();
|
m_class = field[5].get< int8_t >();
|
||||||
m_contentId = field[7].get< uint64_t >();
|
m_contentId = field[7].getUInt64();
|
||||||
m_zoneId = field[8].get< uint16_t >();
|
m_zoneId = field[8].get< uint16_t >();
|
||||||
|
|
||||||
auto pQR2 = g_database.query( "SELECT * FROM characlass WHERE CharacterId = " + std::to_string( charId ) + ";" );
|
auto pQR2 = g_database.query( "SELECT * FROM characlass WHERE CharacterId = " + std::to_string( charId ) + ";" );
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace Core {
|
||||||
std::string getClassString();
|
std::string getClassString();
|
||||||
|
|
||||||
// return the id of the actor
|
// return the id of the actor
|
||||||
uint32_t getId()
|
uint32_t getId() const
|
||||||
{
|
{
|
||||||
return m_iD;
|
return m_iD;
|
||||||
}
|
}
|
||||||
|
@ -45,13 +45,13 @@ namespace Core {
|
||||||
m_contentId = id;
|
m_contentId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t getContentId()
|
uint64_t getContentId() const
|
||||||
{
|
{
|
||||||
return m_contentId;
|
return m_contentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t getAccountId()
|
uint32_t getAccountId() const
|
||||||
{
|
{
|
||||||
return m_accountId;
|
return m_accountId;
|
||||||
}
|
}
|
||||||
|
@ -84,12 +84,12 @@ namespace Core {
|
||||||
m_class = classId;
|
m_class = classId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getClass()
|
uint8_t getClass() const
|
||||||
{
|
{
|
||||||
return m_class;
|
return m_class;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getGuardianDeity()
|
uint8_t getGuardianDeity() const
|
||||||
{
|
{
|
||||||
return m_guardianDeity;
|
return m_guardianDeity;
|
||||||
}
|
}
|
||||||
|
@ -105,17 +105,17 @@ namespace Core {
|
||||||
m_birthMonth = month;
|
m_birthMonth = month;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBirthDay()
|
uint8_t getBirthDay() const
|
||||||
{
|
{
|
||||||
return m_birthDay;
|
return m_birthDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBirthMonth()
|
uint8_t getBirthMonth() const
|
||||||
{
|
{
|
||||||
return m_birthMonth;
|
return m_birthMonth;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getVoice()
|
uint8_t getVoice() const
|
||||||
{
|
{
|
||||||
return m_birthMonth;
|
return m_birthMonth;
|
||||||
}
|
}
|
||||||
|
@ -125,12 +125,12 @@ namespace Core {
|
||||||
m_voice = voice;
|
m_voice = voice;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getZoneId()
|
uint32_t getZoneId() const
|
||||||
{
|
{
|
||||||
return m_zoneId;
|
return m_zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getTribe()
|
uint32_t getTribe() const
|
||||||
{
|
{
|
||||||
return m_tribe;
|
return m_tribe;
|
||||||
}
|
}
|
||||||
|
@ -140,9 +140,9 @@ namespace Core {
|
||||||
m_tribe = tribe;
|
m_tribe = tribe;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getGmRank()
|
uint8_t getGmRank() const
|
||||||
{
|
{
|
||||||
return m_birthMonth;
|
return m_gmRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGmRank( uint8_t rank )
|
void setGmRank( uint8_t rank )
|
||||||
|
|
|
@ -277,7 +277,7 @@ uint64_t Core::Network::SapphireAPI::getNextContentId()
|
||||||
return 0x0040000001000001;
|
return 0x0040000001000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
contentId = pQR->fetch()[0].get< uint64_t >() + 1;
|
contentId = pQR->fetch()[0].getUInt64() + 1;
|
||||||
if( contentId < 0x0040000001000001 )
|
if( contentId < 0x0040000001000001 )
|
||||||
{
|
{
|
||||||
return 0x0040000001000001;
|
return 0x0040000001000001;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
|
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
|
||||||
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
|
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
|
||||||
|
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket144.h"
|
||||||
#include "src/servers/Server_Zone/Actor/Player.h"
|
#include "src/servers/Server_Zone/Actor/Player.h"
|
||||||
#include "src/servers/Server_Zone/Script/ScriptManager.h"
|
#include "src/servers/Server_Zone/Script/ScriptManager.h"
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ Core::Action::ActionCast::ActionCast( Entity::ActorPtr pActor, Entity::ActorPtr
|
||||||
m_startTime = 0;
|
m_startTime = 0;
|
||||||
m_id = actionId;
|
m_id = actionId;
|
||||||
m_handleActionType = HandleActionType::Spell;
|
m_handleActionType = HandleActionType::Spell;
|
||||||
m_castTime = g_exdData.m_actionInfoMap[actionId].cast_time; // TODO: Add security checks.
|
m_castTime = g_exdData.getActionInfo( actionId )->cast_time; // TODO: Add security checks.
|
||||||
m_pSource = pActor;
|
m_pSource = pActor;
|
||||||
m_pTarget = pTarget;
|
m_pTarget = pTarget;
|
||||||
m_bInterrupt = false;
|
m_bInterrupt = false;
|
||||||
|
@ -53,10 +54,11 @@ void Core::Action::ActionCast::onStart()
|
||||||
|
|
||||||
castPacket.data().action_id = m_id;
|
castPacket.data().action_id = m_id;
|
||||||
castPacket.data().unknown = 1;
|
castPacket.data().unknown = 1;
|
||||||
castPacket.data().cast_time = m_castTime / 1000; // This is used for the cast bar above the target bar of the caster.
|
castPacket.data().unknown_1 = m_id;
|
||||||
|
castPacket.data().cast_time = static_cast< float >( m_castTime / 1000 ); // This is used for the cast bar above the target bar of the caster.
|
||||||
castPacket.data().target_id = m_pTarget->getId();
|
castPacket.data().target_id = m_pTarget->getId();
|
||||||
|
|
||||||
m_pSource->sendToInRangeSet( castPacket, false );
|
m_pSource->sendToInRangeSet( castPacket, true );
|
||||||
m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::Casting );
|
m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::Casting );
|
||||||
m_pSource->getAsPlayer()->sendStateFlags();
|
m_pSource->getAsPlayer()->sendStateFlags();
|
||||||
|
|
||||||
|
@ -73,6 +75,10 @@ void Core::Action::ActionCast::onFinish()
|
||||||
pPlayer->unsetStateFlag( PlayerStateFlag::Casting );
|
pPlayer->unsetStateFlag( PlayerStateFlag::Casting );
|
||||||
pPlayer->sendStateFlags();
|
pPlayer->sendStateFlags();
|
||||||
|
|
||||||
|
/*auto control = ActorControlPacket143( m_pTarget->getId(), ActorControlType::Unk7,
|
||||||
|
0x219, m_id, m_id, m_id, m_id );
|
||||||
|
m_pSource->sendToInRangeSet( control, true );*/
|
||||||
|
|
||||||
g_scriptMgr.onCastFinish( pPlayer, m_pTarget, m_id );
|
g_scriptMgr.onCastFinish( pPlayer, m_pTarget, m_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +92,7 @@ void Core::Action::ActionCast::onInterrupt()
|
||||||
m_pSource->getAsPlayer()->sendStateFlags();
|
m_pSource->getAsPlayer()->sendStateFlags();
|
||||||
|
|
||||||
auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt,
|
auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt,
|
||||||
0x219, 0x04, m_id, 1 );
|
0x219, 1, m_id, 1 );
|
||||||
m_pSource->sendToInRangeSet( control, true );
|
m_pSource->sendToInRangeSet( control, true );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ Core::Action::ActionTeleport::ActionTeleport( Entity::ActorPtr pActor, uint16_t
|
||||||
m_startTime = 0;
|
m_startTime = 0;
|
||||||
m_id = 5;
|
m_id = 5;
|
||||||
m_handleActionType = HandleActionType::Teleport;
|
m_handleActionType = HandleActionType::Teleport;
|
||||||
m_castTime = g_exdData.m_actionInfoMap[5].cast_time; // TODO: Add security checks.
|
m_castTime = g_exdData.getActionInfo(5)->cast_time; // TODO: Add security checks.
|
||||||
m_pSource = pActor;
|
m_pSource = pActor;
|
||||||
m_bInterrupt = false;
|
m_bInterrupt = false;
|
||||||
m_targetAetheryte = targetZone;
|
m_targetAetheryte = targetZone;
|
||||||
|
|
|
@ -595,7 +595,7 @@ void Core::Entity::Actor::autoAttack( ActorPtr pTarget )
|
||||||
srand( static_cast< uint32_t >( tick ) );
|
srand( static_cast< uint32_t >( tick ) );
|
||||||
|
|
||||||
uint32_t damage = 10 + rand() % 12;
|
uint32_t damage = 10 + rand() % 12;
|
||||||
uint32_t variation = 0 + rand() % 3;
|
uint32_t variation = 0 + rand() % 4;
|
||||||
|
|
||||||
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
|
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
|
||||||
effectPacket.data().targetId = pTarget->getId();
|
effectPacket.data().targetId = pTarget->getId();
|
||||||
|
@ -606,9 +606,9 @@ void Core::Entity::Actor::autoAttack( ActorPtr pTarget )
|
||||||
effectPacket.data().numEffects = 1;
|
effectPacket.data().numEffects = 1;
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
||||||
effectPacket.data().effectTarget = pTarget->getId();
|
effectPacket.data().effectTarget = pTarget->getId();
|
||||||
effectPacket.data().effects[0].param1 = damage;
|
effectPacket.data().effects[0].value = damage;
|
||||||
effectPacket.data().effects[0].unknown_1 = 3;
|
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
|
||||||
effectPacket.data().effects[0].unknown_2 = 1;
|
effectPacket.data().effects[0].hitSeverity = static_cast< ActionHitSeverityType >( variation );
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
sendToInRangeSet( effectPacket );
|
sendToInRangeSet( effectPacket );
|
||||||
|
@ -627,26 +627,26 @@ void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
/*! \param StatusEffectPtr to be applied to the actor */
|
||||||
void Core::Entity::Actor::addStatusEffectById( int32_t id, int32_t duration, uint16_t param )
|
void Core::Entity::Actor::addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param )
|
||||||
{
|
{
|
||||||
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, shared_from_this(), shared_from_this(), duration, 3000 ) );
|
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(), shared_from_this(), duration, 3000 ) );
|
||||||
effect->setParam( param );
|
effect->setParam( param );
|
||||||
addStatusEffect( effect );
|
addStatusEffect( effect );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
/*! \param StatusEffectPtr to be applied to the actor */
|
||||||
void Core::Entity::Actor::addStatusEffectByIdIfNotExist( int32_t id, int32_t duration, uint16_t param )
|
void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param )
|
||||||
{
|
{
|
||||||
if( !m_pStatusEffectContainer->hasStatusEffect( id ) )
|
if( !m_pStatusEffectContainer->hasStatusEffect( id ) )
|
||||||
{
|
{
|
||||||
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, shared_from_this(), shared_from_this(), duration, 3000 ) );
|
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(), shared_from_this(), duration, 3000 ) );
|
||||||
effect->setParam( param );
|
effect->setParam( param );
|
||||||
addStatusEffect( effect );
|
addStatusEffect( effect );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param Status that should be removed, based on its ID. */
|
/*! \param Status that should be removed, based on its ID. */
|
||||||
void Core::Entity::Actor::removeSingleStatusEffectFromId( int32_t id )
|
void Core::Entity::Actor::removeSingleStatusEffectFromId( uint32_t id )
|
||||||
{
|
{
|
||||||
m_pStatusEffectContainer->removeSingleStatusEffectFromId( id );
|
m_pStatusEffectContainer->removeSingleStatusEffectFromId( id );
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,13 +293,13 @@ public:
|
||||||
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
||||||
|
|
||||||
// add a status effect by id
|
// add a status effect by id
|
||||||
void addStatusEffectById( int32_t id, int32_t duration, uint16_t param = 0 );
|
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
|
||||||
|
|
||||||
// add a status effect by id if it doesn't exist
|
// add a status effect by id if it doesn't exist
|
||||||
void addStatusEffectByIdIfNotExist( int32_t id, int32_t duration, uint16_t param = 0 );
|
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
|
||||||
|
|
||||||
// remove a status effect by id
|
// remove a status effect by id
|
||||||
void removeSingleStatusEffectFromId( int32_t id );
|
void removeSingleStatusEffectFromId( uint32_t id );
|
||||||
|
|
||||||
//get the status effect container
|
//get the status effect container
|
||||||
StatusEffect::StatusEffectContainerPtr getStatusEffectContainer() const;
|
StatusEffect::StatusEffectContainerPtr getStatusEffectContainer() const;
|
||||||
|
|
|
@ -425,7 +425,7 @@ void Core::Entity::BattleNpc::onDeath()
|
||||||
// todo: check for companion
|
// todo: check for companion
|
||||||
if( pHateEntry->m_pActor->isPlayer() ) // && pHateEntry->m_hateAmount >= plsBeHatedThisMuchAtLeast )
|
if( pHateEntry->m_pActor->isPlayer() ) // && pHateEntry->m_hateAmount >= plsBeHatedThisMuchAtLeast )
|
||||||
{
|
{
|
||||||
auto level = pHateEntry->m_pActor->getLevel();
|
uint8_t level = pHateEntry->m_pActor->getLevel();
|
||||||
auto levelDiff = (int)this->m_level - (int)level;
|
auto levelDiff = (int)this->m_level - (int)level;
|
||||||
auto cappedLevelDiff = Math::Util::clamp( levelDiff, 1, 6 );
|
auto cappedLevelDiff = Math::Util::clamp( levelDiff, 1, 6 );
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ extern Core::Data::ExdData g_exdData;
|
||||||
// 3 Versions. SB and HW are linear, ARR is polynomial.
|
// 3 Versions. SB and HW are linear, ARR is polynomial.
|
||||||
// Originally from Player.cpp, calculateStats().
|
// Originally from Player.cpp, calculateStats().
|
||||||
|
|
||||||
uint32_t CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
|
float CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
|
||||||
{
|
{
|
||||||
float base = 0.0f;
|
float base = 0.0f;
|
||||||
uint8_t level = pPlayer->getLevel();
|
uint8_t level = pPlayer->getLevel();
|
||||||
|
@ -37,7 +37,7 @@ uint32_t CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
|
||||||
// SB Base Stat Formula (Aligned)
|
// SB Base Stat Formula (Aligned)
|
||||||
if ( level > 60 )
|
if ( level > 60 )
|
||||||
{
|
{
|
||||||
base = ( ( ( level == 61) ? 224 : 220 ) + ( level - 61 ) * 8);
|
base = ( ( ( level == 61 ) ? 224 : 220 ) + ( level - 61 ) * 8);
|
||||||
}
|
}
|
||||||
// HW Base Stat Formula (Aligned)
|
// HW Base Stat Formula (Aligned)
|
||||||
else if ( level > 50 )
|
else if ( level > 50 )
|
||||||
|
@ -85,7 +85,7 @@ uint32_t CalcBattle::calculateMaxHp( PlayerPtr pPlayer )
|
||||||
else
|
else
|
||||||
approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7596f;
|
approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7596f;
|
||||||
|
|
||||||
uint16_t result = floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) );
|
uint16_t result = static_cast< uint16_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ uint32_t CalcBattle::calculateMaxMp( PlayerPtr pPlayer )
|
||||||
uint16_t jobModMp = classInfoIt->second.mod_mpcpgp;
|
uint16_t jobModMp = classInfoIt->second.mod_mpcpgp;
|
||||||
uint16_t baseMp = paramGrowthInfoIt->second.mp_const;
|
uint16_t baseMp = paramGrowthInfoIt->second.mp_const;
|
||||||
|
|
||||||
uint16_t result = floor( floor( piety - baseStat ) * ( pietyScalar / 100 ) + baseMp ) * jobModMp / 100;
|
uint16_t result = static_cast< uint16_t >( floor( floor( piety - baseStat ) * ( pietyScalar / 100 ) + baseMp ) * jobModMp / 100 );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Entity {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static uint32_t calculateBaseStat( PlayerPtr pPlayer );
|
static float calculateBaseStat( PlayerPtr pPlayer );
|
||||||
static uint32_t calculateMaxMp( PlayerPtr pPlayer );
|
static uint32_t calculateMaxMp( PlayerPtr pPlayer );
|
||||||
static uint32_t calculateMaxHp( PlayerPtr pPlayer );
|
static uint32_t calculateMaxHp( PlayerPtr pPlayer );
|
||||||
static uint32_t calculateHealValue( PlayerPtr pPlayer, uint32_t potency );
|
static uint32_t calculateHealValue( PlayerPtr pPlayer, uint32_t potency );
|
||||||
|
|
|
@ -218,12 +218,12 @@ void Core::Entity::Player::calculateStats()
|
||||||
// TODO: put formula somewhere else...
|
// TODO: put formula somewhere else...
|
||||||
float base = CalcBattle::calculateBaseStat( getAsPlayer() );
|
float base = CalcBattle::calculateBaseStat( getAsPlayer() );
|
||||||
|
|
||||||
m_baseStats.str = base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str;
|
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str );
|
||||||
m_baseStats.dex = base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex;
|
m_baseStats.dex = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex );
|
||||||
m_baseStats.vit = base * ( static_cast< float >( classInfo.mod_vit ) / 100 ) + tribeInfo.mod_vit;
|
m_baseStats.vit = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_vit ) / 100 ) + tribeInfo.mod_vit );
|
||||||
m_baseStats.inte = base * ( static_cast< float >( classInfo.mod_int ) / 100 ) + tribeInfo.mod_int;
|
m_baseStats.inte = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_int ) / 100 ) + tribeInfo.mod_int );
|
||||||
m_baseStats.mnd = base * ( static_cast< float >( classInfo.mod_mnd ) / 100 ) + tribeInfo.mod_mnd;
|
m_baseStats.mnd = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_mnd ) / 100 ) + tribeInfo.mod_mnd );
|
||||||
m_baseStats.pie = base * ( static_cast< float >( classInfo.mod_pie ) / 100 ) + tribeInfo.mod_pie;
|
m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_pie ) / 100 ) + tribeInfo.mod_pie );
|
||||||
|
|
||||||
m_baseStats.skillSpeed = paramGrowthInfo.base_secondary;
|
m_baseStats.skillSpeed = paramGrowthInfo.base_secondary;
|
||||||
m_baseStats.spellSpeed = paramGrowthInfo.base_secondary;
|
m_baseStats.spellSpeed = paramGrowthInfo.base_secondary;
|
||||||
|
@ -243,7 +243,7 @@ void Core::Entity::Player::calculateStats()
|
||||||
m_hp = m_baseStats.max_hp;
|
m_hp = m_baseStats.max_hp;
|
||||||
|
|
||||||
|
|
||||||
m_baseStats.determination = base;
|
m_baseStats.determination = static_cast< uint32_t >( base );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ bool Core::Entity::Player::isAetheryteRegistered( uint8_t aetheryteId ) const
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
Util::valueToFlagByteIndexValue( aetheryteId, value, index );
|
Util::valueToFlagByteIndexValue( aetheryteId, value, index );
|
||||||
|
|
||||||
return m_aetheryte[index] & value;
|
return ( m_aetheryte[index] & value ) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * Core::Entity::Player::getDiscoveryBitmask()
|
uint8_t * Core::Entity::Player::getDiscoveryBitmask()
|
||||||
|
@ -608,7 +608,7 @@ bool Core::Entity::Player::isActionLearned( uint8_t actionId ) const
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
Util::valueToFlagByteIndexValue( actionId, value, index );
|
Util::valueToFlagByteIndexValue( actionId, value, index );
|
||||||
|
|
||||||
return m_unlocks[index] & value;
|
return ( m_unlocks[index] & value ) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Entity::Player::gainExp( uint32_t amount )
|
void Core::Entity::Player::gainExp( uint32_t amount )
|
||||||
|
@ -980,10 +980,11 @@ const uint8_t * Core::Entity::Player::getStateFlags() const
|
||||||
|
|
||||||
bool Core::Entity::Player::actionHasCastTime( uint32_t actionId ) //TODO: Add logic for special cases
|
bool Core::Entity::Player::actionHasCastTime( uint32_t actionId ) //TODO: Add logic for special cases
|
||||||
{
|
{
|
||||||
if( g_exdData.m_actionInfoMap[actionId].is_instant )
|
auto actionInfoPtr = g_exdData.getActionInfo( actionId );
|
||||||
|
if( actionInfoPtr->is_instant )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( g_exdData.m_actionInfoMap[actionId].cast_time == 0 )
|
if( actionInfoPtr->cast_time == 0 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -997,7 +998,7 @@ bool Core::Entity::Player::hasStateFlag( Core::Common::PlayerStateFlag flag ) co
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
Util::valueToFlagByteIndexValue( iFlag, value, index );
|
Util::valueToFlagByteIndexValue( iFlag, value, index );
|
||||||
|
|
||||||
return m_stateFlags[index] & value;
|
return ( m_stateFlags[index] & value ) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Entity::Player::setStateFlag( Core::Common::PlayerStateFlag flag )
|
void Core::Entity::Player::setStateFlag( Core::Common::PlayerStateFlag flag )
|
||||||
|
@ -1463,7 +1464,7 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
|
||||||
//uint64_t tick = Util::getTimeMs();
|
//uint64_t tick = Util::getTimeMs();
|
||||||
//srand(static_cast< uint32_t >(tick));
|
//srand(static_cast< uint32_t >(tick));
|
||||||
|
|
||||||
uint32_t damage = mainWeap->getAutoAttackDmg();
|
uint32_t damage = static_cast< uint32_t >( mainWeap->getAutoAttackDmg() );
|
||||||
uint32_t variation = 0 + rand() % 3;
|
uint32_t variation = 0 + rand() % 3;
|
||||||
|
|
||||||
if ( getClass() == JOB_MACHINIST ||
|
if ( getClass() == JOB_MACHINIST ||
|
||||||
|
@ -1481,9 +1482,9 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
|
||||||
effectPacket.data().effectTargetId = pTarget->getId();
|
effectPacket.data().effectTargetId = pTarget->getId();
|
||||||
effectPacket.data().effectTarget = pTarget->getId();
|
effectPacket.data().effectTarget = pTarget->getId();
|
||||||
effectPacket.data().effects[0].param1 = damage;
|
effectPacket.data().effects[0].value = damage;
|
||||||
effectPacket.data().effects[0].unknown_1 = 3;
|
effectPacket.data().effects[0].effectType = Common::ActionEffectType::Damage;
|
||||||
effectPacket.data().effects[0].unknown_2 = 1;
|
effectPacket.data().effects[0].hitSeverity = Common::ActionHitSeverityType::NormalDamage;
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
sendToInRangeSet(effectPacket, true);
|
sendToInRangeSet(effectPacket, true);
|
||||||
|
@ -1501,9 +1502,9 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
|
||||||
effectPacket.data().actionTextId = 7;
|
effectPacket.data().actionTextId = 7;
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
|
||||||
effectPacket.data().effectTarget = pTarget->getId();
|
effectPacket.data().effectTarget = pTarget->getId();
|
||||||
effectPacket.data().effects[0].param1 = damage;
|
effectPacket.data().effects[0].value = damage;
|
||||||
effectPacket.data().effects[0].unknown_1 = 3;
|
effectPacket.data().effects[0].effectType = Common::ActionEffectType::Damage;
|
||||||
effectPacket.data().effects[0].unknown_2 = 2;
|
effectPacket.data().effects[0].hitSeverity = Common::ActionHitSeverityType::NormalDamage;
|
||||||
effectPacket.data().effects[0].unknown_3 = 71;
|
effectPacket.data().effects[0].unknown_3 = 71;
|
||||||
|
|
||||||
sendToInRangeSet(effectPacket, true);
|
sendToInRangeSet(effectPacket, true);
|
||||||
|
@ -1517,6 +1518,9 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
|
||||||
{
|
{
|
||||||
sendDebug( std::to_string( pTarget.getId() ) );
|
sendDebug( std::to_string( pTarget.getId() ) );
|
||||||
sendDebug( "Handle script skill type: " + std::to_string( type ) );
|
sendDebug( "Handle script skill type: " + std::to_string( type ) );
|
||||||
|
|
||||||
|
auto actionInfoPtr = g_exdData.getActionInfo( actionId );
|
||||||
|
|
||||||
|
|
||||||
switch( type )
|
switch( type )
|
||||||
{
|
{
|
||||||
|
@ -1534,9 +1538,9 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
|
||||||
effectPacket.data().numEffects = 1;
|
effectPacket.data().numEffects = 1;
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
||||||
effectPacket.data().effectTarget = pTarget.getId();
|
effectPacket.data().effectTarget = pTarget.getId();
|
||||||
effectPacket.data().effects[0].param1 = param1;
|
effectPacket.data().effects[0].value = static_cast< int16_t >( param1 );
|
||||||
effectPacket.data().effects[0].unknown_1 = 3;
|
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
|
||||||
effectPacket.data().effects[0].unknown_2 = 1;
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
sendToInRangeSet( effectPacket, true );
|
sendToInRangeSet( effectPacket, true );
|
||||||
|
@ -1544,14 +1548,14 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
|
||||||
if ( !pTarget.isAlive() )
|
if ( !pTarget.isAlive() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pTarget.takeDamage( param1 );
|
pTarget.takeDamage( static_cast< uint32_t >( param1 ) );
|
||||||
pTarget.onActionHostile( shared_from_this() );
|
pTarget.onActionHostile( shared_from_this() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Core::Common::HandleSkillType::StdHeal:
|
case Core::Common::HandleSkillType::StdHeal:
|
||||||
{
|
{
|
||||||
uint32_t calculatedHeal = CalcBattle::calculateHealValue( getAsPlayer(), param1 );
|
uint32_t calculatedHeal = CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) );
|
||||||
|
|
||||||
sendDebug( "STD_HEAL" );
|
sendDebug( "STD_HEAL" );
|
||||||
|
|
||||||
|
@ -1564,9 +1568,9 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
|
||||||
effectPacket.data().numEffects = 1;
|
effectPacket.data().numEffects = 1;
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
||||||
effectPacket.data().effectTarget = pTarget.getId();
|
effectPacket.data().effectTarget = pTarget.getId();
|
||||||
effectPacket.data().effects[0].param1 = calculatedHeal;
|
effectPacket.data().effects[0].value = calculatedHeal;
|
||||||
effectPacket.data().effects[0].unknown_1 = 4;
|
effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
|
||||||
effectPacket.data().effects[0].unknown_2 = 1;
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
sendToInRangeSet( effectPacket, true );
|
sendToInRangeSet( effectPacket, true );
|
||||||
|
@ -1574,6 +1578,41 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId,
|
||||||
if ( !pTarget.isAlive() )
|
if ( !pTarget.isAlive() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// todo: get proper packets: the following was just kind of thrown together from what we know
|
||||||
|
// also toss AoE to another spot and make it generic
|
||||||
|
|
||||||
|
if ( actionInfoPtr->is_aoe )
|
||||||
|
{
|
||||||
|
for ( auto pCurAct : m_inRangePlayers )
|
||||||
|
{
|
||||||
|
assert( pCurAct );
|
||||||
|
if ( !pCurAct->isAlive() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( Math::Util::distance( pTarget.getPos().x, pTarget.getPos().y, pTarget.getPos().z, pCurAct->getPos().x, pCurAct->getPos().y, pCurAct->getPos().z ) <= actionInfoPtr->radius )
|
||||||
|
{
|
||||||
|
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( pCurAct->getId() );
|
||||||
|
effectPacket.data().targetId = pCurAct->getId();
|
||||||
|
effectPacket.data().unknown_1 = 1; // the magic trick for getting it to work
|
||||||
|
effectPacket.data().unknown_2 = 1;
|
||||||
|
effectPacket.data().unknown_8 = 1;
|
||||||
|
effectPacket.data().unknown_5 = 1;
|
||||||
|
effectPacket.data().actionAnimationId = actionId;
|
||||||
|
effectPacket.data().actionTextId = 0;
|
||||||
|
effectPacket.data().numEffects = 1;
|
||||||
|
effectPacket.data().effectTarget = pCurAct->getId();
|
||||||
|
effectPacket.data().effects[0].value = calculatedHeal;
|
||||||
|
effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
|
||||||
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
|
||||||
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
|
pCurAct->sendToInRangeSet( effectPacket, true );
|
||||||
|
pCurAct->heal( calculatedHeal );
|
||||||
|
sendDebug( "AoE hit actor " + pCurAct->getName() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pTarget.heal( calculatedHeal );
|
pTarget.heal( calculatedHeal );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1628,4 +1667,15 @@ void Core::Entity::Player::setOpeningSequence( uint8_t seq )
|
||||||
{
|
{
|
||||||
setSyncFlag( OpeningSeq );
|
setSyncFlag( OpeningSeq );
|
||||||
m_openingSequence = seq;
|
m_openingSequence = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tells client to offset their eorzean time by given timestamp.
|
||||||
|
void Core::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp )
|
||||||
|
{
|
||||||
|
// TODO: maybe change to persistent?
|
||||||
|
GamePacketNew< FFXIVIpcEorzeaTimeOffset, ServerZoneIpcType > packet ( getId() );
|
||||||
|
packet.data().timestamp = timestamp;
|
||||||
|
|
||||||
|
// Send to single player
|
||||||
|
queuePacket( packet );
|
||||||
|
}
|
||||||
|
|
|
@ -499,6 +499,10 @@ public:
|
||||||
|
|
||||||
uint32_t getCFPenaltyMinutes() const;
|
uint32_t getCFPenaltyMinutes() const;
|
||||||
void setCFPenaltyMinutes( uint32_t minutes );
|
void setCFPenaltyMinutes( uint32_t minutes );
|
||||||
|
|
||||||
|
void setEorzeaTimeOffset( uint64_t timestamp );
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_lastWrite;
|
uint32_t m_lastWrite;
|
||||||
uint32_t m_lastPing;
|
uint32_t m_lastPing;
|
||||||
|
|
|
@ -264,14 +264,14 @@ void Core::Entity::Player::onTick()
|
||||||
if( !isAlive() || !isLoadingComplete() )
|
if( !isAlive() || !isLoadingComplete() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32_t addHp = getMaxHp() * 0.1f + 1;
|
uint32_t addHp = static_cast< uint32_t >( getMaxHp() * 0.1f + 1 );
|
||||||
int32_t addMp = getMaxMp() * 0.06f + 1;
|
uint32_t addMp = static_cast< uint32_t >( getMaxMp() * 0.06f + 1 );
|
||||||
int32_t addTp = 100;
|
uint32_t addTp = 100;
|
||||||
|
|
||||||
if( !m_actorIdTohateSlotMap.empty() )
|
if( !m_actorIdTohateSlotMap.empty() )
|
||||||
{
|
{
|
||||||
addHp = getMaxHp() * 0.01f + 1;
|
addHp = static_cast< uint32_t >( getMaxHp() * 0.01f + 1 );
|
||||||
addMp = getMaxHp() * 0.02f + 1;
|
addMp = static_cast< uint32_t >( getMaxMp() * 0.02f + 1 );
|
||||||
addTp = 60;
|
addTp = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ bool Core::Entity::Player::loadActiveQuests()
|
||||||
void Core::Entity::Player::finishQuest( uint16_t questId )
|
void Core::Entity::Player::finishQuest( uint16_t questId )
|
||||||
{
|
{
|
||||||
|
|
||||||
int8_t idx = getQuestIndex( questId );
|
int8_t idx = getQuestIndex( static_cast< uint16_t >( questId ) );
|
||||||
|
|
||||||
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
|
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
|
||||||
{
|
{
|
||||||
|
@ -123,7 +123,7 @@ void Core::Entity::Player::unfinishQuest( uint16_t questId )
|
||||||
void Core::Entity::Player::removeQuest( uint16_t questId )
|
void Core::Entity::Player::removeQuest( uint16_t questId )
|
||||||
{
|
{
|
||||||
|
|
||||||
int8_t idx = getQuestIndex( questId );
|
int8_t idx = getQuestIndex( static_cast< uint16_t >( questId ) );
|
||||||
|
|
||||||
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
|
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -131,7 +131,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
|
||||||
|
|
||||||
field[11].getBinary( reinterpret_cast< char* >( m_customize ), sizeof( m_customize ) );
|
field[11].getBinary( reinterpret_cast< char* >( m_customize ), sizeof( m_customize ) );
|
||||||
|
|
||||||
m_modelMainWeapon = field[12].get< uint64_t >();
|
m_modelMainWeapon = field[12].getUInt64();
|
||||||
|
|
||||||
field[14].getBinary( reinterpret_cast< char* >( m_modelEquip ), sizeof( m_modelEquip ) );
|
field[14].getBinary( reinterpret_cast< char* >( m_modelEquip ), sizeof( m_modelEquip ) );
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
|
||||||
|
|
||||||
field[21].getBinary( reinterpret_cast< char* >( m_howTo ), sizeof( m_howTo ) );
|
field[21].getBinary( reinterpret_cast< char* >( m_howTo ), sizeof( m_howTo ) );
|
||||||
|
|
||||||
m_contentId = field[22].get< uint64_t >();
|
m_contentId = field[22].getUInt64();
|
||||||
|
|
||||||
m_voice = field[23].get< uint32_t >();
|
m_voice = field[23].get< uint32_t >();
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,14 @@ namespace Core {
|
||||||
std::string m_helpText;
|
std::string m_helpText;
|
||||||
|
|
||||||
// userlevel needed to execute the command
|
// userlevel needed to execute the command
|
||||||
Common::UserLevel m_userLevel;
|
uint8_t m_gmLevel;
|
||||||
|
|
||||||
DebugCommand( const std::string& n, pFunc functionPtr, const std::string& hText, Common::UserLevel uLevel )
|
DebugCommand( const std::string& n, pFunc functionPtr, const std::string& hText, uint8_t uLevel )
|
||||||
{
|
{
|
||||||
m_commandName = n;
|
m_commandName = n;
|
||||||
m_pFunc = functionPtr;
|
m_pFunc = functionPtr;
|
||||||
m_helpText = hText;
|
m_helpText = hText;
|
||||||
m_userLevel = uLevel;
|
m_gmLevel = uLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
~DebugCommand()
|
~DebugCommand()
|
||||||
|
@ -54,9 +54,9 @@ namespace Core {
|
||||||
return m_helpText;
|
return m_helpText;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::UserLevel getUserLevel() const
|
uint8_t getRequiredGmLevel() const
|
||||||
{
|
{
|
||||||
return m_userLevel;
|
return m_gmLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include <src/servers/Server_Common/Common.h>
|
#include <src/servers/Server_Common/Common.h>
|
||||||
|
#include <src/servers/Server_Common/Version.h>
|
||||||
#include <src/servers/Server_Common/Database/Database.h>
|
#include <src/servers/Server_Common/Database/Database.h>
|
||||||
#include <src/servers/Server_Common/Network/GamePacketNew.h>
|
#include <src/servers/Server_Common/Network/GamePacketNew.h>
|
||||||
#include <src/servers/Server_Common/Network/CommonNetwork.h>
|
#include <src/servers/Server_Common/Network/CommonNetwork.h>
|
||||||
|
@ -39,16 +40,15 @@ extern Core::ServerZone g_serverZone;
|
||||||
// instanciate and initialize commands
|
// instanciate and initialize commands
|
||||||
Core::DebugCommandHandler::DebugCommandHandler()
|
Core::DebugCommandHandler::DebugCommandHandler()
|
||||||
{
|
{
|
||||||
|
// Push all commands onto the register map ( command name - function - description - required GM level )
|
||||||
// Push all commands onto the register map
|
registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "get", &DebugCommandHandler::get, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "get", &DebugCommandHandler::get, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade Packet.", 1 );
|
||||||
//registerCommand( "debug", &DebugCommandHandler::debug, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 );
|
||||||
registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Loads and injects a premade Packet.", Common::UserLevel::all );
|
registerCommand( "info", &DebugCommandHandler::serverInfo, "Send server info", 0 );
|
||||||
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", Common::UserLevel::all );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ Core::DebugCommandHandler::~DebugCommandHandler()
|
||||||
|
|
||||||
// add a command set to the register map
|
// add a command set to the register map
|
||||||
void Core::DebugCommandHandler::registerCommand( const std::string& n, Core::DebugCommand::pFunc functionPtr,
|
void Core::DebugCommandHandler::registerCommand( const std::string& n, Core::DebugCommand::pFunc functionPtr,
|
||||||
const std::string& hText, Core::Common::UserLevel uLevel )
|
const std::string& hText, uint8_t uLevel )
|
||||||
{
|
{
|
||||||
m_commandMap[std::string( n )] = boost::make_shared<DebugCommand>( n, functionPtr, hText, uLevel );
|
m_commandMap[std::string( n )] = boost::make_shared<DebugCommand>( n, functionPtr, hText, uLevel );
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,6 @@ void Core::DebugCommandHandler::registerCommand( const std::string& n, Core::Deb
|
||||||
void Core::DebugCommandHandler::execCommand( char * data, Core::Entity::PlayerPtr pPlayer )
|
void Core::DebugCommandHandler::execCommand( char * data, Core::Entity::PlayerPtr pPlayer )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( pPlayer->getGmRank() <= 0 )
|
|
||||||
{
|
|
||||||
pPlayer->sendUrgent( "You are not allowed to use debug commands." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// define callback pointer
|
// define callback pointer
|
||||||
void ( DebugCommandHandler::*pf )( char *, Entity::PlayerPtr, boost::shared_ptr< DebugCommand > );
|
void ( DebugCommandHandler::*pf )( char *, Entity::PlayerPtr, boost::shared_ptr< DebugCommand > );
|
||||||
|
|
||||||
|
@ -98,9 +92,14 @@ void Core::DebugCommandHandler::execCommand( char * data, Core::Entity::PlayerPt
|
||||||
if( it == m_commandMap.end() )
|
if( it == m_commandMap.end() )
|
||||||
// no command found, do something... or not
|
// no command found, do something... or not
|
||||||
pPlayer->sendUrgent( "Command not found." );
|
pPlayer->sendUrgent( "Command not found." );
|
||||||
// TODO Notify the client of the failed command
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if( pPlayer->getGmRank() < it->second->getRequiredGmLevel() )
|
||||||
|
{
|
||||||
|
pPlayer->sendUrgent( "You are not allowed to use this command." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// command found, call the callback function and pass parameters if present.
|
// command found, call the callback function and pass parameters if present.
|
||||||
pf = ( *it ).second->m_pFunc;
|
pf = ( *it ).second->m_pFunc;
|
||||||
( this->*pf )( data, pPlayer, ( *it ).second );
|
( this->*pf )( data, pPlayer, ( *it ).second );
|
||||||
|
@ -176,33 +175,6 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
|
||||||
pPlayer->queuePacket( setActorPosPacket );
|
pPlayer->queuePacket( setActorPosPacket );
|
||||||
|
|
||||||
}
|
}
|
||||||
else if( ( subCommand == "zone" ) && ( params != "" ) )
|
|
||||||
{
|
|
||||||
int32_t zoneId;
|
|
||||||
sscanf( params.c_str(), "%i", &zoneId );
|
|
||||||
|
|
||||||
if( zoneId < 1 )
|
|
||||||
pPlayer->sendUrgent( "Zone id out of range." );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pPlayer->setPosition( pPlayer->getPos() );
|
|
||||||
pPlayer->performZoning( zoneId, pPlayer->getPos(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if( ( subCommand == "hp" ) && ( params != "" ) )
|
|
||||||
{
|
|
||||||
int32_t hp;
|
|
||||||
sscanf( params.c_str(), "%i", &hp );
|
|
||||||
|
|
||||||
pPlayer->setHp( hp );
|
|
||||||
|
|
||||||
auto control = Network::Packets::Server::ActorControlPacket142( pPlayer->getId(), Common::ActorControlType::HpSetStat, 1, pPlayer->getHp() );
|
|
||||||
|
|
||||||
pPlayer->sendToInRangeSet( control, true );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if( ( subCommand == "tele" ) && ( params != "" ) )
|
else if( ( subCommand == "tele" ) && ( params != "" ) )
|
||||||
{
|
{
|
||||||
int32_t aetheryteId;
|
int32_t aetheryteId;
|
||||||
|
@ -213,8 +185,8 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
|
||||||
|
|
||||||
else if( ( subCommand == "unlockaetheryte" ) && ( params != "" ) )
|
else if( ( subCommand == "unlockaetheryte" ) && ( params != "" ) )
|
||||||
{
|
{
|
||||||
for( uint8_t i = 0; i < 255; i++ )
|
for( uint8_t i = 0; i < 255; i++ )
|
||||||
pPlayer->registerAetheryte( i );
|
pPlayer->registerAetheryte( i );
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( ( subCommand == "discovery" ) && ( params != "" ) )
|
else if( ( subCommand == "discovery" ) && ( params != "" ) )
|
||||||
|
@ -282,18 +254,25 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
|
||||||
else if( subCommand == "aaah" )
|
else if( subCommand == "aaah" )
|
||||||
{
|
{
|
||||||
int32_t id;
|
int32_t id;
|
||||||
|
|
||||||
sscanf( params.c_str(), "%d", &id );
|
sscanf( params.c_str(), "%d", &id );
|
||||||
|
|
||||||
pPlayer->sendDebug( std::to_string( pPlayer->actionHasCastTime( id ) ) );
|
pPlayer->sendDebug( std::to_string( pPlayer->actionHasCastTime( id ) ) );
|
||||||
}
|
}
|
||||||
else if ( subCommand == "cfpenalty" )
|
else if ( subCommand == "cfpenalty" )
|
||||||
{
|
{
|
||||||
int32_t minutes;
|
int32_t minutes;
|
||||||
|
|
||||||
sscanf( params.c_str(), "%d", &minutes );
|
sscanf( params.c_str(), "%d", &minutes );
|
||||||
|
|
||||||
pPlayer->setCFPenaltyMinutes( minutes );
|
pPlayer->setCFPenaltyMinutes( minutes );
|
||||||
}
|
}
|
||||||
|
else if ( subCommand == "eorzeatime" )
|
||||||
|
{
|
||||||
|
uint64_t timestamp;
|
||||||
|
sscanf( params.c_str(), "%llu", ×tamp );
|
||||||
|
|
||||||
|
pPlayer->setEorzeaTimeOffset( timestamp );
|
||||||
|
pPlayer->sendNotice( "Eorzea time offset: " + std::to_string( timestamp ) );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,37 +303,7 @@ void Core::DebugCommandHandler::add( char * data, Core::Entity::PlayerPtr pPlaye
|
||||||
"subCommand " + subCommand + " params: " + params );
|
"subCommand " + subCommand + " params: " + params );
|
||||||
|
|
||||||
|
|
||||||
if( ( subCommand == "item" ) && ( params != "" ) )
|
if( subCommand == "status" )
|
||||||
{
|
|
||||||
int32_t catalogId;
|
|
||||||
int32_t amount;
|
|
||||||
|
|
||||||
sscanf( params.c_str(), "%d %d", &catalogId, &amount );
|
|
||||||
|
|
||||||
if( amount < 1 || amount > 99 )
|
|
||||||
{
|
|
||||||
amount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ( catalogId == 0xcccccccc ) )
|
|
||||||
{
|
|
||||||
pPlayer->sendUrgent( "Syntaxerror." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !pPlayer->addItem( -1, catalogId, amount ) )
|
|
||||||
pPlayer->sendUrgent( "Item " + std::to_string( catalogId ) + " not found..." );
|
|
||||||
|
|
||||||
}
|
|
||||||
else if( subCommand == "exp" )
|
|
||||||
{
|
|
||||||
int32_t amount;
|
|
||||||
|
|
||||||
sscanf( params.c_str(), "%d", &amount );
|
|
||||||
|
|
||||||
pPlayer->gainExp( amount );
|
|
||||||
}
|
|
||||||
else if( subCommand == "status" )
|
|
||||||
{
|
{
|
||||||
int32_t id;
|
int32_t id;
|
||||||
int32_t duration;
|
int32_t duration;
|
||||||
|
@ -534,3 +483,9 @@ void Core::DebugCommandHandler::nudge( char * data, Entity::PlayerPtr pPlayer, b
|
||||||
pPlayer->queuePacket( setActorPosPacket );
|
pPlayer->queuePacket( setActorPosPacket );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::DebugCommandHandler::serverInfo( char * data, Core::Entity::PlayerPtr pPlayer, boost::shared_ptr< Core::DebugCommand > command )
|
||||||
|
{
|
||||||
|
pPlayer->sendDebug( "SapphireServer " + Version::VERSION + " - " + Version::GIT_HASH );
|
||||||
|
pPlayer->sendDebug( "Sessions: " + std::to_string( g_serverZone.getSessionCount() ) );
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
~DebugCommandHandler();
|
~DebugCommandHandler();
|
||||||
|
|
||||||
// register command to command map
|
// register command to command map
|
||||||
void registerCommand( const std::string& n, DebugCommand::pFunc, const std::string& hText, Common::UserLevel uLevel );
|
void registerCommand( const std::string& n, DebugCommand::pFunc, const std::string& hText, uint8_t uLevel );
|
||||||
|
|
||||||
// execute command if registered
|
// execute command if registered
|
||||||
void execCommand( char * data, Entity::PlayerPtr pPlayer );
|
void execCommand( char * data, Entity::PlayerPtr pPlayer );
|
||||||
|
@ -37,6 +37,7 @@ public:
|
||||||
void injectPacket( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void injectPacket( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
void injectChatPacket( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void injectChatPacket( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
void nudge( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void nudge( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
void serverInfo( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -673,7 +673,7 @@ bool Core::Inventory::load()
|
||||||
|
|
||||||
for( int32_t i = 1; i <= 14; i++ )
|
for( int32_t i = 1; i <= 14; i++ )
|
||||||
{
|
{
|
||||||
uint64_t uItemId = field[i].get< uint64_t >();
|
uint64_t uItemId = field[i].getUInt64();
|
||||||
if( uItemId == 0 )
|
if( uItemId == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -710,7 +710,7 @@ bool Core::Inventory::load()
|
||||||
uint16_t storageId = bagField[0].get< uint16_t >();
|
uint16_t storageId = bagField[0].get< uint16_t >();
|
||||||
for( int32_t i = 1; i <= 25; i++ )
|
for( int32_t i = 1; i <= 25; i++ )
|
||||||
{
|
{
|
||||||
uint64_t uItemId = bagField[i].get< uint64_t >();
|
uint64_t uItemId = bagField[i].getUInt64();
|
||||||
if( uItemId == 0 )
|
if( uItemId == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -743,7 +743,7 @@ bool Core::Inventory::load()
|
||||||
uint16_t storageId = curField[0].get< uint16_t >();
|
uint16_t storageId = curField[0].get< uint16_t >();
|
||||||
for( int32_t i = 1; i <= 12; i++ )
|
for( int32_t i = 1; i <= 12; i++ )
|
||||||
{
|
{
|
||||||
uint64_t uItemId = curField[i].get< uint64_t >();
|
uint64_t uItemId = curField[i].getUInt64();
|
||||||
if( uItemId == 0 )
|
if( uItemId == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -777,7 +777,7 @@ bool Core::Inventory::load()
|
||||||
uint16_t storageId = crystalField[0].get< uint16_t >();
|
uint16_t storageId = crystalField[0].get< uint16_t >();
|
||||||
for( int32_t i = 1; i <= 17; i++ )
|
for( int32_t i = 1; i <= 17; i++ )
|
||||||
{
|
{
|
||||||
uint64_t uItemId = crystalField[i].get< uint64_t >();
|
uint64_t uItemId = crystalField[i].getUInt64();
|
||||||
if( uItemId == 0 )
|
if( uItemId == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
|
||||||
case 0x68: // Remove status (clicking it off)
|
case 0x68: // Remove status (clicking it off)
|
||||||
{
|
{
|
||||||
// todo: check if status can be removed by client from exd
|
// todo: check if status can be removed by client from exd
|
||||||
pPlayer->removeSingleStatusEffectFromId( param1 );
|
pPlayer->removeSingleStatusEffectFromId( static_cast< uint32_t >( param1 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x69: // Cancel cast
|
case 0x69: // Cancel cast
|
||||||
|
|
|
@ -69,6 +69,7 @@ enum GmCommand
|
||||||
Mp = 0x0065,
|
Mp = 0x0065,
|
||||||
Tp = 0x0066,
|
Tp = 0x0066,
|
||||||
Gp = 0x0067,
|
Gp = 0x0067,
|
||||||
|
Exp = 0x0068,
|
||||||
|
|
||||||
Item = 0x00C8,
|
Item = 0x00C8,
|
||||||
Gil = 0x00C9,
|
Gil = 0x00C9,
|
||||||
|
@ -82,6 +83,7 @@ enum GmCommand
|
||||||
QuestInspect = 0x0131,
|
QuestInspect = 0x0131,
|
||||||
GC = 0x0154,
|
GC = 0x0154,
|
||||||
GCRank = 0x0155,
|
GCRank = 0x0155,
|
||||||
|
Teri = 0x0258,
|
||||||
TeriInfo = 0x025D,
|
TeriInfo = 0x025D,
|
||||||
Jump = 0x025E,
|
Jump = 0x025E,
|
||||||
JumpNpc = 0x025F,
|
JumpNpc = 0x025F,
|
||||||
|
@ -189,6 +191,12 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
|
||||||
pPlayer->sendNotice( "Gp for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
|
pPlayer->sendNotice( "Gp for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GmCommand::Exp:
|
||||||
|
{
|
||||||
|
targetPlayer->gainExp( param1 );
|
||||||
|
pPlayer->sendNotice( std::to_string( param1 ) + " Exp was added to " + targetPlayer->getName() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GmCommand::Sex:
|
case GmCommand::Sex:
|
||||||
{
|
{
|
||||||
targetPlayer->setLookAt( CharaLook::Gender, param1 );
|
targetPlayer->setLookAt( CharaLook::Gender, param1 );
|
||||||
|
@ -245,6 +253,12 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
|
||||||
pPlayer->sendUrgent( "Item " + std::to_string( param1 ) + " not found..." );
|
pPlayer->sendUrgent( "Item " + std::to_string( param1 ) + " not found..." );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GmCommand::Time:
|
||||||
|
{
|
||||||
|
pPlayer->setEorzeaTimeOffset( param2 );
|
||||||
|
pPlayer->sendNotice( "Eorzea time offset: " + std::to_string( param2 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GmCommand::Weather:
|
case GmCommand::Weather:
|
||||||
{
|
{
|
||||||
targetPlayer->getCurrentZone()->setWeatherOverride( param1 );
|
targetPlayer->getCurrentZone()->setWeatherOverride( param1 );
|
||||||
|
@ -262,6 +276,18 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
|
||||||
"\nNextWeather:" + std::to_string( pPlayer->getCurrentZone()->getNextWeather() ) );
|
"\nNextWeather:" + std::to_string( pPlayer->getCurrentZone()->getNextWeather() ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GmCommand::Teri:
|
||||||
|
{
|
||||||
|
if( param1 < 128 )
|
||||||
|
pPlayer->sendUrgent( "Zone ID out of range." );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetPlayer->setPosition( targetPlayer->getPos() );
|
||||||
|
targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 );
|
||||||
|
pPlayer->sendNotice( targetPlayer->getName() + " was warped to Zone " + std::to_string( param1 ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GmCommand::Jump:
|
case GmCommand::Jump:
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -493,7 +493,7 @@ void Core::Network::GameConnection::chatHandler( const Packets::GamePacket& inPa
|
||||||
|
|
||||||
uint32_t sourceId = inPacket.getValAt< uint32_t >( 0x24 );
|
uint32_t sourceId = inPacket.getValAt< uint32_t >( 0x24 );
|
||||||
|
|
||||||
if( chatString.at( 0 ) == '@' )
|
if( chatString.at( 0 ) == '!' )
|
||||||
{
|
{
|
||||||
// execute game console command
|
// execute game console command
|
||||||
g_gameCommandMgr.execCommand( const_cast< char * >( chatString.c_str() ) + 1, pPlayer );
|
g_gameCommandMgr.execCommand( const_cast< char * >( chatString.c_str() ) + 1, pPlayer );
|
||||||
|
@ -597,4 +597,4 @@ void Core::Network::GameConnection::tellHandler( const Packets::GamePacket& inPa
|
||||||
//tellPacket.data().u2b = 0x40;
|
//tellPacket.data().u2b = 0x40;
|
||||||
pTargetPlayer->queueChatPacket( tellPacket );
|
pTargetPlayer->queueChatPacket( tellPacket );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP
|
||||||
std::string actionIdStr = boost::str( boost::format( "%|04X|" ) % action );
|
std::string actionIdStr = boost::str( boost::format( "%|04X|" ) % action );
|
||||||
pPlayer->sendDebug( "---------------------------------------" );
|
pPlayer->sendDebug( "---------------------------------------" );
|
||||||
pPlayer->sendDebug( "ActionHandler ( " + actionIdStr + " | " +
|
pPlayer->sendDebug( "ActionHandler ( " + actionIdStr + " | " +
|
||||||
g_exdData.m_actionInfoMap[action].name +
|
g_exdData.getActionInfo( action )->name +
|
||||||
" | " + std::to_string( targetId ) + " )" );
|
" | " + std::to_string( targetId ) + " )" );
|
||||||
|
|
||||||
pPlayer->queuePacket( ActorControlPacket142( pPlayer->getId(), ActorControlType::ActionStart, 0x01, action ) );
|
pPlayer->queuePacket( ActorControlPacket142( pPlayer->getId(), ActorControlType::ActionStart, 0x01, action ) );
|
||||||
|
|
|
@ -346,7 +346,7 @@ bool Core::Scripting::ScriptManager::onMobKill( Entity::PlayerPtr pPlayer, uint1
|
||||||
// loop through all active quests and try to call available onMobKill callbacks
|
// loop through all active quests and try to call available onMobKill callbacks
|
||||||
for( size_t i = 0; i < 30; i++ )
|
for( size_t i = 0; i < 30; i++ )
|
||||||
{
|
{
|
||||||
auto activeQuests = pPlayer->getQuestActive( i );
|
auto activeQuests = pPlayer->getQuestActive( static_cast< uint16_t >( i ) );
|
||||||
if( !activeQuests )
|
if( !activeQuests )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,11 @@ Core::XMLConfigPtr Core::ServerZone::getConfig() const
|
||||||
return m_pConfig;
|
return m_pConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Core::ServerZone::getSessionCount() const
|
||||||
|
{
|
||||||
|
return m_sessionMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
|
bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
|
||||||
uint32_t bnpcNameId, uint32_t modelId, std::string aiName )
|
uint32_t bnpcNameId, uint32_t modelId, std::string aiName )
|
||||||
{
|
{
|
||||||
|
@ -101,7 +106,7 @@ bool Core::ServerZone::loadSettings( int32_t argc, char* argv[] )
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> args( argv + 1, argv + argc );
|
std::vector<std::string> args( argv + 1, argv + argc );
|
||||||
for( auto i = 0; i + 1 < args.size(); i += 2 )
|
for( uint32_t i = 0; i + 1 < args.size(); i += 2 )
|
||||||
{
|
{
|
||||||
std::string arg( "" );
|
std::string arg( "" );
|
||||||
std::string val( "" );
|
std::string val( "" );
|
||||||
|
|
|
@ -33,6 +33,8 @@ namespace Core {
|
||||||
|
|
||||||
XMLConfigPtr getConfig() const;
|
XMLConfigPtr getConfig() const;
|
||||||
|
|
||||||
|
size_t getSessionCount() const;
|
||||||
|
|
||||||
bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
|
bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
|
||||||
uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
|
uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,8 @@ void Core::StatusEffect::StatusEffectContainer::addStatusEffect( StatusEffectPtr
|
||||||
m_effectMap[nextSlot] = pEffect;
|
m_effectMap[nextSlot] = pEffect;
|
||||||
|
|
||||||
GamePacketNew< Server::FFXIVIpcAddStatusEffect, ServerZoneIpcType > statusEffectAdd( m_pOwner->getId() );
|
GamePacketNew< Server::FFXIVIpcAddStatusEffect, ServerZoneIpcType > statusEffectAdd( m_pOwner->getId() );
|
||||||
statusEffectAdd.data().actor_id = m_pOwner->getId();
|
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
|
||||||
statusEffectAdd.data().actor_id1 = m_pOwner->getId();
|
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
|
||||||
statusEffectAdd.data().current_hp = m_pOwner->getHp();
|
statusEffectAdd.data().current_hp = m_pOwner->getHp();
|
||||||
statusEffectAdd.data().current_mp = m_pOwner->getMp();
|
statusEffectAdd.data().current_mp = m_pOwner->getMp();
|
||||||
statusEffectAdd.data().current_tp = m_pOwner->getTp();
|
statusEffectAdd.data().current_tp = m_pOwner->getTp();
|
||||||
|
@ -71,6 +71,7 @@ void Core::StatusEffect::StatusEffectContainer::addStatusEffect( StatusEffectPtr
|
||||||
//statusEffectAdd.data().unknown2 = 28;
|
//statusEffectAdd.data().unknown2 = 28;
|
||||||
statusEffectAdd.data().param = pEffect->getParam();
|
statusEffectAdd.data().param = pEffect->getParam();
|
||||||
|
|
||||||
|
|
||||||
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
|
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
|
||||||
m_pOwner->sendToInRangeSet( statusEffectAdd, sendToSelf );
|
m_pOwner->sendToInRangeSet( statusEffectAdd, sendToSelf );
|
||||||
|
|
||||||
|
@ -142,8 +143,8 @@ void Core::StatusEffect::StatusEffectContainer::update()
|
||||||
{
|
{
|
||||||
uint64_t currentTimeMs = Util::getTimeMs();
|
uint64_t currentTimeMs = Util::getTimeMs();
|
||||||
|
|
||||||
uint64_t thisTickDmg = 0;
|
uint32_t thisTickDmg = 0;
|
||||||
uint64_t thisTickHeal = 0;
|
uint32_t thisTickHeal = 0;
|
||||||
|
|
||||||
for( auto effectIt : m_effectMap )
|
for( auto effectIt : m_effectMap )
|
||||||
{
|
{
|
||||||
|
|
|
@ -189,7 +189,7 @@ void Zone::loadCellCache()
|
||||||
Entity::BattleNpcPtr pBNpc( new Entity::BattleNpc( modelId, nameId,
|
Entity::BattleNpcPtr pBNpc( new Entity::BattleNpc( modelId, nameId,
|
||||||
pos,
|
pos,
|
||||||
sizeId, type, level, behaviour, mobType ) );
|
sizeId, type, level, behaviour, mobType ) );
|
||||||
pBNpc->setRotation( rotation );
|
pBNpc->setRotation( static_cast< float >( rotation ) );
|
||||||
cache.push_back( pBNpc );
|
cache.push_back( pBNpc );
|
||||||
|
|
||||||
//pushActor( pBNpc );
|
//pushActor( pBNpc );
|
||||||
|
|
Loading…
Add table
Reference in a new issue