mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 12:31:31 +00:00
commit
519c049902
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,5 +33,7 @@ Build_32/
|
|||||||
build_32/
|
build_32/
|
||||||
Build_64/
|
Build_64/
|
||||||
build_64/
|
build_64/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
log/
|
log/
|
||||||
logs/
|
logs/
|
||||||
|
|||||||
@ -13,12 +13,6 @@
|
|||||||
#EQEMU_LOG_LEVEL_QUEST
|
#EQEMU_LOG_LEVEL_QUEST
|
||||||
#EQEMU_LOG_LEVEL_COMMANDS
|
#EQEMU_LOG_LEVEL_COMMANDS
|
||||||
#EQEMU_LOG_LEVEL_CRASH
|
#EQEMU_LOG_LEVEL_CRASH
|
||||||
#EQEMU_STREAM_SEND_RATE
|
|
||||||
#EQEMU_STREAM_DECAY_RATE
|
|
||||||
#EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL
|
|
||||||
#EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX
|
|
||||||
#EQEMU_STREAM_AVERAGE_DELTA_MAX
|
|
||||||
#EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS
|
|
||||||
#EQEMU_DEPOP_INVALIDATES_CACHE
|
#EQEMU_DEPOP_INVALIDATES_CACHE
|
||||||
#EQEMU_ENABLE_BOTS
|
#EQEMU_ENABLE_BOTS
|
||||||
#EQEMU_DISABLE_LOGSYS
|
#EQEMU_DISABLE_LOGSYS
|
||||||
@ -78,7 +72,7 @@ IF(MSVC)
|
|||||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
|
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
|
||||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
|
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
|
||||||
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
|
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
|
||||||
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x64")
|
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x86")
|
||||||
IF(MSVC_VERSION GREATER 1800)
|
IF(MSVC_VERSION GREATER 1800)
|
||||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
|
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
|
||||||
ELSEIF(MSVC_VERSION EQUAL 1800)
|
ELSEIF(MSVC_VERSION EQUAL 1800)
|
||||||
@ -237,14 +231,6 @@ SET(EQEMU_LOG_LEVEL_CRASH 3 CACHE STRING "EQEmu logging level for [Crash]:
|
|||||||
|
|
||||||
MARK_AS_ADVANCED(EQEMU_LOG_LEVEL_STATUS EQEMU_LOG_LEVEL_NORMAL EQEMU_LOG_LEVEL_ERROR EQEMU_LOG_LEVEL_DEBUG EQEMU_LOG_LEVEL_QUEST EQEMU_LOG_LEVEL_COMMANDS EQEMU_LOG_LEVEL_CRASH)
|
MARK_AS_ADVANCED(EQEMU_LOG_LEVEL_STATUS EQEMU_LOG_LEVEL_NORMAL EQEMU_LOG_LEVEL_ERROR EQEMU_LOG_LEVEL_DEBUG EQEMU_LOG_LEVEL_QUEST EQEMU_LOG_LEVEL_COMMANDS EQEMU_LOG_LEVEL_CRASH)
|
||||||
|
|
||||||
SET(EQEMU_STREAM_SEND_RATE 1048576 CACHE STRING "Advanced: Base amount of data stream can send before throttle.")
|
|
||||||
SET(EQEMU_STREAM_DECAY_RATE 78642 CACHE STRING "Advanced: Base amount of data stream recovers per tic.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL 3.0 CACHE STRING "Advanced: Multiplier on retransmit timeout.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX 5000 CACHE STRING "Advanced: Max in ms for retransmit timeout timer.")
|
|
||||||
SET(EQEMU_STREAM_AVERAGE_DELTA_MAX 2500 CACHE STRING "Advanced: The maximum average delta in ms allowed.")
|
|
||||||
SET(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS TRUE CACHE BOOL "Advanced: Whether or not acked packets can be retransmitted")
|
|
||||||
MARK_AS_ADVANCED(EQEMU_STREAM_SEND_RATE EQEMU_STREAM_DECAY_RATE EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX EQEMU_STREAM_AVERAGE_DELTA_MAX EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
|
|
||||||
#NPC Types Cache Behavior
|
#NPC Types Cache Behavior
|
||||||
OPTION(EQEMU_DEPOP_INVALIDATES_CACHE "#repop invalidates the npc_types cache (will cause a larger database hit on #repop but is more convienent)." ON)
|
OPTION(EQEMU_DEPOP_INVALIDATES_CACHE "#repop invalidates the npc_types cache (will cause a larger database hit on #repop but is more convienent)." ON)
|
||||||
|
|
||||||
@ -306,11 +292,6 @@ ADD_DEFINITIONS(-DEQDEBUG=${EQEMU_DEBUG_LEVEL})
|
|||||||
ADD_DEFINITIONS(-DINVERSEXY)
|
ADD_DEFINITIONS(-DINVERSEXY)
|
||||||
ADD_DEFINITIONS(-DFIELD_ITEMS)
|
ADD_DEFINITIONS(-DFIELD_ITEMS)
|
||||||
ADD_DEFINITIONS(-DMAP_DIR="${EQEMU_MAP_DIR}")
|
ADD_DEFINITIONS(-DMAP_DIR="${EQEMU_MAP_DIR}")
|
||||||
ADD_DEFINITIONS(-DRATEBASE=${EQEMU_STREAM_SEND_RATE})
|
|
||||||
ADD_DEFINITIONS(-DDECAYBASE=${EQEMU_STREAM_DECAY_RATE})
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_TIMEOUT_MULT=${EQEMU_STREAM_RETRANSMIT_TIMEOUT_MUL})
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_TIMEOUT_MAX=${EQEMU_STREAM_RETRANSMIT_TIMEOUT_MAX})
|
|
||||||
ADD_DEFINITIONS(-DAVERAGE_DELTA_MAX=${EQEMU_STREAM_AVERAGE_DELTA_MAX})
|
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_STATUS=${EQEMU_LOG_LEVEL_STATUS})
|
ADD_DEFINITIONS(-DLOG_LEVEL_STATUS=${EQEMU_LOG_LEVEL_STATUS})
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_NORMAL=${EQEMU_LOG_LEVEL_NORMAL})
|
ADD_DEFINITIONS(-DLOG_LEVEL_NORMAL=${EQEMU_LOG_LEVEL_NORMAL})
|
||||||
ADD_DEFINITIONS(-DLOG_LEVEL_ERROR=${EQEMU_LOG_LEVEL_ERROR})
|
ADD_DEFINITIONS(-DLOG_LEVEL_ERROR=${EQEMU_LOG_LEVEL_ERROR})
|
||||||
@ -320,12 +301,6 @@ ADD_DEFINITIONS(-DLOG_LEVEL_COMMANDS=${EQEMU_LOG_LEVEL_COMMANDS})
|
|||||||
ADD_DEFINITIONS(-DLOG_LEVEL_CRASH=${EQEMU_LOG_LEVEL_CRASH})
|
ADD_DEFINITIONS(-DLOG_LEVEL_CRASH=${EQEMU_LOG_LEVEL_CRASH})
|
||||||
ADD_DEFINITIONS(-DGLM_FORCE_RADIANS)
|
ADD_DEFINITIONS(-DGLM_FORCE_RADIANS)
|
||||||
|
|
||||||
IF(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_ACKED_PACKETS=true)
|
|
||||||
ELSE(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
ADD_DEFINITIONS(-DRETRANSMIT_ACKED_PACKETS=false)
|
|
||||||
ENDIF(EQEMU_STREAM_RETRANSMIT_ACKED_PACKETS)
|
|
||||||
|
|
||||||
#Find everything we need
|
#Find everything we need
|
||||||
FIND_PACKAGE(ZLIB REQUIRED)
|
FIND_PACKAGE(ZLIB REQUIRED)
|
||||||
FIND_PACKAGE(MySQL REQUIRED)
|
FIND_PACKAGE(MySQL REQUIRED)
|
||||||
|
|||||||
12
README.md
12
README.md
@ -8,7 +8,7 @@
|
|||||||
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
|
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
|
||||||
* MySQL/MariaDB is used as the database engine (over 200+ tables)
|
* MySQL/MariaDB is used as the database engine (over 200+ tables)
|
||||||
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
|
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
|
||||||
* Open source database (Project EQ) has content up to expansion GoD (included in server installs)
|
* Open source database (Project EQ) has content up to expansion OoW (included in server installs)
|
||||||
* Game server environments and databases can be heavily customized to create all new experiences
|
* Game server environments and databases can be heavily customized to create all new experiences
|
||||||
* Hundreds of Quests/events created and maintained by Project EQ
|
* Hundreds of Quests/events created and maintained by Project EQ
|
||||||
|
|
||||||
@ -20,14 +20,14 @@
|
|||||||
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
|
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
|
||||||
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
|
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
|
||||||
|
|
||||||
### > Debian/Ubuntu
|
|
||||||
|
|
||||||
|
### > Debian/Ubuntu/CentOS/Fedora
|
||||||
|
* You can use curl or wget to kick off the installer (whichever your OS has)
|
||||||
|
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
|
||||||
|
|
||||||
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
||||||
|
|
||||||
### > CentOS/Fedora
|
|
||||||
|
|
||||||
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
|
|
||||||
|
|
||||||
## Supported Clients
|
## Supported Clients
|
||||||
|
|
||||||
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|
||||||
|
|||||||
@ -1,25 +1,71 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
== 7/14/2017 ==
|
||||||
|
Akkadius: HP Update tuning - HP Updates are now forced when a client is targeted
|
||||||
|
Akkadius: Client position updates should be smoother (granted the client has a good connection)
|
||||||
|
- Clients should also no longer randomly disappear
|
||||||
|
|
||||||
|
== 7/11/2017 ==
|
||||||
|
Akkadius: Raid/Group/XTarget HP/Mana/Endurance updates now only send when percentage changes
|
||||||
|
Akkadius: Raid/Group Mana/Endurance updates should now update real-time once again
|
||||||
|
Akkadius: Fixed an issue with clients looking like they are 'skipping' when they are moving in view of another client
|
||||||
|
Akkadius: Fixed an issue with NPC's who are ghosted in plain view of a client when they are not really there
|
||||||
|
|
||||||
|
== 7/9/2017 ==
|
||||||
|
Akkadius: Fix HP update issues, rework logic for more accurate HP updates
|
||||||
|
Akkadius: Massive reductions in unnecessary network traffic especially during high spam combat fights
|
||||||
|
- HP Updates now only send to others when HP percentage changes (0-100%)
|
||||||
|
- HP Updates were sending excessively even during idle zones when HP wasn't changing at all
|
||||||
|
- Attack animations now only send once per second versus up to a hundred times a second per Mob/Client
|
||||||
|
- 17,000 OP_ClientUpdate packets per second have been observed in combat scenarios, some of the major culprits have been
|
||||||
|
throttled without affecting what the client should see
|
||||||
|
- Before and After packet differences under similar load/tests (Packets per second)
|
||||||
|
- 7,000 - 8,000 OP_Animation pps After: 600-800 pps
|
||||||
|
- 13,0000 - 17,000 OP_MobHealth pps After: 1-10 pps
|
||||||
|
- 15,0000 - 20,000 OP_ClientUpdate pps After: 500-1,000 pps
|
||||||
|
- Packet reports from a 46 client test here:
|
||||||
|
https://gist.github.com/Akkadius/28b7ad2fdd82bdd15ea737c68f404346
|
||||||
|
- Servers who use Marquee HP updates will also recieve far less packet spam as they will only be sent when HP changes
|
||||||
|
|
||||||
|
== 7/1/2017 ==
|
||||||
|
Akkadius: Resolve issues with NPC's hopping to the ceiling in small corridors
|
||||||
|
Akkadius: Improved grounding issues with NPC's during combat
|
||||||
|
Akkadius: Improved scenarios where NPC's need to be dragged out of the ground - they should correct themselves far more consistently
|
||||||
|
- Scenarios where an NPC is coming up from the bottom floor, or from the top floor, they will correct much better
|
||||||
|
- A video of these tests can be found here: https://www.youtube.com/watch?v=HtC7bVNM7ZQ&feature=youtu.be
|
||||||
|
|
||||||
|
== 6/28/2017 ==
|
||||||
|
Akkadius: Fixed issues with Z correctness when NPCs are pathing on normal grids
|
||||||
|
Akkadius: Fixed issues with Z correctness when NPCs are engaged with players following
|
||||||
|
Akkadius: NPC corpses should fall into the ground far less
|
||||||
|
|
||||||
|
== 6/25/2017 ==
|
||||||
|
Akkadius: New rules made by developers are now automatically created when world boots up, this keeps
|
||||||
|
from having to issue schema SQL updates every time rules are added.
|
||||||
|
- Whenever a rule isn't present in the database, it will be automatically created
|
||||||
|
Akkadius: Sped up saylink retrieval x1000 helpful for dialogues, plugins with many saylinks
|
||||||
|
|
||||||
== 4/16/2017 ==
|
== 4/16/2017 ==
|
||||||
KLS: Merge eqstream branch
|
KLS: Merge eqstream branch
|
||||||
-UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs).
|
- UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs).
|
||||||
-TCP Server to Server connection stack completely rewritten.
|
- TCP Server to Server connection stack completely rewritten.
|
||||||
-Server connections reconnect much more reliably and quickly now.
|
- Server connections reconnect much more reliably and quickly now.
|
||||||
-Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/).
|
- Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/).
|
||||||
-Protocol behind the tcp connections has changed (see breaking changes section).
|
- Protocol behind the tcp connections has changed (see breaking changes section).
|
||||||
-API significantly changed and should be easier to write new servers or handlers for.
|
- API significantly changed and should be easier to write new servers or handlers for.
|
||||||
-Telnet console connection has been separated out from the current port (see breaking changes section).
|
- Telnet console connection has been separated out from the current port (see breaking changes section).
|
||||||
-Because of changes to the TCP stack, lsreconnect and echo have been disabled.
|
- Because of changes to the TCP stack, lsreconnect and echo have been disabled.
|
||||||
-The server tic rate has been changed to be approx 30 fps from 500+ fps.
|
- The server tic rate has been changed to be approx 30 fps from 500+ fps.
|
||||||
-Changed how missiles and movement were calculated slightly to account for this (Missiles in particular are not perfect but close enough).
|
- Changed how missiles and movement were calculated slightly to account for this (Missiles in particular are not perfect but close enough).
|
||||||
|
|
||||||
-Breaking changes:
|
- Breaking changes:
|
||||||
-Users who use the cmake install feature should be aware that the install directory is now %cmake_install_dir%/bin instead of just %cmake_install_dir%/
|
- Users who use the cmake install feature should be aware that the install directory is now %cmake_install_dir%/bin instead of just %cmake_install_dir%/
|
||||||
-To support new features such as encryption the underlying protocol had to change... however some servers such as the public login server will be slow to change so we've included a compatibility layer for legacy login connections:
|
- To support new features such as encryption the underlying protocol had to change... however some servers such as the public login server will be slow to change so we've included a compatibility layer for legacy login connections:
|
||||||
-You should add <legacy>1</legacy> to the login section of your configuration file when connecting to a server that is using the old protocol.
|
- You should add <legacy>1</legacy> to the login section of your configuration file when connecting to a server that is using the old protocol.
|
||||||
-The central eqemu login server uses the old protocol and probably will for the forseeable future so if your server is connecting to it be sure to add that tag to your configuration file in that section.
|
- The central eqemu login server uses the old protocol and probably will for the forseeable future so if your server is connecting to it be sure to add that tag to your configuration file in that section.
|
||||||
-Telnet no longer uses the same port as the Server to Server connection and because of this the tcp tag no longer has any effect on telnet connections.
|
- Telnet no longer uses the same port as the Server to Server connection and because of this the tcp tag no longer has any effect on telnet connections.
|
||||||
-To enable telnet you need to add a telnet tag in the world section of configuration such as:
|
- To enable telnet you need to add a telnet tag in the world section of configuration such as:
|
||||||
<telnet ip="0.0.0.0" port="9001" enabled="true"/>
|
<telnet ip="0.0.0.0" port="9001" enabled="true"/>
|
||||||
|
|
||||||
== 4/1/2017 ==
|
== 4/1/2017 ==
|
||||||
|
|||||||
@ -103,6 +103,7 @@ SET(common_sources
|
|||||||
tinyxml/tinyxml.cpp
|
tinyxml/tinyxml.cpp
|
||||||
tinyxml/tinyxmlerror.cpp
|
tinyxml/tinyxmlerror.cpp
|
||||||
tinyxml/tinyxmlparser.cpp
|
tinyxml/tinyxmlparser.cpp
|
||||||
|
util/directory.cpp
|
||||||
util/uuid.cpp
|
util/uuid.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -257,6 +258,7 @@ SET(common_headers
|
|||||||
tinyxml/tinystr.h
|
tinyxml/tinystr.h
|
||||||
tinyxml/tinyxml.h
|
tinyxml/tinyxml.h
|
||||||
util/memory_stream.h
|
util/memory_stream.h
|
||||||
|
util/directory.h
|
||||||
util/uuid.h
|
util/uuid.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -366,6 +368,8 @@ SOURCE_GROUP(TinyXML FILES
|
|||||||
|
|
||||||
SOURCE_GROUP(Util FILES
|
SOURCE_GROUP(Util FILES
|
||||||
util/memory_stream.h
|
util/memory_stream.h
|
||||||
|
util/directory.cpp
|
||||||
|
util/directory.h
|
||||||
util/uuid.cpp
|
util/uuid.cpp
|
||||||
util/uuid.h
|
util/uuid.h
|
||||||
)
|
)
|
||||||
|
|||||||
@ -355,6 +355,7 @@ N(OP_OpenTributeMaster),
|
|||||||
N(OP_PDeletePetition),
|
N(OP_PDeletePetition),
|
||||||
N(OP_PetBuffWindow),
|
N(OP_PetBuffWindow),
|
||||||
N(OP_PetCommands),
|
N(OP_PetCommands),
|
||||||
|
N(OP_PetCommandState),
|
||||||
N(OP_PetHoTT),
|
N(OP_PetHoTT),
|
||||||
N(OP_Petition),
|
N(OP_Petition),
|
||||||
N(OP_PetitionBug),
|
N(OP_PetitionBug),
|
||||||
@ -407,6 +408,7 @@ N(OP_ReloadUI),
|
|||||||
N(OP_RemoveAllDoors),
|
N(OP_RemoveAllDoors),
|
||||||
N(OP_RemoveBlockedBuffs),
|
N(OP_RemoveBlockedBuffs),
|
||||||
N(OP_RemoveNimbusEffect),
|
N(OP_RemoveNimbusEffect),
|
||||||
|
N(OP_RemoveTrap),
|
||||||
N(OP_Report),
|
N(OP_Report),
|
||||||
N(OP_ReqClientSpawn),
|
N(OP_ReqClientSpawn),
|
||||||
N(OP_ReqNewZone),
|
N(OP_ReqNewZone),
|
||||||
@ -522,6 +524,7 @@ N(OP_TributeToggle),
|
|||||||
N(OP_TributeUpdate),
|
N(OP_TributeUpdate),
|
||||||
N(OP_Untargetable),
|
N(OP_Untargetable),
|
||||||
N(OP_UpdateAA),
|
N(OP_UpdateAA),
|
||||||
|
N(OP_UpdateAura),
|
||||||
N(OP_UpdateLeadershipAA),
|
N(OP_UpdateLeadershipAA),
|
||||||
N(OP_VetClaimReply),
|
N(OP_VetClaimReply),
|
||||||
N(OP_VetClaimRequest),
|
N(OP_VetClaimRequest),
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
//SpawnAppearance types: (compared two clients for server-originating types: SoF & RoF2)
|
//SpawnAppearance types: (compared two clients for server-originating types: SoF & RoF2)
|
||||||
#define AT_Die 0 // this causes the client to keel over and zone to bind point (default action)
|
#define AT_Die 0 // this causes the client to keel over and zone to bind point (default action)
|
||||||
#define AT_WhoLevel 1 // the level that shows up on /who
|
#define AT_WhoLevel 1 // the level that shows up on /who
|
||||||
//#define AT_2 2 // unknown
|
#define AT_HPMax 2 // idk
|
||||||
#define AT_Invis 3 // 0 = visible, 1 = invisible
|
#define AT_Invis 3 // 0 = visible, 1 = invisible
|
||||||
#define AT_PVP 4 // 0 = blue, 1 = pvp (red)
|
#define AT_PVP 4 // 0 = blue, 1 = pvp (red)
|
||||||
#define AT_Light 5 // light type emitted by player (lightstone, shiny shield)
|
#define AT_Light 5 // light type emitted by player (lightstone, shiny shield)
|
||||||
@ -36,33 +36,37 @@
|
|||||||
#define AT_SpawnID 16 // server to client, sets player spawn id
|
#define AT_SpawnID 16 // server to client, sets player spawn id
|
||||||
#define AT_HP 17 // Client->Server, my HP has changed (like regen tic)
|
#define AT_HP 17 // Client->Server, my HP has changed (like regen tic)
|
||||||
#define AT_Linkdead 18 // 0 = normal, 1 = linkdead
|
#define AT_Linkdead 18 // 0 = normal, 1 = linkdead
|
||||||
#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate
|
#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate max 5, see GravityBehavior enum
|
||||||
#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM
|
#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM
|
||||||
#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
||||||
#define AT_GuildID 22
|
#define AT_GuildID 22
|
||||||
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
||||||
#define AT_AFK 24 // 0 = normal, 1 = afk
|
#define AT_AFK 24 // 0 = normal, 1 = afk
|
||||||
#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks
|
#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks
|
||||||
//#define AT_27 27 // unknown
|
#define AT_Summoned 27 // Unsure
|
||||||
#define AT_Split 28 // 0 = normal, 1 = autosplit on (not showing in SoF+) (client-to-server only)
|
#define AT_Split 28 // 0 = normal, 1 = autosplit on (not showing in SoF+) (client-to-server only)
|
||||||
#define AT_Size 29 // spawn's size (present: SoF, absent: RoF2)
|
#define AT_Size 29 // spawn's size (present: SoF, absent: RoF2)
|
||||||
//#define AT_30 30 // unknown
|
#define AT_SetType 30 // 0 = PC, 1 = NPC, 2 <= = corpse
|
||||||
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name
|
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name, Trader on RoF2?
|
||||||
//#define AT_32 32 // unknown
|
#define AT_AARank 32 // AA Rank Title ID thingy, does is this the title in /who?
|
||||||
//#define AT_33 33 // unknown
|
#define AT_CancelSneakHide 33 // Turns off Hide and Sneak
|
||||||
//#define AT_34 34 // unknown (present: SoF, absent: RoF2)
|
//#define AT_34 34 // unknown (present: SoF, absent: RoF2)
|
||||||
//#define AT_35 35 // unknown
|
#define AT_AreaHPRegen 35 // guild hall regen pool sets to value * 0.001
|
||||||
//#define AT_36 36 // unknown
|
#define AT_AreaManaRegen 36 // guild hall regen pool sets to value * 0.001
|
||||||
//#define AT_37 37 // unknown
|
#define AT_AreaEndRegen 37 // guild hall regen pool sets to value * 0.001
|
||||||
//#define AT_38 38 // unknown
|
#define AT_FreezeBuffs 38 // Freezes beneficial buff timers
|
||||||
//#define AT_39 39 // unknown
|
#define AT_NpcTintIndex 39 // not 100% sure
|
||||||
|
#define AT_GroupConsent 40 // auto consent group
|
||||||
|
#define AT_RaidConsent 41 // auto consent raid
|
||||||
|
#define AT_GuildConsent 42 // auto consent guild
|
||||||
#define AT_ShowHelm 43 // 0 = hide graphic, 1 = show graphic
|
#define AT_ShowHelm 43 // 0 = hide graphic, 1 = show graphic
|
||||||
#define AT_DamageState 44 // The damage state of a destructible object (0 through 4)
|
#define AT_DamageState 44 // The damage state of a destructible object (0 through 10) plays soundids most only have 2 or 4 states though
|
||||||
//#define AT_46 46 // unknown
|
#define AT_EQPlayers 45 // /eqplayersupdate
|
||||||
//#define AT_48 48 // unknown
|
#define AT_FindBits 46 // set FindBits, whatever those are!
|
||||||
//#define AT_49 49 // unknown
|
#define AT_TextureType 48 // TextureType
|
||||||
//#define AT_52 52 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
#define AT_FacePick 49 // Turns off face pick window? maybe ...
|
||||||
//#define AT_53 53 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
#define AT_GuildShow 52 // this is what MQ2 call sit, not sure
|
||||||
|
#define AT_Offline 53 // Offline mode
|
||||||
|
|
||||||
//#define AT_Trader 300 // Bazaar Trader Mode (not present in SoF or RoF2)
|
//#define AT_Trader 300 // Bazaar Trader Mode (not present in SoF or RoF2)
|
||||||
|
|
||||||
|
|||||||
@ -305,6 +305,7 @@ union
|
|||||||
uint8 DestructibleUnk8;
|
uint8 DestructibleUnk8;
|
||||||
uint32 DestructibleUnk9;
|
uint32 DestructibleUnk9;
|
||||||
bool targetable_with_hotkey;
|
bool targetable_with_hotkey;
|
||||||
|
bool show_name;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1116,6 +1117,11 @@ struct PetCommand_Struct {
|
|||||||
/*004*/ uint32 target;
|
/*004*/ uint32 target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PetCommandState_Struct {
|
||||||
|
/*00*/ uint32 button_id;
|
||||||
|
/*04*/ uint32 state;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Delete Spawn
|
** Delete Spawn
|
||||||
** Length: 4 Bytes
|
** Length: 4 Bytes
|
||||||
@ -1690,6 +1696,7 @@ struct OnLevelMessage_Struct
|
|||||||
uint32 Duration;
|
uint32 Duration;
|
||||||
uint32 PopupID;
|
uint32 PopupID;
|
||||||
uint32 NegativeID;
|
uint32 NegativeID;
|
||||||
|
uint32 SoundControls;
|
||||||
char ButtonName0[25];
|
char ButtonName0[25];
|
||||||
char ButtonName1[25];
|
char ButtonName1[25];
|
||||||
};
|
};
|
||||||
@ -5326,6 +5333,24 @@ struct fling_struct {
|
|||||||
/* 28 */
|
/* 28 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// used when action == 0
|
||||||
|
struct AuraCreate_Struct {
|
||||||
|
/* 00 */ uint32 action; // 0 = add, 1 = delete, 2 = reset
|
||||||
|
/* 04 */ uint32 type; // unsure -- normal auras show 1 clicky (ex. Circle of Power) show 0
|
||||||
|
/* 08 */ char aura_name[64];
|
||||||
|
/* 72 */ uint32 entity_id;
|
||||||
|
/* 76 */ uint32 icon;
|
||||||
|
/* 80 */
|
||||||
|
};
|
||||||
|
|
||||||
|
// used when action == 1
|
||||||
|
struct AuraDestory_Struct {
|
||||||
|
/* 00 */ uint32 action; // 0 = add, 1 = delete, 2 = reset
|
||||||
|
/* 04 */ uint32 entity_id;
|
||||||
|
/* 08 */
|
||||||
|
};
|
||||||
|
// I think we can assume it's just action for 2, client doesn't seem to do anything with the rest of the data in that case
|
||||||
|
|
||||||
// Restore structure packing to default
|
// Restore structure packing to default
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#include "global_define.h"
|
#include "global_define.h"
|
||||||
#include "eq_stream_proxy.h"
|
#include "eq_stream_proxy.h"
|
||||||
#include "struct_strategy.h"
|
#include "struct_strategy.h"
|
||||||
|
#include "eqemu_logsys.h"
|
||||||
|
#include "opcodemgr.h"
|
||||||
|
|
||||||
|
|
||||||
EQStreamProxy::EQStreamProxy(std::shared_ptr<EQStreamInterface> &stream, const StructStrategy *structs, OpcodeManager **opcodes)
|
EQStreamProxy::EQStreamProxy(std::shared_ptr<EQStreamInterface> &stream, const StructStrategy *structs, OpcodeManager **opcodes)
|
||||||
@ -39,6 +41,11 @@ void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
|||||||
if(p == nullptr)
|
if(p == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (p->GetOpcode() != OP_SpecialMesg) {
|
||||||
|
Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||||
|
Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
EQApplicationPacket *newp = p->Copy();
|
EQApplicationPacket *newp = p->Copy();
|
||||||
FastQueuePacket(&newp, ack_req);
|
FastQueuePacket(&newp, ack_req);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,6 +86,8 @@ enum LogCategory {
|
|||||||
Login_Server,
|
Login_Server,
|
||||||
Client_Login,
|
Client_Login,
|
||||||
Headless_Client,
|
Headless_Client,
|
||||||
|
HP_Update,
|
||||||
|
FixZ,
|
||||||
MaxCategoryID /* Don't Remove this*/
|
MaxCategoryID /* Don't Remove this*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,7 +137,10 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
|
|||||||
"Packet :: Server -> Client (Dump)",
|
"Packet :: Server -> Client (Dump)",
|
||||||
"Packet :: Client -> Server (Dump)",
|
"Packet :: Client -> Server (Dump)",
|
||||||
"Login Server",
|
"Login Server",
|
||||||
"Client Login"
|
"Client Login",
|
||||||
|
"Headless Client",
|
||||||
|
"HP Update",
|
||||||
|
"FixZ"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -332,7 +332,7 @@ namespace EQEmu
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ItemEffect_Struct {
|
struct ItemEffect_Struct {
|
||||||
int16 Effect;
|
int32 Effect;
|
||||||
uint8 Type;
|
uint8 Type;
|
||||||
uint8 Level;
|
uint8 Level;
|
||||||
uint8 Level2;
|
uint8 Level2;
|
||||||
|
|||||||
@ -25,6 +25,23 @@ void EQ::Net::ConsoleServer::RegisterLogin(ConsoleServerLoginCallback fn)
|
|||||||
m_login = fn;
|
m_login = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EQ::Net::ConsoleServerConnection *EQ::Net::ConsoleServer::FindByAccountName(const std::string &acct_name) {
|
||||||
|
for (auto &iter : m_connections) {
|
||||||
|
if (iter.second->UserName().compare(acct_name) == 0) {
|
||||||
|
return iter.second.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EQ::Net::ConsoleServer::SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell) {
|
||||||
|
for (auto &iter : m_connections) {
|
||||||
|
iter.second->SendChannelMessage(scm, onTell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EQ::Net::ConsoleServer::ConnectionDisconnected(ConsoleServerConnection *c)
|
void EQ::Net::ConsoleServer::ConnectionDisconnected(ConsoleServerConnection *c)
|
||||||
{
|
{
|
||||||
auto iter = m_connections.find(c->GetUUID());
|
auto iter = m_connections.find(c->GetUUID());
|
||||||
|
|||||||
@ -25,7 +25,8 @@ namespace EQ
|
|||||||
|
|
||||||
void RegisterCall(const std::string& command, int status_required, const std::string& help_definition, ConsoleServerCallback fn);
|
void RegisterCall(const std::string& command, int status_required, const std::string& help_definition, ConsoleServerCallback fn);
|
||||||
void RegisterLogin(ConsoleServerLoginCallback fn);
|
void RegisterLogin(ConsoleServerLoginCallback fn);
|
||||||
|
ConsoleServerConnection *FindByAccountName(const std::string &acct_name);
|
||||||
|
void SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell);
|
||||||
private:
|
private:
|
||||||
void ConnectionDisconnected(ConsoleServerConnection *c);
|
void ConnectionDisconnected(ConsoleServerConnection *c);
|
||||||
void ProcessCommand(ConsoleServerConnection *c, const std::string& cmd);
|
void ProcessCommand(ConsoleServerConnection *c, const std::string& cmd);
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#include "../common/util/uuid.h"
|
#include "../common/util/uuid.h"
|
||||||
#include "../common/net/packet.h"
|
#include "../common/net/packet.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/servertalk.h"
|
||||||
|
#include "../common/rulesys.h"
|
||||||
|
|
||||||
EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent, std::shared_ptr<TCPConnection> connection)
|
EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent, std::shared_ptr<TCPConnection> connection)
|
||||||
{
|
{
|
||||||
@ -107,6 +109,53 @@ void EQ::Net::ConsoleServerConnection::QueueMessage(const std::string &msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EQ::Net::ConsoleServerConnection::SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell) {
|
||||||
|
if (!m_accept_messages) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (scm->chan_num) {
|
||||||
|
if (RuleB(Chat, ServerWideAuction)) {
|
||||||
|
case 4: {
|
||||||
|
QueueMessage(fmt::format("{0} auctions, '{1}'", scm->from, scm->message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuleB(Chat, ServerWideOOC)) {
|
||||||
|
case 5: {
|
||||||
|
QueueMessage(fmt::format("{0} says ooc, '{1}'", scm->from, scm->message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 6: {
|
||||||
|
QueueMessage(fmt::format("{0} BROADCASTS, '{1}'", scm->from, scm->message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7: {
|
||||||
|
QueueMessage(fmt::format("[{0}] tells you, '{1}'", scm->from, scm->message));
|
||||||
|
if (onTell) {
|
||||||
|
onTell();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 11: {
|
||||||
|
QueueMessage(fmt::format("{0} GMSAYS, '{1}'", scm->from, scm->message));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void EQ::Net::ConsoleServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
|
void EQ::Net::ConsoleServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < sz; ++i) {
|
for (size_t i = 0; i < sz; ++i) {
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
struct ServerChannelMessage_Struct;
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
namespace Net
|
namespace Net
|
||||||
@ -42,6 +44,7 @@ namespace EQ
|
|||||||
bool AcceptMessages() const { return m_accept_messages; }
|
bool AcceptMessages() const { return m_accept_messages; }
|
||||||
void SetAcceptMessages(bool v) { m_accept_messages = v; }
|
void SetAcceptMessages(bool v) { m_accept_messages = v; }
|
||||||
void QueueMessage(const std::string &msg);
|
void QueueMessage(const std::string &msg);
|
||||||
|
bool SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell);
|
||||||
private:
|
private:
|
||||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||||
void OnDisconnect(TCPConnection* c);
|
void OnDisconnect(TCPConnection* c);
|
||||||
|
|||||||
@ -135,26 +135,26 @@ void EQ::Net::DaybreakConnectionManager::Process()
|
|||||||
|
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case StatusConnecting: {
|
case StatusConnecting: {
|
||||||
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
|
||||||
if ((size_t)time_since_last_send.count() > m_options.connect_delay_ms) {
|
|
||||||
connection->SendConnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case StatusConnected: {
|
|
||||||
if (m_options.keepalive_delay_ms != 0) {
|
|
||||||
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
||||||
if ((size_t)time_since_last_send.count() > m_options.keepalive_delay_ms) {
|
if ((size_t)time_since_last_send.count() > m_options.connect_delay_ms) {
|
||||||
connection->SendKeepAlive();
|
connection->SendConnect();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusConnected: {
|
||||||
|
if (m_options.keepalive_delay_ms != 0) {
|
||||||
|
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
||||||
|
if ((size_t)time_since_last_send.count() > m_options.keepalive_delay_ms) {
|
||||||
|
connection->SendKeepAlive();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
case StatusDisconnecting:
|
||||||
case StatusDisconnecting:
|
connection->Process();
|
||||||
connection->Process();
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iter++;
|
iter++;
|
||||||
@ -170,12 +170,12 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend()
|
|||||||
|
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case StatusConnected:
|
case StatusConnected:
|
||||||
case StatusDisconnecting:
|
case StatusDisconnecting:
|
||||||
connection->ProcessResend();
|
connection->ProcessResend();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter++;
|
iter++;
|
||||||
@ -382,13 +382,8 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.GetInt8(0) != 0) {
|
|
||||||
LogF(Logs::Detail, Logs::Netcode, "Error parsing packet, did not start with a 0 frame, not a valid protocol packet.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto opcode = p.GetInt8(1);
|
auto opcode = p.GetInt8(1);
|
||||||
if (opcode == OP_KeepAlive || opcode == OP_OutboundPing) {
|
if (p.GetInt8(0) == 0 && (opcode == OP_KeepAlive || opcode == OP_OutboundPing)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,14 +401,20 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
|||||||
|
|
||||||
for (int i = 1; i >= 0; --i) {
|
for (int i = 1; i >= 0; --i) {
|
||||||
switch (m_encode_passes[i]) {
|
switch (m_encode_passes[i]) {
|
||||||
case EncodeCompression:
|
case EncodeCompression:
|
||||||
Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
if(temp.GetInt8(0) == 0)
|
||||||
break;
|
Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||||
case EncodeXOR:
|
else
|
||||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
Decompress(temp, 1, temp.Length() - 1);
|
||||||
break;
|
break;
|
||||||
default:
|
case EncodeXOR:
|
||||||
break;
|
if (temp.GetInt8(0) == 0)
|
||||||
|
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||||
|
else
|
||||||
|
Decode(temp, 1, temp.Length() - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,11 +425,14 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
|||||||
|
|
||||||
for (int i = 1; i >= 0; --i) {
|
for (int i = 1; i >= 0; --i) {
|
||||||
switch (m_encode_passes[i]) {
|
switch (m_encode_passes[i]) {
|
||||||
case EncodeXOR:
|
case EncodeXOR:
|
||||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
if (temp.GetInt8(0) == 0)
|
||||||
break;
|
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||||
default:
|
else
|
||||||
break;
|
Decode(temp, 1, temp.Length() - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,274 +494,274 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (p.GetInt8(1)) {
|
switch (p.GetInt8(1)) {
|
||||||
case OP_Combined: {
|
case OP_Combined: {
|
||||||
if (m_status == StatusDisconnecting) {
|
if (m_status == StatusDisconnecting) {
|
||||||
SendDisconnect();
|
SendDisconnect();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *current = (char*)p.Data() + 2;
|
|
||||||
char *end = (char*)p.Data() + p.Length();
|
|
||||||
while (current < end) {
|
|
||||||
uint8_t subpacket_length = *(uint8_t*)current;
|
|
||||||
current += 1;
|
|
||||||
|
|
||||||
if (end < current + subpacket_length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
char *current = (char*)p.Data() + 2;
|
||||||
current += subpacket_length;
|
char *end = (char*)p.Data() + p.Length();
|
||||||
}
|
while (current < end) {
|
||||||
break;
|
uint8_t subpacket_length = *(uint8_t*)current;
|
||||||
}
|
current += 1;
|
||||||
|
|
||||||
case OP_AppCombined:
|
if (end < current + subpacket_length) {
|
||||||
{
|
return;
|
||||||
if (m_status == StatusDisconnecting) {
|
|
||||||
SendDisconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *current = (uint8_t*)p.Data() + 2;
|
|
||||||
uint8_t *end = (uint8_t*)p.Data() + p.Length();
|
|
||||||
|
|
||||||
while (current < end) {
|
|
||||||
uint32_t subpacket_length = 0;
|
|
||||||
if (*current == 0xFF)
|
|
||||||
{
|
|
||||||
if (end < current + 3) {
|
|
||||||
throw std::out_of_range("Error in OP_AppCombined, end < current + 3");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(current + 1) == 0xFF && *(current + 2) == 0xFF) {
|
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||||
if (end < current + 7) {
|
current += subpacket_length;
|
||||||
throw std::out_of_range("Error in OP_AppCombined, end < current + 7");
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_AppCombined:
|
||||||
|
{
|
||||||
|
if (m_status == StatusDisconnecting) {
|
||||||
|
SendDisconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *current = (uint8_t*)p.Data() + 2;
|
||||||
|
uint8_t *end = (uint8_t*)p.Data() + p.Length();
|
||||||
|
|
||||||
|
while (current < end) {
|
||||||
|
uint32_t subpacket_length = 0;
|
||||||
|
if (*current == 0xFF)
|
||||||
|
{
|
||||||
|
if (end < current + 3) {
|
||||||
|
throw std::out_of_range("Error in OP_AppCombined, end < current + 3");
|
||||||
}
|
}
|
||||||
|
|
||||||
subpacket_length = (uint32_t)(
|
if (*(current + 1) == 0xFF && *(current + 2) == 0xFF) {
|
||||||
(*(current + 3) << 24) |
|
if (end < current + 7) {
|
||||||
(*(current + 4) << 16) |
|
throw std::out_of_range("Error in OP_AppCombined, end < current + 7");
|
||||||
(*(current + 5) << 8) |
|
}
|
||||||
(*(current + 6))
|
|
||||||
);
|
subpacket_length = (uint32_t)(
|
||||||
current += 7;
|
(*(current + 3) << 24) |
|
||||||
|
(*(current + 4) << 16) |
|
||||||
|
(*(current + 5) << 8) |
|
||||||
|
(*(current + 6))
|
||||||
|
);
|
||||||
|
current += 7;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
subpacket_length = (uint32_t)(
|
||||||
|
(*(current + 1) << 8) |
|
||||||
|
(*(current + 2))
|
||||||
|
);
|
||||||
|
current += 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
subpacket_length = (uint32_t)(
|
subpacket_length = (uint32_t)((*(current + 0)));
|
||||||
(*(current + 1) << 8) |
|
current += 1;
|
||||||
(*(current + 2))
|
}
|
||||||
);
|
|
||||||
current += 3;
|
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||||
|
current += subpacket_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_SessionRequest:
|
||||||
|
{
|
||||||
|
if (m_status == StatusConnected) {
|
||||||
|
auto request = p.GetSerialize<DaybreakConnect>(0);
|
||||||
|
|
||||||
|
if (NetworkToHost(request.connect_code) != m_connect_code) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DaybreakConnectReply reply;
|
||||||
|
reply.zero = 0;
|
||||||
|
reply.opcode = OP_SessionResponse;
|
||||||
|
reply.connect_code = HostToNetwork(m_connect_code);
|
||||||
|
reply.encode_key = HostToNetwork(m_encode_key);
|
||||||
|
reply.crc_bytes = m_crc_bytes;
|
||||||
|
reply.max_packet_size = HostToNetwork(m_max_packet_size);
|
||||||
|
reply.encode_pass1 = m_encode_passes[0];
|
||||||
|
reply.encode_pass2 = m_encode_passes[1];
|
||||||
|
DynamicPacket p;
|
||||||
|
p.PutSerialize(0, reply);
|
||||||
|
InternalSend(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_SessionResponse:
|
||||||
|
{
|
||||||
|
if (m_status == StatusConnecting) {
|
||||||
|
auto reply = p.GetSerialize<DaybreakConnectReply>(0);
|
||||||
|
|
||||||
|
if (m_connect_code == reply.connect_code) {
|
||||||
|
m_encode_key = reply.encode_key;
|
||||||
|
m_crc_bytes = reply.crc_bytes;
|
||||||
|
m_encode_passes[0] = (DaybreakEncodeType)reply.encode_pass1;
|
||||||
|
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
|
||||||
|
m_max_packet_size = reply.max_packet_size;
|
||||||
|
ChangeStatus(StatusConnected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
break;
|
||||||
subpacket_length = (uint32_t)((*(current + 0)));
|
|
||||||
current += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
|
||||||
current += subpacket_length;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case OP_SessionRequest:
|
case OP_Packet:
|
||||||
{
|
case OP_Packet2:
|
||||||
if (m_status == StatusConnected) {
|
case OP_Packet3:
|
||||||
auto request = p.GetSerialize<DaybreakConnect>(0);
|
case OP_Packet4:
|
||||||
|
{
|
||||||
if (NetworkToHost(request.connect_code) != m_connect_code) {
|
if (m_status == StatusDisconnecting) {
|
||||||
|
SendDisconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DaybreakConnectReply reply;
|
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||||
reply.zero = 0;
|
auto sequence = NetworkToHost(header.sequence);
|
||||||
reply.opcode = OP_SessionResponse;
|
auto stream_id = header.opcode - OP_Packet;
|
||||||
reply.connect_code = HostToNetwork(m_connect_code);
|
auto stream = &m_streams[stream_id];
|
||||||
reply.encode_key = HostToNetwork(m_encode_key);
|
|
||||||
reply.crc_bytes = m_crc_bytes;
|
|
||||||
reply.max_packet_size = HostToNetwork(m_max_packet_size);
|
|
||||||
reply.encode_pass1 = m_encode_passes[0];
|
|
||||||
reply.encode_pass2 = m_encode_passes[1];
|
|
||||||
DynamicPacket p;
|
|
||||||
p.PutSerialize(0, reply);
|
|
||||||
InternalSend(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
auto order = CompareSequence(stream->sequence_in, sequence);
|
||||||
}
|
if (order == SequenceFuture) {
|
||||||
|
SendOutOfOrderAck(stream_id, sequence);
|
||||||
case OP_SessionResponse:
|
AddToQueue(stream_id, sequence, p);
|
||||||
{
|
|
||||||
if (m_status == StatusConnecting) {
|
|
||||||
auto reply = p.GetSerialize<DaybreakConnectReply>(0);
|
|
||||||
|
|
||||||
if (m_connect_code == reply.connect_code) {
|
|
||||||
m_encode_key = reply.encode_key;
|
|
||||||
m_crc_bytes = reply.crc_bytes;
|
|
||||||
m_encode_passes[0] = (DaybreakEncodeType)reply.encode_pass1;
|
|
||||||
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
|
|
||||||
m_max_packet_size = reply.max_packet_size;
|
|
||||||
ChangeStatus(StatusConnected);
|
|
||||||
}
|
}
|
||||||
}
|
else if (order == SequencePast) {
|
||||||
break;
|
SendAck(stream_id, stream->sequence_in - 1);
|
||||||
}
|
|
||||||
|
|
||||||
case OP_Packet:
|
|
||||||
case OP_Packet2:
|
|
||||||
case OP_Packet3:
|
|
||||||
case OP_Packet4:
|
|
||||||
{
|
|
||||||
if (m_status == StatusDisconnecting) {
|
|
||||||
SendDisconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
|
||||||
auto sequence = NetworkToHost(header.sequence);
|
|
||||||
auto stream_id = header.opcode - OP_Packet;
|
|
||||||
auto stream = &m_streams[stream_id];
|
|
||||||
|
|
||||||
auto order = CompareSequence(stream->sequence_in, sequence);
|
|
||||||
if (order == SequenceFuture) {
|
|
||||||
SendOutOfOrderAck(stream_id, sequence);
|
|
||||||
AddToQueue(stream_id, sequence, p);
|
|
||||||
}
|
|
||||||
else if (order == SequencePast) {
|
|
||||||
SendAck(stream_id, stream->sequence_in - 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
RemoveFromQueue(stream_id, sequence);
|
|
||||||
SendAck(stream_id, stream->sequence_in);
|
|
||||||
stream->sequence_in++;
|
|
||||||
StaticPacket next((char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size());
|
|
||||||
ProcessDecodedPacket(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_Fragment:
|
|
||||||
case OP_Fragment2:
|
|
||||||
case OP_Fragment3:
|
|
||||||
case OP_Fragment4:
|
|
||||||
{
|
|
||||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
|
||||||
auto sequence = NetworkToHost(header.sequence);
|
|
||||||
auto stream_id = header.opcode - OP_Fragment;
|
|
||||||
auto stream = &m_streams[stream_id];
|
|
||||||
|
|
||||||
auto order = CompareSequence(stream->sequence_in, sequence);
|
|
||||||
|
|
||||||
if (order == SequenceFuture) {
|
|
||||||
SendOutOfOrderAck(stream_id, sequence);
|
|
||||||
AddToQueue(stream_id, sequence, p);
|
|
||||||
}
|
|
||||||
else if (order == SequencePast) {
|
|
||||||
SendAck(stream_id, stream->sequence_in - 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
RemoveFromQueue(stream_id, sequence);
|
|
||||||
SendAck(stream_id, stream->sequence_in);
|
|
||||||
stream->sequence_in++;
|
|
||||||
|
|
||||||
if (stream->fragment_total_bytes == 0) {
|
|
||||||
auto fragheader = p.GetSerialize<DaybreakReliableFragmentHeader>(0);
|
|
||||||
stream->fragment_total_bytes = NetworkToHost(fragheader.total_size);
|
|
||||||
stream->fragment_current_bytes = 0;
|
|
||||||
stream->fragment_packet.Reserve(stream->fragment_total_bytes);
|
|
||||||
stream->fragment_packet.PutData(
|
|
||||||
stream->fragment_current_bytes,
|
|
||||||
(char*)p.Data() + DaybreakReliableFragmentHeader::size(), p.Length() - DaybreakReliableFragmentHeader::size());
|
|
||||||
|
|
||||||
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableFragmentHeader::size());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stream->fragment_packet.PutData(
|
RemoveFromQueue(stream_id, sequence);
|
||||||
stream->fragment_current_bytes,
|
SendAck(stream_id, stream->sequence_in);
|
||||||
(char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size());
|
stream->sequence_in++;
|
||||||
|
StaticPacket next((char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size());
|
||||||
|
ProcessDecodedPacket(next);
|
||||||
|
}
|
||||||
|
|
||||||
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableHeader::size());
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream->fragment_current_bytes >= stream->fragment_total_bytes) {
|
case OP_Fragment:
|
||||||
ProcessDecodedPacket(stream->fragment_packet);
|
case OP_Fragment2:
|
||||||
stream->fragment_packet.Clear();
|
case OP_Fragment3:
|
||||||
stream->fragment_total_bytes = 0;
|
case OP_Fragment4:
|
||||||
|
{
|
||||||
|
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||||
|
auto sequence = NetworkToHost(header.sequence);
|
||||||
|
auto stream_id = header.opcode - OP_Fragment;
|
||||||
|
auto stream = &m_streams[stream_id];
|
||||||
|
|
||||||
|
auto order = CompareSequence(stream->sequence_in, sequence);
|
||||||
|
|
||||||
|
if (order == SequenceFuture) {
|
||||||
|
SendOutOfOrderAck(stream_id, sequence);
|
||||||
|
AddToQueue(stream_id, sequence, p);
|
||||||
|
}
|
||||||
|
else if (order == SequencePast) {
|
||||||
|
SendAck(stream_id, stream->sequence_in - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RemoveFromQueue(stream_id, sequence);
|
||||||
|
SendAck(stream_id, stream->sequence_in);
|
||||||
|
stream->sequence_in++;
|
||||||
|
|
||||||
|
if (stream->fragment_total_bytes == 0) {
|
||||||
|
auto fragheader = p.GetSerialize<DaybreakReliableFragmentHeader>(0);
|
||||||
|
stream->fragment_total_bytes = NetworkToHost(fragheader.total_size);
|
||||||
stream->fragment_current_bytes = 0;
|
stream->fragment_current_bytes = 0;
|
||||||
|
stream->fragment_packet.Reserve(stream->fragment_total_bytes);
|
||||||
|
stream->fragment_packet.PutData(
|
||||||
|
stream->fragment_current_bytes,
|
||||||
|
(char*)p.Data() + DaybreakReliableFragmentHeader::size(), p.Length() - DaybreakReliableFragmentHeader::size());
|
||||||
|
|
||||||
|
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableFragmentHeader::size());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stream->fragment_packet.PutData(
|
||||||
|
stream->fragment_current_bytes,
|
||||||
|
(char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size());
|
||||||
|
|
||||||
|
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableHeader::size());
|
||||||
|
|
||||||
|
if (stream->fragment_current_bytes >= stream->fragment_total_bytes) {
|
||||||
|
ProcessDecodedPacket(stream->fragment_packet);
|
||||||
|
stream->fragment_packet.Clear();
|
||||||
|
stream->fragment_total_bytes = 0;
|
||||||
|
stream->fragment_current_bytes = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
case OP_Ack:
|
||||||
}
|
case OP_Ack2:
|
||||||
|
case OP_Ack3:
|
||||||
case OP_Ack:
|
case OP_Ack4:
|
||||||
case OP_Ack2:
|
{
|
||||||
case OP_Ack3:
|
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||||
case OP_Ack4:
|
auto sequence = NetworkToHost(header.sequence);
|
||||||
{
|
auto stream_id = header.opcode - OP_Ack;
|
||||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
Ack(stream_id, sequence);
|
||||||
auto sequence = NetworkToHost(header.sequence);
|
break;
|
||||||
auto stream_id = header.opcode - OP_Ack;
|
|
||||||
Ack(stream_id, sequence);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_OutOfOrderAck:
|
|
||||||
case OP_OutOfOrderAck2:
|
|
||||||
case OP_OutOfOrderAck3:
|
|
||||||
case OP_OutOfOrderAck4:
|
|
||||||
{
|
|
||||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
|
||||||
auto sequence = NetworkToHost(header.sequence);
|
|
||||||
auto stream_id = header.opcode - OP_OutOfOrderAck;
|
|
||||||
OutOfOrderAck(stream_id, sequence);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_SessionDisconnect:
|
|
||||||
{
|
|
||||||
if (m_status == StatusConnected || m_status == StatusDisconnecting) {
|
|
||||||
FlushBuffer();
|
|
||||||
SendDisconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeStatus(StatusDisconnecting);
|
case OP_OutOfOrderAck:
|
||||||
break;
|
case OP_OutOfOrderAck2:
|
||||||
}
|
case OP_OutOfOrderAck3:
|
||||||
|
case OP_OutOfOrderAck4:
|
||||||
case OP_Padding:
|
{
|
||||||
{
|
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||||
auto self = m_self.lock();
|
auto sequence = NetworkToHost(header.sequence);
|
||||||
if (m_owner->m_on_packet_recv && self) {
|
auto stream_id = header.opcode - OP_OutOfOrderAck;
|
||||||
m_owner->m_on_packet_recv(self, StaticPacket((char*)p.Data() + 1, p.Length() - 1));
|
OutOfOrderAck(stream_id, sequence);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_SessionStatRequest:
|
|
||||||
{
|
|
||||||
auto request = p.GetSerialize<DaybreakSessionStatRequest>(0);
|
|
||||||
|
|
||||||
DaybreakSessionStatResponse response;
|
case OP_SessionDisconnect:
|
||||||
response.zero = 0;
|
{
|
||||||
response.opcode = OP_SessionStatResponse;
|
if (m_status == StatusConnected || m_status == StatusDisconnecting) {
|
||||||
response.timestamp = request.timestamp;
|
FlushBuffer();
|
||||||
response.our_timestamp = EQ::Net::HostToNetwork(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
SendDisconnect();
|
||||||
response.client_sent = request.packets_sent;
|
}
|
||||||
response.client_recv = request.packets_recv;
|
|
||||||
response.server_sent = EQ::Net::HostToNetwork(m_stats.sent_packets);
|
ChangeStatus(StatusDisconnecting);
|
||||||
response.server_recv = EQ::Net::HostToNetwork(m_stats.recv_packets);
|
break;
|
||||||
DynamicPacket out;
|
}
|
||||||
out.PutSerialize(0, response);
|
|
||||||
InternalSend(out);
|
case OP_Padding:
|
||||||
break;
|
{
|
||||||
}
|
auto self = m_self.lock();
|
||||||
case OP_SessionStatResponse:
|
if (m_owner->m_on_packet_recv && self) {
|
||||||
break;
|
m_owner->m_on_packet_recv(self, StaticPacket((char*)p.Data() + 1, p.Length() - 1));
|
||||||
default:
|
}
|
||||||
LogF(Logs::Detail, Logs::Netcode, "Unhandled opcode {0:#x}", p.GetInt8(1));
|
break;
|
||||||
break;
|
}
|
||||||
|
case OP_SessionStatRequest:
|
||||||
|
{
|
||||||
|
auto request = p.GetSerialize<DaybreakSessionStatRequest>(0);
|
||||||
|
|
||||||
|
DaybreakSessionStatResponse response;
|
||||||
|
response.zero = 0;
|
||||||
|
response.opcode = OP_SessionStatResponse;
|
||||||
|
response.timestamp = request.timestamp;
|
||||||
|
response.our_timestamp = EQ::Net::HostToNetwork(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||||
|
response.client_sent = request.packets_sent;
|
||||||
|
response.client_recv = request.packets_recv;
|
||||||
|
response.server_sent = EQ::Net::HostToNetwork(m_stats.sent_packets);
|
||||||
|
response.server_recv = EQ::Net::HostToNetwork(m_stats.recv_packets);
|
||||||
|
DynamicPacket out;
|
||||||
|
out.PutSerialize(0, response);
|
||||||
|
InternalSend(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OP_SessionStatResponse:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogF(Logs::Detail, Logs::Netcode, "Unhandled opcode {0:#x}", p.GetInt8(1));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -782,16 +786,16 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
|
|||||||
int calculated = 0;
|
int calculated = 0;
|
||||||
int actual = 0;
|
int actual = 0;
|
||||||
switch (m_crc_bytes) {
|
switch (m_crc_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
actual = NetworkToHost(*(int16_t*)&data[p.Length() - (size_t)m_crc_bytes]) & 0xffff;
|
actual = NetworkToHost(*(int16_t*)&data[p.Length() - (size_t)m_crc_bytes]) & 0xffff;
|
||||||
calculated = Crc32(data, (int)(p.Length() - (size_t)m_crc_bytes), m_encode_key) & 0xffff;
|
calculated = Crc32(data, (int)(p.Length() - (size_t)m_crc_bytes), m_encode_key) & 0xffff;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
actual = NetworkToHost(*(int32_t*)&data[p.Length() - (size_t)m_crc_bytes]);
|
actual = NetworkToHost(*(int32_t*)&data[p.Length() - (size_t)m_crc_bytes]);
|
||||||
calculated = Crc32(data, (int)(p.Length() - (size_t)m_crc_bytes), m_encode_key);
|
calculated = Crc32(data, (int)(p.Length() - (size_t)m_crc_bytes), m_encode_key);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actual == calculated) {
|
if (actual == calculated) {
|
||||||
@ -809,14 +813,14 @@ void EQ::Net::DaybreakConnection::AppendCRC(Packet &p)
|
|||||||
|
|
||||||
int calculated = 0;
|
int calculated = 0;
|
||||||
switch (m_crc_bytes) {
|
switch (m_crc_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key) & 0xffff;
|
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key) & 0xffff;
|
||||||
p.PutInt16(p.Length(), EQ::Net::HostToNetwork((int16_t)calculated));
|
p.PutInt16(p.Length(), EQ::Net::HostToNetwork((int16_t)calculated));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key);
|
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key);
|
||||||
p.PutInt32(p.Length(), EQ::Net::HostToNetwork(calculated));
|
p.PutInt32(p.Length(), EQ::Net::HostToNetwork(calculated));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,7 +1059,7 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
|
|||||||
while (iter != s->sent_packets.end()) {
|
while (iter != s->sent_packets.end()) {
|
||||||
auto order = CompareSequence(seq, iter->first);
|
auto order = CompareSequence(seq, iter->first);
|
||||||
|
|
||||||
if (order != SequenceFuture) {
|
if (order != SequenceFuture) {
|
||||||
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.last_sent).count();
|
uint64_t round_time = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(now - iter->second.last_sent).count();
|
||||||
|
|
||||||
m_stats.max_ping = std::max(m_stats.max_ping, round_time);
|
m_stats.max_ping = std::max(m_stats.max_ping, round_time);
|
||||||
@ -1187,27 +1191,24 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
|
|||||||
|
|
||||||
if (PacketCanBeEncoded(p)) {
|
if (PacketCanBeEncoded(p)) {
|
||||||
DynamicPacket out;
|
DynamicPacket out;
|
||||||
|
out.PutPacket(0, p);
|
||||||
if (p.GetUInt8(0) != 0) {
|
|
||||||
out.PutUInt8(0, 0);
|
|
||||||
out.PutUInt8(1, OP_Combined);
|
|
||||||
out.PutUInt8(2, p.Length());
|
|
||||||
out.PutPacket(3, p);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.PutPacket(0, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
switch (m_encode_passes[i]) {
|
switch (m_encode_passes[i]) {
|
||||||
case EncodeCompression:
|
case EncodeCompression:
|
||||||
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
if(out.GetInt8(0) == 0)
|
||||||
break;
|
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||||
case EncodeXOR:
|
else
|
||||||
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
Compress(out, 1, out.Length() - 1);
|
||||||
break;
|
break;
|
||||||
default:
|
case EncodeXOR:
|
||||||
break;
|
if (out.GetInt8(0) == 0)
|
||||||
|
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||||
|
else
|
||||||
|
Encode(out, 1, out.Length() - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -218,7 +218,7 @@ namespace EQ
|
|||||||
encode_passes[1] = DaybreakEncodeType::EncodeNone;
|
encode_passes[1] = DaybreakEncodeType::EncodeNone;
|
||||||
port = 0;
|
port = 0;
|
||||||
hold_size = 448;
|
hold_size = 448;
|
||||||
hold_length_ms = 10;
|
hold_length_ms = 50;
|
||||||
simulated_in_packet_loss = 0;
|
simulated_in_packet_loss = 0;
|
||||||
simulated_out_packet_loss = 0;
|
simulated_out_packet_loss = 0;
|
||||||
tic_rate_hertz = 60.0;
|
tic_rate_hertz = 60.0;
|
||||||
|
|||||||
@ -81,7 +81,12 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_connection->QueuePacket(out);
|
if (ack_req) {
|
||||||
|
m_connection->QueuePacket(out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_connection->QueuePacket(out, 0, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -139,6 +139,10 @@ void EQ::Net::Packet::PutCString(size_t offset, const char *str)
|
|||||||
|
|
||||||
void EQ::Net::Packet::PutPacket(size_t offset, const Packet &p)
|
void EQ::Net::Packet::PutPacket(size_t offset, const Packet &p)
|
||||||
{
|
{
|
||||||
|
if (p.Length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Length() < offset + p.Length()) {
|
if (Length() < offset + p.Length()) {
|
||||||
if (!Resize(offset + p.Length())) {
|
if (!Resize(offset + p.Length())) {
|
||||||
throw std::out_of_range("Packet::PutPacket(), could not resize packet and would of written past the end.");
|
throw std::out_of_range("Packet::PutPacket(), could not resize packet and would of written past the end.");
|
||||||
@ -150,6 +154,10 @@ void EQ::Net::Packet::PutPacket(size_t offset, const Packet &p)
|
|||||||
|
|
||||||
void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
||||||
{
|
{
|
||||||
|
if (length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Length() < offset + length) {
|
if (Length() < offset + length) {
|
||||||
if (!Resize(offset + length)) {
|
if (!Resize(offset + length)) {
|
||||||
throw std::out_of_range("Packet::PutData(), could not resize packet and would of written past the end.");
|
throw std::out_of_range("Packet::PutData(), could not resize packet and would of written past the end.");
|
||||||
|
|||||||
@ -1849,6 +1849,7 @@ namespace RoF
|
|||||||
eq->Text_Count = 4096;
|
eq->Text_Count = 4096;
|
||||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||||
OUT(Buttons);
|
OUT(Buttons);
|
||||||
|
OUT(SoundControls);
|
||||||
OUT(Duration);
|
OUT(Duration);
|
||||||
OUT(PopupID);
|
OUT(PopupID);
|
||||||
OUT(NegativeID);
|
OUT(NegativeID);
|
||||||
@ -3929,7 +3930,7 @@ namespace RoF
|
|||||||
if (strlen(emu->suffix))
|
if (strlen(emu->suffix))
|
||||||
PacketSize += strlen(emu->suffix) + 1;
|
PacketSize += strlen(emu->suffix) + 1;
|
||||||
|
|
||||||
bool ShowName = 1;
|
bool ShowName = emu->show_name;
|
||||||
if (emu->bodytype >= 66)
|
if (emu->bodytype >= 66)
|
||||||
{
|
{
|
||||||
emu->race = 127;
|
emu->race = 127;
|
||||||
|
|||||||
@ -1927,6 +1927,7 @@ namespace RoF2
|
|||||||
eq->Text_Count = 4096;
|
eq->Text_Count = 4096;
|
||||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||||
OUT(Buttons);
|
OUT(Buttons);
|
||||||
|
OUT(SoundControls);
|
||||||
OUT(Duration);
|
OUT(Duration);
|
||||||
OUT(PopupID);
|
OUT(PopupID);
|
||||||
OUT(NegativeID);
|
OUT(NegativeID);
|
||||||
@ -4085,7 +4086,7 @@ namespace RoF2
|
|||||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowName = 1;
|
bool ShowName = emu->show_name;
|
||||||
if (emu->bodytype >= 66)
|
if (emu->bodytype >= 66)
|
||||||
{
|
{
|
||||||
emu->race = 127;
|
emu->race = 127;
|
||||||
@ -4119,6 +4120,7 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||||
|
// actually melee range variable, this probably screws the shit out of melee ranges :D
|
||||||
if (emu->DestructibleObject)
|
if (emu->DestructibleObject)
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, 10); // was int and 0x41200000
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, 10); // was int and 0x41200000
|
||||||
@ -4127,7 +4129,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height?
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height?
|
||||||
}
|
}
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); // 0 PC, 1 NPC etc
|
||||||
|
|
||||||
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
|
structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer;
|
||||||
|
|
||||||
@ -4158,6 +4160,7 @@ namespace RoF2
|
|||||||
|
|
||||||
Buffer += sizeof(structs::Spawn_Struct_Bitfields);
|
Buffer += sizeof(structs::Spawn_Struct_Bitfields);
|
||||||
|
|
||||||
|
// actually part of bitfields
|
||||||
uint8 OtherData = 0;
|
uint8 OtherData = 0;
|
||||||
|
|
||||||
if (emu->class_ == 62) //LDoN Chest
|
if (emu->class_ == 62) //LDoN Chest
|
||||||
@ -4173,6 +4176,7 @@ namespace RoF2
|
|||||||
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||||
|
// float EmitterScalingRadius
|
||||||
|
|
||||||
if (emu->DestructibleObject)
|
if (emu->DestructibleObject)
|
||||||
{
|
{
|
||||||
@ -4182,6 +4186,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3
|
||||||
}
|
}
|
||||||
|
// int DefaultEmitterID
|
||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
|
||||||
|
|
||||||
if (emu->DestructibleObject || emu->class_ == 62)
|
if (emu->DestructibleObject || emu->class_ == 62)
|
||||||
@ -4191,8 +4196,9 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleString);
|
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleString);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleAppearance);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleAppearance);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk1);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk1); // ObjectAnimationID
|
||||||
|
|
||||||
|
// these 10 are SoundIDs
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID1);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID1);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID2);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID2);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID3);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID3);
|
||||||
@ -4204,8 +4210,8 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk5);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk5);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk6);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk6);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk7);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk7);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructibleUnk8);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructibleUnk8); // bInteractiveObjectCollidable
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk9);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk9); // IteractiveObjectType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4213,6 +4219,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
// Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not
|
// Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not
|
||||||
// present. Will sort that out later.
|
// present. Will sort that out later.
|
||||||
|
// This is the CharacterPropertyHash, it can have multiple fields
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype);
|
||||||
}
|
}
|
||||||
@ -4232,10 +4239,10 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_tattoo);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_tattoo);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_details);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_details);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); // InNonPCRaceIllusion
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown9
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // material
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown10
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // variation
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // unknown11
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // headtype
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->size);
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->size);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->face);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->face);
|
||||||
@ -4243,6 +4250,7 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->runspeed);
|
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->runspeed);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->race);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->race);
|
||||||
|
|
||||||
|
// From MQ2: todo: create enum for this byte. Holding: Nothing=0 A RightHand Weapon=1 A Shield=2 Dual Wielding Two Weapons=3 A Spear=4 A LeftHand Weapon=5 A Two Handed Weapon=6 A bow=7
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // ShowEQ calls this 'Holding'
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // ShowEQ calls this 'Holding'
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->deity);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->deity);
|
||||||
if (emu->NPC)
|
if (emu->NPC)
|
||||||
@ -4275,19 +4283,19 @@ namespace RoF2
|
|||||||
|
|
||||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->lastName);
|
VARSTRUCT_ENCODE_STRING(Buffer, emu->lastName);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // aatitle ??
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // aatitle
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC ? 0 : 1); // unknown - Must be 1 for guild name to be shown abover players head.
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC ? 0 : 1); // unknown - Must be 1 for guild name to be shown abover players head.
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // TempPet
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // FindBits MQ2 name
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // NpcTintIndex
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // PrimaryTintIndex
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // SecondaryTintIndex
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
|
||||||
|
|
||||||
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
|
||||||
{
|
{
|
||||||
@ -4355,12 +4363,16 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->suffix);
|
VARSTRUCT_ENCODE_STRING(Buffer, emu->suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skipping two ints
|
||||||
|
// unknown, maybe some sort of spawn ID
|
||||||
|
// SplineID -- no idea
|
||||||
Buffer += 8;
|
Buffer += 8;
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->IsMercenary);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->IsMercenary);
|
||||||
VARSTRUCT_ENCODE_STRING(Buffer, "0000000000000000");
|
VARSTRUCT_ENCODE_STRING(Buffer, "0000000000000000"); // RealEstateItemGuid
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // RealEstateID
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // RealEstateItemID
|
||||||
// 29 zero bytes follow
|
// 29 zero bytes follow
|
||||||
|
// PhysicsEffects follow here ... unsure what they are but it's a count followed by a struct like {spellid, casterid, effectid, baseeffect}
|
||||||
Buffer += 29;
|
Buffer += 29;
|
||||||
if (Buffer != (BufferStart + PacketSize))
|
if (Buffer != (BufferStart + PacketSize))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -328,38 +328,43 @@ showeq -> eqemu
|
|||||||
sed -e 's/_t//g' -e 's/seto_0xFF/set_to_0xFF/g'
|
sed -e 's/_t//g' -e 's/seto_0xFF/set_to_0xFF/g'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// I think this is actually 5 bytes
|
||||||
|
// IDA's pseudocode reads this as 5 bytes pulled into 2 DWORDs
|
||||||
struct Spawn_Struct_Bitfields
|
struct Spawn_Struct_Bitfields
|
||||||
{
|
{
|
||||||
|
// byte 1
|
||||||
/*00*/ unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
/*00*/ unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
||||||
/*02*/ unsigned ispet:1; // Guessed based on observing live spawns
|
/*02*/ unsigned ispet:1; // Guessed based on observing live spawns
|
||||||
/*03*/ unsigned afk:1; // 0=no, 1=afk
|
/*03*/ unsigned afk:1; // 0=no, 1=afk
|
||||||
/*04*/ unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
/*04*/ unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||||
/*06*/ unsigned gm:1;
|
/*06*/ unsigned gm:1;
|
||||||
/*06*/ unsigned sneak:1;
|
/*07*/ unsigned sneak:1;
|
||||||
|
// byte 2
|
||||||
/*08*/ unsigned lfg:1;
|
/*08*/ unsigned lfg:1;
|
||||||
/*09*/ unsigned unknown09:1;
|
/*09*/ unsigned betabuffed:1;
|
||||||
/*10*/ unsigned invis:1; // May have invis & sneak the wrong way around ... not sure how to tell which is which
|
/*10*/ unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||||
/*11*/ unsigned invis1:1; // GM Invis? Can only be seen with #gm on - same for the below
|
|
||||||
/*12*/ unsigned invis2:1; // This one also make the NPC/PC invis
|
|
||||||
/*13*/ unsigned invis3:1; // This one also make the NPC/PC invis
|
|
||||||
/*14*/ unsigned invis4:1; // This one also make the NPC/PC invis
|
|
||||||
/*15*/ unsigned invis6:1; // This one also make the NPC/PC invis
|
|
||||||
/*16*/ unsigned invis7:1; // This one also make the NPC/PC invis
|
|
||||||
/*17*/ unsigned invis8:1; // This one also make the NPC/PC invis
|
|
||||||
/*18*/ unsigned invis9:1; // This one also make the NPC/PC invis
|
|
||||||
/*19*/ unsigned invis10:1; // This one also make the NPC/PC invis
|
|
||||||
/*20*/ unsigned invis11:1; // This one also make the NPC/PC invis
|
|
||||||
/*21*/ unsigned invis12:1; // This one also make the NPC/PC invis
|
|
||||||
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF2
|
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF2
|
||||||
/*23*/ unsigned showhelm:1;
|
/*23*/ unsigned showhelm:1;
|
||||||
|
// byte 4
|
||||||
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
||||||
/*25*/ unsigned trader:1;
|
/*25*/ unsigned trader:1;
|
||||||
/*26*/ unsigned unknown26:1;
|
/*26*/ unsigned animationonpop:1;
|
||||||
/*27*/ unsigned targetable:1;
|
/*27*/ unsigned targetable:1;
|
||||||
/*28*/ unsigned targetable_with_hotkey:1;
|
/*28*/ unsigned targetable_with_hotkey:1;
|
||||||
/*29*/ unsigned showname:1;
|
/*29*/ unsigned showname:1;
|
||||||
/*30*/ unsigned unknown30:1;
|
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
|
||||||
/*30*/ unsigned untargetable:1; // Untargetable with mouse
|
/*31*/ unsigned untargetable:1; // bClickThrough
|
||||||
|
/* do these later
|
||||||
|
32 unsigned buyer:1;
|
||||||
|
33 unsigned offline:1;
|
||||||
|
34 unsigned interactiveobject:1;
|
||||||
|
35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
|
||||||
|
36 unsigned title:1;
|
||||||
|
37 unsigned suffix:1;
|
||||||
|
38 unsigned padding1:1;
|
||||||
|
39 unsigned padding2:1;
|
||||||
|
40 unsinged padding3:1;
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
// Unknown in RoF2
|
// Unknown in RoF2
|
||||||
unsigned betabuffed:1;
|
unsigned betabuffed:1;
|
||||||
@ -498,7 +503,7 @@ struct Spawn_Struct
|
|||||||
|
|
||||||
/*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4)
|
/*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4)
|
||||||
/*0000*/ //char suffix[0]; // only read if(hasTitleOrSuffix & 8)
|
/*0000*/ //char suffix[0]; // only read if(hasTitleOrSuffix & 8)
|
||||||
char unknown20[8];
|
char unknown20[8]; // 2 ints, first unknown, 2nd SplineID
|
||||||
uint8 IsMercenary; // If NPC == 1 and this == 1, then the NPC name is Orange.
|
uint8 IsMercenary; // If NPC == 1 and this == 1, then the NPC name is Orange.
|
||||||
/*0000*/ char unknown21[55];
|
/*0000*/ char unknown21[55];
|
||||||
};
|
};
|
||||||
@ -2092,7 +2097,7 @@ struct OnLevelMessage_Struct {
|
|||||||
/*0000*/ uint32 ButtonName1_Count;
|
/*0000*/ uint32 ButtonName1_Count;
|
||||||
/*0000*/ char ButtonName1[25];
|
/*0000*/ char ButtonName1[25];
|
||||||
/*0000*/ uint8 Buttons;
|
/*0000*/ uint8 Buttons;
|
||||||
/*0000*/ uint8 Unknown4275; // Something to do with audio controls
|
/*0000*/ uint8 SoundControls; // Something to do with audio controls
|
||||||
/*0000*/ uint32 Duration;
|
/*0000*/ uint32 Duration;
|
||||||
/*0000*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
/*0000*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
||||||
/*0000*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
/*0000*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
||||||
|
|||||||
@ -339,18 +339,7 @@ struct Spawn_Struct_Bitfields
|
|||||||
/*06*/ unsigned sneak:1;
|
/*06*/ unsigned sneak:1;
|
||||||
/*08*/ unsigned lfg:1;
|
/*08*/ unsigned lfg:1;
|
||||||
/*09*/ unsigned unknown09:1;
|
/*09*/ unsigned unknown09:1;
|
||||||
/*10*/ unsigned invis:1; // May have invis & sneak the wrong way around ... not sure how to tell which is which
|
/*10*/ unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||||
/*11*/ unsigned invis1:1; // GM Invis? Can only be seen with #gm on - same for the below
|
|
||||||
/*12*/ unsigned invis2:1; // This one also make the NPC/PC invis
|
|
||||||
/*13*/ unsigned invis3:1; // This one also make the NPC/PC invis
|
|
||||||
/*14*/ unsigned invis4:1; // This one also make the NPC/PC invis
|
|
||||||
/*15*/ unsigned invis6:1; // This one also make the NPC/PC invis
|
|
||||||
/*16*/ unsigned invis7:1; // This one also make the NPC/PC invis
|
|
||||||
/*17*/ unsigned invis8:1; // This one also make the NPC/PC invis
|
|
||||||
/*18*/ unsigned invis9:1; // This one also make the NPC/PC invis
|
|
||||||
/*19*/ unsigned invis10:1; // This one also make the NPC/PC invis
|
|
||||||
/*20*/ unsigned invis11:1; // This one also make the NPC/PC invis
|
|
||||||
/*21*/ unsigned invis12:1; // This one also make the NPC/PC invis
|
|
||||||
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF
|
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF
|
||||||
/*23*/ unsigned showhelm:1;
|
/*23*/ unsigned showhelm:1;
|
||||||
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
||||||
@ -2122,7 +2111,7 @@ struct OnLevelMessage_Struct {
|
|||||||
/*0000*/ uint32 ButtonName1_Count;
|
/*0000*/ uint32 ButtonName1_Count;
|
||||||
/*0000*/ char ButtonName1[25];
|
/*0000*/ char ButtonName1[25];
|
||||||
/*0000*/ uint8 Buttons;
|
/*0000*/ uint8 Buttons;
|
||||||
/*0000*/ uint8 Unknown4275; // Something to do with audio controls
|
/*0000*/ uint8 SoundControls; // Something to do with audio controls
|
||||||
/*0000*/ uint32 Duration;
|
/*0000*/ uint32 Duration;
|
||||||
/*0000*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
/*0000*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
||||||
/*0000*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
/*0000*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
||||||
|
|||||||
@ -1373,6 +1373,7 @@ namespace SoD
|
|||||||
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
||||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||||
OUT(Buttons);
|
OUT(Buttons);
|
||||||
|
OUT(SoundControls);
|
||||||
OUT(Duration);
|
OUT(Duration);
|
||||||
OUT(PopupID);
|
OUT(PopupID);
|
||||||
OUT(NegativeID);
|
OUT(NegativeID);
|
||||||
@ -2559,7 +2560,7 @@ namespace SoD
|
|||||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowName = 1;
|
bool ShowName = emu->show_name;
|
||||||
if (emu->bodytype >= 66)
|
if (emu->bodytype >= 66)
|
||||||
{
|
{
|
||||||
emu->race = 127;
|
emu->race = 127;
|
||||||
@ -3291,73 +3292,60 @@ namespace SoD
|
|||||||
|
|
||||||
switch (eq->command)
|
switch (eq->command)
|
||||||
{
|
{
|
||||||
case 0x04:
|
case 1: // back off
|
||||||
emu->command = 0x00; // /pet health
|
emu->command = 28;
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 2: // get lost
|
||||||
emu->command = 0x01; // /pet leader
|
emu->command = 29;
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 3: // as you were ???
|
||||||
emu->command = 0x02; // /pet attack or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x03: // Case Guessed
|
case 4: // report HP
|
||||||
emu->command = 0x03; // /pet qattack
|
emu->command = 0;
|
||||||
case 0x08:
|
|
||||||
emu->command = 0x04; // /pet follow or Pet Window
|
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 5: // guard here
|
||||||
emu->command = 0x05; // /pet guard or Pet Window
|
emu->command = 5;
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 6: // guard me
|
||||||
emu->command = 0x07; // /pet sit or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x0a:
|
case 7: // attack
|
||||||
emu->command = 0x08; // /pet stand or Pet Window
|
emu->command = 2;
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 8: // follow
|
||||||
emu->command = 0x1e; // /pet guard me
|
emu->command = 4;
|
||||||
break;
|
break;
|
||||||
case 0x0f: // Case Made Up
|
case 9: // sit down
|
||||||
emu->command = 0x09; // /pet stop
|
emu->command = 7;
|
||||||
break;
|
break;
|
||||||
case 0x0b:
|
case 10: // stand up
|
||||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
emu->command = 8;
|
||||||
break;
|
break;
|
||||||
case 0x0e:
|
case 11: // taunt toggle
|
||||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
emu->command = 12;
|
||||||
break;
|
break;
|
||||||
case 0x0c:
|
case 12: // hold toggle
|
||||||
emu->command = 0x0f; // /pet hold
|
emu->command = 15;
|
||||||
break;
|
break;
|
||||||
case 0x1b:
|
case 13: // taunt on
|
||||||
emu->command = 0x10; // /pet hold on
|
emu->command = 13;
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 14: // no taunt
|
||||||
emu->command = 0x11; // /pet hold off
|
emu->command = 14;
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
// 15 is target, doesn't send packet
|
||||||
emu->command = 0x12; // Slumber?
|
case 16: // leader
|
||||||
|
emu->command = 1;
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 17: // feign
|
||||||
emu->command = 0x15; // /pet no cast
|
emu->command = 27;
|
||||||
break;
|
break;
|
||||||
case 0x0d: // Case Made Up
|
case 18: // no cast toggle
|
||||||
emu->command = 0x16; // Pet Window No Cast
|
emu->command = 21;
|
||||||
break;
|
break;
|
||||||
case 0x13:
|
case 19: // focus toggle
|
||||||
emu->command = 0x18; // /pet focus
|
emu->command = 24;
|
||||||
break;
|
|
||||||
case 0x19:
|
|
||||||
emu->command = 0x19; // /pet focus on
|
|
||||||
break;
|
|
||||||
case 0x1a:
|
|
||||||
emu->command = 0x1a; // /pet focus off
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
emu->command = 0x1c; // /pet back off
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
emu->command = 0x1d; // /pet get lost
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emu->command = eq->command;
|
emu->command = eq->command;
|
||||||
|
|||||||
@ -250,8 +250,7 @@ struct Spawn_Struct_Bitfields
|
|||||||
unsigned sneak:1;
|
unsigned sneak:1;
|
||||||
unsigned lfg:1;
|
unsigned lfg:1;
|
||||||
unsigned padding5:1;
|
unsigned padding5:1;
|
||||||
unsigned invis:1; // 0 = visible, 1 = invis/sneaking
|
unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||||
unsigned padding7:11;
|
|
||||||
unsigned gm:1;
|
unsigned gm:1;
|
||||||
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||||
unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
||||||
@ -1760,7 +1759,7 @@ struct OnLevelMessage_Struct {
|
|||||||
/*4224*/ char ButtonName0[25]; // If Buttons = 1, these two are the text for the left and right buttons respectively
|
/*4224*/ char ButtonName0[25]; // If Buttons = 1, these two are the text for the left and right buttons respectively
|
||||||
/*4249*/ char ButtonName1[25];
|
/*4249*/ char ButtonName1[25];
|
||||||
/*4274*/ uint8 Buttons;
|
/*4274*/ uint8 Buttons;
|
||||||
/*4275*/ uint8 Unknown4275; // Something to do with audio controls
|
/*4275*/ uint8 SoundControls; // Something to do with audio controls
|
||||||
/*4276*/ uint32 Duration;
|
/*4276*/ uint32 Duration;
|
||||||
/*4280*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
/*4280*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
||||||
/*4284*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
/*4284*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
||||||
|
|||||||
@ -2097,7 +2097,7 @@ namespace SoF
|
|||||||
int k;
|
int k;
|
||||||
for (r = 0; r < entrycount; r++, eq++, emu++) {
|
for (r = 0; r < entrycount; r++, eq++, emu++) {
|
||||||
|
|
||||||
eq->showname = 1; //New Field - Toggles Name Display on or off - 0 = off, 1 = on
|
eq->showname = emu->show_name ? 1 : 0; //New Field - Toggles Name Display on or off - 0 = off, 1 = on
|
||||||
eq->linkdead = 0; //New Field - Toggles LD on or off after name - 0 = off, 1 = on
|
eq->linkdead = 0; //New Field - Toggles LD on or off after name - 0 = off, 1 = on
|
||||||
eq->statue = 0; //New Field - 1 freezes animation
|
eq->statue = 0; //New Field - 1 freezes animation
|
||||||
eq->showhelm = emu->showhelm;
|
eq->showhelm = emu->showhelm;
|
||||||
@ -2136,10 +2136,10 @@ namespace SoF
|
|||||||
eq->findable = emu->findable;
|
eq->findable = emu->findable;
|
||||||
if (emu->bodytype >= 66)
|
if (emu->bodytype >= 66)
|
||||||
{
|
{
|
||||||
eq->bodytype = 11; //non-targetable
|
eq->bodytype = 11; //non-targetable
|
||||||
eq->showname = 0; //no visible name
|
eq->showname = 0; //no visible name
|
||||||
eq->race = 127; //invisible man
|
eq->race = 127; //invisible man
|
||||||
eq->gender = 0; //invisible men are gender 0
|
eq->gender = 0; //invisible men are gender 0
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2675,73 +2675,60 @@ namespace SoF
|
|||||||
|
|
||||||
switch (eq->command)
|
switch (eq->command)
|
||||||
{
|
{
|
||||||
case 0x04:
|
case 1: // back off
|
||||||
emu->command = 0x00; // /pet health
|
emu->command = 28;
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 2: // get lost
|
||||||
emu->command = 0x01; // /pet leader
|
emu->command = 29;
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 3: // as you were ???
|
||||||
emu->command = 0x02; // /pet attack or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x03: // Case Guessed
|
case 4: // report HP
|
||||||
emu->command = 0x03; // /pet qattack
|
emu->command = 0;
|
||||||
case 0x08:
|
|
||||||
emu->command = 0x04; // /pet follow or Pet Window
|
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 5: // guard here
|
||||||
emu->command = 0x05; // /pet guard or Pet Window
|
emu->command = 5;
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 6: // guard me
|
||||||
emu->command = 0x07; // /pet sit or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x0a:
|
case 7: // attack
|
||||||
emu->command = 0x08; // /pet stand or Pet Window
|
emu->command = 2;
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 8: // follow
|
||||||
emu->command = 0x1e; // /pet guard me
|
emu->command = 4;
|
||||||
break;
|
break;
|
||||||
case 0x0f: // Case Made Up
|
case 9: // sit down
|
||||||
emu->command = 0x09; // Stop?
|
emu->command = 7;
|
||||||
break;
|
break;
|
||||||
case 0x0b:
|
case 10: // stand up
|
||||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
emu->command = 8;
|
||||||
break;
|
break;
|
||||||
case 0x0e:
|
case 11: // taunt toggle
|
||||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
emu->command = 12;
|
||||||
break;
|
break;
|
||||||
case 0x0c:
|
case 12: // hold toggle
|
||||||
emu->command = 0x0f; // /pet hold
|
emu->command = 15;
|
||||||
break;
|
break;
|
||||||
case 0x1b:
|
case 13: // taunt on
|
||||||
emu->command = 0x10; // /pet hold on
|
emu->command = 13;
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 14: // no taunt
|
||||||
emu->command = 0x11; // /pet hold off
|
emu->command = 14;
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
// 15 is target, doesn't send packet
|
||||||
emu->command = 0x12; // Slumber?
|
case 16: // leader
|
||||||
|
emu->command = 1;
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 17: // feign
|
||||||
emu->command = 0x15; // /pet no cast
|
emu->command = 27;
|
||||||
break;
|
break;
|
||||||
case 0x0d: // Case Made Up
|
case 18: // no cast toggle
|
||||||
emu->command = 0x16; // Pet Window No Cast
|
emu->command = 21;
|
||||||
break;
|
break;
|
||||||
case 0x13:
|
case 19: // focus toggle
|
||||||
emu->command = 0x18; // /pet focus
|
emu->command = 24;
|
||||||
break;
|
|
||||||
case 0x19:
|
|
||||||
emu->command = 0x19; // /pet focus on
|
|
||||||
break;
|
|
||||||
case 0x1a:
|
|
||||||
emu->command = 0x1a; // /pet focus off
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
emu->command = 0x1c; // /pet back off
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
emu->command = 0x1d; // /pet get lost
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emu->command = eq->command;
|
emu->command = eq->command;
|
||||||
|
|||||||
@ -2030,73 +2030,60 @@ namespace Titanium
|
|||||||
|
|
||||||
switch (eq->command)
|
switch (eq->command)
|
||||||
{
|
{
|
||||||
case 0x04:
|
case 1: // back off
|
||||||
emu->command = 0x00; // /pet health
|
emu->command = 28;
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 2: // get lost
|
||||||
emu->command = 0x01; // /pet leader
|
emu->command = 29;
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 3: // as you were ???
|
||||||
emu->command = 0x02; // /pet attack or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x03: // Case Guessed
|
case 4: // report HP
|
||||||
emu->command = 0x03; // /pet qattack
|
emu->command = 0;
|
||||||
case 0x08:
|
|
||||||
emu->command = 0x04; // /pet follow or Pet Window
|
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case 5: // guard here
|
||||||
emu->command = 0x05; // /pet guard or Pet Window
|
emu->command = 5;
|
||||||
break;
|
break;
|
||||||
case 0x09:
|
case 6: // guard me
|
||||||
emu->command = 0x07; // /pet sit or Pet Window
|
emu->command = 4; // fuck it follow
|
||||||
break;
|
break;
|
||||||
case 0x0a:
|
case 7: // attack
|
||||||
emu->command = 0x08; // /pet stand or Pet Window
|
emu->command = 2;
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 8: // follow
|
||||||
emu->command = 0x1e; // /pet guard me
|
emu->command = 4;
|
||||||
break;
|
break;
|
||||||
case 0x0f: // Case Made Up
|
case 9: // sit down
|
||||||
emu->command = 0x09; // Stop?
|
emu->command = 7;
|
||||||
break;
|
break;
|
||||||
case 0x0b:
|
case 10: // stand up
|
||||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
emu->command = 8;
|
||||||
break;
|
break;
|
||||||
case 0x0e:
|
case 11: // taunt toggle
|
||||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
emu->command = 12;
|
||||||
break;
|
break;
|
||||||
case 0x0c:
|
case 12: // hold toggle
|
||||||
emu->command = 0x0f; // /pet hold
|
emu->command = 15;
|
||||||
break;
|
break;
|
||||||
case 0x1b:
|
case 13: // taunt on
|
||||||
emu->command = 0x10; // /pet hold on
|
emu->command = 13;
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 14: // no taunt
|
||||||
emu->command = 0x11; // /pet hold off
|
emu->command = 14;
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
// 15 is target, doesn't send packet
|
||||||
emu->command = 0x12; // Slumber?
|
case 16: // leader
|
||||||
|
emu->command = 1;
|
||||||
break;
|
break;
|
||||||
case 0x12:
|
case 17: // feign
|
||||||
emu->command = 0x15; // /pet no cast
|
emu->command = 27;
|
||||||
break;
|
break;
|
||||||
case 0x0d: // Case Made Up
|
case 18: // no cast toggle
|
||||||
emu->command = 0x16; // Pet Window No Cast
|
emu->command = 21;
|
||||||
break;
|
break;
|
||||||
case 0x13:
|
case 19: // focus toggle
|
||||||
emu->command = 0x18; // /pet focus
|
emu->command = 24;
|
||||||
break;
|
|
||||||
case 0x19:
|
|
||||||
emu->command = 0x19; // /pet focus on
|
|
||||||
break;
|
|
||||||
case 0x1a:
|
|
||||||
emu->command = 0x1a; // /pet focus off
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
emu->command = 0x1c; // /pet back off
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
emu->command = 0x1d; // /pet get lost
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emu->command = eq->command;
|
emu->command = eq->command;
|
||||||
|
|||||||
@ -1607,6 +1607,7 @@ namespace UF
|
|||||||
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
||||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||||
OUT(Buttons);
|
OUT(Buttons);
|
||||||
|
OUT(SoundControls);
|
||||||
OUT(Duration);
|
OUT(Duration);
|
||||||
OUT(PopupID);
|
OUT(PopupID);
|
||||||
OUT(NegativeID);
|
OUT(NegativeID);
|
||||||
@ -2843,7 +2844,7 @@ namespace UF
|
|||||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowName = 1;
|
bool ShowName = emu->show_name;
|
||||||
if (emu->bodytype >= 66)
|
if (emu->bodytype >= 66)
|
||||||
{
|
{
|
||||||
emu->race = 127;
|
emu->race = 127;
|
||||||
|
|||||||
@ -250,8 +250,7 @@ struct Spawn_Struct_Bitfields
|
|||||||
unsigned sneak:1;
|
unsigned sneak:1;
|
||||||
unsigned lfg:1;
|
unsigned lfg:1;
|
||||||
unsigned padding5:1;
|
unsigned padding5:1;
|
||||||
unsigned invis:1; // 0 = visible, 1 = invis/sneaking
|
unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||||
unsigned padding7:11;
|
|
||||||
unsigned gm:1;
|
unsigned gm:1;
|
||||||
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||||
unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
||||||
@ -1801,7 +1800,7 @@ struct OnLevelMessage_Struct {
|
|||||||
/*4224*/ char ButtonName0[25]; // If Buttons = 1, these two are the text for the left and right buttons respectively
|
/*4224*/ char ButtonName0[25]; // If Buttons = 1, these two are the text for the left and right buttons respectively
|
||||||
/*4249*/ char ButtonName1[25];
|
/*4249*/ char ButtonName1[25];
|
||||||
/*4274*/ uint8 Buttons;
|
/*4274*/ uint8 Buttons;
|
||||||
/*4275*/ uint8 Unknown4275; // Something to do with audio controls
|
/*4275*/ uint8 SoundControls; // Something to do with audio controls
|
||||||
/*4276*/ uint32 Duration;
|
/*4276*/ uint32 Duration;
|
||||||
/*4280*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
/*4280*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 <PopupID> is returned on clicking the left button
|
||||||
/*4284*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
/*4284*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 <NegativeID> is returned on clicking the right button
|
||||||
|
|||||||
@ -134,7 +134,6 @@ RULE_INT(Character, TradeskillUpMakePoison, 2) // Make Poison skillup rate adjus
|
|||||||
RULE_INT(Character, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster.
|
RULE_INT(Character, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster.
|
||||||
RULE_INT(Character, TradeskillUpResearch, 1) // Research skillup rate adjust. Lower is faster.
|
RULE_INT(Character, TradeskillUpResearch, 1) // Research skillup rate adjust. Lower is faster.
|
||||||
RULE_INT(Character, TradeskillUpTinkering, 2) // Tinkering skillup rate adjust. Lower is faster.
|
RULE_INT(Character, TradeskillUpTinkering, 2) // Tinkering skillup rate adjust. Lower is faster.
|
||||||
RULE_BOOL(Character, SpamHPUpdates, false) // if your server has stupid amounts of HP that causes client display issues, turn this on!
|
|
||||||
RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of screen < 100%
|
RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of screen < 100%
|
||||||
RULE_INT(Character, IksarCommonTongue, 95) // 95 By default (live-like?)
|
RULE_INT(Character, IksarCommonTongue, 95) // 95 By default (live-like?)
|
||||||
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)
|
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)
|
||||||
@ -151,6 +150,7 @@ RULE_BOOL(Character, AllowMQTarget, false) // Disables putting players in the 'h
|
|||||||
RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound behavior
|
RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound behavior
|
||||||
RULE_BOOL(Character, GrantHoTTOnCreate, false) // Grant Health of Target's Target leadership AA on character creation
|
RULE_BOOL(Character, GrantHoTTOnCreate, false) // Grant Health of Target's Target leadership AA on character creation
|
||||||
RULE_BOOL(Character, UseOldConSystem, false) // Grant Health of Target's Target leadership AA on character creation
|
RULE_BOOL(Character, UseOldConSystem, false) // Grant Health of Target's Target leadership AA on character creation
|
||||||
|
RULE_BOOL(Character, OPClientUpdateVisualDebug, false) // Shows a pulse and forward directional particle each time the client sends its position to server
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Mercs)
|
RULE_CATEGORY(Mercs)
|
||||||
@ -235,7 +235,6 @@ RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone AL
|
|||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Zone)
|
RULE_CATEGORY(Zone)
|
||||||
RULE_INT(Zone, NPCPositonUpdateTicCount, 32) //ms between intervals of sending a position update to the entire zone.
|
|
||||||
RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
|
RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
|
||||||
RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
|
RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
|
||||||
RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on.
|
RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on.
|
||||||
@ -274,6 +273,8 @@ RULE_BOOL(Map, FixPathingZWhenLoading, true) //increases zone boot times a bit
|
|||||||
RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time.
|
RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time.
|
||||||
RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints.
|
RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints.
|
||||||
RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well.
|
RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well.
|
||||||
|
RULE_BOOL(Map, FixZWhenMoving, true) // Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)
|
||||||
|
RULE_BOOL(Map, MobZVisualDebug, false) // Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss)
|
||||||
RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply.
|
RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply.
|
||||||
RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply.
|
RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply.
|
||||||
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply.
|
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply.
|
||||||
@ -289,7 +290,7 @@ RULE_BOOL(Pathing, AggroReturnToGrid, true) // Enable pathing for aggroed roamin
|
|||||||
RULE_BOOL(Pathing, Guard, true) // Enable pathing for mobs moving to their guard point.
|
RULE_BOOL(Pathing, Guard, true) // Enable pathing for mobs moving to their guard point.
|
||||||
RULE_BOOL(Pathing, Find, true) // Enable pathing for FindPerson requests from the client.
|
RULE_BOOL(Pathing, Find, true) // Enable pathing for FindPerson requests from the client.
|
||||||
RULE_BOOL(Pathing, Fear, true) // Enable pathing for fear
|
RULE_BOOL(Pathing, Fear, true) // Enable pathing for fear
|
||||||
RULE_REAL(Pathing, ZDiffThreshold, 10) // If a mob las LOS to it's target, it will run to it if the Z difference is < this.
|
RULE_REAL(Pathing, ZDiffThresholdNew, 80) // If a mob las LOS to it's target, it will run to it if the Z difference is < this.
|
||||||
RULE_INT(Pathing, LOSCheckFrequency, 1000) // A mob will check for LOS to it's target this often (milliseconds).
|
RULE_INT(Pathing, LOSCheckFrequency, 1000) // A mob will check for LOS to it's target this often (milliseconds).
|
||||||
RULE_INT(Pathing, RouteUpdateFrequencyShort, 1000) // How often a new route will be calculated if the target has moved.
|
RULE_INT(Pathing, RouteUpdateFrequencyShort, 1000) // How often a new route will be calculated if the target has moved.
|
||||||
RULE_INT(Pathing, RouteUpdateFrequencyLong, 5000) // How often a new route will be calculated if the target has moved.
|
RULE_INT(Pathing, RouteUpdateFrequencyLong, 5000) // How often a new route will be calculated if the target has moved.
|
||||||
@ -348,6 +349,7 @@ RULE_INT(Spells, MaxTotalSlotsNPC, 60) // default to Tit's limit
|
|||||||
RULE_INT(Spells, MaxTotalSlotsPET, 30) // default to Tit's limit
|
RULE_INT(Spells, MaxTotalSlotsPET, 30) // default to Tit's limit
|
||||||
RULE_BOOL (Spells, EnableBlockedBuffs, true)
|
RULE_BOOL (Spells, EnableBlockedBuffs, true)
|
||||||
RULE_INT(Spells, ReflectType, 3) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells
|
RULE_INT(Spells, ReflectType, 3) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells
|
||||||
|
RULE_BOOL(Spells, ReflectMessagesClose, true) // Live functionality is for Reflect messages to show to players within close proximity, false shows just player reflecting
|
||||||
RULE_INT(Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim
|
RULE_INT(Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim
|
||||||
RULE_BOOL(Spells, LiveLikeFocusEffects, true) // Determines whether specific healing, dmg and mana reduction focuses are randomized
|
RULE_BOOL(Spells, LiveLikeFocusEffects, true) // Determines whether specific healing, dmg and mana reduction focuses are randomized
|
||||||
RULE_INT(Spells, BaseImmunityLevel, 55) // The level that targets start to be immune to stun, fear and mez spells with a max level of 0.
|
RULE_INT(Spells, BaseImmunityLevel, 55) // The level that targets start to be immune to stun, fear and mez spells with a max level of 0.
|
||||||
@ -397,6 +399,7 @@ RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect
|
|||||||
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
|
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
|
||||||
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
|
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
|
||||||
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
|
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
|
||||||
|
RULE_BOOL(Spells, OldRainTargets, false) // use old incorrectly implemented max targets for rains
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
|
|||||||
@ -189,6 +189,7 @@
|
|||||||
#define ServerOP_ReloadWorld 0x4009
|
#define ServerOP_ReloadWorld 0x4009
|
||||||
#define ServerOP_ReloadLogs 0x4010
|
#define ServerOP_ReloadLogs 0x4010
|
||||||
#define ServerOP_ReloadPerlExportSettings 0x4011
|
#define ServerOP_ReloadPerlExportSettings 0x4011
|
||||||
|
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
||||||
/* Query Server OP Codes */
|
/* Query Server OP Codes */
|
||||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
#define ServerOP_QSPlayerLogTrades 0x5010
|
||||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
#define ServerOP_QSPlayerLogHandins 0x5011
|
||||||
@ -1263,6 +1264,12 @@ struct CZSetEntVarByNPCTypeID_Struct {
|
|||||||
char m_var[256];
|
char m_var[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CZSetEntVarByClientName_Struct {
|
||||||
|
char CharName[64];
|
||||||
|
char id[256];
|
||||||
|
char m_var[256];
|
||||||
|
};
|
||||||
|
|
||||||
struct ReloadWorld_Struct{
|
struct ReloadWorld_Struct{
|
||||||
uint32 Option;
|
uint32 Option;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1674,6 +1674,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
|||||||
for (y = 0; y < 16; y++)
|
for (y = 0; y < 16; y++)
|
||||||
sp[tempid].deities[y]=atoi(row[126+y]);
|
sp[tempid].deities[y]=atoi(row[126+y]);
|
||||||
|
|
||||||
|
sp[tempid].new_icon=atoi(row[144]);
|
||||||
sp[tempid].uninterruptable=atoi(row[146]) != 0;
|
sp[tempid].uninterruptable=atoi(row[146]) != 0;
|
||||||
sp[tempid].ResistDiff=atoi(row[147]);
|
sp[tempid].ResistDiff=atoi(row[147]);
|
||||||
sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
|
sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
|
||||||
|
|||||||
@ -468,7 +468,7 @@ typedef enum {
|
|||||||
#define SE_Blank 254 // implemented
|
#define SE_Blank 254 // implemented
|
||||||
#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
|
#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
|
||||||
#define SE_ShroudofStealth 256 // implemented
|
#define SE_ShroudofStealth 256 // implemented
|
||||||
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold
|
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold
|
||||||
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
|
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
|
||||||
#define SE_CombatStability 259 // implemented[AA] - damage mitigation
|
#define SE_CombatStability 259 // implemented[AA] - damage mitigation
|
||||||
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
|
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
|
||||||
@ -478,7 +478,7 @@ typedef enum {
|
|||||||
#define SE_HastenedAASkill 264 // implemented
|
#define SE_HastenedAASkill 264 // implemented
|
||||||
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
|
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
|
||||||
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
|
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
|
||||||
#define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast
|
#define SE_AddPetCommand 267 // implemented - sets command base2 to base1
|
||||||
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
|
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
|
||||||
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
|
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
|
||||||
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)
|
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)
|
||||||
@ -562,9 +562,9 @@ typedef enum {
|
|||||||
#define SE_LimitManaMin 348 // implemented
|
#define SE_LimitManaMin 348 // implemented
|
||||||
#define SE_ShieldEquipDmgMod 349 // implemented[AA] Increase melee base damage (indirectly increasing hate) when wearing a shield.
|
#define SE_ShieldEquipDmgMod 349 // implemented[AA] Increase melee base damage (indirectly increasing hate) when wearing a shield.
|
||||||
#define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana.
|
#define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana.
|
||||||
//#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this
|
#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this
|
||||||
//#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755)
|
#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755)
|
||||||
//#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect
|
#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect
|
||||||
//#define SE_DeactivateAllTraps 354 // *not implemented - looks to be some type of invulnerability? Test DAT (8757)
|
//#define SE_DeactivateAllTraps 354 // *not implemented - looks to be some type of invulnerability? Test DAT (8757)
|
||||||
//#define SE_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758)
|
//#define SE_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758)
|
||||||
//#define SE_ChangeTriggerType 356 // not used
|
//#define SE_ChangeTriggerType 356 // not used
|
||||||
@ -757,7 +757,7 @@ struct SPDat_Spell_Struct
|
|||||||
// -- DIETY_BERTOXXULOUS ... DIETY_VEESHAN
|
// -- DIETY_BERTOXXULOUS ... DIETY_VEESHAN
|
||||||
/* 142 */ //int8 npc_no_cast; // 142: between 0 & 100 -- NPC_NO_CAST
|
/* 142 */ //int8 npc_no_cast; // 142: between 0 & 100 -- NPC_NO_CAST
|
||||||
/* 143 */ //int ai_pt_bonus; // 143: always set to 0, client doesn't save this -- AI_PT_BONUS
|
/* 143 */ //int ai_pt_bonus; // 143: always set to 0, client doesn't save this -- AI_PT_BONUS
|
||||||
/* 144 */ //int16 new_icon // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -- NEW_ICON
|
/* 144 */ int16 new_icon; // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -- NEW_ICON
|
||||||
/* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is, particles I think -- SPELL_EFFECT_INDEX
|
/* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is, particles I think -- SPELL_EFFECT_INDEX
|
||||||
/* 146 */ bool uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -- NO_INTERRUPT
|
/* 146 */ bool uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -- NO_INTERRUPT
|
||||||
/* 147 */ int16 ResistDiff; // -- RESIST_MOD
|
/* 147 */ int16 ResistDiff; // -- RESIST_MOD
|
||||||
|
|||||||
49
common/util/directory.cpp
Normal file
49
common/util/directory.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "directory.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "win_dirent.h"
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct EQ::Directory::impl {
|
||||||
|
DIR *m_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
EQ::Directory::Directory(const std::string &path)
|
||||||
|
{
|
||||||
|
m_impl = new impl;
|
||||||
|
m_impl->m_dir = opendir(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::Directory::~Directory()
|
||||||
|
{
|
||||||
|
if (m_impl->m_dir) {
|
||||||
|
closedir(m_impl->m_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EQ::Directory::Exists()
|
||||||
|
{
|
||||||
|
return m_impl->m_dir != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::Directory::GetFiles(std::vector<std::string>& files)
|
||||||
|
{
|
||||||
|
if (m_impl->m_dir) {
|
||||||
|
struct dirent *ent;
|
||||||
|
while ((ent = readdir(m_impl->m_dir)) != nullptr) {
|
||||||
|
switch (ent->d_type) {
|
||||||
|
case DT_REG:
|
||||||
|
files.push_back(ent->d_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rewinddir(m_impl->m_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
common/util/directory.h
Normal file
19
common/util/directory.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace EQ {
|
||||||
|
class Directory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Directory(const std::string &path);
|
||||||
|
~Directory();
|
||||||
|
|
||||||
|
bool Exists();
|
||||||
|
void GetFiles(std::vector<std::string> &files);
|
||||||
|
private:
|
||||||
|
struct impl;
|
||||||
|
impl *m_impl;
|
||||||
|
};
|
||||||
|
}
|
||||||
928
common/util/win_dirent.h
Normal file
928
common/util/win_dirent.h
Normal file
@ -0,0 +1,928 @@
|
|||||||
|
/*
|
||||||
|
* Dirent interface for Microsoft Visual Studio
|
||||||
|
* Version 1.21
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2012 Toni Ronkko
|
||||||
|
* This file is part of dirent. Dirent may be freely distributed
|
||||||
|
* under the MIT license. For all details and documentation, see
|
||||||
|
* https://github.com/tronkko/dirent
|
||||||
|
*/
|
||||||
|
#ifndef DIRENT_H
|
||||||
|
#define DIRENT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include windows.h without Windows Sockets 1.1 to prevent conflicts with
|
||||||
|
* Windows Sockets 2.0.
|
||||||
|
*/
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Indicates that d_type field is available in dirent structure */
|
||||||
|
#define _DIRENT_HAVE_D_TYPE
|
||||||
|
|
||||||
|
/* Indicates that d_namlen field is available in dirent structure */
|
||||||
|
#define _DIRENT_HAVE_D_NAMLEN
|
||||||
|
|
||||||
|
/* Entries missing from MSVC 6.0 */
|
||||||
|
#if !defined(FILE_ATTRIBUTE_DEVICE)
|
||||||
|
# define FILE_ATTRIBUTE_DEVICE 0x40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* File type and permission flags for stat(), general mask */
|
||||||
|
#if !defined(S_IFMT)
|
||||||
|
# define S_IFMT _S_IFMT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Directory bit */
|
||||||
|
#if !defined(S_IFDIR)
|
||||||
|
# define S_IFDIR _S_IFDIR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Character device bit */
|
||||||
|
#if !defined(S_IFCHR)
|
||||||
|
# define S_IFCHR _S_IFCHR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Pipe bit */
|
||||||
|
#if !defined(S_IFFIFO)
|
||||||
|
# define S_IFFIFO _S_IFFIFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Regular file bit */
|
||||||
|
#if !defined(S_IFREG)
|
||||||
|
# define S_IFREG _S_IFREG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Read permission */
|
||||||
|
#if !defined(S_IREAD)
|
||||||
|
# define S_IREAD _S_IREAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write permission */
|
||||||
|
#if !defined(S_IWRITE)
|
||||||
|
# define S_IWRITE _S_IWRITE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Execute permission */
|
||||||
|
#if !defined(S_IEXEC)
|
||||||
|
# define S_IEXEC _S_IEXEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Pipe */
|
||||||
|
#if !defined(S_IFIFO)
|
||||||
|
# define S_IFIFO _S_IFIFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Block device */
|
||||||
|
#if !defined(S_IFBLK)
|
||||||
|
# define S_IFBLK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Link */
|
||||||
|
#if !defined(S_IFLNK)
|
||||||
|
# define S_IFLNK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Socket */
|
||||||
|
#if !defined(S_IFSOCK)
|
||||||
|
# define S_IFSOCK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Read user permission */
|
||||||
|
#if !defined(S_IRUSR)
|
||||||
|
# define S_IRUSR S_IREAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write user permission */
|
||||||
|
#if !defined(S_IWUSR)
|
||||||
|
# define S_IWUSR S_IWRITE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Execute user permission */
|
||||||
|
#if !defined(S_IXUSR)
|
||||||
|
# define S_IXUSR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Read group permission */
|
||||||
|
#if !defined(S_IRGRP)
|
||||||
|
# define S_IRGRP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write group permission */
|
||||||
|
#if !defined(S_IWGRP)
|
||||||
|
# define S_IWGRP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Execute group permission */
|
||||||
|
#if !defined(S_IXGRP)
|
||||||
|
# define S_IXGRP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Read others permission */
|
||||||
|
#if !defined(S_IROTH)
|
||||||
|
# define S_IROTH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write others permission */
|
||||||
|
#if !defined(S_IWOTH)
|
||||||
|
# define S_IWOTH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Execute others permission */
|
||||||
|
#if !defined(S_IXOTH)
|
||||||
|
# define S_IXOTH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maximum length of file name */
|
||||||
|
#if !defined(PATH_MAX)
|
||||||
|
# define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
|
#if !defined(FILENAME_MAX)
|
||||||
|
# define FILENAME_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
|
#if !defined(NAME_MAX)
|
||||||
|
# define NAME_MAX FILENAME_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* File type flags for d_type */
|
||||||
|
#define DT_UNKNOWN 0
|
||||||
|
#define DT_REG S_IFREG
|
||||||
|
#define DT_DIR S_IFDIR
|
||||||
|
#define DT_FIFO S_IFIFO
|
||||||
|
#define DT_SOCK S_IFSOCK
|
||||||
|
#define DT_CHR S_IFCHR
|
||||||
|
#define DT_BLK S_IFBLK
|
||||||
|
#define DT_LNK S_IFLNK
|
||||||
|
|
||||||
|
/* Macros for converting between st_mode and d_type */
|
||||||
|
#define IFTODT(mode) ((mode) & S_IFMT)
|
||||||
|
#define DTTOIF(type) (type)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File type macros. Note that block devices, sockets and links cannot be
|
||||||
|
* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
|
||||||
|
* only defined for compatibility. These macros should always return false
|
||||||
|
* on Windows.
|
||||||
|
*/
|
||||||
|
#if !defined(S_ISFIFO)
|
||||||
|
# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISDIR)
|
||||||
|
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISREG)
|
||||||
|
# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISLNK)
|
||||||
|
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISSOCK)
|
||||||
|
# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISCHR)
|
||||||
|
# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||||
|
#endif
|
||||||
|
#if !defined(S_ISBLK)
|
||||||
|
# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Return the exact length of d_namlen without zero terminator */
|
||||||
|
#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
|
||||||
|
|
||||||
|
/* Return number of bytes needed to store d_namlen */
|
||||||
|
#define _D_ALLOC_NAMLEN(p) (PATH_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Wide-character version */
|
||||||
|
struct _wdirent {
|
||||||
|
/* Always zero */
|
||||||
|
long d_ino;
|
||||||
|
|
||||||
|
/* Structure size */
|
||||||
|
unsigned short d_reclen;
|
||||||
|
|
||||||
|
/* Length of name without \0 */
|
||||||
|
size_t d_namlen;
|
||||||
|
|
||||||
|
/* File type */
|
||||||
|
int d_type;
|
||||||
|
|
||||||
|
/* File name */
|
||||||
|
wchar_t d_name[PATH_MAX];
|
||||||
|
};
|
||||||
|
typedef struct _wdirent _wdirent;
|
||||||
|
|
||||||
|
struct _WDIR {
|
||||||
|
/* Current directory entry */
|
||||||
|
struct _wdirent ent;
|
||||||
|
|
||||||
|
/* Private file data */
|
||||||
|
WIN32_FIND_DATAW data;
|
||||||
|
|
||||||
|
/* True if data is valid */
|
||||||
|
int cached;
|
||||||
|
|
||||||
|
/* Win32 search handle */
|
||||||
|
HANDLE handle;
|
||||||
|
|
||||||
|
/* Initial directory name */
|
||||||
|
wchar_t *patt;
|
||||||
|
};
|
||||||
|
typedef struct _WDIR _WDIR;
|
||||||
|
|
||||||
|
static _WDIR *_wopendir (const wchar_t *dirname);
|
||||||
|
static struct _wdirent *_wreaddir (_WDIR *dirp);
|
||||||
|
static int _wclosedir (_WDIR *dirp);
|
||||||
|
static void _wrewinddir (_WDIR* dirp);
|
||||||
|
|
||||||
|
|
||||||
|
/* For compatibility with Symbian */
|
||||||
|
#define wdirent _wdirent
|
||||||
|
#define WDIR _WDIR
|
||||||
|
#define wopendir _wopendir
|
||||||
|
#define wreaddir _wreaddir
|
||||||
|
#define wclosedir _wclosedir
|
||||||
|
#define wrewinddir _wrewinddir
|
||||||
|
|
||||||
|
|
||||||
|
/* Multi-byte character versions */
|
||||||
|
struct dirent {
|
||||||
|
/* Always zero */
|
||||||
|
long d_ino;
|
||||||
|
|
||||||
|
/* Structure size */
|
||||||
|
unsigned short d_reclen;
|
||||||
|
|
||||||
|
/* Length of name without \0 */
|
||||||
|
size_t d_namlen;
|
||||||
|
|
||||||
|
/* File type */
|
||||||
|
int d_type;
|
||||||
|
|
||||||
|
/* File name */
|
||||||
|
char d_name[PATH_MAX];
|
||||||
|
};
|
||||||
|
typedef struct dirent dirent;
|
||||||
|
|
||||||
|
struct DIR {
|
||||||
|
struct dirent ent;
|
||||||
|
struct _WDIR *wdirp;
|
||||||
|
};
|
||||||
|
typedef struct DIR DIR;
|
||||||
|
|
||||||
|
static DIR *opendir (const char *dirname);
|
||||||
|
static struct dirent *readdir (DIR *dirp);
|
||||||
|
static int closedir (DIR *dirp);
|
||||||
|
static void rewinddir (DIR* dirp);
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal utility functions */
|
||||||
|
static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
|
||||||
|
static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
|
||||||
|
|
||||||
|
static int dirent_mbstowcs_s(
|
||||||
|
size_t *pReturnValue,
|
||||||
|
wchar_t *wcstr,
|
||||||
|
size_t sizeInWords,
|
||||||
|
const char *mbstr,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
static int dirent_wcstombs_s(
|
||||||
|
size_t *pReturnValue,
|
||||||
|
char *mbstr,
|
||||||
|
size_t sizeInBytes,
|
||||||
|
const wchar_t *wcstr,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
static void dirent_set_errno (int error);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open directory stream DIRNAME for read and return a pointer to the
|
||||||
|
* internal working area that is used to retrieve individual directory
|
||||||
|
* entries.
|
||||||
|
*/
|
||||||
|
static _WDIR*
|
||||||
|
_wopendir(
|
||||||
|
const wchar_t *dirname)
|
||||||
|
{
|
||||||
|
_WDIR *dirp = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Must have directory name */
|
||||||
|
if (dirname == NULL || dirname[0] == '\0') {
|
||||||
|
dirent_set_errno (ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate new _WDIR structure */
|
||||||
|
dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
|
||||||
|
if (dirp != NULL) {
|
||||||
|
DWORD n;
|
||||||
|
|
||||||
|
/* Reset _WDIR structure */
|
||||||
|
dirp->handle = INVALID_HANDLE_VALUE;
|
||||||
|
dirp->patt = NULL;
|
||||||
|
dirp->cached = 0;
|
||||||
|
|
||||||
|
/* Compute the length of full path plus zero terminator
|
||||||
|
*
|
||||||
|
* Note that on WinRT there's no way to convert relative paths
|
||||||
|
* into absolute paths, so just assume its an absolute path.
|
||||||
|
*/
|
||||||
|
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||||
|
n = wcslen(dirname);
|
||||||
|
# else
|
||||||
|
n = GetFullPathNameW (dirname, 0, NULL, NULL);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* Allocate room for absolute directory name and search pattern */
|
||||||
|
dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
|
||||||
|
if (dirp->patt) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert relative directory name to an absolute one. This
|
||||||
|
* allows rewinddir() to function correctly even when current
|
||||||
|
* working directory is changed between opendir() and rewinddir().
|
||||||
|
*
|
||||||
|
* Note that on WinRT there's no way to convert relative paths
|
||||||
|
* into absolute paths, so just assume its an absolute path.
|
||||||
|
*/
|
||||||
|
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||||
|
wcsncpy_s(dirp->patt, n+1, dirname, n);
|
||||||
|
# else
|
||||||
|
n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
|
||||||
|
# endif
|
||||||
|
if (n > 0) {
|
||||||
|
wchar_t *p;
|
||||||
|
|
||||||
|
/* Append search pattern \* to the directory name */
|
||||||
|
p = dirp->patt + n;
|
||||||
|
if (dirp->patt < p) {
|
||||||
|
switch (p[-1]) {
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
case ':':
|
||||||
|
/* Directory ends in path separator, e.g. c:\temp\ */
|
||||||
|
/*NOP*/;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Directory name doesn't end in path separator */
|
||||||
|
*p++ = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = '*';
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
/* Open directory stream and retrieve the first entry */
|
||||||
|
if (dirent_first (dirp)) {
|
||||||
|
/* Directory stream opened successfully */
|
||||||
|
error = 0;
|
||||||
|
} else {
|
||||||
|
/* Cannot retrieve first entry */
|
||||||
|
error = 1;
|
||||||
|
dirent_set_errno (ENOENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Cannot retrieve full path name */
|
||||||
|
dirent_set_errno (ENOENT);
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Cannot allocate memory for search pattern */
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Cannot allocate _WDIR structure */
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up in case of error */
|
||||||
|
if (error && dirp) {
|
||||||
|
_wclosedir (dirp);
|
||||||
|
dirp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read next directory entry. The directory entry is returned in dirent
|
||||||
|
* structure in the d_name field. Individual directory entries returned by
|
||||||
|
* this function include regular files, sub-directories, pseudo-directories
|
||||||
|
* "." and ".." as well as volume labels, hidden files and system files.
|
||||||
|
*/
|
||||||
|
static struct _wdirent*
|
||||||
|
_wreaddir(
|
||||||
|
_WDIR *dirp)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATAW *datap;
|
||||||
|
struct _wdirent *entp;
|
||||||
|
|
||||||
|
/* Read next directory entry */
|
||||||
|
datap = dirent_next (dirp);
|
||||||
|
if (datap) {
|
||||||
|
size_t n;
|
||||||
|
DWORD attr;
|
||||||
|
|
||||||
|
/* Pointer to directory entry to return */
|
||||||
|
entp = &dirp->ent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy file name as wide-character string. If the file name is too
|
||||||
|
* long to fit in to the destination buffer, then truncate file name
|
||||||
|
* to PATH_MAX characters and zero-terminate the buffer.
|
||||||
|
*/
|
||||||
|
n = 0;
|
||||||
|
while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
|
||||||
|
entp->d_name[n] = datap->cFileName[n];
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
dirp->ent.d_name[n] = 0;
|
||||||
|
|
||||||
|
/* Length of file name excluding zero terminator */
|
||||||
|
entp->d_namlen = n;
|
||||||
|
|
||||||
|
/* File type */
|
||||||
|
attr = datap->dwFileAttributes;
|
||||||
|
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
|
||||||
|
entp->d_type = DT_CHR;
|
||||||
|
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
||||||
|
entp->d_type = DT_DIR;
|
||||||
|
} else {
|
||||||
|
entp->d_type = DT_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset dummy fields */
|
||||||
|
entp->d_ino = 0;
|
||||||
|
entp->d_reclen = sizeof (struct _wdirent);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Last directory entry read */
|
||||||
|
entp = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return entp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close directory stream opened by opendir() function. This invalidates the
|
||||||
|
* DIR structure as well as any directory entry read previously by
|
||||||
|
* _wreaddir().
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_wclosedir(
|
||||||
|
_WDIR *dirp)
|
||||||
|
{
|
||||||
|
int ok;
|
||||||
|
if (dirp) {
|
||||||
|
|
||||||
|
/* Release search handle */
|
||||||
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
FindClose (dirp->handle);
|
||||||
|
dirp->handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release search pattern */
|
||||||
|
if (dirp->patt) {
|
||||||
|
free (dirp->patt);
|
||||||
|
dirp->patt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release directory structure */
|
||||||
|
free (dirp);
|
||||||
|
ok = /*success*/0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Invalid directory stream */
|
||||||
|
dirent_set_errno (EBADF);
|
||||||
|
ok = /*failure*/-1;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rewind directory stream such that _wreaddir() returns the very first
|
||||||
|
* file name again.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_wrewinddir(
|
||||||
|
_WDIR* dirp)
|
||||||
|
{
|
||||||
|
if (dirp) {
|
||||||
|
/* Release existing search handle */
|
||||||
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
FindClose (dirp->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open new search handle */
|
||||||
|
dirent_first (dirp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get first directory entry (internal) */
|
||||||
|
static WIN32_FIND_DATAW*
|
||||||
|
dirent_first(
|
||||||
|
_WDIR *dirp)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATAW *datap;
|
||||||
|
|
||||||
|
/* Open directory and retrieve the first entry */
|
||||||
|
dirp->handle = FindFirstFileExW(
|
||||||
|
dirp->patt, FindExInfoStandard, &dirp->data,
|
||||||
|
FindExSearchNameMatch, NULL, 0);
|
||||||
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
|
||||||
|
/* a directory entry is now waiting in memory */
|
||||||
|
datap = &dirp->data;
|
||||||
|
dirp->cached = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Failed to re-open directory: no directory entry in memory */
|
||||||
|
dirp->cached = 0;
|
||||||
|
datap = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
return datap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get next directory entry (internal) */
|
||||||
|
static WIN32_FIND_DATAW*
|
||||||
|
dirent_next(
|
||||||
|
_WDIR *dirp)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATAW *p;
|
||||||
|
|
||||||
|
/* Get next directory entry */
|
||||||
|
if (dirp->cached != 0) {
|
||||||
|
|
||||||
|
/* A valid directory entry already in memory */
|
||||||
|
p = &dirp->data;
|
||||||
|
dirp->cached = 0;
|
||||||
|
|
||||||
|
} else if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
|
||||||
|
/* Get the next directory entry from stream */
|
||||||
|
if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
|
||||||
|
/* Got a file */
|
||||||
|
p = &dirp->data;
|
||||||
|
} else {
|
||||||
|
/* The very last entry has been processed or an error occured */
|
||||||
|
FindClose (dirp->handle);
|
||||||
|
dirp->handle = INVALID_HANDLE_VALUE;
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* End of directory stream reached */
|
||||||
|
p = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open directory stream using plain old C-string.
|
||||||
|
*/
|
||||||
|
static DIR*
|
||||||
|
opendir(
|
||||||
|
const char *dirname)
|
||||||
|
{
|
||||||
|
struct DIR *dirp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Must have directory name */
|
||||||
|
if (dirname == NULL || dirname[0] == '\0') {
|
||||||
|
dirent_set_errno (ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory for DIR structure */
|
||||||
|
dirp = (DIR*) malloc (sizeof (struct DIR));
|
||||||
|
if (dirp) {
|
||||||
|
wchar_t wname[PATH_MAX];
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Convert directory name to wide-character string */
|
||||||
|
error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
|
||||||
|
if (!error) {
|
||||||
|
|
||||||
|
/* Open directory stream using wide-character name */
|
||||||
|
dirp->wdirp = _wopendir (wname);
|
||||||
|
if (dirp->wdirp) {
|
||||||
|
/* Directory stream opened */
|
||||||
|
error = 0;
|
||||||
|
} else {
|
||||||
|
/* Failed to open directory stream */
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Cannot convert file name to wide-character string. This
|
||||||
|
* occurs if the string contains invalid multi-byte sequences or
|
||||||
|
* the output buffer is too small to contain the resulting
|
||||||
|
* string.
|
||||||
|
*/
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Cannot allocate DIR structure */
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up in case of error */
|
||||||
|
if (error && dirp) {
|
||||||
|
free (dirp);
|
||||||
|
dirp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read next directory entry.
|
||||||
|
*
|
||||||
|
* When working with text consoles, please note that file names returned by
|
||||||
|
* readdir() are represented in the default ANSI code page while any output to
|
||||||
|
* console is typically formatted on another code page. Thus, non-ASCII
|
||||||
|
* characters in file names will not usually display correctly on console. The
|
||||||
|
* problem can be fixed in two ways: (1) change the character set of console
|
||||||
|
* to 1252 using chcp utility and use Lucida Console font, or (2) use
|
||||||
|
* _cprintf function when writing to console. The _cprinf() will re-encode
|
||||||
|
* ANSI strings to the console code page so many non-ASCII characters will
|
||||||
|
* display correcly.
|
||||||
|
*/
|
||||||
|
static struct dirent*
|
||||||
|
readdir(
|
||||||
|
DIR *dirp)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATAW *datap;
|
||||||
|
struct dirent *entp;
|
||||||
|
|
||||||
|
/* Read next directory entry */
|
||||||
|
datap = dirent_next (dirp->wdirp);
|
||||||
|
if (datap) {
|
||||||
|
size_t n;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Attempt to convert file name to multi-byte string */
|
||||||
|
error = dirent_wcstombs_s(
|
||||||
|
&n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the file name cannot be represented by a multi-byte string,
|
||||||
|
* then attempt to use old 8+3 file name. This allows traditional
|
||||||
|
* Unix-code to access some file names despite of unicode
|
||||||
|
* characters, although file names may seem unfamiliar to the user.
|
||||||
|
*
|
||||||
|
* Be ware that the code below cannot come up with a short file
|
||||||
|
* name unless the file system provides one. At least
|
||||||
|
* VirtualBox shared folders fail to do this.
|
||||||
|
*/
|
||||||
|
if (error && datap->cAlternateFileName[0] != '\0') {
|
||||||
|
error = dirent_wcstombs_s(
|
||||||
|
&n, dirp->ent.d_name, PATH_MAX,
|
||||||
|
datap->cAlternateFileName, PATH_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
DWORD attr;
|
||||||
|
|
||||||
|
/* Initialize directory entry for return */
|
||||||
|
entp = &dirp->ent;
|
||||||
|
|
||||||
|
/* Length of file name excluding zero terminator */
|
||||||
|
entp->d_namlen = n - 1;
|
||||||
|
|
||||||
|
/* File attributes */
|
||||||
|
attr = datap->dwFileAttributes;
|
||||||
|
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
|
||||||
|
entp->d_type = DT_CHR;
|
||||||
|
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
||||||
|
entp->d_type = DT_DIR;
|
||||||
|
} else {
|
||||||
|
entp->d_type = DT_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset dummy fields */
|
||||||
|
entp->d_ino = 0;
|
||||||
|
entp->d_reclen = sizeof (struct dirent);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Cannot convert file name to multi-byte string so construct
|
||||||
|
* an errornous directory entry and return that. Note that
|
||||||
|
* we cannot return NULL as that would stop the processing
|
||||||
|
* of directory entries completely.
|
||||||
|
*/
|
||||||
|
entp = &dirp->ent;
|
||||||
|
entp->d_name[0] = '?';
|
||||||
|
entp->d_name[1] = '\0';
|
||||||
|
entp->d_namlen = 1;
|
||||||
|
entp->d_type = DT_UNKNOWN;
|
||||||
|
entp->d_ino = 0;
|
||||||
|
entp->d_reclen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* No more directory entries */
|
||||||
|
entp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close directory stream.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
closedir(
|
||||||
|
DIR *dirp)
|
||||||
|
{
|
||||||
|
int ok;
|
||||||
|
if (dirp) {
|
||||||
|
|
||||||
|
/* Close wide-character directory stream */
|
||||||
|
ok = _wclosedir (dirp->wdirp);
|
||||||
|
dirp->wdirp = NULL;
|
||||||
|
|
||||||
|
/* Release multi-byte character version */
|
||||||
|
free (dirp);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Invalid directory stream */
|
||||||
|
dirent_set_errno (EBADF);
|
||||||
|
ok = /*failure*/-1;
|
||||||
|
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rewind directory stream to beginning.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rewinddir(
|
||||||
|
DIR* dirp)
|
||||||
|
{
|
||||||
|
/* Rewind wide-character string directory stream */
|
||||||
|
_wrewinddir (dirp->wdirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert multi-byte string to wide character string */
|
||||||
|
static int
|
||||||
|
dirent_mbstowcs_s(
|
||||||
|
size_t *pReturnValue,
|
||||||
|
wchar_t *wcstr,
|
||||||
|
size_t sizeInWords,
|
||||||
|
const char *mbstr,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
|
||||||
|
/* Microsoft Visual Studio 2005 or later */
|
||||||
|
error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Older Visual Studio or non-Microsoft compiler */
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Convert to wide-character string (or count characters) */
|
||||||
|
n = mbstowcs (wcstr, mbstr, sizeInWords);
|
||||||
|
if (!wcstr || n < count) {
|
||||||
|
|
||||||
|
/* Zero-terminate output buffer */
|
||||||
|
if (wcstr && sizeInWords) {
|
||||||
|
if (n >= sizeInWords) {
|
||||||
|
n = sizeInWords - 1;
|
||||||
|
}
|
||||||
|
wcstr[n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Length of resuting multi-byte string WITH zero terminator */
|
||||||
|
if (pReturnValue) {
|
||||||
|
*pReturnValue = n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Could not convert string */
|
||||||
|
error = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert wide-character string to multi-byte string */
|
||||||
|
static int
|
||||||
|
dirent_wcstombs_s(
|
||||||
|
size_t *pReturnValue,
|
||||||
|
char *mbstr,
|
||||||
|
size_t sizeInBytes, /* max size of mbstr */
|
||||||
|
const wchar_t *wcstr,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
|
||||||
|
/* Microsoft Visual Studio 2005 or later */
|
||||||
|
error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Older Visual Studio or non-Microsoft compiler */
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Convert to multi-byte string (or count the number of bytes needed) */
|
||||||
|
n = wcstombs (mbstr, wcstr, sizeInBytes);
|
||||||
|
if (!mbstr || n < count) {
|
||||||
|
|
||||||
|
/* Zero-terminate output buffer */
|
||||||
|
if (mbstr && sizeInBytes) {
|
||||||
|
if (n >= sizeInBytes) {
|
||||||
|
n = sizeInBytes - 1;
|
||||||
|
}
|
||||||
|
mbstr[n] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Length of resulting multi-bytes string WITH zero-terminator */
|
||||||
|
if (pReturnValue) {
|
||||||
|
*pReturnValue = n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Cannot convert string */
|
||||||
|
error = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set errno variable */
|
||||||
|
static void
|
||||||
|
dirent_set_errno(
|
||||||
|
int error)
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
|
||||||
|
/* Microsoft Visual Studio 2005 and later */
|
||||||
|
_set_errno (error);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Non-Microsoft compiler or older Microsoft compiler */
|
||||||
|
errno = error;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /*DIRENT_H*/
|
||||||
@ -30,7 +30,7 @@
|
|||||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9110
|
#define CURRENT_BINARY_DATABASE_VERSION 9114
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
|
||||||
#else
|
#else
|
||||||
|
|||||||
159
utils/mods/classic_wow_experience.lua
Normal file
159
utils/mods/classic_wow_experience.lua
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
--Mod file to demo changing the experience tables
|
||||||
|
--In this case I used some old wow tables (roughly it's not 100%)
|
||||||
|
|
||||||
|
function GetRequiredAAExperience(e)
|
||||||
|
e.level = 51;
|
||||||
|
return GetEXPForLevel(e);
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetExperienceForKill(e)
|
||||||
|
local ML = e.other:GetLevel();
|
||||||
|
local CL = e.self:GetLevel();
|
||||||
|
|
||||||
|
if(ML > CL) then
|
||||||
|
local lmod = (ML - CL) * 0.05;
|
||||||
|
if(lmod > 1.0) then
|
||||||
|
lmod = 1.0;
|
||||||
|
end
|
||||||
|
e.ReturnValue = BaseXP(ML) * (1 + lmod);
|
||||||
|
elseif(ML < CL) then
|
||||||
|
local lmod = (CL - ML) * 0.05;
|
||||||
|
if(lmod > 1.0) then
|
||||||
|
lmod = 1.0;
|
||||||
|
end
|
||||||
|
e.ReturnValue = BaseXP(ML) * (1 - lmod);
|
||||||
|
else
|
||||||
|
e.ReturnValue = BaseXP(ML);
|
||||||
|
end
|
||||||
|
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function BaseXP(L)
|
||||||
|
local base = L * 5;
|
||||||
|
|
||||||
|
if(L < 60) then
|
||||||
|
base = base + 45;
|
||||||
|
elseif(L < 70) then
|
||||||
|
base = base + 235;
|
||||||
|
elseif(L < 80) then
|
||||||
|
base = base + 580;
|
||||||
|
else
|
||||||
|
base = base + 1875;
|
||||||
|
end
|
||||||
|
|
||||||
|
return base;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetEXPForLevel(e)
|
||||||
|
local exp_table = {
|
||||||
|
0,
|
||||||
|
400,
|
||||||
|
900,
|
||||||
|
1400,
|
||||||
|
2100,
|
||||||
|
2800,
|
||||||
|
3600,
|
||||||
|
4500,
|
||||||
|
5400,
|
||||||
|
6500,
|
||||||
|
7600,
|
||||||
|
8700,
|
||||||
|
9800,
|
||||||
|
11000,
|
||||||
|
12300,
|
||||||
|
13600,
|
||||||
|
15000,
|
||||||
|
16400,
|
||||||
|
17800,
|
||||||
|
19300,
|
||||||
|
20800,
|
||||||
|
22400,
|
||||||
|
24000,
|
||||||
|
25500,
|
||||||
|
27200,
|
||||||
|
28900,
|
||||||
|
30500,
|
||||||
|
32200,
|
||||||
|
33900,
|
||||||
|
36300,
|
||||||
|
38800,
|
||||||
|
41600,
|
||||||
|
44600,
|
||||||
|
48000,
|
||||||
|
51400,
|
||||||
|
55000,
|
||||||
|
58700,
|
||||||
|
62400,
|
||||||
|
66200,
|
||||||
|
70200,
|
||||||
|
74300,
|
||||||
|
78500,
|
||||||
|
82800,
|
||||||
|
87100,
|
||||||
|
91600,
|
||||||
|
96300,
|
||||||
|
101000,
|
||||||
|
105800,
|
||||||
|
110700,
|
||||||
|
115700,
|
||||||
|
120900,
|
||||||
|
126100,
|
||||||
|
131500,
|
||||||
|
137000,
|
||||||
|
142500,
|
||||||
|
148200,
|
||||||
|
154000,
|
||||||
|
159900,
|
||||||
|
165800,
|
||||||
|
172000,
|
||||||
|
290000,
|
||||||
|
317000,
|
||||||
|
349000,
|
||||||
|
386000,
|
||||||
|
428000,
|
||||||
|
475000,
|
||||||
|
527000,
|
||||||
|
585000,
|
||||||
|
648000,
|
||||||
|
717000,
|
||||||
|
1523800,
|
||||||
|
1539000,
|
||||||
|
1555700,
|
||||||
|
1571800,
|
||||||
|
1587900,
|
||||||
|
1604200,
|
||||||
|
1620700,
|
||||||
|
1637400,
|
||||||
|
1653900,
|
||||||
|
1670800,
|
||||||
|
1670800,
|
||||||
|
1670800,
|
||||||
|
2121500,
|
||||||
|
2669000,
|
||||||
|
3469000,
|
||||||
|
4583000,
|
||||||
|
13000000,
|
||||||
|
15080000,
|
||||||
|
22600000,
|
||||||
|
27300000,
|
||||||
|
32800000
|
||||||
|
};
|
||||||
|
|
||||||
|
if(e.level < 1) then
|
||||||
|
e.ReturnValue = 0;
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
if(e.level > 91) then
|
||||||
|
e.ReturnValue = exp_table[91];
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
e.ReturnValue = exp_table[e.level];
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
754
utils/mods/legacy_combat.lua
Normal file
754
utils/mods/legacy_combat.lua
Normal file
@ -0,0 +1,754 @@
|
|||||||
|
MonkACBonusWeight = RuleI.Get(Rule.MonkACBonusWeight);
|
||||||
|
NPCACFactor = RuleR.Get(Rule.NPCACFactor);
|
||||||
|
OldACSoftcapRules = RuleB.Get(Rule.OldACSoftcapRules);
|
||||||
|
ClothACSoftcap = RuleI.Get(Rule.ClothACSoftcap);
|
||||||
|
LeatherACSoftcap = RuleI.Get(Rule.LeatherACSoftcap);
|
||||||
|
MonkACSoftcap = RuleI.Get(Rule.MonkACSoftcap);
|
||||||
|
ChainACSoftcap = RuleI.Get(Rule.ChainACSoftcap);
|
||||||
|
PlateACSoftcap = RuleI.Get(Rule.PlateACSoftcap);
|
||||||
|
|
||||||
|
AAMitigationACFactor = RuleR.Get(Rule.AAMitigationACFactor);
|
||||||
|
WarriorACSoftcapReturn = RuleR.Get(Rule.WarriorACSoftcapReturn);
|
||||||
|
KnightACSoftcapReturn = RuleR.Get(Rule.KnightACSoftcapReturn);
|
||||||
|
LowPlateChainACSoftcapReturn = RuleR.Get(Rule.LowPlateChainACSoftcapReturn);
|
||||||
|
LowChainLeatherACSoftcapReturn = RuleR.Get(Rule.LowChainLeatherACSoftcapReturn);
|
||||||
|
CasterACSoftcapReturn = RuleR.Get(Rule.CasterACSoftcapReturn);
|
||||||
|
MiscACSoftcapReturn = RuleR.Get(Rule.MiscACSoftcapReturn);
|
||||||
|
WarACSoftcapReturn = RuleR.Get(Rule.WarACSoftcapReturn);
|
||||||
|
ClrRngMnkBrdACSoftcapReturn = RuleR.Get(Rule.ClrRngMnkBrdACSoftcapReturn);
|
||||||
|
PalShdACSoftcapReturn = RuleR.Get(Rule.PalShdACSoftcapReturn);
|
||||||
|
DruNecWizEncMagACSoftcapReturn = RuleR.Get(Rule.DruNecWizEncMagACSoftcapReturn);
|
||||||
|
RogShmBstBerACSoftcapReturn = RuleR.Get(Rule.RogShmBstBerACSoftcapReturn);
|
||||||
|
SoftcapFactor = RuleR.Get(Rule.SoftcapFactor);
|
||||||
|
ACthac0Factor = RuleR.Get(Rule.ACthac0Factor);
|
||||||
|
ACthac20Factor = RuleR.Get(Rule.ACthac20Factor);
|
||||||
|
|
||||||
|
MeleeBaseCritChance = 0.0;
|
||||||
|
ClientBaseCritChance = 0.0;
|
||||||
|
BerserkBaseCritChance = 6.0;
|
||||||
|
WarBerBaseCritChance = 3.0;
|
||||||
|
RogueCritThrowingChance = 25;
|
||||||
|
RogueDeadlyStrikeChance = 80;
|
||||||
|
RogueDeadlyStrikeMod = 2;
|
||||||
|
|
||||||
|
BaseHitChance = RuleR.Get(Rule.BaseHitChance);
|
||||||
|
NPCBonusHitChance = RuleR.Get(Rule.NPCBonusHitChance);
|
||||||
|
HitFalloffMinor = RuleR.Get(Rule.HitFalloffMinor);
|
||||||
|
HitFalloffModerate = RuleR.Get(Rule.HitFalloffModerate);
|
||||||
|
HitFalloffMajor = RuleR.Get(Rule.HitFalloffMajor);
|
||||||
|
HitBonusPerLevel = RuleR.Get(Rule.HitBonusPerLevel);
|
||||||
|
AgiHitFactor = RuleR.Get(Rule.AgiHitFactor);
|
||||||
|
WeaponSkillFalloff = RuleR.Get(Rule.WeaponSkillFalloff);
|
||||||
|
ArcheryHitPenalty = RuleR.Get(Rule.ArcheryHitPenalty);
|
||||||
|
UseOldDamageIntervalRules = RuleB.Get(Rule.UseOldDamageIntervalRules);
|
||||||
|
|
||||||
|
CriticalMessageRange = RuleI.Get(Rule.CriticalDamage);
|
||||||
|
|
||||||
|
function MeleeMitigation(e)
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
|
||||||
|
if e.hit.damage_done < 0 or e.hit.base_damage == 0 then
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
e.hit.damage_done = 2 * e.hit.base_damage * GetDamageTable(e.other, e.hit.skill) / 100;
|
||||||
|
e.hit = DoMeleeMitigation(e.self, e.other, e.hit, e.opts);
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckHitChance(e)
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
|
||||||
|
local other = e.other;
|
||||||
|
local attacker = other;
|
||||||
|
local self = e.self;
|
||||||
|
local defender = self;
|
||||||
|
local chancetohit = BaseHitChance;
|
||||||
|
local chance_mod = 0;
|
||||||
|
|
||||||
|
if(e.opts ~= nil) then
|
||||||
|
chance_mod = e.opts.hit_chance;
|
||||||
|
end
|
||||||
|
|
||||||
|
if(attacker:IsNPC() and not attacker:IsPet()) then
|
||||||
|
chancetohit = chancetohit + NPCBonusHitChance;
|
||||||
|
end
|
||||||
|
|
||||||
|
local pvpmode = false;
|
||||||
|
if(self:IsClient() and other:IsClient()) then
|
||||||
|
pvpmode = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (chance_mod >= 10000) then
|
||||||
|
e.ReturnValue = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
local avoidanceBonus = 0;
|
||||||
|
local hitBonus = 0;
|
||||||
|
|
||||||
|
local attacker_level = attacker:GetLevel();
|
||||||
|
if(attacker_level < 1) then
|
||||||
|
attacker_level = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
local defender_level = defender:GetLevel();
|
||||||
|
if(defender_level < 1) then
|
||||||
|
defender_level = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
local level_difference = attacker_level - defender_level;
|
||||||
|
local range = defender_level;
|
||||||
|
range = ((range / 4) + 3);
|
||||||
|
|
||||||
|
if(level_difference < 0) then
|
||||||
|
if(level_difference >= -range) then
|
||||||
|
chancetohit = chancetohit + ((level_difference / range) * HitFalloffMinor);
|
||||||
|
elseif (level_difference >= -(range+3.0)) then
|
||||||
|
chancetohit = chancetohit - HitFalloffMinor;
|
||||||
|
chancetohit = chancetohit + (((level_difference + range) / 3.0) * HitFalloffModerate);
|
||||||
|
else
|
||||||
|
chancetohit = chancetohit - (HitFalloffMinor + HitFalloffModerate);
|
||||||
|
chancetohit = chancetohit + (((level_difference + range + 3.0) / 12.0) * HitFalloffMajor);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
chancetohit = chancetohit + (HitBonusPerLevel * level_difference);
|
||||||
|
end
|
||||||
|
|
||||||
|
chancetohit = chancetohit - (defender:GetAGI() * AgiHitFactor);
|
||||||
|
|
||||||
|
if(attacker:IsClient()) then
|
||||||
|
chancetohit = chancetohit - (WeaponSkillFalloff * (attacker:CastToClient():MaxSkill(e.hit.skill) - attacker:GetSkill(e.hit.skill)));
|
||||||
|
end
|
||||||
|
|
||||||
|
if(defender:IsClient()) then
|
||||||
|
chancetohit = chancetohit + (WeaponSkillFalloff * (defender:CastToClient():MaxSkill(Skill.Defense) - defender:GetSkill(Skill.Defense)));
|
||||||
|
end
|
||||||
|
|
||||||
|
local attacker_spellbonuses = attacker:GetSpellBonuses();
|
||||||
|
local attacker_itembonuses = attacker:GetItemBonuses();
|
||||||
|
local attacker_aabonuses = attacker:GetAABonuses();
|
||||||
|
local defender_spellbonuses = defender:GetSpellBonuses();
|
||||||
|
local defender_itembonuses = defender:GetItemBonuses();
|
||||||
|
local defender_aabonuses = defender:GetAABonuses();
|
||||||
|
|
||||||
|
if(attacker_spellbonuses:MeleeSkillCheckSkill() == e.hit.skill or attacker_spellbonuses:MeleeSkillCheckSkill() == 255) then
|
||||||
|
chancetohit = chancetohit + attacker_spellbonuses:MeleeSkillCheck();
|
||||||
|
end
|
||||||
|
|
||||||
|
if(attacker_itembonuses:MeleeSkillCheckSkill() == e.hit.skill or attacker_itembonuses:MeleeSkillCheckSkill() == 255) then
|
||||||
|
chancetohit = chancetohit + attacker_itembonuses:MeleeSkillCheck();
|
||||||
|
end
|
||||||
|
|
||||||
|
avoidanceBonus = defender_spellbonuses:AvoidMeleeChanceEffect() +
|
||||||
|
defender_itembonuses:AvoidMeleeChanceEffect() +
|
||||||
|
defender_aabonuses:AvoidMeleeChanceEffect() +
|
||||||
|
(defender_itembonuses:AvoidMeleeChance() / 10.0);
|
||||||
|
|
||||||
|
local owner = Mob();
|
||||||
|
if (defender:IsPet()) then
|
||||||
|
owner = defender:GetOwner();
|
||||||
|
elseif (defender:IsNPC() and defender:CastToNPC():GetSwarmOwner()) then
|
||||||
|
local entity_list = eq.get_entity_list();
|
||||||
|
owner = entity_list:GetMobID(defender:CastToNPC():GetSwarmOwner());
|
||||||
|
end
|
||||||
|
|
||||||
|
if (owner.valid) then
|
||||||
|
avoidanceBonus = avoidanceBonus + owner:GetAABonuses():PetAvoidance() + owner:GetSpellBonuses():PetAvoidance() + owner:GetItemBonuses():PetAvoidance();
|
||||||
|
end
|
||||||
|
|
||||||
|
if(defender:IsNPC()) then
|
||||||
|
avoidanceBonus = avoidanceBonus + (defender:CastToNPC():GetAvoidanceRating() / 10.0);
|
||||||
|
end
|
||||||
|
|
||||||
|
hitBonus = hitBonus + attacker_itembonuses:HitChanceEffect(e.hit.skill) +
|
||||||
|
attacker_spellbonuses:HitChanceEffect(e.hit.skill) +
|
||||||
|
attacker_aabonuses:HitChanceEffect(e.hit.skill) +
|
||||||
|
attacker_itembonuses:HitChanceEffect(Skill.HIGHEST_SKILL + 1) +
|
||||||
|
attacker_spellbonuses:HitChanceEffect(Skill.HIGHEST_SKILL + 1) +
|
||||||
|
attacker_aabonuses:HitChanceEffect(Skill.HIGHEST_SKILL + 1);
|
||||||
|
|
||||||
|
hitBonus = hitBonus + (attacker_itembonuses:Accuracy(Skill.HIGHEST_SKILL + 1) +
|
||||||
|
attacker_spellbonuses:Accuracy(Skill.HIGHEST_SKILL + 1) +
|
||||||
|
attacker_aabonuses:Accuracy(Skill.HIGHEST_SKILL + 1) +
|
||||||
|
attacker_aabonuses:Accuracy(e.hit.skill) +
|
||||||
|
attacker_itembonuses:HitChance()) / 15.0;
|
||||||
|
|
||||||
|
hitBonus = hitBonus + chance_mod;
|
||||||
|
|
||||||
|
if(attacker:IsNPC()) then
|
||||||
|
hitBonus = hitBonus + (attacker:CastToNPC():GetAccuracyRating() / 10.0);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (e.hit.skill == Skill.Archery) then
|
||||||
|
hitBonus = hitBonus - (hitBonus * ArcheryHitPenalty);
|
||||||
|
end
|
||||||
|
|
||||||
|
chancetohit = chancetohit + ((chancetohit * (hitBonus - avoidanceBonus)) / 100.0);
|
||||||
|
|
||||||
|
if(chancetohit > 1000 or chancetohit < -1000) then
|
||||||
|
elseif(chancetohit > 95) then
|
||||||
|
chancetohit = 95;
|
||||||
|
elseif(chancetohit < 5) then
|
||||||
|
chancetohit = 5;
|
||||||
|
end
|
||||||
|
|
||||||
|
local tohit_roll = Random.Real(0, 100);
|
||||||
|
if(tohit_roll <= chancetohit) then
|
||||||
|
e.ReturnValue = true;
|
||||||
|
else
|
||||||
|
e.ReturnValue = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function TryCriticalHit(e)
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
|
||||||
|
local self = e.self;
|
||||||
|
local defender = e.other;
|
||||||
|
|
||||||
|
if(e.hit.damage_done < 1 or defender.null) then
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((self:IsPet() and self:GetOwner():IsClient()) or (self:IsNPC() and self:CastToNPC():GetSwarmOwner() ~= 0)) then
|
||||||
|
e.hit = TryPetCriticalHit(self, defender, e.hit);
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (self:IsPet() and self:GetOwner().valid and self:GetOwner():IsBot()) then
|
||||||
|
e.hit = TryPetCriticalHit(self, defender, e.hit);
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
local critChance = 0.0;
|
||||||
|
local IsBerskerSPA = false;
|
||||||
|
local aabonuses = self:GetAABonuses();
|
||||||
|
local itembonuses = self:GetItemBonuses();
|
||||||
|
local spellbonuses = self:GetSpellBonuses();
|
||||||
|
local entity_list = eq.get_entity_list();
|
||||||
|
|
||||||
|
if (defender:GetBodyType() == BT.Undead or defender:GetBodyType() == BT.SummonedUndead or defender:GetBodyType() == BT.Vampire) then
|
||||||
|
local SlayRateBonus = aabonuses:SlayUndead(0) + itembonuses:SlayUndead(0) + spellbonuses:SlayUndead(0);
|
||||||
|
if (SlayRateBonus > 0) then
|
||||||
|
local slayChance = SlayRateBonus / 10000.0;
|
||||||
|
if (Random.RollReal(slayChance)) then
|
||||||
|
local SlayDmgBonus = aabonuses:SlayUndead(1) + itembonuses:SlayUndead(1) + spellbonuses:SlayUndead(1);
|
||||||
|
e.hit.damage_done = (e.hit.damage_done * SlayDmgBonus * 2.25) / 100;
|
||||||
|
|
||||||
|
if (self:GetGender() == 1) then
|
||||||
|
entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses her target! (%d)', self:GetCleanName(), e.hit.damage_done));
|
||||||
|
else
|
||||||
|
entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses his target! (%d)', self:GetCleanName(), e.hit.damage_done));
|
||||||
|
end
|
||||||
|
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
critChance = critChance + MeleeBaseCritChance;
|
||||||
|
|
||||||
|
if (self:IsClient()) then
|
||||||
|
critChance = critChance + ClientBaseCritChance;
|
||||||
|
|
||||||
|
if (spellbonuses:BerserkSPA() or itembonuses:BerserkSPA() or aabonuses:BerserkSPA()) then
|
||||||
|
IsBerskerSPA = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (((self:GetClass() == Class.WARRIOR or self:GetClass() == Class.BERSERKER) and self:GetLevel() >= 12) or IsBerskerSPA) then
|
||||||
|
if (self:IsBerserk() or IsBerskerSPA) then
|
||||||
|
critChance = critChance + BerserkBaseCritChance;
|
||||||
|
else
|
||||||
|
critChance = critChance + WarBerBaseCritChance;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local deadlyChance = 0;
|
||||||
|
local deadlyMod = 0;
|
||||||
|
if (e.hit.skill == Skill.Archery and self:GetClass() == Class.RANGER and self:GetSkill(Skill.Archery) >= 65) then
|
||||||
|
critChance = critChance + 6;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (e.hit.skill == Skill.Throwing and self:GetClass() == Class.ROGUE and self:GetSkill(Skill.Throwing) >= 65) then
|
||||||
|
critChance = critChance + RogueCritThrowingChance;
|
||||||
|
deadlyChance = RogueDeadlyStrikeChance;
|
||||||
|
deadlyMod = RogueDeadlyStrikeMod;
|
||||||
|
end
|
||||||
|
|
||||||
|
local CritChanceBonus = GetCriticalChanceBonus(self, e.hit.skill);
|
||||||
|
|
||||||
|
if (CritChanceBonus > 0 or critChance > 0) then
|
||||||
|
if (self:GetDEX() <= 255) then
|
||||||
|
critChance = critChance + (self:GetDEX() / 125.0);
|
||||||
|
elseif (self:GetDEX() > 255) then
|
||||||
|
critChance = critChance + ((self:GetDEX() - 255) / 500.0) + 2.0;
|
||||||
|
end
|
||||||
|
critChance = critChance + (critChance * CritChanceBonus / 100.0);
|
||||||
|
end
|
||||||
|
|
||||||
|
if(opts ~= nil) then
|
||||||
|
critChance = critChance * opts.crit_percent;
|
||||||
|
critChance = critChance + opts.crit_flat;
|
||||||
|
end
|
||||||
|
|
||||||
|
if(critChance > 0) then
|
||||||
|
|
||||||
|
critChance = critChance / 100;
|
||||||
|
|
||||||
|
if(Random.RollReal(critChance)) then
|
||||||
|
local critMod = 200;
|
||||||
|
local crip_success = false;
|
||||||
|
local CripplingBlowChance = GetCrippBlowChance(self);
|
||||||
|
|
||||||
|
if (CripplingBlowChance > 0 or (self:IsBerserk() or IsBerskerSPA)) then
|
||||||
|
if (not self:IsBerserk() and not IsBerskerSPA) then
|
||||||
|
critChance = critChance * (CripplingBlowChance / 100.0);
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((self:IsBerserk() or IsBerskerSPA) or Random.RollReal(critChance)) then
|
||||||
|
critMod = 400;
|
||||||
|
crip_success = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
critMod = critMod + GetCritDmgMod(self, e.hit.skill) * 2;
|
||||||
|
e.hit.damage_done = e.hit.damage_done * critMod / 100;
|
||||||
|
|
||||||
|
local deadlySuccess = false;
|
||||||
|
if (deadlyChance > 0 and Random.RollReal(deadlyChance / 100.0)) then
|
||||||
|
if (self:BehindMob(defender, self:GetX(), self:GetY())) then
|
||||||
|
e.hit.damage_done = e.hit.damage_done * deadlyMod;
|
||||||
|
deadlySuccess = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (crip_success) then
|
||||||
|
entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s lands a Crippling Blow! (%d)', self:GetCleanName(), e.hit.damage_done));
|
||||||
|
if (defender:GetLevel() <= 55 and not defender:GetSpecialAbility(SpecialAbility.unstunable)) then
|
||||||
|
defender:Emote("staggers.");
|
||||||
|
defender:Stun(0);
|
||||||
|
end
|
||||||
|
elseif (deadlySuccess) then
|
||||||
|
entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a Deadly Strike! (%d)', self:GetCleanName(), e.hit.damage_done));
|
||||||
|
else
|
||||||
|
entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)', self:GetCleanName(), e.hit.damage_done));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function TryPetCriticalHit(self, defender, hit)
|
||||||
|
if(hit.damage_done < 1) then
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
local owner = Mob();
|
||||||
|
local critChance = MeleeBaseCritChance;
|
||||||
|
local critMod = 163;
|
||||||
|
|
||||||
|
if (self:IsPet()) then
|
||||||
|
owner = self:GetOwner();
|
||||||
|
elseif (self:IsNPC() and self:CastToNPC():GetSwarmOwner()) then
|
||||||
|
local entity_list = eq.get_entity_list();
|
||||||
|
owner = entity_list:GetMobID(self:CastToNPC():GetSwarmOwner());
|
||||||
|
else
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (owner.null) then
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
local CritPetChance = owner:GetAABonuses():PetCriticalHit() + owner:GetItemBonuses():PetCriticalHit() + owner:GetSpellBonuses():PetCriticalHit();
|
||||||
|
local CritChanceBonus = GetCriticalChanceBonus(self, hit.skill);
|
||||||
|
|
||||||
|
if (CritPetChance or critChance) then
|
||||||
|
critChance = critChance + CritPetChance;
|
||||||
|
critChance = critChance + (critChance * CritChanceBonus / 100.0);
|
||||||
|
end
|
||||||
|
|
||||||
|
if(critChance > 0) then
|
||||||
|
critChance = critChance / 100;
|
||||||
|
|
||||||
|
if(Random.RollReal(critChance)) then
|
||||||
|
local entity_list = eq.get_entity_list();
|
||||||
|
critMod = critMod + GetCritDmgMod(self, hit.skill) * 2;
|
||||||
|
hit.damage_done = (hit.damage_done * critMod) / 100;
|
||||||
|
entity_list:FilteredMessageClose(this, false, CriticalMessageRange,
|
||||||
|
MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)',
|
||||||
|
self:GetCleanName(), e.hit.damage_done));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetCriticalChanceBonus(self, skill)
|
||||||
|
|
||||||
|
local critical_chance = 0;
|
||||||
|
|
||||||
|
local aabonuses = self:GetAABonuses();
|
||||||
|
local itembonuses = self:GetItemBonuses();
|
||||||
|
local spellbonuses = self:GetSpellBonuses();
|
||||||
|
|
||||||
|
critical_chance = critical_chance + itembonuses:CriticalHitChance(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critical_chance = critical_chance + spellbonuses:CriticalHitChance(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critical_chance = critical_chance + aabonuses:CriticalHitChance(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critical_chance = critical_chance + itembonuses:CriticalHitChance(skill);
|
||||||
|
critical_chance = critical_chance + spellbonuses:CriticalHitChance(skill);
|
||||||
|
critical_chance = critical_chance + aabonuses:CriticalHitChance(skill);
|
||||||
|
|
||||||
|
return critical_chance;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetCritDmgMod(self, skill)
|
||||||
|
local critDmg_mod = 0;
|
||||||
|
|
||||||
|
local aabonuses = self:GetAABonuses();
|
||||||
|
local itembonuses = self:GetItemBonuses();
|
||||||
|
local spellbonuses = self:GetSpellBonuses();
|
||||||
|
|
||||||
|
critDmg_mod = critDmg_mod + itembonuses:CritDmgMod(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critDmg_mod = critDmg_mod + spellbonuses:CritDmgMod(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critDmg_mod = critDmg_mod + aabonuses:CritDmgMod(Skill.HIGHEST_SKILL + 1);
|
||||||
|
critDmg_mod = critDmg_mod + itembonuses:CritDmgMod(skill);
|
||||||
|
critDmg_mod = critDmg_mod + spellbonuses:CritDmgMod(skill);
|
||||||
|
critDmg_mod = critDmg_mod + aabonuses:CritDmgMod(skill);
|
||||||
|
|
||||||
|
return critDmg_mod;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetCrippBlowChance(self)
|
||||||
|
local aabonuses = self:GetAABonuses();
|
||||||
|
local itembonuses = self:GetItemBonuses();
|
||||||
|
local spellbonuses = self:GetSpellBonuses();
|
||||||
|
local crip_chance = itembonuses:CrippBlowChance() + spellbonuses:CrippBlowChance() + aabonuses:CrippBlowChance();
|
||||||
|
|
||||||
|
if(crip_chance < 0) then
|
||||||
|
crip_chance = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
return crip_chance;
|
||||||
|
end
|
||||||
|
|
||||||
|
function DoMeleeMitigation(defender, attacker, hit, opts)
|
||||||
|
if hit.damage_done <= 0 then
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
local aabonuses = defender:GetAABonuses();
|
||||||
|
local itembonuses = defender:GetItemBonuses();
|
||||||
|
local spellbonuses = defender:GetSpellBonuses();
|
||||||
|
|
||||||
|
local aa_mit = (aabonuses:CombatStability() + itembonuses:CombatStability() + spellbonuses:CombatStability()) / 100.0;
|
||||||
|
local softcap = (defender:GetSkill(15) + defender:GetLevel()) * SoftcapFactor * (1.0 + aa_mit);
|
||||||
|
local mitigation_rating = 0.0;
|
||||||
|
local attack_rating = 0.0;
|
||||||
|
local shield_ac = 0;
|
||||||
|
local armor = 0;
|
||||||
|
local weight = 0.0;
|
||||||
|
local monkweight = MonkACBonusWeight;
|
||||||
|
|
||||||
|
if defender:IsClient() then
|
||||||
|
armor, shield_ac = GetRawACNoShield(defender);
|
||||||
|
weight = defender:CastToClient():CalcCurrentWeight() / 10;
|
||||||
|
elseif defender:IsNPC() then
|
||||||
|
armor = defender:CastToNPC():GetRawAC();
|
||||||
|
local PetACBonus = 0;
|
||||||
|
|
||||||
|
if not defender:IsPet() then
|
||||||
|
armor = armor / NPCACFactor;
|
||||||
|
end
|
||||||
|
|
||||||
|
local owner = Mob();
|
||||||
|
if defender:IsPet() then
|
||||||
|
owner = defender:GetOwner();
|
||||||
|
elseif defender:CastToNPC():GetSwarmOwner() ~= 0 then
|
||||||
|
local entity_list = eq.get_entity_list();
|
||||||
|
owner = entity_list:GetMobID(defender:CastToNPC():GetSwarmOwner());
|
||||||
|
end
|
||||||
|
|
||||||
|
if owner.valid then
|
||||||
|
PetACBonus = owner:GetAABonuses():PetMeleeMitigation() + owner:GetItemBonuses():PetMeleeMitigation() + owner:GetSpellBonuses():PetMeleeMitigation();
|
||||||
|
end
|
||||||
|
|
||||||
|
armor = armor + defender:GetSpellBonuses():AC() + defender:GetItemBonuses():AC() + PetACBonus + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (opts ~= nil) then
|
||||||
|
armor = armor * (1.0 - opts.armor_pen_percent);
|
||||||
|
armor = armor - opts.armor_pen_flat;
|
||||||
|
end
|
||||||
|
|
||||||
|
local defender_class = defender:GetClass();
|
||||||
|
if OldACSoftcapRules then
|
||||||
|
if defender_class == Class.WIZARD or defender_class == Class.MAGICIAN or defender_class == Class.NECROMANCER or defender_class == Class.ENCHANTER then
|
||||||
|
softcap = ClothACSoftcap;
|
||||||
|
elseif defender_class == Class.MONK and weight <= monkweight then
|
||||||
|
softcap = MonkACSoftcap;
|
||||||
|
elseif defender_class == Class.DRUID or defender_class == Class.BEASTLORD or defender_class == Class.MONK then
|
||||||
|
softcap = LeatherACSoftcap;
|
||||||
|
elseif defender_class == Class.SHAMAN or defender_class == Class.ROGUE or defender_class == Class.BERSERKER or defender_class == Class.RANGER then
|
||||||
|
softcap = ChainACSoftcap;
|
||||||
|
else
|
||||||
|
softcap = PlateACSoftcap;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
softcap = softcap + shield_ac;
|
||||||
|
armor = armor + shield_ac;
|
||||||
|
|
||||||
|
if OldACSoftcapRules then
|
||||||
|
softcap = softcap + (softcap * (aa_mit * AAMitigationACFactor));
|
||||||
|
end
|
||||||
|
|
||||||
|
if armor > softcap then
|
||||||
|
local softcap_armor = armor - softcap;
|
||||||
|
if OldACSoftcapRules then
|
||||||
|
if defender_class == Class.WARRIOR then
|
||||||
|
softcap_armor = softcap_armor * WarriorACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.SHADOWKNIGHT or defender_class == Class.PALADIN or (defender_class == Class.MONK and weight <= monkweight) then
|
||||||
|
softcap_armor = softcap_armor * KnightACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.CLERIC or defender_class == Class.BARD or defender_class == Class.BERSERKER or defender_class == Class.ROGUE or defender_class == Class.SHAMAN or defender_class == Class.MONK then
|
||||||
|
softcap_armor = softcap_armor * LowPlateChainACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.RANGER or defender_class == Class.BEASTLORD then
|
||||||
|
softcap_armor = softcap_armor * LowChainLeatherACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.WIZARD or defender_class == Class.MAGICIAN or defender_class == Class.NECROMANCER or defender_class == Class.ENCHANTER or defender_class == Class.DRUID then
|
||||||
|
softcap_armor = softcap_armor * CasterACSoftcapReturn;
|
||||||
|
else
|
||||||
|
softcap_armor = softcap_armor * MiscACSoftcapReturn;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if defender_class == Class.WARRIOR then
|
||||||
|
softcap_armor = softcap_armor * WarACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.PALADIN or defender_class == Class.SHADOWKNIGHT then
|
||||||
|
softcap_armor = softcap_armor * PalShdACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.CLERIC or defender_class == Class.RANGER or defender_class == Class.MONK or defender_class == Class.BARD then
|
||||||
|
softcap_armor = softcap_armor * ClrRngMnkBrdACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.DRUID or defender_class == Class.NECROMANCER or defender_class == Class.WIZARD or defender_class == Class.ENCHANTER or defender_class == Class.MAGICIAN then
|
||||||
|
softcap_armor = softcap_armor * DruNecWizEncMagACSoftcapReturn;
|
||||||
|
elseif defender_class == Class.ROGUE or defender_class == Class.SHAMAN or defender_class == Class.BEASTLORD or defender_class == Class.BERSERKER then
|
||||||
|
softcap_armor = softcap_armor * RogShmBstBerACSoftcapReturn;
|
||||||
|
else
|
||||||
|
softcap_armor = softcap_armor * MiscACSoftcapReturn;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
armor = softcap + softcap_armor;
|
||||||
|
end
|
||||||
|
|
||||||
|
local mitigation_rating;
|
||||||
|
if defender_class == Class.WIZARD or defender_class == Class.MAGICIAN or defender_class == Class.NECROMANCER or defender_class == Class.ENCHANTER then
|
||||||
|
mitigation_rating = ((defender:GetSkill(Skill.Defense) + defender:GetItemBonuses():HeroicAGI() / 10) / 4.0) + armor + 1;
|
||||||
|
else
|
||||||
|
mitigation_rating = ((defender:GetSkill(Skill.Defense) + defender:GetItemBonuses():HeroicAGI() / 10) / 3.0) + (armor * 1.333333) + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
mitigation_rating = mitigation_rating * 0.847;
|
||||||
|
|
||||||
|
local attack_rating;
|
||||||
|
if attacker:IsClient() then
|
||||||
|
attack_rating = (attacker:CastToClient():CalcATK() + ((attacker:GetSTR() - 66) * 0.9) + (attacker:GetSkill(Skill.Offense)*1.345));
|
||||||
|
else
|
||||||
|
attack_rating = (attacker:GetATK() + (attacker:GetSkill(Skill.Offense)*1.345) + ((attacker:GetSTR() - 66) * 0.9));
|
||||||
|
end
|
||||||
|
|
||||||
|
hit.damage_done = GetMeleeMitDmg(defender, attacker, hit.damage_done, hit.min_damage, mitigation_rating, attack_rating);
|
||||||
|
|
||||||
|
if hit.damage_done < 0 then
|
||||||
|
hit.damage_done = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating)
|
||||||
|
if defender:IsClient() then
|
||||||
|
return ClientGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating);
|
||||||
|
else
|
||||||
|
return MobGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ClientGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating)
|
||||||
|
if (not attacker:IsNPC() or UseOldDamageIntervalRules) then
|
||||||
|
return MobGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating);
|
||||||
|
end
|
||||||
|
|
||||||
|
local d = 10;
|
||||||
|
local dmg_interval = (damage - min_damage) / 19.0;
|
||||||
|
local dmg_bonus = min_damage - dmg_interval;
|
||||||
|
local spellMeleeMit = (defender:GetSpellBonuses():MeleeMitigationEffect() + defender:GetItemBonuses():MeleeMitigationEffect() + defender:GetAABonuses():MeleeMitigationEffect()) / 100.0;
|
||||||
|
if (defender:GetClass() == Class.WARRIOR) then
|
||||||
|
spellMeleeMit = spellMeleeMit - 0.05;
|
||||||
|
end
|
||||||
|
|
||||||
|
dmg_bonus = dmg_bonus - (dmg_bonus * (defender:GetItemBonuses():MeleeMitigation() / 100.0));
|
||||||
|
dmg_interval = dmg_interval + (dmg_interval * spellMeleeMit);
|
||||||
|
|
||||||
|
local mit_roll = Random.Real(0, mitigation_rating);
|
||||||
|
local atk_roll = Random.Real(0, attack_rating);
|
||||||
|
|
||||||
|
if (atk_roll > mit_roll) then
|
||||||
|
local a_diff = atk_roll - mit_roll;
|
||||||
|
local thac0 = attack_rating * ACthac0Factor;
|
||||||
|
local thac0cap = attacker:GetLevel() * 9 + 20;
|
||||||
|
if (thac0 > thac0cap) then
|
||||||
|
thac0 = thac0cap;
|
||||||
|
end
|
||||||
|
|
||||||
|
d = d + (10 * (a_diff / thac0));
|
||||||
|
elseif (mit_roll > atk_roll) then
|
||||||
|
local m_diff = mit_roll - atk_roll;
|
||||||
|
local thac20 = mitigation_rating * ACthac20Factor;
|
||||||
|
local thac20cap = defender:GetLevel() * 9 + 20;
|
||||||
|
if (thac20 > thac20cap) then
|
||||||
|
thac20 = thac20cap;
|
||||||
|
end
|
||||||
|
|
||||||
|
d = d - (10 * (m_diff / thac20));
|
||||||
|
end
|
||||||
|
|
||||||
|
if (d < 1) then
|
||||||
|
d = 1;
|
||||||
|
elseif (d > 20) then
|
||||||
|
d = 20;
|
||||||
|
end
|
||||||
|
|
||||||
|
return math.floor(dmg_bonus + dmg_interval * d);
|
||||||
|
end
|
||||||
|
|
||||||
|
function MobGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_rating, attack_rating)
|
||||||
|
local d = 10.0;
|
||||||
|
local mit_roll = Random.Real(0, mitigation_rating);
|
||||||
|
local atk_roll = Random.Real(0, attack_rating);
|
||||||
|
|
||||||
|
if (atk_roll > mit_roll) then
|
||||||
|
local a_diff = atk_roll - mit_roll;
|
||||||
|
local thac0 = attack_rating * ACthac0Factor;
|
||||||
|
local thac0cap = attacker:GetLevel() * 9 + 20;
|
||||||
|
if (thac0 > thac0cap) then
|
||||||
|
thac0 = thac0cap;
|
||||||
|
end
|
||||||
|
|
||||||
|
d = d - (10.0 * (a_diff / thac0));
|
||||||
|
elseif (mit_roll > atk_roll) then
|
||||||
|
local m_diff = mit_roll - atk_roll;
|
||||||
|
local thac20 = mitigation_rating * ACthac20Factor;
|
||||||
|
local thac20cap = defender:GetLevel() * 9 + 20;
|
||||||
|
if (thac20 > thac20cap) then
|
||||||
|
thac20 = thac20cap;
|
||||||
|
end
|
||||||
|
|
||||||
|
d = d + (10.0 * (m_diff / thac20));
|
||||||
|
end
|
||||||
|
|
||||||
|
if (d < 0.0) then
|
||||||
|
d = 0.0;
|
||||||
|
elseif (d > 20.0) then
|
||||||
|
d = 20.0;
|
||||||
|
end
|
||||||
|
|
||||||
|
local interval = (damage - min_damage) / 20.0;
|
||||||
|
damage = damage - (math.floor(d) * interval);
|
||||||
|
damage = damage - (min_damage * defender:GetItemBonuses():MeleeMitigation() / 100);
|
||||||
|
damage = damage + (damage * (defender:GetSpellBonuses():MeleeMitigationEffect() + defender:GetItemBonuses():MeleeMitigationEffect() + defender:GetAABonuses():MeleeMitigationEffect()) / 100);
|
||||||
|
|
||||||
|
return damage;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetRawACNoShield(self)
|
||||||
|
self = self:CastToClient();
|
||||||
|
|
||||||
|
local ac = self:GetItemBonuses():AC() + self:GetSpellBonuses():AC() + self:GetAABonuses():AC();
|
||||||
|
local shield_ac = 0;
|
||||||
|
local inst = self:GetInventory():GetItem(Slot.Secondary);
|
||||||
|
|
||||||
|
if inst.valid then
|
||||||
|
if inst:GetItem():ItemType() == 8 then
|
||||||
|
shield_ac = inst:GetItem():AC();
|
||||||
|
|
||||||
|
for i = 1, 6 do
|
||||||
|
local augment = inst:GetAugment(i - 1);
|
||||||
|
if augment.valid then
|
||||||
|
shield_ac = shield_ac + augment:GetItem():AC();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ac = ac - shield_ac;
|
||||||
|
return ac, shield_ac;
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetDamageTable(attacker, skill)
|
||||||
|
if not attacker:IsClient() then
|
||||||
|
return 100;
|
||||||
|
end
|
||||||
|
|
||||||
|
if attacker:GetLevel() <= 51 then
|
||||||
|
local ret_table = 0;
|
||||||
|
local str_over_75 = 0;
|
||||||
|
if attacker:GetSTR() > 75 then
|
||||||
|
str_over_75 = attacker:GetSTR() - 75;
|
||||||
|
end
|
||||||
|
|
||||||
|
if str_over_75 > 255 then
|
||||||
|
ret_table = (attacker:GetSkill(skill) + 255) / 2;
|
||||||
|
else
|
||||||
|
ret_table = (attacker:GetSkill(skill) + str_over_75) / 2;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ret_table < 100 then
|
||||||
|
return 100;
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret_table;
|
||||||
|
elseif attacker:GetLevel() >= 90 then
|
||||||
|
if attacker:GetClass() == 7 then
|
||||||
|
return 379;
|
||||||
|
else
|
||||||
|
return 345;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local dmg_table = { 275, 275, 275, 275, 275, 280, 280, 280, 280, 285, 285, 285, 290, 290, 295, 295, 300, 300, 300, 305, 305, 305, 310, 310, 315, 315, 320, 320, 320, 325, 325, 325, 330, 330, 335, 335, 340, 340, 340 };
|
||||||
|
|
||||||
|
if attacker:GetClass() == 7 then
|
||||||
|
local monkDamageTableBonus = 20;
|
||||||
|
return (dmg_table[attacker:GetLevel() - 50] * (100 + monkDamageTableBonus) / 100);
|
||||||
|
else
|
||||||
|
return dmg_table[attacker:GetLevel() - 50];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 100;
|
||||||
|
end
|
||||||
|
|
||||||
|
function ApplyDamageTable(e)
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function CommonOutgoingHitSuccess(e)
|
||||||
|
e = ApplyMeleeDamageBonus(e);
|
||||||
|
e.hit.damage_done = e.hit.damage_done + (e.hit.damage_done * e.other:GetSkillDmgTaken(e.hit.skill) / 100) + (e.self:GetSkillDmgAmt(e.hit.skill) + e.other:GetFcDamageAmtIncoming(e.self, 0, true, e.hit.skill));
|
||||||
|
e = TryCriticalHit(e);
|
||||||
|
e.self:CheckNumHitsRemaining(5, -1, 65535);
|
||||||
|
e.IgnoreDefault = true;
|
||||||
|
return e;
|
||||||
|
end
|
||||||
|
|
||||||
|
function ApplyMeleeDamageBonus(e)
|
||||||
|
local dmgbonusmod = e.self:GetMeleeDamageMod_SE(e.hit.skill);
|
||||||
|
if (opts) then
|
||||||
|
dmgbonusmod = dmgbonusmod + e.opts.melee_damage_bonus_flat;
|
||||||
|
end
|
||||||
|
|
||||||
|
e.hit.damage_done = e.hit.damage_done + (e.hit.damage_done * dmgbonusmod / 100);
|
||||||
|
return e;
|
||||||
|
end
|
||||||
1
utils/mods/load_order.txt
Normal file
1
utils/mods/load_order.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
legacy_combat.lua
|
||||||
@ -196,6 +196,7 @@ OP_Consent=0x400e
|
|||||||
OP_ConsentDeny=0x34c1
|
OP_ConsentDeny=0x34c1
|
||||||
OP_AutoFire=0x314e
|
OP_AutoFire=0x314e
|
||||||
OP_PetCommands=0x0093
|
OP_PetCommands=0x0093
|
||||||
|
OP_PetCommandState=0x74ed
|
||||||
OP_PetHoTT=0x0df4
|
OP_PetHoTT=0x0df4
|
||||||
OP_DeleteSpell=0x305c
|
OP_DeleteSpell=0x305c
|
||||||
OP_Surname=0x1a87
|
OP_Surname=0x1a87
|
||||||
@ -671,3 +672,7 @@ OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
|||||||
OP_InitialHPUpdate=0x0000
|
OP_InitialHPUpdate=0x0000
|
||||||
|
|
||||||
OP_ItemRecastDelay=0x57ed
|
OP_ItemRecastDelay=0x57ed
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x1fa9
|
||||||
|
OP_RemoveTrap=0x6a4d
|
||||||
|
|||||||
@ -195,6 +195,7 @@ OP_Consent=0x1fd1
|
|||||||
OP_ConsentDeny=0x7a45
|
OP_ConsentDeny=0x7a45
|
||||||
OP_AutoFire=0x241e
|
OP_AutoFire=0x241e
|
||||||
OP_PetCommands=0x0159
|
OP_PetCommands=0x0159
|
||||||
|
OP_PetCommandState=0x1dc8
|
||||||
OP_PetHoTT=0x794a
|
OP_PetHoTT=0x794a
|
||||||
OP_DeleteSpell=0x3358
|
OP_DeleteSpell=0x3358
|
||||||
OP_Surname=0x0423
|
OP_Surname=0x0423
|
||||||
@ -674,3 +675,7 @@ OP_RAWOutOfSession=0x0000
|
|||||||
# we need to document the differences between these packets to make identifying them easier
|
# we need to document the differences between these packets to make identifying them easier
|
||||||
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||||
OP_InitialHPUpdate=0x0000
|
OP_InitialHPUpdate=0x0000
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x1456
|
||||||
|
OP_RemoveTrap=0x71da
|
||||||
|
|||||||
@ -669,3 +669,7 @@ OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
|||||||
OP_InitialHPUpdate=0x0000 #
|
OP_InitialHPUpdate=0x0000 #
|
||||||
|
|
||||||
OP_ItemRecastDelay=0x15c4
|
OP_ItemRecastDelay=0x15c4
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x169a
|
||||||
|
OP_RemoveTrap=0x4bb6
|
||||||
|
|||||||
@ -658,3 +658,7 @@ OP_ItemRecastDelay=0x0ada
|
|||||||
#OP_NpcMoveUpdate=0x0d11 #SEQ 10/07/08 --NEW FROM SEQ
|
#OP_NpcMoveUpdate=0x0d11 #SEQ 10/07/08 --NEW FROM SEQ
|
||||||
#OP_Zone_MissingName01=0x0000 #
|
#OP_Zone_MissingName01=0x0000 #
|
||||||
#new titles avaliable: #
|
#new titles avaliable: #
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x62a9
|
||||||
|
OP_RemoveTrap=0x7bd9
|
||||||
|
|||||||
@ -198,6 +198,7 @@ OP_Consent=0x6bb9 # C
|
|||||||
OP_ConsentDeny=0x4cd1 # C
|
OP_ConsentDeny=0x4cd1 # C
|
||||||
OP_AutoFire=0x5db5 # C
|
OP_AutoFire=0x5db5 # C
|
||||||
OP_PetCommands=0x7706 # C
|
OP_PetCommands=0x7706 # C
|
||||||
|
OP_PetCommandState=0x1a79
|
||||||
OP_PetHoTT=0x2528
|
OP_PetHoTT=0x2528
|
||||||
OP_DeleteSpell=0x0698 # C
|
OP_DeleteSpell=0x0698 # C
|
||||||
OP_Surname=0x44ae # C
|
OP_Surname=0x44ae # C
|
||||||
@ -684,3 +685,7 @@ OP_ItemRecastDelay=0x82d7
|
|||||||
|
|
||||||
# unhandled
|
# unhandled
|
||||||
OP_ShieldGroup=0x23a1
|
OP_ShieldGroup=0x23a1
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x2480
|
||||||
|
OP_RemoveTrap=0x0115
|
||||||
|
|||||||
@ -49,6 +49,7 @@ if(-e "eqemu_server_skip_update.txt"){
|
|||||||
|
|
||||||
#::: Check for script self update
|
#::: Check for script self update
|
||||||
do_self_update_check_routine() if !$skip_self_update_check;
|
do_self_update_check_routine() if !$skip_self_update_check;
|
||||||
|
get_windows_wget();
|
||||||
get_perl_version();
|
get_perl_version();
|
||||||
read_eqemu_config_xml();
|
read_eqemu_config_xml();
|
||||||
get_mysql_path();
|
get_mysql_path();
|
||||||
@ -200,7 +201,7 @@ sub new_server {
|
|||||||
}
|
}
|
||||||
closedir(DIR);
|
closedir(DIR);
|
||||||
|
|
||||||
if($file_count > 1 && (!-e "install_variables.txt" && !-e "../install_variables.txt")){
|
if($file_count > 4 && (!-e "install_variables.txt" && !-e "../install_variables.txt")){
|
||||||
print "[New Server] ERROR: You must run eqemu_server.pl in an empty directory\n";
|
print "[New Server] ERROR: You must run eqemu_server.pl in an empty directory\n";
|
||||||
<>;
|
<>;
|
||||||
exit;
|
exit;
|
||||||
@ -280,6 +281,8 @@ sub new_server {
|
|||||||
|
|
||||||
show_install_summary_info();
|
show_install_summary_info();
|
||||||
|
|
||||||
|
rmtree('updates_staged');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -517,6 +520,13 @@ sub get_perl_version {
|
|||||||
no warnings;
|
no warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_windows_wget {
|
||||||
|
if(!-e "wget.exe" && $OS eq "Windows"){
|
||||||
|
eval "use LWP::Simple qw(getstore);";
|
||||||
|
getstore("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/wget.exe", "wget.exe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub do_self_update_check_routine {
|
sub do_self_update_check_routine {
|
||||||
|
|
||||||
#::: Check for internet connection before updating
|
#::: Check for internet connection before updating
|
||||||
@ -524,7 +534,7 @@ sub do_self_update_check_routine {
|
|||||||
print "[Update] Cannot check update without internet connection...\n";
|
print "[Update] Cannot check update without internet connection...\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#::: Check for script changes :: eqemu_server.pl
|
#::: Check for script changes :: eqemu_server.pl
|
||||||
get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
|
get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
|
||||||
|
|
||||||
@ -997,68 +1007,14 @@ sub get_remote_file{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($OS eq "Windows"){
|
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
|
||||||
#::: For non-text type requests...
|
$wget = `wget -N --no-check-certificate --quiet -O $destination_file $request_url`;
|
||||||
if($content_type == 1){
|
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
||||||
$break = 0;
|
if($wget=~/unable to resolve/i){
|
||||||
while($break == 0) {
|
print "Error, no connection or failed request...\n\n";
|
||||||
eval "use LWP::Simple qw(getstore);";
|
#die;
|
||||||
# use LWP::Simple qw(getstore);
|
|
||||||
# print "request is " . $request_url . "\n";
|
|
||||||
# print "destination file is supposed to be " . $destination_file . "\n";
|
|
||||||
if(!getstore($request_url, $destination_file)){
|
|
||||||
print "[Download] Error, no connection or failed request...\n\n";
|
|
||||||
}
|
|
||||||
# sleep(1);
|
|
||||||
#::: Make sure the file exists before continuing...
|
|
||||||
if(-e $destination_file) {
|
|
||||||
$break = 1;
|
|
||||||
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
|
||||||
} else { $break = 0; }
|
|
||||||
usleep(500);
|
|
||||||
|
|
||||||
if($no_retry){
|
|
||||||
$break = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$break = 0;
|
|
||||||
while($break == 0) {
|
|
||||||
require LWP::UserAgent;
|
|
||||||
my $ua = LWP::UserAgent->new;
|
|
||||||
$ua->timeout(10);
|
|
||||||
$ua->env_proxy;
|
|
||||||
my $response = $ua->get($request_url);
|
|
||||||
if ($response->is_success){
|
|
||||||
open (FILE, '> ' . $destination_file . '');
|
|
||||||
print FILE $response->decoded_content;
|
|
||||||
close (FILE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "[Download] Error, no connection or failed request...\n\n";
|
|
||||||
}
|
|
||||||
if(-e $destination_file) {
|
|
||||||
$break = 1;
|
|
||||||
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
|
||||||
} else { $break = 0; }
|
|
||||||
usleep(500);
|
|
||||||
|
|
||||||
if($no_retry){
|
|
||||||
$break = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($OS eq "Linux"){
|
|
||||||
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
|
|
||||||
$wget = `wget --no-check-certificate --quiet -O $destination_file $request_url`;
|
|
||||||
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
|
||||||
if($wget=~/unable to resolve/i){
|
|
||||||
print "Error, no connection or failed request...\n\n";
|
|
||||||
#die;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#::: Trim Whitespaces
|
#::: Trim Whitespaces
|
||||||
@ -1498,7 +1454,7 @@ sub map_files_fetch_bulk{
|
|||||||
get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
|
get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
|
||||||
unzip('maps/maps.zip', 'maps/');
|
unzip('maps/maps.zip', 'maps/');
|
||||||
my @files;
|
my @files;
|
||||||
my $start_dir = "maps/EQEmuMaps-master/maps";
|
my $start_dir = "maps/EQEmuMaps-master/";
|
||||||
find(
|
find(
|
||||||
sub { push @files, $File::Find::name unless -d; },
|
sub { push @files, $File::Find::name unless -d; },
|
||||||
$start_dir
|
$start_dir
|
||||||
@ -1551,12 +1507,12 @@ sub map_files_fetch{
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub quest_files_fetch{
|
sub quest_files_fetch{
|
||||||
if (!-e "updates_staged/Quests-Plugins-master/quests/") {
|
if (!-e "updates_staged/projecteqquests-master/") {
|
||||||
print "[Update] Fetching Latest Quests --- \n";
|
print "[Update] Fetching Latest Quests --- \n";
|
||||||
get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
|
get_remote_file("https://codeload.github.com/ProjectEQ/projecteqquests/zip/master", "updates_staged/projecteqquests-master.zip", 1);
|
||||||
print "[Install] Fetched latest quests...\n";
|
print "[Install] Fetched latest quests...\n";
|
||||||
mkdir('updates_staged');
|
mkdir('updates_staged');
|
||||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fc = 0;
|
$fc = 0;
|
||||||
@ -1564,7 +1520,7 @@ sub quest_files_fetch{
|
|||||||
use File::Compare;
|
use File::Compare;
|
||||||
|
|
||||||
my @files;
|
my @files;
|
||||||
my $start_dir = "updates_staged/Quests-Plugins-master/quests/";
|
my $start_dir = "updates_staged/projecteqquests-master/";
|
||||||
find(
|
find(
|
||||||
sub { push @files, $File::Find::name unless -d; },
|
sub { push @files, $File::Find::name unless -d; },
|
||||||
$start_dir
|
$start_dir
|
||||||
@ -1573,7 +1529,7 @@ sub quest_files_fetch{
|
|||||||
if($file=~/\.pl|\.lua|\.ext/i){
|
if($file=~/\.pl|\.lua|\.ext/i){
|
||||||
$staged_file = $file;
|
$staged_file = $file;
|
||||||
$destination_file = $file;
|
$destination_file = $file;
|
||||||
$destination_file =~s/updates_staged\/Quests-Plugins-master\///g;
|
$destination_file =~s/updates_staged\/projecteqquests-master\//quests\//g;
|
||||||
|
|
||||||
if (!-e $destination_file) {
|
if (!-e $destination_file) {
|
||||||
copy_file($staged_file, $destination_file);
|
copy_file($staged_file, $destination_file);
|
||||||
@ -1603,27 +1559,28 @@ sub quest_files_fetch{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rmtree('updates_staged');
|
|
||||||
|
|
||||||
if($fc == 0){
|
if($fc == 0){
|
||||||
print "[Update] No Quest Updates found... \n\n";
|
print "[Update] No Quest Updates found... \n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub lua_modules_fetch {
|
sub lua_modules_fetch {
|
||||||
if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") {
|
if (!-e "updates_staged/projecteqquests-master/") {
|
||||||
print "[Update] Fetching Latest LUA Modules --- \n";
|
print "[Update] Fetching Latest lua modules --- \n";
|
||||||
get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
|
get_remote_file("https://codeload.github.com/ProjectEQ/projecteqquests/zip/master", "updates_staged/projecteqquests-master.zip", 1);
|
||||||
print "[Update] Fetched latest LUA Modules...\n";
|
print "[Install] Fetched latest lua modules...\n";
|
||||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
mkdir('updates_staged');
|
||||||
|
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fc = 0;
|
$fc = 0;
|
||||||
use File::Find;
|
use File::Find;
|
||||||
use File::Compare;
|
use File::Compare;
|
||||||
|
|
||||||
|
mkdir('lua_modules');
|
||||||
|
|
||||||
my @files;
|
my @files;
|
||||||
my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/";
|
my $start_dir = "updates_staged/projecteqquests-master/lua_modules/";
|
||||||
find(
|
find(
|
||||||
sub { push @files, $File::Find::name unless -d; },
|
sub { push @files, $File::Find::name unless -d; },
|
||||||
$start_dir
|
$start_dir
|
||||||
@ -1632,7 +1589,7 @@ sub lua_modules_fetch {
|
|||||||
if($file=~/\.pl|\.lua|\.ext/i){
|
if($file=~/\.pl|\.lua|\.ext/i){
|
||||||
$staged_file = $file;
|
$staged_file = $file;
|
||||||
$destination_file = $file;
|
$destination_file = $file;
|
||||||
$destination_file =~s/updates_staged\/Quests-Plugins-master\/quests\///g;
|
$destination_file =~s/updates_staged\/projecteqquests-master\/lua_modules\//lua_modules\//g;
|
||||||
|
|
||||||
if (!-e $destination_file) {
|
if (!-e $destination_file) {
|
||||||
copy_file($staged_file, $destination_file);
|
copy_file($staged_file, $destination_file);
|
||||||
@ -1667,19 +1624,22 @@ sub lua_modules_fetch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub plugins_fetch{
|
sub plugins_fetch{
|
||||||
if (!-e "updates_staged/Quests-Plugins-master/plugins/") {
|
if (!-e "updates_staged/projecteqquests-master/") {
|
||||||
print "[Update] Fetching Latest Plugins\n";
|
print "[Update] Fetching Latest plugins --- \n";
|
||||||
get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
|
get_remote_file("https://codeload.github.com/ProjectEQ/projecteqquests/zip/master", "updates_staged/projecteqquests-master.zip", 1);
|
||||||
print "[Update] Fetched latest plugins\n";
|
print "[Install] Fetched latest plugins...\n";
|
||||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
mkdir('updates_staged');
|
||||||
|
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$fc = 0;
|
$fc = 0;
|
||||||
use File::Find;
|
use File::Find;
|
||||||
use File::Compare;
|
use File::Compare;
|
||||||
|
|
||||||
|
mkdir('plugins');
|
||||||
|
|
||||||
my @files;
|
my @files;
|
||||||
my $start_dir = "updates_staged/Quests-Plugins-master/plugins/";
|
my $start_dir = "updates_staged/projecteqquests-master/plugins/";
|
||||||
find(
|
find(
|
||||||
sub { push @files, $File::Find::name unless -d; },
|
sub { push @files, $File::Find::name unless -d; },
|
||||||
$start_dir
|
$start_dir
|
||||||
@ -1688,7 +1648,7 @@ sub plugins_fetch{
|
|||||||
if($file=~/\.pl|\.lua|\.ext/i){
|
if($file=~/\.pl|\.lua|\.ext/i){
|
||||||
$staged_file = $file;
|
$staged_file = $file;
|
||||||
$destination_file = $file;
|
$destination_file = $file;
|
||||||
$destination_file =~s/updates_staged\/Quests-Plugins-master\///g;
|
$destination_file =~s/updates_staged\/projecteqquests-master\///g;
|
||||||
|
|
||||||
if (!-e $destination_file) {
|
if (!-e $destination_file) {
|
||||||
copy_file($staged_file, $destination_file);
|
copy_file($staged_file, $destination_file);
|
||||||
@ -2220,3 +2180,4 @@ sub generate_random_password {
|
|||||||
|
|
||||||
return $randpassword;
|
return $randpassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -114,9 +114,24 @@ if [[ "$OS" == "Debian" ]]; then
|
|||||||
apt-get $apt_options install open-vm-tools
|
apt-get $apt_options install open-vm-tools
|
||||||
apt-get $apt_options install unzip
|
apt-get $apt_options install unzip
|
||||||
apt-get $apt_options install uuid-dev
|
apt-get $apt_options install uuid-dev
|
||||||
|
apt-get $apt_options install wget
|
||||||
apt-get $apt_options install zlib-bin
|
apt-get $apt_options install zlib-bin
|
||||||
apt-get $apt_options install zlibc
|
apt-get $apt_options install zlibc
|
||||||
|
apt-get $apt_options install libsodium-dev
|
||||||
|
apt-get $apt_options install libsodium18
|
||||||
|
|
||||||
|
# If libsodium18 isn't installed (Debian), let's download both that and the dev package and install them.
|
||||||
|
if dpkg-query -s "libsodium18" 1>/dev/null 2>&1; then
|
||||||
|
echo "Sodium library already installed."
|
||||||
|
else
|
||||||
|
wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium-dev_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium-dev.deb
|
||||||
|
wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium18_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium18.deb
|
||||||
|
dpkg -i /home/eqemu/libsodium*.deb
|
||||||
|
# Cleanup after ourselves
|
||||||
|
rm -f /home/eqemu/libsodium-dev.deb
|
||||||
|
rm -f /home/eqemu/libsodium18.deb
|
||||||
|
fi
|
||||||
|
|
||||||
#::: Install FTP for remote FTP access
|
#::: Install FTP for remote FTP access
|
||||||
echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections
|
echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections
|
||||||
apt-get -y -q install proftpd
|
apt-get -y -q install proftpd
|
||||||
@ -149,8 +164,35 @@ EOF
|
|||||||
|
|
||||||
elif [[ "$OS" == "fedora_core" ]]; then
|
elif [[ "$OS" == "fedora_core" ]]; then
|
||||||
# Do Fedora stuff
|
# Do Fedora stuff
|
||||||
dnf -y install open-vm-tools vim cmake boost-devel zlib-devel mariadb-server mariadb-devel mariadb-libs perl perl-DBD-MySQL perl-IO-stringy perl-devel lua-devel lua-sql-mysql dos2unix php-mysql proftpd wget compat-lua-libs compat-lua-devel compat-lua perl-Time-HiRes
|
dnf -y install open-vm-tools
|
||||||
dnf -y groupinstall "Development Tools" "Basic Web Server" "C Development Tools and Libraries"
|
dnf -y install vim
|
||||||
|
dnf -y install cmake
|
||||||
|
dnf -y install boost-devel
|
||||||
|
dnf -y install zlib-devel
|
||||||
|
dnf -y install mariadb-server
|
||||||
|
dnf -y install mariadb-devel
|
||||||
|
dnf -y install mariadb-libs
|
||||||
|
dnf -y install perl
|
||||||
|
dnf -y install perl-DBD-MySQL
|
||||||
|
dnf -y install perl-IO-stringy
|
||||||
|
dnf -y install perl-devel
|
||||||
|
dnf -y install lua-devel
|
||||||
|
dnf -y install lua-sql-mysql
|
||||||
|
dnf -y install dos2unix
|
||||||
|
dnf -y install php-mysql
|
||||||
|
dnf -y install php-mysqlnd
|
||||||
|
dnf -y install proftpd
|
||||||
|
dnf -y install wget
|
||||||
|
dnf -y install compat-lua-libs
|
||||||
|
dnf -y install compat-lua-devel
|
||||||
|
dnf -y install compat-lua
|
||||||
|
dnf -y install perl-Time-HiRes
|
||||||
|
dnf -y install libuuid-devel
|
||||||
|
dnf -y install libsodium
|
||||||
|
dnf -y install libsodium-devel
|
||||||
|
dnf -y groupinstall "Development Tools"
|
||||||
|
dnf -y groupinstall "Basic Web Server"
|
||||||
|
dnf -y groupinstall "C Development Tools and Libraries"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$OS" == "fedora_core" ]] || [[ "$OS" == "red_hat" ]]; then
|
if [[ "$OS" == "fedora_core" ]] || [[ "$OS" == "red_hat" ]]; then
|
||||||
|
|||||||
@ -364,6 +364,10 @@
|
|||||||
9108|2017_04_07_ignore_despawn.sql|SHOW COLUMNS FROM `npc_types` LIKE 'ignore_despawn'|empty|
|
9108|2017_04_07_ignore_despawn.sql|SHOW COLUMNS FROM `npc_types` LIKE 'ignore_despawn'|empty|
|
||||||
9109|2017_04_08_doors_disable_timer.sql|SHOW COLUMNS FROM `doors` LIKE 'disable_timer'|empty|
|
9109|2017_04_08_doors_disable_timer.sql|SHOW COLUMNS FROM `doors` LIKE 'disable_timer'|empty|
|
||||||
9110|2017_04_10_graveyard.sql|show index from graveyard WHERE key_name = 'zone_id_nonunique'|empty|
|
9110|2017_04_10_graveyard.sql|show index from graveyard WHERE key_name = 'zone_id_nonunique'|empty|
|
||||||
|
9111|2017_06_24_saylink_index.sql|SHOW INDEX FROM `saylink` WHERE `key_name` = 'phrase_index'|empty|
|
||||||
|
9112|2017_06_24_rule_values_expand.sql|SHOW COLUMNS FROM rule_values WHERE Field = 'rule_value' and Type = 'varchar(30)'|empty|
|
||||||
|
9113|2017_07_19_show_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'show_name'|empty|
|
||||||
|
9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
2
utils/sql/git/required/2017_06_24_rule_values_expand.sql
Normal file
2
utils/sql/git/required/2017_06_24_rule_values_expand.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `rule_values`
|
||||||
|
MODIFY COLUMN `rule_value` varchar(30) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `rule_name`;
|
||||||
2
utils/sql/git/required/2017_06_24_saylink_index.sql
Normal file
2
utils/sql/git/required/2017_06_24_saylink_index.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `saylink`
|
||||||
|
ADD INDEX `phrase_index` (`phrase`) USING BTREE ;
|
||||||
3
utils/sql/git/required/2017_07_19_show_name.sql
Normal file
3
utils/sql/git/required/2017_07_19_show_name.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE `npc_types` ADD COLUMN `show_name` TINYINT(2) NOT NULL DEFAULT 1;
|
||||||
|
ALTER TABLE `npc_types` ADD COLUMN `untargetable` TINYINT(2) NOT NULL DEFAULT 0;
|
||||||
|
UPDATE `npc_types` SET `show_name` = 0, `untargetable` = 1 WHERE `bodytype` >= 66;
|
||||||
127
utils/sql/git/required/2017_07_22_aura.sql
Normal file
127
utils/sql/git/required/2017_07_22_aura.sql
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
CREATE TABLE `auras` (
|
||||||
|
`type` INT(10) NOT NULL,
|
||||||
|
`npc_type` INT(10) NOT NULL,
|
||||||
|
`name` VARCHAR(64) NOT NULL,
|
||||||
|
`spell_id` INT(10) NOT NULL,
|
||||||
|
`distance` INT(10) NOT NULL DEFAULT 60,
|
||||||
|
`aura_type` INT(10) NOT NULL DEFAULT 1,
|
||||||
|
`spawn_type` INT(10) NOT NULL DEFAULT 0,
|
||||||
|
`movement` INT(10) NOT NULL DEFAULT 0,
|
||||||
|
`duration` INT(10) NOT NULL DEFAULT 5400,
|
||||||
|
`icon` INT(10) NOT NULL DEFAULT -1,
|
||||||
|
`cast_time` INT(10) NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY(`type`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `character_auras` (
|
||||||
|
`id` INT(10) NOT NULL,
|
||||||
|
`slot` TINYINT(10) NOT NULL,
|
||||||
|
`spell_id` INT(10) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`, `slot`)
|
||||||
|
);
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOAuraOfTheMuse55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8926, npc_type=@suggestedid, name="Aura_of_Insight", spell_id=8939, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=99, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOAuraOfTheMuse", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8488, npc_type=@suggestedid, name="Aura_of_the_Muse", spell_id=8489, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOChampionsAura55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8921, npc_type=@suggestedid, name="Myrmidon's_Aura", spell_id=8935, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOChampionsAura", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8468, npc_type=@suggestedid, name="Champion's_Aura", spell_id=8469, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOBlessedAura55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8925, npc_type=@suggestedid, name="Holy_Aura", spell_id=8938, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOBlessedAura", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8481, npc_type=@suggestedid, name="Blessed_Aura", spell_id=8482, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOMastersAura55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8923, npc_type=@suggestedid, name="Disciples_Aura", spell_id=8937, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOMastersAura", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8474, npc_type=@suggestedid, name="Master's_Aura", spell_id=8475, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOQuicksandTrap55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8933, npc_type=@suggestedid, name="Earthen_Strength", spell_id=8948, distance=60, aura_type=2, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOQuicksandTrap", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8518, npc_type=@suggestedid, name="Rathe's_Strength", spell_id=8519, distance=60, aura_type=2, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOIllusionistsAura55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8931, npc_type=@suggestedid, name="Beguiler's_Aura", spell_id=8946, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOIllusionistsAura", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8509, npc_type=@suggestedid, name="Illusionist's_Aura", spell_id=8510, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOLivingVineTrap55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8929, npc_type=@suggestedid, name="Aura_of_the_Grove", spell_id=8943, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=1, cast_time=12;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOLivingVineTrap", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8499, npc_type=@suggestedid, name="Aura_of_Life", spell_id=8500, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=1, cast_time=12;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOAuraOfThePious55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8928, npc_type=@suggestedid, name="Aura_of_the_Zealot", spell_id=8940, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOAuraOfThePious", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8495, npc_type=@suggestedid, name="Aura_of_the_Pious", spell_id=8496, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOBloodlustAura55", lastname="", level="55", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8924, npc_type=@suggestedid, name="Aura_of_Rage", spell_id=8959, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOBloodlustAura", lastname="", level="70", race="127", class="62", bodytype="11", hp="4027.6216", mana="0.0000", gender="0", texture="0", helmtexture="0", herosforgemodel="0", size="2", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8477, npc_type=@suggestedid, name="Bloodlust_Aura", spell_id=8478, distance=60, aura_type=1, spawn_type=0, movement=0, duration=5400, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOIdolOfMalaTrap55", lastname="", level="55", race="514", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="2.5", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8930, npc_type=@suggestedid, name="Soul_Idol", spell_id=8945, distance=60, aura_type=3, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=12;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOIdolOfMalaTrap", lastname="", level="70", race="514", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="2.5", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8504, npc_type=@suggestedid, name="Spirit_Idol", spell_id=8505, distance=60, aura_type=3, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=12;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IODeathRuneTrap55", lastname="", level="55", race="510", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8934, npc_type=@suggestedid, name="a_dark_rune", spell_id=8949, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IODeathRuneTrap", lastname="", level="70", race="510", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8523, npc_type=@suggestedid, name="a_death_rune", spell_id=8524, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOFireRuneTrap55", lastname="", level="55", race="510", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8932, npc_type=@suggestedid, name="a_fiery_rune", spell_id=8947, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOFireRuneTrap", lastname="", level="70", race="510", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8513, npc_type=@suggestedid, name="a_fire_rune", spell_id=8514, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOPoisonSpikesTrap55", lastname="", level="55", race="513", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8922, npc_type=@suggestedid, name="poison_spurs", spell_id=8936, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
|
||||||
|
SELECT IFNULL((MAX(id) + 1), 2000000) INTO @suggestedid FROM npc_types where id LIKE '2000___';
|
||||||
|
INSERT INTO npc_types SET id=@suggestedid, name="IOPoisonSpikesTrap", lastname="", level="70", race="513", class="62", bodytype="5", hp="4027.6216", mana="0.0000", gender="2", texture="0", helmtexture="0", herosforgemodel="0", size="3", hp_regen_rate="0", mana_regen_rate="0", loottable_id="0", npc_spells_id="0", mindmg="52.7514", maxdmg="166.8270", attack_count="-1", special_abilities="12,1^13,1^14,1^15,1^16,1^17,1^18,1^19,1^20,1^21,1^22,1^23,1^24,1^25,1^28,1^31,1^35,1^", aggroradius="70", assistradius="0", face="0", luclin_hairstyle="0", luclin_haircolor="0", luclin_eyecolor="0", luclin_eyecolor2="0", luclin_beardcolor="0", luclin_beard="0", drakkin_heritage="0", drakkin_tattoo="0", drakkin_details="0", armortint_red="0", armortint_green="0", armortint_blue="0", d_melee_texture1="0", d_melee_texture2="0", prim_melee_type="28", sec_melee_type="28", runspeed="1.25", MR="21.1027", CR="21.1027", DR="21.1027", FR="21.1027", PR="21.1027", Corrup="21.1027", PhR="48.3333", see_invis="0", see_invis_undead="0", qglobal="0", AC="257.3784", npc_aggro="0", spawn_limit="0", attack_delay="29.4486", findable="0", STR="205.0000", STA="205.0000", DEX="205.0000", AGI="205.0000", _INT="205.0000", WIS="205.0000", CHA="205.0000", see_hide="0", see_improved_hide="0", trackable="0", ATK="0", Accuracy="0", Avoidance="0", slow_mitigation="0", version="0", maxlevel="0", scalerate="100", private_corpse="0", unique_spawn_by_name="0", underwater="0", emoteid="0", spellscale="100", healscale="100", no_target_hotkey="0", raid_target="0", light="0", ignore_despawn="0", show_name="0";
|
||||||
|
INSERT INTO auras SET type=8471, npc_type=@suggestedid, name="Poison Spikes", spell_id=8472, distance=25, aura_type=4, spawn_type=1, movement=1, duration=120, icon=-1, cast_time=-1;
|
||||||
|
UPDATE npc_types SET special_abilities = TRIM(TRAILING '^' FROM special_abilities);
|
||||||
|
|
||||||
@ -449,17 +449,36 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cle->SetOnline();
|
|
||||||
|
|
||||||
if(minilogin){
|
if(minilogin){
|
||||||
|
cle->SetOnline();
|
||||||
WorldConfig::DisableStats();
|
WorldConfig::DisableStats();
|
||||||
Log(Logs::General, Logs::World_Server, "MiniLogin Account #%d",cle->AccountID());
|
Log(Logs::General, Logs::World_Server, "MiniLogin Account #%d",cle->AccountID());
|
||||||
}
|
}
|
||||||
else {
|
else if (!is_player_zoning) {
|
||||||
if (!is_player_zoning) {
|
// Track who is in and who is out of the game
|
||||||
Log(Logs::General, Logs::World_Server,
|
char *inout= (char *) "";
|
||||||
"Account (%s) Logging in :: LSID: %d ", cle->AccountName(), cle->LSID());
|
|
||||||
|
if (cle->GetOnline() == CLE_Status_Never){
|
||||||
|
// Desktop -> Char Select
|
||||||
|
inout = (char *) "In";
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Game -> Char Select
|
||||||
|
inout=(char *) "Out";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always at Char select at this point.
|
||||||
|
// Either from a fresh client launch or coming back from the game.
|
||||||
|
// Exiting the game entirely does not come through here.
|
||||||
|
// Could use a Logging Out Completely message somewhere.
|
||||||
|
cle->SetOnline(CLE_Status_CharSelect);
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::World_Server,
|
||||||
|
"Account (%s) Logging(%s) to character select :: LSID: %d ",
|
||||||
|
cle->AccountName(), inout, cle->LSID());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cle->SetOnline();
|
||||||
}
|
}
|
||||||
|
|
||||||
const WorldConfig *Config=WorldConfig::get();
|
const WorldConfig *Config=WorldConfig::get();
|
||||||
@ -1021,6 +1040,7 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
|||||||
}
|
}
|
||||||
case OP_WorldLogout:
|
case OP_WorldLogout:
|
||||||
{
|
{
|
||||||
|
// I don't see this getting executed on logout
|
||||||
eqs->Close();
|
eqs->Close();
|
||||||
cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction.
|
cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction.
|
||||||
return false;
|
return false;
|
||||||
@ -1261,6 +1281,10 @@ void Client::Clearance(int8 response)
|
|||||||
} else {
|
} else {
|
||||||
zs_addr = zs->GetIP().c_str();
|
zs_addr = zs->GetIP().c_str();
|
||||||
|
|
||||||
|
if (!zs_addr[0]) {
|
||||||
|
zs_addr = WorldConfig::get()->LocalAddress.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
if(strcmp(zs_addr, "127.0.0.1") == 0)
|
if(strcmp(zs_addr, "127.0.0.1") == 0)
|
||||||
{
|
{
|
||||||
Log(Logs::Detail, Logs::World_Server, "Local zone address was %s, setting local address to: %s", zs_addr, WorldConfig::get()->LocalAddress.c_str());
|
Log(Logs::Detail, Logs::World_Server, "Local zone address was %s, setting local address to: %s", zs_addr, WorldConfig::get()->LocalAddress.c_str());
|
||||||
|
|||||||
@ -50,6 +50,7 @@ public:
|
|||||||
inline const char* LSName() const { return plsname; }
|
inline const char* LSName() const { return plsname; }
|
||||||
inline int16 WorldAdmin() const { return pworldadmin; }
|
inline int16 WorldAdmin() const { return pworldadmin; }
|
||||||
inline const char* GetLSKey() const { return plskey; }
|
inline const char* GetLSKey() const { return plskey; }
|
||||||
|
inline const int8 GetOnline() const { return pOnline; }
|
||||||
|
|
||||||
// Account stuff
|
// Account stuff
|
||||||
inline uint32 AccountID() const { return paccountid; }
|
inline uint32 AccountID() const { return paccountid; }
|
||||||
|
|||||||
@ -332,6 +332,8 @@ int main(int argc, char** argv) {
|
|||||||
database.ClearMerchantTemp();
|
database.ClearMerchantTemp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuleManager::Instance()->SaveRules(&database);
|
||||||
|
|
||||||
Log(Logs::General, Logs::World_Server, "Loading EQ time of day..");
|
Log(Logs::General, Logs::World_Server, "Loading EQ time of day..");
|
||||||
TimeOfDay_Struct eqTime;
|
TimeOfDay_Struct eqTime;
|
||||||
time_t realtime;
|
time_t realtime;
|
||||||
@ -392,12 +394,12 @@ int main(int argc, char** argv) {
|
|||||||
server_connection->Listen(server_opts);
|
server_connection->Listen(server_opts);
|
||||||
Log(Logs::General, Logs::World_Server, "Server (TCP) listener started.");
|
Log(Logs::General, Logs::World_Server, "Server (TCP) listener started.");
|
||||||
|
|
||||||
server_connection->OnConnectionIdentified("Zone", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
server_connection->OnConnectionIdentified("Zone", [&console](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||||
LogF(Logs::General, Logs::World_Server, "New Zone Server connection from {2} at {0}:{1}",
|
LogF(Logs::General, Logs::World_Server, "New Zone Server connection from {2} at {0}:{1}",
|
||||||
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
|
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
|
||||||
|
|
||||||
numzones++;
|
numzones++;
|
||||||
zoneserver_list.Add(new ZoneServer(connection));
|
zoneserver_list.Add(new ZoneServer(connection, console.get()));
|
||||||
});
|
});
|
||||||
|
|
||||||
server_connection->OnConnectionRemoved("Zone", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
server_connection->OnConnectionRemoved("Zone", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ extern UCSConnection UCSLink;
|
|||||||
extern QueryServConnection QSLink;
|
extern QueryServConnection QSLink;
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
|
|
||||||
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
|
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
|
||||||
: tcpc(connection), zone_boot_timer(5000) {
|
: tcpc(connection), zone_boot_timer(5000) {
|
||||||
|
|
||||||
/* Set Process tracking variable defaults */
|
/* Set Process tracking variable defaults */
|
||||||
@ -73,6 +73,8 @@ ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> conn
|
|||||||
zone_boot_timer.Disable();
|
zone_boot_timer.Disable();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this->console = console;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneServer::~ZoneServer() {
|
ZoneServer::~ZoneServer() {
|
||||||
@ -412,6 +414,27 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (scm->chan_num == 7 || scm->chan_num == 14) {
|
if (scm->chan_num == 7 || scm->chan_num == 14) {
|
||||||
|
if (scm->deliverto[0] == '*') {
|
||||||
|
|
||||||
|
if (console) {
|
||||||
|
auto con = console->FindByAccountName(&scm->deliverto[1]);
|
||||||
|
if (((!con) || (!con->SendChannelMessage(scm, [&scm]() {
|
||||||
|
auto pack = new ServerPacket(ServerOP_ChannelMessage,
|
||||||
|
sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1);
|
||||||
|
memcpy(pack->pBuffer, scm, pack->size);
|
||||||
|
ServerChannelMessage_Struct* scm2 = (ServerChannelMessage_Struct*)pack->pBuffer;
|
||||||
|
strcpy(scm2->deliverto, scm2->from);
|
||||||
|
scm2->noreply = true;
|
||||||
|
client_list.SendPacket(scm->from, pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}))) && (!scm->noreply))
|
||||||
|
{
|
||||||
|
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "%s is not online at this time.", scm->to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
|
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
|
||||||
if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
|
if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
|
||||||
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
|
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
|
||||||
@ -462,6 +485,20 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
cle->Server()->SendPacket(pack);
|
cle->Server()->SendPacket(pack);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (scm->chan_num == 5 || scm->chan_num == 6 || scm->chan_num == 11) {
|
||||||
|
if (console) {
|
||||||
|
console->SendChannelMessage(scm, [&scm]() {
|
||||||
|
auto pack = new ServerPacket(ServerOP_ChannelMessage,
|
||||||
|
sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1);
|
||||||
|
memcpy(pack->pBuffer, scm, pack->size);
|
||||||
|
ServerChannelMessage_Struct* scm2 = (ServerChannelMessage_Struct*)pack->pBuffer;
|
||||||
|
strcpy(scm2->deliverto, scm2->from);
|
||||||
|
scm2->noreply = true;
|
||||||
|
client_list.SendPacket(scm->from, pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
zoneserver_list.SendPacket(pack);
|
zoneserver_list.SendPacket(pack);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1248,6 +1285,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
case ServerOP_CZSignalNPC:
|
case ServerOP_CZSignalNPC:
|
||||||
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
||||||
case ServerOP_CZSignalClient:
|
case ServerOP_CZSignalClient:
|
||||||
|
case ServerOP_CZSetEntityVariableByClientName:
|
||||||
case ServerOP_WWMarquee:
|
case ServerOP_WWMarquee:
|
||||||
case ServerOP_DepopAllPlayersCorpses:
|
case ServerOP_DepopAllPlayersCorpses:
|
||||||
case ServerOP_DepopPlayerCorpse:
|
case ServerOP_DepopPlayerCorpse:
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
#include "../net/servertalk_server.h"
|
#include "../net/servertalk_server.h"
|
||||||
#include "../event/timer.h"
|
#include "../event/timer.h"
|
||||||
#include "../timer.h"
|
#include "../timer.h"
|
||||||
|
#include "console.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ class ServerPacket;
|
|||||||
|
|
||||||
class ZoneServer : public WorldTCPConnection {
|
class ZoneServer : public WorldTCPConnection {
|
||||||
public:
|
public:
|
||||||
ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console);
|
||||||
~ZoneServer();
|
~ZoneServer();
|
||||||
virtual inline bool IsZoneServer() { return true; }
|
virtual inline bool IsZoneServer() { return true; }
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ private:
|
|||||||
uint32 zone_os_process_id;
|
uint32 zone_os_process_id;
|
||||||
std::string launcher_name; //the launcher which started us
|
std::string launcher_name; //the launcher which started us
|
||||||
std::string launched_name; //the name of the zone we launched.
|
std::string launched_name; //the name of the zone we launched.
|
||||||
|
EQ::Net::ConsoleServer *console;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -5,6 +5,7 @@ SET(zone_sources
|
|||||||
aa_ability.cpp
|
aa_ability.cpp
|
||||||
aggro.cpp
|
aggro.cpp
|
||||||
aggromanager.cpp
|
aggromanager.cpp
|
||||||
|
aura.cpp
|
||||||
attack.cpp
|
attack.cpp
|
||||||
beacon.cpp
|
beacon.cpp
|
||||||
bonuses.cpp
|
bonuses.cpp
|
||||||
@ -51,6 +52,7 @@ SET(zone_sources
|
|||||||
lua_item.cpp
|
lua_item.cpp
|
||||||
lua_iteminst.cpp
|
lua_iteminst.cpp
|
||||||
lua_mob.cpp
|
lua_mob.cpp
|
||||||
|
lua_mod.cpp
|
||||||
lua_npc.cpp
|
lua_npc.cpp
|
||||||
lua_object.cpp
|
lua_object.cpp
|
||||||
lua_packet.cpp
|
lua_packet.cpp
|
||||||
@ -59,6 +61,7 @@ SET(zone_sources
|
|||||||
lua_raid.cpp
|
lua_raid.cpp
|
||||||
lua_spawn.cpp
|
lua_spawn.cpp
|
||||||
lua_spell.cpp
|
lua_spell.cpp
|
||||||
|
lua_stat_bonuses.cpp
|
||||||
embperl.cpp
|
embperl.cpp
|
||||||
embxs.cpp
|
embxs.cpp
|
||||||
entity.cpp
|
entity.cpp
|
||||||
@ -134,6 +137,7 @@ SET(zone_headers
|
|||||||
aa.h
|
aa.h
|
||||||
aa_ability.h
|
aa_ability.h
|
||||||
aggromanager.h
|
aggromanager.h
|
||||||
|
aura.h
|
||||||
basic_functions.h
|
basic_functions.h
|
||||||
beacon.h
|
beacon.h
|
||||||
bot.h
|
bot.h
|
||||||
@ -173,6 +177,7 @@ SET(zone_headers
|
|||||||
lua_item.h
|
lua_item.h
|
||||||
lua_iteminst.h
|
lua_iteminst.h
|
||||||
lua_mob.h
|
lua_mob.h
|
||||||
|
lua_mod.h
|
||||||
lua_npc.h
|
lua_npc.h
|
||||||
lua_object.h
|
lua_object.h
|
||||||
lua_packet.h
|
lua_packet.h
|
||||||
@ -182,6 +187,7 @@ SET(zone_headers
|
|||||||
lua_raid.h
|
lua_raid.h
|
||||||
lua_spawn.h
|
lua_spawn.h
|
||||||
lua_spell.h
|
lua_spell.h
|
||||||
|
lua_stat_bonuses.h
|
||||||
map.h
|
map.h
|
||||||
masterentity.h
|
masterentity.h
|
||||||
maxskill.h
|
maxskill.h
|
||||||
|
|||||||
17
zone/aa.cpp
17
zone/aa.cpp
@ -46,8 +46,16 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
|||||||
if (targ != nullptr && targ->IsCorpse())
|
if (targ != nullptr && targ->IsCorpse())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// yep, even these need pet power!
|
||||||
|
int act_power = 0;
|
||||||
|
|
||||||
|
if (IsClient()) {
|
||||||
|
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
|
||||||
|
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
|
||||||
|
}
|
||||||
|
|
||||||
PetRecord record;
|
PetRecord record;
|
||||||
if (!database.GetPetEntry(spells[spell_id].teleport_zone, &record))
|
if (!database.GetPoweredPetEntry(spells[spell_id].teleport_zone, act_power, &record))
|
||||||
{
|
{
|
||||||
Log(Logs::General, Logs::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
|
Log(Logs::General, Logs::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
|
||||||
Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
|
Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
|
||||||
@ -908,7 +916,7 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) {
|
|||||||
void Client::SendAlternateAdvancementStats() {
|
void Client::SendAlternateAdvancementStats() {
|
||||||
auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct));
|
auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct));
|
||||||
AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer;
|
AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer;
|
||||||
aps->experience = (uint32)(((float)330.0f * (float)m_pp.expAA) / (float)max_AAXP);
|
aps->experience = (uint32)(((float)330.0f * (float)m_pp.expAA) / (float)GetRequiredAAExperience());
|
||||||
aps->unspent = m_pp.aapoints;
|
aps->unspent = m_pp.aapoints;
|
||||||
aps->percentage = m_epp.perAA;
|
aps->percentage = m_epp.perAA;
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
@ -1194,6 +1202,11 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
|||||||
Message_StringID(MT_SpellFailure, SNEAK_RESTRICT);
|
Message_StringID(MT_SpellFailure, SNEAK_RESTRICT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Modern clients don't require pet targeted for AA casts that are ST_Pet
|
||||||
|
if (spells[rank->spell].targettype == ST_Pet || spells[rank->spell].targettype == ST_SummonedPet)
|
||||||
|
target_id = GetPetID();
|
||||||
|
|
||||||
// Bards can cast instant cast AAs while they are casting another song
|
// Bards can cast instant cast AAs while they are casting another song
|
||||||
if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
||||||
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
|
||||||
|
|||||||
117
zone/attack.cpp
117
zone/attack.cpp
@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "water_map.h"
|
#include "water_map.h"
|
||||||
#include "worldserver.h"
|
#include "worldserver.h"
|
||||||
#include "zone.h"
|
#include "zone.h"
|
||||||
|
#include "lua_parser.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -52,7 +53,7 @@ extern WorldServer worldserver;
|
|||||||
extern EntityList entity_list;
|
extern EntityList entity_list;
|
||||||
extern Zone* zone;
|
extern Zone* zone;
|
||||||
|
|
||||||
bool Mob::AttackAnimation(EQEmu::skills::SkillType &skillinuse, int Hand, const EQEmu::ItemInstance* weapon)
|
EQEmu::skills::SkillType Mob::AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse)
|
||||||
{
|
{
|
||||||
// Determine animation
|
// Determine animation
|
||||||
int type = 0;
|
int type = 0;
|
||||||
@ -137,7 +138,8 @@ bool Mob::AttackAnimation(EQEmu::skills::SkillType &skillinuse, int Hand, const
|
|||||||
type = animDualWield;
|
type = animDualWield;
|
||||||
|
|
||||||
DoAnim(type, 0, false);
|
DoAnim(type, 0, false);
|
||||||
return true;
|
|
||||||
|
return skillinuse;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Mob::compute_tohit(EQEmu::skills::SkillType skillinuse)
|
int Mob::compute_tohit(EQEmu::skills::SkillType skillinuse)
|
||||||
@ -271,6 +273,16 @@ int Mob::GetTotalDefense()
|
|||||||
// and does other mitigation checks. 'this' is the mob being attacked.
|
// and does other mitigation checks. 'this' is the mob being attacked.
|
||||||
bool Mob::CheckHitChance(Mob* other, DamageHitInfo &hit)
|
bool Mob::CheckHitChance(Mob* other, DamageHitInfo &hit)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool lua_ret = false;
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
lua_ret = LuaParser::Instance()->CheckHitChance(this, other, hit, ignoreDefault);
|
||||||
|
|
||||||
|
if(ignoreDefault) {
|
||||||
|
return lua_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Mob *attacker = other;
|
Mob *attacker = other;
|
||||||
Mob *defender = this;
|
Mob *defender = this;
|
||||||
Log(Logs::Detail, Logs::Attack, "CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
|
Log(Logs::Detail, Logs::Attack, "CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
|
||||||
@ -301,6 +313,16 @@ bool Mob::CheckHitChance(Mob* other, DamageHitInfo &hit)
|
|||||||
|
|
||||||
bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool lua_ret = false;
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
lua_ret = LuaParser::Instance()->AvoidDamage(this, other, hit, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return lua_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* called when a mob is attacked, does the checks to see if it's a hit
|
/* called when a mob is attacked, does the checks to see if it's a hit
|
||||||
* and does other mitigation checks. 'this' is the mob being attacked.
|
* and does other mitigation checks. 'this' is the mob being attacked.
|
||||||
*
|
*
|
||||||
@ -871,6 +893,15 @@ double Mob::RollD20(int offense, int mitigation)
|
|||||||
|
|
||||||
void Mob::MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
void Mob::MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
LuaParser::Instance()->MeleeMitigation(this, attacker, hit, opts, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hit.damage_done < 0 || hit.base_damage == 0)
|
if (hit.damage_done < 0 || hit.base_damage == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1237,6 +1268,7 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
|||||||
return;
|
return;
|
||||||
Log(Logs::Detail, Logs::Combat, "%s::DoAttack vs %s base %d min %d offense %d tohit %d skill %d", GetName(),
|
Log(Logs::Detail, Logs::Combat, "%s::DoAttack vs %s base %d min %d offense %d tohit %d skill %d", GetName(),
|
||||||
other->GetName(), hit.base_damage, hit.min_damage, hit.offense, hit.tohit, hit.skill);
|
other->GetName(), hit.base_damage, hit.min_damage, hit.offense, hit.tohit, hit.skill);
|
||||||
|
|
||||||
// check to see if we hit..
|
// check to see if we hit..
|
||||||
if (other->AvoidDamage(this, hit)) {
|
if (other->AvoidDamage(this, hit)) {
|
||||||
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||||
@ -1331,7 +1363,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
DamageHitInfo my_hit;
|
DamageHitInfo my_hit;
|
||||||
// calculate attack_skill and skillinuse depending on hand and weapon
|
// calculate attack_skill and skillinuse depending on hand and weapon
|
||||||
// also send Packet to near clients
|
// also send Packet to near clients
|
||||||
AttackAnimation(my_hit.skill, Hand, weapon);
|
my_hit.skill = AttackAnimation(Hand, weapon);
|
||||||
Log(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon ? weapon->GetItem()->Name : "Fist", Hand, my_hit.skill);
|
Log(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon ? weapon->GetItem()->Name : "Fist", Hand, my_hit.skill);
|
||||||
|
|
||||||
// Now figure out damage
|
// Now figure out damage
|
||||||
@ -1892,7 +1924,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
|||||||
//do attack animation regardless of whether or not we can hit below
|
//do attack animation regardless of whether or not we can hit below
|
||||||
int16 charges = 0;
|
int16 charges = 0;
|
||||||
EQEmu::ItemInstance weapon_inst(weapon, charges);
|
EQEmu::ItemInstance weapon_inst(weapon, charges);
|
||||||
AttackAnimation(my_hit.skill, Hand, &weapon_inst);
|
my_hit.skill = AttackAnimation(Hand, &weapon_inst, my_hit.skill);
|
||||||
|
|
||||||
//basically "if not immune" then do the attack
|
//basically "if not immune" then do the attack
|
||||||
if (weapon_damage > 0) {
|
if (weapon_damage > 0) {
|
||||||
@ -2190,7 +2222,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
|
|||||||
Group *kg = entity_list.GetGroupByClient(give_exp_client);
|
Group *kg = entity_list.GetGroupByClient(give_exp_client);
|
||||||
Raid *kr = entity_list.GetRaidByClient(give_exp_client);
|
Raid *kr = entity_list.GetRaidByClient(give_exp_client);
|
||||||
|
|
||||||
int32 finalxp = EXP_FORMULA;
|
int32 finalxp = give_exp_client->GetExperienceForKill(this);
|
||||||
finalxp = give_exp_client->mod_client_xp(finalxp, this);
|
finalxp = give_exp_client->mod_client_xp(finalxp, this);
|
||||||
|
|
||||||
if (kr) {
|
if (kr) {
|
||||||
@ -2356,6 +2388,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
|
|||||||
|
|
||||||
entity_list.UnMarkNPC(GetID());
|
entity_list.UnMarkNPC(GetID());
|
||||||
entity_list.RemoveNPC(GetID());
|
entity_list.RemoveNPC(GetID());
|
||||||
|
|
||||||
this->SetID(0);
|
this->SetID(0);
|
||||||
|
|
||||||
if (killer != 0 && emoteid != 0)
|
if (killer != 0 && emoteid != 0)
|
||||||
@ -2477,7 +2510,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id)
|
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id, bool pet_command)
|
||||||
{
|
{
|
||||||
if (!other)
|
if (!other)
|
||||||
return;
|
return;
|
||||||
@ -2516,13 +2549,18 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && !IsFocused()) { //ignore aggro if hold and !focus
|
// Pet that is /pet hold on will not add to their hate list if they're not engaged
|
||||||
return;
|
// Pet that is /pet hold on and /pet focus on will not add others to their hate list
|
||||||
}
|
// Pet that is /pet ghold on will never add to their hate list unless /pet attack or /pet qattack
|
||||||
|
|
||||||
if (IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && GetOwner()->GetAA(aaAdvancedPetDiscipline) >= 1 && IsFocused()) {
|
// we skip these checks if it's forced through a pet command
|
||||||
if (!targetmob)
|
if (!pet_command) {
|
||||||
return;
|
if (IsPet()) {
|
||||||
|
if ((IsGHeld() || (IsHeld() && IsFocused())) && !on_hatelist) // we want them to be able to climb the hate list
|
||||||
|
return;
|
||||||
|
if ((IsHeld() || IsPetStop() || IsPetRegroup()) && !wasengaged) // not 100% sure on stop/regroup kind of hard to test, but regroup is like "classic hold"
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
|
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
|
||||||
@ -2627,7 +2665,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
|
if (mypet && !mypet->IsHeld() && !mypet->IsPetStop()) { // I have a pet, add other to it
|
||||||
if (!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
|
if (!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
|
||||||
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||||
}
|
}
|
||||||
@ -2796,6 +2834,8 @@ uint8 Mob::GetWeaponDamageBonus(const EQEmu::ItemData *weapon, bool offhand)
|
|||||||
}
|
}
|
||||||
return damage_bonus;
|
return damage_bonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Mob::GetHandToHandDamage(void)
|
int Mob::GetHandToHandDamage(void)
|
||||||
@ -3306,7 +3346,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
|||||||
} //end `if there is some damage being done and theres anattacker person involved`
|
} //end `if there is some damage being done and theres anattacker person involved`
|
||||||
|
|
||||||
Mob *pet = GetPet();
|
Mob *pet = GetPet();
|
||||||
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse())
|
// pets that have GHold will never automatically add NPCs
|
||||||
|
// pets that have Hold and no Focus will add NPCs if they're engaged
|
||||||
|
// pets that have Hold and Focus will not add NPCs
|
||||||
|
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld())
|
||||||
{
|
{
|
||||||
if (!pet->IsHeld()) {
|
if (!pet->IsHeld()) {
|
||||||
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
|
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
|
||||||
@ -3355,8 +3398,6 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
|||||||
|
|
||||||
SetHP(GetHP() - damage);
|
SetHP(GetHP() - damage);
|
||||||
|
|
||||||
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
|
|
||||||
this->CastToClient()->SendHPUpdateMarquee();
|
|
||||||
|
|
||||||
if (HasDied()) {
|
if (HasDied()) {
|
||||||
bool IsSaved = false;
|
bool IsSaved = false;
|
||||||
@ -3507,8 +3548,11 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
|||||||
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
|
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||||
if (IsNPC()) {
|
if (IsNPC()) {
|
||||||
// Is this adequate?
|
// Is this adequate?
|
||||||
|
|
||||||
Teleport(new_pos);
|
Teleport(new_pos);
|
||||||
SendPosUpdate();
|
if (position_update_melee_push_timer.Check()) {
|
||||||
|
SendPositionUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -4056,7 +4100,7 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
|
|||||||
|
|
||||||
if (critChance > 0) {
|
if (critChance > 0) {
|
||||||
if (zone->random.Roll(critChance)) {
|
if (zone->random.Roll(critChance)) {
|
||||||
critMod += GetCritDmgMob(hit.skill);
|
critMod += GetCritDmgMod(hit.skill);
|
||||||
hit.damage_done += 5;
|
hit.damage_done += 5;
|
||||||
hit.damage_done = (hit.damage_done * critMod) / 100;
|
hit.damage_done = (hit.damage_done * critMod) / 100;
|
||||||
|
|
||||||
@ -4077,6 +4121,15 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
|
|||||||
|
|
||||||
void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
LuaParser::Instance()->TryCriticalHit(this, defender, hit, opts, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hit.damage_done < 1 || !defender)
|
if (hit.damage_done < 1 || !defender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -4185,7 +4238,11 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
// step 2: calculate damage
|
// step 2: calculate damage
|
||||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||||
int og_damage = hit.damage_done;
|
int og_damage = hit.damage_done;
|
||||||
int crit_mod = 170 + GetCritDmgMob(hit.skill);
|
int crit_mod = 170 + GetCritDmgMod(hit.skill);
|
||||||
|
if (crit_mod < 100) {
|
||||||
|
crit_mod = 100;
|
||||||
|
}
|
||||||
|
|
||||||
hit.damage_done = hit.damage_done * crit_mod / 100;
|
hit.damage_done = hit.damage_done * crit_mod / 100;
|
||||||
Log(Logs::Detail, Logs::Combat,
|
Log(Logs::Detail, Logs::Combat,
|
||||||
"Crit success roll %d dex chance %d og dmg %d crit_mod %d new dmg %d", roll, dex_bonus,
|
"Crit success roll %d dex chance %d og dmg %d crit_mod %d new dmg %d", roll, dex_bonus,
|
||||||
@ -4246,7 +4303,7 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
// Crippling blows also have a chance to stun
|
// Crippling blows also have a chance to stun
|
||||||
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
||||||
// staggers message.
|
// staggers message.
|
||||||
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(IMMUNE_STUN)) {
|
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(UNSTUNABLE)) {
|
||||||
defender->Emote("staggers.");
|
defender->Emote("staggers.");
|
||||||
defender->Stun(2000);
|
defender->Stun(2000);
|
||||||
}
|
}
|
||||||
@ -4527,6 +4584,15 @@ const DamageTable &Mob::GetDamageTable() const
|
|||||||
|
|
||||||
void Mob::ApplyDamageTable(DamageHitInfo &hit)
|
void Mob::ApplyDamageTable(DamageHitInfo &hit)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
LuaParser::Instance()->ApplyDamageTable(this, hit, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// someone may want to add this to custom servers, can remove this if that's the case
|
// someone may want to add this to custom servers, can remove this if that's the case
|
||||||
if (!IsClient()
|
if (!IsClient()
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
@ -4862,6 +4928,15 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
|||||||
if (!defender)
|
if (!defender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
LuaParser::Instance()->CommonOutgoingHitSuccess(this, defender, hit, opts, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// BER weren't parsing the halving
|
// BER weren't parsing the halving
|
||||||
if (hit.skill == EQEmu::skills::SkillArchery ||
|
if (hit.skill == EQEmu::skills::SkillArchery ||
|
||||||
(hit.skill == EQEmu::skills::SkillThrowing && GetClass() != BERSERKER))
|
(hit.skill == EQEmu::skills::SkillThrowing && GetClass() != BERSERKER))
|
||||||
@ -5295,4 +5370,4 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
936
zone/aura.cpp
Normal file
936
zone/aura.cpp
Normal file
@ -0,0 +1,936 @@
|
|||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
#include "aura.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "string_ids.h"
|
||||||
|
#include "raids.h"
|
||||||
|
|
||||||
|
Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record)
|
||||||
|
: NPC(type_data, 0, owner->GetPosition(), FlyMode3), spell_id(record.spell_id), distance(record.distance),
|
||||||
|
remove_timer(record.duration), movement_timer(100), process_timer(100), aura_id(-1)
|
||||||
|
{
|
||||||
|
GiveNPCTypeData(type_data); // we will delete this later on
|
||||||
|
m_owner = owner->GetID();
|
||||||
|
|
||||||
|
if (record.cast_time) {
|
||||||
|
cast_timer.SetTimer(record.cast_time);
|
||||||
|
cast_timer.Disable(); // we don't want to be enabled yet
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.aura_type < static_cast<int>(AuraType::Max))
|
||||||
|
type = static_cast<AuraType>(record.aura_type);
|
||||||
|
else
|
||||||
|
type = AuraType::OnAllGroupMembers;
|
||||||
|
|
||||||
|
if (record.spawn_type < static_cast<int>(AuraSpawns::Max))
|
||||||
|
spawn_type = static_cast<AuraSpawns>(record.spawn_type);
|
||||||
|
else
|
||||||
|
spawn_type = AuraSpawns::GroupMembers;
|
||||||
|
|
||||||
|
if (record.movement < static_cast<int>(AuraMovement::Max))
|
||||||
|
movement_type = static_cast<AuraMovement>(record.movement);
|
||||||
|
else
|
||||||
|
movement_type = AuraMovement::Follow;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AuraType::OnAllFriendlies:
|
||||||
|
process_func = &Aura::ProcessOnAllFriendlies;
|
||||||
|
break;
|
||||||
|
case AuraType::OnAllGroupMembers:
|
||||||
|
process_func = &Aura::ProcessOnAllGroupMembers;
|
||||||
|
break;
|
||||||
|
case AuraType::OnGroupMembersPets:
|
||||||
|
process_func = &Aura::ProcessOnGroupMembersPets;
|
||||||
|
break;
|
||||||
|
case AuraType::Totem:
|
||||||
|
process_func = &Aura::ProcessTotem;
|
||||||
|
break;
|
||||||
|
case AuraType::EnterTrap:
|
||||||
|
process_func = &Aura::ProcessEnterTrap;
|
||||||
|
break;
|
||||||
|
case AuraType::ExitTrap:
|
||||||
|
process_func = &Aura::ProcessExitTrap;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
process_func = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mob *Aura::GetOwner()
|
||||||
|
{
|
||||||
|
return entity_list.GetMob(m_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not 100% sure how this one should work and PVP affects ...
|
||||||
|
void Aura::ProcessOnAllFriendlies(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
std::set<int> delayed_remove;
|
||||||
|
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
if (mob->IsClient() || mob->IsPetOwnerClient() || mob->IsMerc()) {
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
|
||||||
|
if (it != casted_on.end()) { // we are already on the list, let's check for removal
|
||||||
|
if (DistanceSquared(GetPosition(), mob->GetPosition()) > distance)
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else { // not on list, lets check if we're in range
|
||||||
|
if (DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : delayed_remove) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove
|
||||||
|
mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
|
||||||
|
casted_on.erase(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it
|
||||||
|
if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty())
|
||||||
|
cast_timer.Start();
|
||||||
|
|
||||||
|
if (!cast_timer.Enabled() || !cast_timer.Check())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto &e : casted_on) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::ProcessOnAllGroupMembers(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
std::set<int> delayed_remove;
|
||||||
|
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||||
|
|
||||||
|
if (owner->IsRaidGrouped() && owner->IsClient()) { // currently raids are just client, but safety check
|
||||||
|
auto raid = owner->GetRaid();
|
||||||
|
if (raid == nullptr) { // well shit
|
||||||
|
owner->RemoveAura(GetID(), false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto group_id = raid->GetGroup(owner->CastToClient());
|
||||||
|
|
||||||
|
// some lambdas so the for loop is less horrible ...
|
||||||
|
auto verify_raid_client = [&raid, &group_id, this](Client *c) {
|
||||||
|
auto idx = raid->GetPlayerIndex(c);
|
||||||
|
if (c->GetID() == m_owner) {
|
||||||
|
return DistanceSquared(GetPosition(), c->GetPosition()) <= distance;
|
||||||
|
} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
} else if (DistanceSquared(GetPosition(), c->GetPosition()) > distance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto verify_raid_client_pet = [&raid, &group_id, this](Mob *m) {
|
||||||
|
auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient());
|
||||||
|
if (m->GetOwner()->GetID() == m_owner) {
|
||||||
|
return DistanceSquared(GetPosition(), m->GetPosition()) <= distance;
|
||||||
|
} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
} else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto verify_raid_client_swarm = [&raid, &group_id, this](NPC *n) {
|
||||||
|
auto owner = entity_list.GetMob(n->GetSwarmOwner());
|
||||||
|
if (owner == nullptr)
|
||||||
|
return false;
|
||||||
|
auto idx = raid->GetPlayerIndex(owner->CastToClient());
|
||||||
|
if (owner->GetID() == m_owner) {
|
||||||
|
return DistanceSquared(GetPosition(), n->GetPosition()) <= distance;
|
||||||
|
} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
} else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
// step 1: check if we're already managing this NPC's buff
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
if (it != casted_on.end()) {
|
||||||
|
// verify still good!
|
||||||
|
if (mob->IsClient()) {
|
||||||
|
if (!verify_raid_client(mob->CastToClient()))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) {
|
||||||
|
if (!verify_raid_client_pet(mob))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
|
||||||
|
auto npc = mob->CastToNPC();
|
||||||
|
if (!verify_raid_client_swarm(npc))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else { // we're not on it!
|
||||||
|
if (mob->IsClient() && verify_raid_client(mob->CastToClient())) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
|
||||||
|
auto npc = mob->CastToNPC();
|
||||||
|
if (verify_raid_client_swarm(npc)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (owner->IsGrouped()) {
|
||||||
|
auto group = owner->GetGroup();
|
||||||
|
if (group == nullptr) { // uh oh
|
||||||
|
owner->RemoveAura(GetID(), false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lambdas to make for loop less ugly
|
||||||
|
auto verify_group_pet = [&group, this](Mob *m) {
|
||||||
|
auto owner = m->GetOwner();
|
||||||
|
if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto verify_group_swarm = [&group, this](NPC *n) {
|
||||||
|
auto owner = entity_list.GetMob(n->GetSwarmOwner());
|
||||||
|
if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
|
||||||
|
if (it != casted_on.end()) { // make sure we're still valid
|
||||||
|
if (mob->IsPet()) {
|
||||||
|
if (!verify_group_pet(mob))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) {
|
||||||
|
if (!verify_group_swarm(mob->CastToNPC()))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (!group->IsGroupMember(mob) || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) {
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else { // not on, check if we should be!
|
||||||
|
if (mob->IsPet() && verify_group_pet(mob)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (group->IsGroupMember(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto verify_solo = [&owner, this](Mob *m) {
|
||||||
|
if (m->IsPet() && m->GetOwnerID() == owner->GetID())
|
||||||
|
return true;
|
||||||
|
else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == owner->GetID())
|
||||||
|
return true;
|
||||||
|
else if (m->GetID() == owner->GetID())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
bool good = verify_solo(mob);
|
||||||
|
|
||||||
|
if (it != casted_on.end()) { // make sure still valid
|
||||||
|
if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) {
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : delayed_remove) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove
|
||||||
|
mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
|
||||||
|
casted_on.erase(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it
|
||||||
|
if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty())
|
||||||
|
cast_timer.Start();
|
||||||
|
|
||||||
|
if (!cast_timer.Enabled() || !cast_timer.Check())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// some auras have to recast (DRU for example, non-buff too)
|
||||||
|
for (auto &e : casted_on) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::ProcessOnGroupMembersPets(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
std::set<int> delayed_remove;
|
||||||
|
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||||
|
// This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura)
|
||||||
|
auto group_member = owner->GetOwnerOrSelf();
|
||||||
|
|
||||||
|
if (group_member->IsRaidGrouped() && group_member->IsClient()) { // currently raids are just client, but safety check
|
||||||
|
auto raid = group_member->GetRaid();
|
||||||
|
if (raid == nullptr) { // well shit
|
||||||
|
owner->RemoveAura(GetID(), false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto group_id = raid->GetGroup(group_member->CastToClient());
|
||||||
|
|
||||||
|
// some lambdas so the for loop is less horrible ...
|
||||||
|
auto verify_raid_client_pet = [&raid, &group_id, &group_member, this](Mob *m) {
|
||||||
|
auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient());
|
||||||
|
if (m->GetOwner()->GetID() == group_member->GetID()) {
|
||||||
|
return DistanceSquared(GetPosition(), m->GetPosition()) <= distance;
|
||||||
|
} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
} else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto verify_raid_client_swarm = [&raid, &group_id, &group_member, this](NPC *n) {
|
||||||
|
auto owner = entity_list.GetMob(n->GetSwarmOwner());
|
||||||
|
if (owner == nullptr)
|
||||||
|
return false;
|
||||||
|
auto idx = raid->GetPlayerIndex(owner->CastToClient());
|
||||||
|
if (owner->GetID() == group_member->GetID()) {
|
||||||
|
return DistanceSquared(GetPosition(), n->GetPosition()) <= distance;
|
||||||
|
} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
} else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
// step 1: check if we're already managing this NPC's buff
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
if (it != casted_on.end()) {
|
||||||
|
// verify still good!
|
||||||
|
if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) {
|
||||||
|
if (!verify_raid_client_pet(mob))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
|
||||||
|
auto npc = mob->CastToNPC();
|
||||||
|
if (!verify_raid_client_swarm(npc))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else { // we're not on it!
|
||||||
|
if (mob->IsClient()) {
|
||||||
|
continue; // never hit client
|
||||||
|
} else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
|
||||||
|
auto npc = mob->CastToNPC();
|
||||||
|
if (verify_raid_client_swarm(npc)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (group_member->IsGrouped()) {
|
||||||
|
auto group = group_member->GetGroup();
|
||||||
|
if (group == nullptr) { // uh oh
|
||||||
|
owner->RemoveAura(GetID(), false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lambdas to make for loop less ugly
|
||||||
|
auto verify_group_pet = [&group, this](Mob *m) {
|
||||||
|
auto owner = m->GetOwner();
|
||||||
|
if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto verify_group_swarm = [&group, this](NPC *n) {
|
||||||
|
auto owner = entity_list.GetMob(n->GetSwarmOwner());
|
||||||
|
if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
|
||||||
|
if (it != casted_on.end()) { // make sure we're still valid
|
||||||
|
if (mob->IsPet()) {
|
||||||
|
if (!verify_group_pet(mob))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) {
|
||||||
|
if (!verify_group_swarm(mob->CastToNPC()))
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else { // not on, check if we should be!
|
||||||
|
if (mob->IsClient()) {
|
||||||
|
continue;
|
||||||
|
} else if (mob->IsPet() && verify_group_pet(mob)) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto verify_solo = [&group_member, this](Mob *m) {
|
||||||
|
if (m->IsPet() && m->GetOwnerID() == group_member->GetID())
|
||||||
|
return true;
|
||||||
|
else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == group_member->GetID())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
bool good = verify_solo(mob);
|
||||||
|
|
||||||
|
if (it != casted_on.end()) { // make sure still valid
|
||||||
|
if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) {
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
} else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
if (is_buff)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : delayed_remove) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove
|
||||||
|
mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
|
||||||
|
casted_on.erase(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it
|
||||||
|
if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty())
|
||||||
|
cast_timer.Start();
|
||||||
|
|
||||||
|
if (!cast_timer.Enabled() || !cast_timer.Check())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// some auras have to recast (DRU for example, non-buff too)
|
||||||
|
for (auto &e : casted_on) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::ProcessTotem(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
std::set<int> delayed_remove;
|
||||||
|
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
if (mob == this)
|
||||||
|
continue;
|
||||||
|
if (mob == owner)
|
||||||
|
continue;
|
||||||
|
if (owner->IsAttackAllowed(mob)) { // might need more checks ...
|
||||||
|
bool in_range = DistanceSquared(GetPosition(), mob->GetPosition()) <= distance;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
if (it != casted_on.end()) {
|
||||||
|
if (!in_range)
|
||||||
|
delayed_remove.insert(mob->GetID());
|
||||||
|
} else if (in_range) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : delayed_remove) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove
|
||||||
|
mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
|
||||||
|
casted_on.erase(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it
|
||||||
|
if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty())
|
||||||
|
cast_timer.Start();
|
||||||
|
|
||||||
|
if (!cast_timer.Enabled() || !cast_timer.Check())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto &e : casted_on) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr)
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::ProcessEnterTrap(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
if (mob == this)
|
||||||
|
continue;
|
||||||
|
// might need more checks ...
|
||||||
|
if (owner->IsAttackAllowed(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
owner->RemoveAura(GetID(), false); // if we're a buff (ex. NEC) we don't want to strip :P
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::ProcessExitTrap(Mob *owner)
|
||||||
|
{
|
||||||
|
auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
|
||||||
|
|
||||||
|
for (auto &e : mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
if (mob == this)
|
||||||
|
continue;
|
||||||
|
// might need more checks ...
|
||||||
|
if (owner->IsAttackAllowed(mob)) {
|
||||||
|
bool in_range = DistanceSquared(GetPosition(), mob->GetPosition()) <= distance;
|
||||||
|
auto it = casted_on.find(mob->GetID());
|
||||||
|
if (it != casted_on.end()) {
|
||||||
|
if (!in_range) {
|
||||||
|
SpellFinished(spell_id, mob);
|
||||||
|
owner->RemoveAura(GetID(), false); // if we're a buff we don't want to strip :P
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (in_range) {
|
||||||
|
casted_on.insert(mob->GetID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is less than ideal, but other solutions are a bit all over the place
|
||||||
|
// and hard to reason about
|
||||||
|
void Aura::ProcessSpawns()
|
||||||
|
{
|
||||||
|
const auto &clients = entity_list.GetClientList();
|
||||||
|
for (auto &e : clients) {
|
||||||
|
auto c = e.second;
|
||||||
|
bool spawned = spawned_for.find(c->GetID()) != spawned_for.end();
|
||||||
|
if (ShouldISpawnFor(c)) {
|
||||||
|
if (!spawned) {
|
||||||
|
EQApplicationPacket app;
|
||||||
|
CreateSpawnPacket(&app, this);
|
||||||
|
c->QueuePacket(&app);
|
||||||
|
SendArmorAppearance(c);
|
||||||
|
spawned_for.insert(c->GetID());
|
||||||
|
}
|
||||||
|
} else if (spawned) {
|
||||||
|
EQApplicationPacket app;
|
||||||
|
CreateDespawnPacket(&app, false);
|
||||||
|
c->QueuePacket(&app);
|
||||||
|
spawned_for.erase(c->GetID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Aura::Process()
|
||||||
|
{
|
||||||
|
// Aura::Depop clears buffs
|
||||||
|
if (p_depop)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto owner = entity_list.GetMob(m_owner);
|
||||||
|
if (owner == nullptr) {
|
||||||
|
Depop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove_timer.Check()) {
|
||||||
|
owner->RemoveAura(GetID(), false, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movement_type == AuraMovement::Follow && GetPosition() != owner->GetPosition() && movement_timer.Check()) {
|
||||||
|
m_Position = owner->GetPosition();
|
||||||
|
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
auto spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
||||||
|
MakeSpawnUpdate(spu);
|
||||||
|
auto it = spawned_for.begin();
|
||||||
|
while (it != spawned_for.end()) {
|
||||||
|
auto client = entity_list.GetClientByID(*it);
|
||||||
|
if (client) {
|
||||||
|
client->QueuePacket(app);
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
it = spawned_for.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: waypoints?
|
||||||
|
|
||||||
|
if (!process_timer.Check())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (spawn_type != AuraSpawns::Noone)
|
||||||
|
ProcessSpawns(); // bit of a hack
|
||||||
|
|
||||||
|
if (process_func)
|
||||||
|
process_func(*this, owner);
|
||||||
|
|
||||||
|
// TODO: quest calls
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Aura::ShouldISpawnFor(Client *c)
|
||||||
|
{
|
||||||
|
if (spawn_type == AuraSpawns::Noone)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (spawn_type == AuraSpawns::Everyone)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// hey, it's our owner!
|
||||||
|
if (c->GetID() == m_owner)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// so this one is a bit trickier
|
||||||
|
auto owner = GetOwner();
|
||||||
|
if (owner == nullptr)
|
||||||
|
return false; // hmm
|
||||||
|
|
||||||
|
owner = owner->GetOwnerOrSelf(); // pet auras we need the pet's owner
|
||||||
|
if (owner == nullptr) // shouldn't really be needed
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// gotta check again for pet aura case -.-
|
||||||
|
if (owner == c)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (owner->IsRaidGrouped() && owner->IsClient()) {
|
||||||
|
auto raid = owner->GetRaid();
|
||||||
|
if (raid == nullptr)
|
||||||
|
return false; // hmm
|
||||||
|
auto group_id = raid->GetGroup(owner->CastToClient());
|
||||||
|
if (group_id == 0xFFFFFFFF) // owner handled above, and they're in a raid and groupless
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto idx = raid->GetPlayerIndex(c);
|
||||||
|
if (idx == 0xFFFFFFFF) // they're not in our raid!
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (raid->members[idx].GroupNumber != group_id) // in our raid, but not our group
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true; // we got here so we know that 1 they're in our raid and 2 they're in our group!
|
||||||
|
} else if (owner->IsGrouped()) {
|
||||||
|
auto group = owner->GetGroup();
|
||||||
|
if (group == nullptr)
|
||||||
|
return false; // hmm
|
||||||
|
|
||||||
|
// easy, in our group
|
||||||
|
return group->IsGroupMember(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// our owner is not raided or grouped, and they're handled above so we don't spawn!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aura::Depop(bool skip_strip)
|
||||||
|
{
|
||||||
|
// NEC trap casts a dot, so we need some way to not strip :P
|
||||||
|
if (!skip_strip && IsBuffSpell(spell_id)) {
|
||||||
|
for (auto &e : casted_on) {
|
||||||
|
auto mob = entity_list.GetMob(e);
|
||||||
|
if (mob != nullptr)
|
||||||
|
mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
casted_on.clear();
|
||||||
|
p_depop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates an aura from a casted spell
|
||||||
|
void Mob::MakeAura(uint16 spell_id)
|
||||||
|
{
|
||||||
|
// TODO: verify room in AuraMgr
|
||||||
|
if (!IsValidSpell(spell_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
AuraRecord record;
|
||||||
|
if (!database.GetAuraEntry(spell_id, record)) {
|
||||||
|
Message(13, "Unable to find data for aura %s", spells[spell_id].name);
|
||||||
|
Log(Logs::General, Logs::Error, "Unable to find data for aura %d, check auras table.", spell_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidSpell(record.spell_id)) {
|
||||||
|
Message(13, "Casted spell (%d) is not valid for aura %s", record.spell_id, spells[spell_id].name);
|
||||||
|
Log(Logs::General, Logs::Error, "Casted spell (%d) is not valid for aura %d, check auras table.",
|
||||||
|
record.spell_id, spell_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.aura_type > static_cast<int>(AuraType::Max)) {
|
||||||
|
return; // TODO: log
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trap = false;
|
||||||
|
|
||||||
|
switch (static_cast<AuraType>(record.aura_type)) {
|
||||||
|
case AuraType::ExitTrap:
|
||||||
|
case AuraType::EnterTrap:
|
||||||
|
case AuraType::Totem:
|
||||||
|
trap = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
trap = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanSpawnAura(trap))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto base = database.LoadNPCTypesData(record.npc_type);
|
||||||
|
if (base == nullptr) {
|
||||||
|
Message(13, "Unable to load NPC data for aura %s", spells[spell_id].teleport_zone);
|
||||||
|
Log(Logs::General, Logs::Error,
|
||||||
|
"Unable to load NPC data for aura %s (NPC ID %d), check auras and npc_types tables.",
|
||||||
|
spells[spell_id].teleport_zone, record.npc_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto npc_type = new NPCType;
|
||||||
|
memcpy(npc_type, base, sizeof(NPCType));
|
||||||
|
|
||||||
|
strn0cpy(npc_type->name, record.name, 64);
|
||||||
|
|
||||||
|
auto npc = new Aura(npc_type, this, record);
|
||||||
|
npc->SetAuraID(spell_id);
|
||||||
|
entity_list.AddNPC(npc, false);
|
||||||
|
|
||||||
|
if (trap)
|
||||||
|
AddTrap(npc, record);
|
||||||
|
else
|
||||||
|
AddAura(npc, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZoneDatabase::GetAuraEntry(uint16 spell_id, AuraRecord &record)
|
||||||
|
{
|
||||||
|
auto query = StringFormat("SELECT npc_type, name, spell_id, distance, aura_type, spawn_type, movement, "
|
||||||
|
"duration, icon, cast_time FROM auras WHERE type='%d'",
|
||||||
|
spell_id);
|
||||||
|
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (results.RowCount() != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
|
||||||
|
record.npc_type = atoi(row[0]);
|
||||||
|
strn0cpy(record.name, row[1], 64);
|
||||||
|
record.spell_id = atoi(row[2]);
|
||||||
|
record.distance = atoi(row[3]);
|
||||||
|
record.distance *= record.distance; // so we can avoid sqrt
|
||||||
|
record.aura_type = atoi(row[4]);
|
||||||
|
record.spawn_type = atoi(row[5]);
|
||||||
|
record.movement = atoi(row[6]);
|
||||||
|
record.duration = atoi(row[7]) * 1000; // DB is in seconds
|
||||||
|
record.icon = atoi(row[8]);
|
||||||
|
record.cast_time = atoi(row[9]) * 1000; // DB is in seconds
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::AddAura(Aura *aura, AuraRecord &record)
|
||||||
|
{
|
||||||
|
// this is called only when it's safe
|
||||||
|
assert(aura != nullptr);
|
||||||
|
strn0cpy(aura_mgr.auras[aura_mgr.count].name, aura->GetCleanName(), 64);
|
||||||
|
aura_mgr.auras[aura_mgr.count].spawn_id = aura->GetID();
|
||||||
|
aura_mgr.auras[aura_mgr.count].aura = aura;
|
||||||
|
if (record.icon == -1)
|
||||||
|
aura_mgr.auras[aura_mgr.count].icon = spells[record.spell_id].new_icon;
|
||||||
|
else
|
||||||
|
aura_mgr.auras[aura_mgr.count].icon = record.icon;
|
||||||
|
if (IsClient()) {
|
||||||
|
auto outapp = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraCreate_Struct));
|
||||||
|
auto aura_create = (AuraCreate_Struct *)outapp->pBuffer;
|
||||||
|
aura_create->action = 0;
|
||||||
|
aura_create->type = 1; // this can be 0 sometimes too
|
||||||
|
strn0cpy(aura_create->aura_name, aura_mgr.auras[aura_mgr.count].name, 64);
|
||||||
|
aura_create->entity_id = aura_mgr.auras[aura_mgr.count].spawn_id;
|
||||||
|
aura_create->icon = aura_mgr.auras[aura_mgr.count].icon;
|
||||||
|
CastToClient()->FastQueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
// we can increment this now
|
||||||
|
aura_mgr.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::AddTrap(Aura *aura, AuraRecord &record)
|
||||||
|
{
|
||||||
|
// this is called only when it's safe
|
||||||
|
assert(aura != nullptr);
|
||||||
|
strn0cpy(trap_mgr.auras[trap_mgr.count].name, aura->GetCleanName(), 64);
|
||||||
|
trap_mgr.auras[trap_mgr.count].spawn_id = aura->GetID();
|
||||||
|
trap_mgr.auras[trap_mgr.count].aura = aura;
|
||||||
|
if (record.icon == -1)
|
||||||
|
trap_mgr.auras[trap_mgr.count].icon = spells[record.spell_id].new_icon;
|
||||||
|
else
|
||||||
|
trap_mgr.auras[trap_mgr.count].icon = record.icon;
|
||||||
|
// doesn't send to client
|
||||||
|
trap_mgr.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mob::CanSpawnAura(bool trap)
|
||||||
|
{
|
||||||
|
if (trap && !HasFreeTrapSlots()) {
|
||||||
|
Message_StringID(MT_SpellFailure, NO_MORE_TRAPS);
|
||||||
|
return false;
|
||||||
|
} else if (!trap && !HasFreeAuraSlots()) {
|
||||||
|
Message_StringID(MT_SpellFailure, NO_MORE_AURAS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::RemoveAllAuras()
|
||||||
|
{
|
||||||
|
if (IsClient()) {
|
||||||
|
database.SaveAuras(CastToClient());
|
||||||
|
EQApplicationPacket outapp(OP_UpdateAura, 4);
|
||||||
|
outapp.WriteUInt32(2);
|
||||||
|
CastToClient()->QueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is sent on camp/zone, so it just despawns?
|
||||||
|
if (aura_mgr.count) {
|
||||||
|
for (auto &e : aura_mgr.auras) {
|
||||||
|
if (e.aura)
|
||||||
|
e.aura->Depop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aura_mgr.count = 0;
|
||||||
|
|
||||||
|
if (trap_mgr.count) {
|
||||||
|
for (auto &e : trap_mgr.auras) {
|
||||||
|
if (e.aura)
|
||||||
|
e.aura->Depop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trap_mgr.count = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::RemoveAura(int spawn_id, bool skip_strip, bool expired)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < aura_mgr.count; ++i) {
|
||||||
|
auto &aura = aura_mgr.auras[i];
|
||||||
|
if (aura.spawn_id == spawn_id) {
|
||||||
|
if (aura.aura)
|
||||||
|
aura.aura->Depop(skip_strip);
|
||||||
|
if (expired && IsClient()) {
|
||||||
|
CastToClient()->SendColoredText(
|
||||||
|
CC_Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color
|
||||||
|
// need to update client UI too
|
||||||
|
auto app = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraDestory_Struct));
|
||||||
|
auto ads = (AuraDestory_Struct *)app->pBuffer;
|
||||||
|
ads->action = 1; // delete
|
||||||
|
ads->entity_id = spawn_id;
|
||||||
|
CastToClient()->QueuePacket(app);
|
||||||
|
safe_delete(app);
|
||||||
|
}
|
||||||
|
while (aura_mgr.count - 1 > i) {
|
||||||
|
i++;
|
||||||
|
aura.spawn_id = aura_mgr.auras[i].spawn_id;
|
||||||
|
aura.icon = aura_mgr.auras[i].icon;
|
||||||
|
aura.aura = aura_mgr.auras[i].aura;
|
||||||
|
aura_mgr.auras[i].aura = nullptr;
|
||||||
|
strn0cpy(aura.name, aura_mgr.auras[i].name, 64);
|
||||||
|
}
|
||||||
|
aura_mgr.count--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < trap_mgr.count; ++i) {
|
||||||
|
auto &aura = trap_mgr.auras[i];
|
||||||
|
if (aura.spawn_id == spawn_id) {
|
||||||
|
if (aura.aura)
|
||||||
|
aura.aura->Depop(skip_strip);
|
||||||
|
if (expired && IsClient())
|
||||||
|
CastToClient()->SendColoredText(
|
||||||
|
CC_Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color
|
||||||
|
while (trap_mgr.count - 1 > i) {
|
||||||
|
i++;
|
||||||
|
aura.spawn_id = trap_mgr.auras[i].spawn_id;
|
||||||
|
aura.icon = trap_mgr.auras[i].icon;
|
||||||
|
aura.aura = trap_mgr.auras[i].aura;
|
||||||
|
trap_mgr.auras[i].aura = nullptr;
|
||||||
|
strn0cpy(aura.name, trap_mgr.auras[i].name, 64);
|
||||||
|
}
|
||||||
|
trap_mgr.count--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
91
zone/aura.h
Normal file
91
zone/aura.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#ifndef AURA_H
|
||||||
|
#define AURA_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "mob.h"
|
||||||
|
#include "npc.h"
|
||||||
|
#include "../common/types.h"
|
||||||
|
#include "../common/timer.h"
|
||||||
|
|
||||||
|
class Group;
|
||||||
|
class Raid;
|
||||||
|
class Mob;
|
||||||
|
struct NPCType;
|
||||||
|
|
||||||
|
enum class AuraType {
|
||||||
|
OnAllFriendlies, // AE PC/Pet basically (ex. Circle of Power)
|
||||||
|
OnAllGroupMembers, // Normal buffing aura (ex. Champion's Aura)
|
||||||
|
OnGroupMembersPets, // Hits just pets (ex. Rathe's Strength)
|
||||||
|
Totem, // Starts pulsing on a timer when an enemy enters (ex. Idol of Malos)
|
||||||
|
EnterTrap, // Casts once when an enemy enters (ex. Fire Rune)
|
||||||
|
ExitTrap, // Casts when they start to flee (ex. Poison Spikes Trap)
|
||||||
|
FullyScripted, // We just call script function not a predefined
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AuraSpawns {
|
||||||
|
GroupMembers, // most auras use this
|
||||||
|
Everyone, // this is like traps and clickies who cast on everyone
|
||||||
|
Noone, // custom!
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AuraMovement {
|
||||||
|
Follow, // follows caster
|
||||||
|
Stationary,
|
||||||
|
Pathing, // some sorted pathing TODO: implement
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
class Aura : public NPC
|
||||||
|
{
|
||||||
|
// NOTE: We may have to override more virtual functions if they're causing issues
|
||||||
|
public:
|
||||||
|
Aura(NPCType *type_data, Mob *owner, AuraRecord &record);
|
||||||
|
~Aura() { };
|
||||||
|
|
||||||
|
bool IsAura() const { return true; }
|
||||||
|
bool Process();
|
||||||
|
void Depop(bool skip_strip = false);
|
||||||
|
Mob *GetOwner();
|
||||||
|
|
||||||
|
void ProcessOnAllFriendlies(Mob *owner);
|
||||||
|
void ProcessOnAllGroupMembers(Mob *owner);
|
||||||
|
void ProcessOnGroupMembersPets(Mob *owner);
|
||||||
|
void ProcessTotem(Mob *owner);
|
||||||
|
void ProcessEnterTrap(Mob *owner);
|
||||||
|
void ProcessExitTrap(Mob *owner);
|
||||||
|
void ProcessSpawns();
|
||||||
|
|
||||||
|
// we only save auras that follow you, and player casted
|
||||||
|
inline bool AuraZones() { return movement_type == AuraMovement::Follow && aura_id > -1; }
|
||||||
|
inline int GetSpellID() { return spell_id; }
|
||||||
|
inline int GetAuraID() { return aura_id; }
|
||||||
|
inline void SetAuraID(int in) { aura_id = in; }
|
||||||
|
|
||||||
|
bool ShouldISpawnFor(Client *c);
|
||||||
|
// so when we join a group, we need to spawn not already spawned auras
|
||||||
|
// This is only possible when spawn type is GroupMembers
|
||||||
|
inline bool JoinGroupSpawnCheck() { return spawn_type == AuraSpawns::GroupMembers; }
|
||||||
|
private:
|
||||||
|
int m_owner;
|
||||||
|
int aura_id; // spell ID of the aura spell -1 if aura isn't from a casted spell
|
||||||
|
int spell_id; // spell we cast
|
||||||
|
int distance; // distance we remove
|
||||||
|
Timer remove_timer; // when we depop
|
||||||
|
Timer process_timer; // rate limit process calls
|
||||||
|
Timer cast_timer; // some auras pulse
|
||||||
|
Timer movement_timer; // rate limit movement updates
|
||||||
|
AuraType type;
|
||||||
|
AuraSpawns spawn_type;
|
||||||
|
AuraMovement movement_type;
|
||||||
|
|
||||||
|
std::function<void(Aura &, Mob *)> process_func;
|
||||||
|
std::set<int> casted_on; // we keep track of the other entities we've casted on
|
||||||
|
std::set<int> spawned_for;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* !AURA_H */
|
||||||
|
|
||||||
@ -68,6 +68,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
|
|||||||
resist_adjust = 0;
|
resist_adjust = 0;
|
||||||
spell_iterations = 0;
|
spell_iterations = 0;
|
||||||
caster_id = 0;
|
caster_id = 0;
|
||||||
|
max_targets = 4; // default
|
||||||
|
|
||||||
if(lifetime)
|
if(lifetime)
|
||||||
remove_timer.Start();
|
remove_timer.Start();
|
||||||
@ -93,10 +94,12 @@ bool Beacon::Process()
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
Mob *caster = entity_list.GetMob(caster_id);
|
Mob *caster = entity_list.GetMob(caster_id);
|
||||||
if(caster && spell_iterations--)
|
if(caster && spell_iterations-- && max_targets)
|
||||||
{
|
{
|
||||||
bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()); //NPC AE spells do not affect the NPC caster
|
// NPCs should never be affected by an AE they cast. PB AEs shouldn't affect caster either
|
||||||
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust);
|
// I don't think any other cases that get here matter
|
||||||
|
bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()) && spells[spell_id].targettype != ST_AECaster;
|
||||||
|
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -126,6 +129,8 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 resist_adj
|
|||||||
this->resist_adjust = resist_adjust;
|
this->resist_adjust = resist_adjust;
|
||||||
spell_iterations = spells[spell_id].AEDuration / 2500;
|
spell_iterations = spells[spell_id].AEDuration / 2500;
|
||||||
spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1
|
spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1
|
||||||
|
if (spells[spell_id].aemaxtargets)
|
||||||
|
max_targets = spells[spell_id].aemaxtargets;
|
||||||
spell_timer.Start(2500);
|
spell_timer.Start(2500);
|
||||||
spell_timer.Trigger();
|
spell_timer.Trigger();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,7 @@ protected:
|
|||||||
int16 resist_adjust;
|
int16 resist_adjust;
|
||||||
int spell_iterations;
|
int spell_iterations;
|
||||||
Timer spell_timer;
|
Timer spell_timer;
|
||||||
|
int max_targets;
|
||||||
|
|
||||||
uint16 caster_id;
|
uint16 caster_id;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -48,6 +48,14 @@ void Mob::CalcBonuses()
|
|||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
CalcAC();
|
CalcAC();
|
||||||
|
|
||||||
|
/* Fast walking NPC's are prone to disappear into walls/hills
|
||||||
|
We set this here because NPC's can cast spells to change walkspeed/runspeed
|
||||||
|
*/
|
||||||
|
float get_walk_speed = static_cast<float>(0.025f * this->GetWalkspeed());
|
||||||
|
if (get_walk_speed >= 0.9 && this->fix_z_timer.GetDuration() != 100) {
|
||||||
|
this->fix_z_timer.SetTimer(100);
|
||||||
|
}
|
||||||
|
|
||||||
rooted = FindType(SE_Root);
|
rooted = FindType(SE_Root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,9 +1092,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
break;
|
break;
|
||||||
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
||||||
if (base2 == ALL_SKILLS)
|
if (base2 == ALL_SKILLS)
|
||||||
newbon->CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] += base1;
|
newbon->CritDmgMod[EQEmu::skills::HIGHEST_SKILL + 1] += base1;
|
||||||
else
|
else
|
||||||
newbon->CritDmgMob[base2] += base1;
|
newbon->CritDmgMod[base2] += base1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1442,11 +1450,27 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
newbon->FeignedCastOnChance = base1;
|
newbon->FeignedCastOnChance = base1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SE_AddPetCommand:
|
||||||
|
if (base1 && base2 < PET_MAXCOMMANDS)
|
||||||
|
newbon->PetCommands[base2] = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SE_FeignedMinion:
|
||||||
|
if (newbon->FeignedMinionChance < base1)
|
||||||
|
newbon->FeignedMinionChance = base1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SE_AdditionalAura:
|
||||||
|
newbon->aura_slots += base1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SE_IncreaseTrapCount:
|
||||||
|
newbon->trap_slots += base1;
|
||||||
|
break;
|
||||||
|
|
||||||
// to do
|
// to do
|
||||||
case SE_PetDiscipline:
|
case SE_PetDiscipline:
|
||||||
break;
|
break;
|
||||||
case SE_PetDiscipline2:
|
|
||||||
break;
|
|
||||||
case SE_PotionBeltSlots:
|
case SE_PotionBeltSlots:
|
||||||
break;
|
break;
|
||||||
case SE_BandolierSlots:
|
case SE_BandolierSlots:
|
||||||
@ -1465,8 +1489,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
break;
|
break;
|
||||||
case SE_TrapCircumvention:
|
case SE_TrapCircumvention:
|
||||||
break;
|
break;
|
||||||
case SE_FeignedMinion:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// not handled here
|
// not handled here
|
||||||
case SE_HastenedAASkill:
|
case SE_HastenedAASkill:
|
||||||
@ -2435,9 +2457,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
|||||||
if (base2 > EQEmu::skills::HIGHEST_SKILL)
|
if (base2 > EQEmu::skills::HIGHEST_SKILL)
|
||||||
break;
|
break;
|
||||||
if(base2 == ALL_SKILLS)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value;
|
new_bonus->CritDmgMod[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->CritDmgMob[base2] += effect_value;
|
new_bonus->CritDmgMod[base2] += effect_value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3187,6 +3209,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
|||||||
if (new_bonus->FeignedCastOnChance < effect_value)
|
if (new_bonus->FeignedCastOnChance < effect_value)
|
||||||
new_bonus->FeignedCastOnChance = effect_value;
|
new_bonus->FeignedCastOnChance = effect_value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SE_AdditionalAura:
|
||||||
|
if (new_bonus->aura_slots < effect_value)
|
||||||
|
new_bonus->aura_slots = effect_value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SE_IncreaseTrapCount:
|
||||||
|
if (new_bonus->trap_slots < effect_value)
|
||||||
|
new_bonus->trap_slots = effect_value;
|
||||||
|
break;
|
||||||
|
|
||||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||||
if (IsAISpellEffect) {
|
if (IsAISpellEffect) {
|
||||||
@ -4197,9 +4229,9 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
|||||||
{
|
{
|
||||||
for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++)
|
for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++)
|
||||||
{
|
{
|
||||||
spellbonuses.CritDmgMob[e] = effect_value;
|
spellbonuses.CritDmgMod[e] = effect_value;
|
||||||
aabonuses.CritDmgMob[e] = effect_value;
|
aabonuses.CritDmgMod[e] = effect_value;
|
||||||
itembonuses.CritDmgMob[e] = effect_value;
|
itembonuses.CritDmgMod[e] = effect_value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
28
zone/bot.cpp
28
zone/bot.cpp
@ -22,6 +22,7 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "doors.h"
|
#include "doors.h"
|
||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
|
#include "lua_parser.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/say_link.h"
|
#include "../common/say_link.h"
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
|
|||||||
GenerateBaseStats();
|
GenerateBaseStats();
|
||||||
// Calculate HitPoints Last As It Uses Base Stats
|
// Calculate HitPoints Last As It Uses Base Stats
|
||||||
cur_hp = GenerateBaseHitPoints();
|
cur_hp = GenerateBaseHitPoints();
|
||||||
cur_mana = GenerateBaseManaPoints();
|
current_mana = GenerateBaseManaPoints();
|
||||||
cur_end = CalcBaseEndurance();
|
cur_end = CalcBaseEndurance();
|
||||||
hp_regen = CalcHPRegen();
|
hp_regen = CalcHPRegen();
|
||||||
mana_regen = CalcManaRegen();
|
mana_regen = CalcManaRegen();
|
||||||
@ -128,7 +129,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
|||||||
_baseRace = npcTypeData.race;
|
_baseRace = npcTypeData.race;
|
||||||
_baseGender = npcTypeData.gender;
|
_baseGender = npcTypeData.gender;
|
||||||
cur_hp = npcTypeData.cur_hp;
|
cur_hp = npcTypeData.cur_hp;
|
||||||
cur_mana = npcTypeData.Mana;
|
current_mana = npcTypeData.Mana;
|
||||||
RestRegenHP = 0;
|
RestRegenHP = 0;
|
||||||
RestRegenMana = 0;
|
RestRegenMana = 0;
|
||||||
RestRegenEndurance = 0;
|
RestRegenEndurance = 0;
|
||||||
@ -205,8 +206,8 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
|||||||
SpellOnTarget(756, this); // Rezz effects
|
SpellOnTarget(756, this); // Rezz effects
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cur_mana > max_mana)
|
if(current_mana > max_mana)
|
||||||
cur_mana = max_mana;
|
current_mana = max_mana;
|
||||||
|
|
||||||
cur_end = max_end;
|
cur_end = max_end;
|
||||||
}
|
}
|
||||||
@ -2171,7 +2172,7 @@ void Bot::AI_Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(IsMoving())
|
if(IsMoving())
|
||||||
SendPosUpdate();
|
SendPositionUpdate();
|
||||||
else
|
else
|
||||||
SendPosition();
|
SendPosition();
|
||||||
}
|
}
|
||||||
@ -2382,7 +2383,7 @@ void Bot::AI_Process() {
|
|||||||
|
|
||||||
// TODO: Test RuleB(Bots, UpdatePositionWithTimer)
|
// TODO: Test RuleB(Bots, UpdatePositionWithTimer)
|
||||||
if(IsMoving())
|
if(IsMoving())
|
||||||
SendPosUpdate();
|
SendPositionUpdate();
|
||||||
else
|
else
|
||||||
SendPosition();
|
SendPosition();
|
||||||
}
|
}
|
||||||
@ -2504,7 +2505,7 @@ void Bot::AI_Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(IsMoving())
|
if(IsMoving())
|
||||||
SendPosUpdate();
|
SendPositionUpdate();
|
||||||
else
|
else
|
||||||
SendPosition();
|
SendPosition();
|
||||||
}
|
}
|
||||||
@ -2928,6 +2929,7 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
|
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
|
||||||
ns->spawn.helm = helmtexture; //(GetShowHelm() ? helmtexture : 0); //0xFF;
|
ns->spawn.helm = helmtexture; //(GetShowHelm() ? helmtexture : 0); //0xFF;
|
||||||
ns->spawn.equip_chest2 = texture; //0xFF;
|
ns->spawn.equip_chest2 = texture; //0xFF;
|
||||||
|
ns->spawn.show_name = true;
|
||||||
const EQEmu::ItemData* item = nullptr;
|
const EQEmu::ItemData* item = nullptr;
|
||||||
const EQEmu::ItemInstance* inst = nullptr;
|
const EQEmu::ItemInstance* inst = nullptr;
|
||||||
uint32 spawnedbotid = 0;
|
uint32 spawnedbotid = 0;
|
||||||
@ -3852,11 +3854,11 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, EQEmu::skills::SkillT
|
|||||||
}
|
}
|
||||||
|
|
||||||
//void Bot::AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false)
|
//void Bot::AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false)
|
||||||
void Bot::AddToHateList(Mob* other, uint32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
|
void Bot::AddToHateList(Mob* other, uint32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic, bool pet_command) {
|
||||||
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic);
|
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic, pet_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) {
|
bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) {
|
||||||
if (!other) {
|
if (!other) {
|
||||||
SetTarget(nullptr);
|
SetTarget(nullptr);
|
||||||
Log(Logs::General, Logs::Error, "A null Mob object was passed to Bot::Attack for evaluation!");
|
Log(Logs::General, Logs::Error, "A null Mob object was passed to Bot::Attack for evaluation!");
|
||||||
@ -3919,7 +3921,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
|
|||||||
// calculate attack_skill and skillinuse depending on hand and weapon
|
// calculate attack_skill and skillinuse depending on hand and weapon
|
||||||
// also send Packet to near clients
|
// also send Packet to near clients
|
||||||
DamageHitInfo my_hit;
|
DamageHitInfo my_hit;
|
||||||
AttackAnimation(my_hit.skill, Hand, weapon);
|
my_hit.skill = AttackAnimation(Hand, weapon);
|
||||||
Log(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, my_hit.skill);
|
Log(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, my_hit.skill);
|
||||||
|
|
||||||
// Now figure out damage
|
// Now figure out damage
|
||||||
@ -5556,8 +5558,8 @@ int32 Bot::CalcMaxMana() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cur_mana > max_mana)
|
if(current_mana > max_mana)
|
||||||
cur_mana = max_mana;
|
current_mana = max_mana;
|
||||||
else if(max_mana < 0)
|
else if(max_mana < 0)
|
||||||
max_mana = 0;
|
max_mana = 0;
|
||||||
|
|
||||||
|
|||||||
@ -325,7 +325,7 @@ public:
|
|||||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||||
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
||||||
void Camp(bool databaseSave = true);
|
void Camp(bool databaseSave = true);
|
||||||
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
|
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false, bool pet_command = false);
|
||||||
virtual void SetTarget(Mob* mob);
|
virtual void SetTarget(Mob* mob);
|
||||||
virtual void Zone();
|
virtual void Zone();
|
||||||
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }
|
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }
|
||||||
|
|||||||
288
zone/client.cpp
288
zone/client.cpp
@ -119,7 +119,6 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
//these must be listed in the order they appear in client.h
|
|
||||||
position_timer(250),
|
position_timer(250),
|
||||||
hpupdate_timer(2000),
|
hpupdate_timer(2000),
|
||||||
camp_timer(29000),
|
camp_timer(29000),
|
||||||
@ -158,10 +157,15 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
|
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
|
||||||
last_region_type(RegionTypeUnsupported),
|
last_region_type(RegionTypeUnsupported),
|
||||||
m_dirtyautohaters(false),
|
m_dirtyautohaters(false),
|
||||||
npc_close_scan_timer(6000)
|
npc_close_scan_timer(6000),
|
||||||
|
hp_self_update_throttle_timer(300),
|
||||||
|
hp_other_update_throttle_timer(500),
|
||||||
|
position_update_timer(10000)
|
||||||
{
|
{
|
||||||
for(int cf=0; cf < _FilterCount; cf++)
|
|
||||||
ClientFilters[cf] = FilterShow;
|
for (int client_filter = 0; client_filter < _FilterCount; client_filter++)
|
||||||
|
ClientFilters[client_filter] = FilterShow;
|
||||||
|
|
||||||
character_id = 0;
|
character_id = 0;
|
||||||
conn_state = NoPacketsReceived;
|
conn_state = NoPacketsReceived;
|
||||||
client_data_loaded = false;
|
client_data_loaded = false;
|
||||||
@ -190,8 +194,10 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
strcpy(account_name, "");
|
strcpy(account_name, "");
|
||||||
tellsoff = false;
|
tellsoff = false;
|
||||||
last_reported_mana = 0;
|
last_reported_mana = 0;
|
||||||
last_reported_endur = 0;
|
last_reported_endurance = 0;
|
||||||
gmhideme = false;
|
last_reported_endurance_percent = 0;
|
||||||
|
last_reported_mana_percent = 0;
|
||||||
|
gm_hide_me = false;
|
||||||
AFK = false;
|
AFK = false;
|
||||||
LFG = false;
|
LFG = false;
|
||||||
LFGFromLevel = 0;
|
LFGFromLevel = 0;
|
||||||
@ -255,7 +261,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
memset(&m_epp, 0, sizeof(m_epp));
|
memset(&m_epp, 0, sizeof(m_epp));
|
||||||
PendingTranslocate = false;
|
PendingTranslocate = false;
|
||||||
PendingSacrifice = false;
|
PendingSacrifice = false;
|
||||||
BoatID = 0;
|
controlling_boat_id = 0;
|
||||||
|
|
||||||
KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS));
|
KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS));
|
||||||
GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS));
|
GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS));
|
||||||
@ -268,7 +274,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
RestRegenMana = 0;
|
RestRegenMana = 0;
|
||||||
RestRegenEndurance = 0;
|
RestRegenEndurance = 0;
|
||||||
XPRate = 100;
|
XPRate = 100;
|
||||||
cur_end = 0;
|
current_endurance = 0;
|
||||||
|
|
||||||
m_TimeSinceLastPositionCheck = 0;
|
m_TimeSinceLastPositionCheck = 0;
|
||||||
m_DistanceSinceLastPositionCheck = 0.0f;
|
m_DistanceSinceLastPositionCheck = 0.0f;
|
||||||
@ -286,7 +292,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
HideCorpseMode = HideCorpseNone;
|
HideCorpseMode = HideCorpseNone;
|
||||||
PendingGuildInvitation = false;
|
PendingGuildInvitation = false;
|
||||||
|
|
||||||
cur_end = 0;
|
current_endurance = 0;
|
||||||
|
|
||||||
InitializeBuffSlots();
|
InitializeBuffSlots();
|
||||||
|
|
||||||
@ -357,7 +363,7 @@ Client::~Client() {
|
|||||||
m_tradeskill_object = nullptr;
|
m_tradeskill_object = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
close_npcs.clear();
|
close_mobs.clear();
|
||||||
|
|
||||||
if(IsDueling() && GetDuelTarget() != 0) {
|
if(IsDueling() && GetDuelTarget() != 0) {
|
||||||
Entity* entity = entity_list.GetID(GetDuelTarget());
|
Entity* entity = entity_list.GetID(GetDuelTarget());
|
||||||
@ -598,8 +604,8 @@ bool Client::Save(uint8 iCommitNow) {
|
|||||||
m_pp.cur_hp = GetHP();
|
m_pp.cur_hp = GetHP();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pp.mana = cur_mana;
|
m_pp.mana = current_mana;
|
||||||
m_pp.endurance = cur_end;
|
m_pp.endurance = current_endurance;
|
||||||
|
|
||||||
/* Save Character Currency */
|
/* Save Character Currency */
|
||||||
database.SaveCharacterCurrency(CharacterID(), &m_pp);
|
database.SaveCharacterCurrency(CharacterID(), &m_pp);
|
||||||
@ -697,12 +703,13 @@ bool Client::AddPacket(const EQApplicationPacket *pApp, bool bAckreq) {
|
|||||||
//drop the packet because it will never get sent.
|
//drop the packet because it will never get sent.
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
auto c = new CLIENTPACKET;
|
|
||||||
|
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
|
||||||
|
|
||||||
c->ack_req = bAckreq;
|
c->ack_req = bAckreq;
|
||||||
c->app = pApp->Copy();
|
c->app = pApp->Copy();
|
||||||
|
|
||||||
clientpackets.Append(c);
|
clientpackets.push_back(std::move(c));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,26 +721,23 @@ bool Client::AddPacket(EQApplicationPacket** pApp, bool bAckreq) {
|
|||||||
//drop the packet because it will never get sent.
|
//drop the packet because it will never get sent.
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
auto c = new CLIENTPACKET;
|
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
|
||||||
|
|
||||||
c->ack_req = bAckreq;
|
c->ack_req = bAckreq;
|
||||||
c->app = *pApp;
|
c->app = *pApp;
|
||||||
*pApp = nullptr;
|
*pApp = nullptr;
|
||||||
|
|
||||||
clientpackets.Append(c);
|
clientpackets.push_back(std::move(c));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::SendAllPackets() {
|
bool Client::SendAllPackets() {
|
||||||
LinkedListIterator<CLIENTPACKET*> iterator(clientpackets);
|
|
||||||
|
|
||||||
CLIENTPACKET* cp = nullptr;
|
CLIENTPACKET* cp = nullptr;
|
||||||
iterator.Reset();
|
while (!clientpackets.empty()) {
|
||||||
while(iterator.MoreElements()) {
|
cp = clientpackets.front().get();
|
||||||
cp = iterator.GetData();
|
|
||||||
if(eqs)
|
if(eqs)
|
||||||
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
|
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
|
||||||
iterator.RemoveCurrent();
|
clientpackets.pop_front();
|
||||||
Log(Logs::Moderate, Logs::Client_Server_Packet, "Transmitting a packet");
|
Log(Logs::Moderate, Logs::Client_Server_Packet, "Transmitting a packet");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1257,6 +1261,37 @@ void Client::Message(uint32 type, const char* message, ...) {
|
|||||||
safe_delete_array(buffer);
|
safe_delete_array(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...) {
|
||||||
|
if (!FilteredMessageCheck(sender, filter))
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_list argptr;
|
||||||
|
auto buffer = new char[4096];
|
||||||
|
va_start(argptr, message);
|
||||||
|
vsnprintf(buffer, 4096, message, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
size_t len = strlen(buffer);
|
||||||
|
|
||||||
|
//client dosent like our packet all the time unless
|
||||||
|
//we make it really big, then it seems to not care that
|
||||||
|
//our header is malformed.
|
||||||
|
//len = 4096 - sizeof(SpecialMesg_Struct);
|
||||||
|
|
||||||
|
uint32 len_packet = sizeof(SpecialMesg_Struct) + len;
|
||||||
|
auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet);
|
||||||
|
SpecialMesg_Struct* sm = (SpecialMesg_Struct*)app->pBuffer;
|
||||||
|
sm->header[0] = 0x00; // Header used for #emote style messages..
|
||||||
|
sm->header[1] = 0x00; // Play around with these to see other types
|
||||||
|
sm->header[2] = 0x00;
|
||||||
|
sm->msg_type = type;
|
||||||
|
memcpy(sm->message, buffer, len + 1);
|
||||||
|
|
||||||
|
FastQueuePacket(&app);
|
||||||
|
|
||||||
|
safe_delete_array(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::QuestJournalledMessage(const char *npcname, const char* message) {
|
void Client::QuestJournalledMessage(const char *npcname, const char* message) {
|
||||||
|
|
||||||
// npcnames longer than 60 characters crash the client when they log back in
|
// npcnames longer than 60 characters crash the client when they log back in
|
||||||
@ -1790,67 +1825,86 @@ const int32& Client::SetMana(int32 amount) {
|
|||||||
amount = 0;
|
amount = 0;
|
||||||
if (amount > GetMaxMana())
|
if (amount > GetMaxMana())
|
||||||
amount = GetMaxMana();
|
amount = GetMaxMana();
|
||||||
if (amount != cur_mana)
|
if (amount != current_mana)
|
||||||
update = true;
|
update = true;
|
||||||
cur_mana = amount;
|
current_mana = amount;
|
||||||
if (update)
|
if (update)
|
||||||
Mob::SetMana(amount);
|
Mob::SetMana(amount);
|
||||||
SendManaUpdatePacket();
|
CheckManaEndUpdate();
|
||||||
return cur_mana;
|
return current_mana;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendManaUpdatePacket() {
|
void Client::CheckManaEndUpdate() {
|
||||||
if (!Connected())
|
if (!Connected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
if (last_reported_mana != current_mana || last_reported_endurance != current_endurance) {
|
||||||
SendManaUpdate();
|
|
||||||
SendEnduranceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_reported_mana != cur_mana || last_reported_endur != cur_end) {
|
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
|
SendManaUpdate();
|
||||||
|
SendEnduranceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct));
|
auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct));
|
||||||
ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer;
|
ManaChange_Struct* mana_change = (ManaChange_Struct*)outapp->pBuffer;
|
||||||
manachange->new_mana = cur_mana;
|
mana_change->new_mana = current_mana;
|
||||||
manachange->stamina = cur_end;
|
mana_change->stamina = current_endurance;
|
||||||
manachange->spell_id = casting_spell_id;
|
mana_change->spell_id = casting_spell_id;
|
||||||
manachange->keepcasting = 1;
|
mana_change->keepcasting = 1;
|
||||||
outapp->priority = 6;
|
outapp->priority = 6;
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
Group *g = GetGroup();
|
/* Let others know when our mana percent has changed */
|
||||||
|
if (this->GetManaPercent() != last_reported_mana_percent) {
|
||||||
|
Group *group = this->GetGroup();
|
||||||
|
Raid *raid = this->GetRaid();
|
||||||
|
|
||||||
if(g)
|
if (raid) {
|
||||||
{
|
raid->SendManaPacketFrom(this);
|
||||||
outapp = new EQApplicationPacket(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
}
|
||||||
auto outapp2 =
|
else if (group) {
|
||||||
new EQApplicationPacket(OP_MobEnduranceUpdate, sizeof(MobEnduranceUpdate_Struct));
|
group->SendManaPacketFrom(this);
|
||||||
|
}
|
||||||
|
|
||||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp->pBuffer;
|
auto mana_packet = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct));
|
||||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp2->pBuffer;
|
ManaUpdate_Struct* mana_update = (ManaUpdate_Struct*)mana_packet->pBuffer;
|
||||||
|
mana_update->cur_mana = GetMana();
|
||||||
|
mana_update->max_mana = GetMaxMana();
|
||||||
|
mana_update->spawn_id = GetID();
|
||||||
|
QueuePacket(mana_packet);
|
||||||
|
entity_list.QueueClientsByXTarget(this, mana_packet, false);
|
||||||
|
safe_delete(mana_packet);
|
||||||
|
|
||||||
mmus->spawn_id = meus->spawn_id = GetID();
|
last_reported_mana_percent = this->GetManaPercent();
|
||||||
|
|
||||||
mmus->mana = GetManaPercent();
|
|
||||||
meus->endurance = GetEndurancePercent();
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
|
||||||
if (g->members[i] && g->members[i]->IsClient() && (g->members[i] != this) && (g->members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD))
|
|
||||||
{
|
|
||||||
g->members[i]->CastToClient()->QueuePacket(outapp);
|
|
||||||
g->members[i]->CastToClient()->QueuePacket(outapp2);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_delete(outapp);
|
|
||||||
safe_delete(outapp2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Let others know when our endurance percent has changed */
|
||||||
|
if (this->GetEndurancePercent() != last_reported_endurance_percent) {
|
||||||
|
Group *group = this->GetGroup();
|
||||||
|
Raid *raid = this->GetRaid();
|
||||||
|
|
||||||
last_reported_mana = cur_mana;
|
if (raid) {
|
||||||
last_reported_endur = cur_end;
|
raid->SendEndurancePacketFrom(this);
|
||||||
|
}
|
||||||
|
else if (group) {
|
||||||
|
group->SendEndurancePacketFrom(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||||
|
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
|
||||||
|
endurance_update->cur_end = GetEndurance();
|
||||||
|
endurance_update->max_end = GetMaxEndurance();
|
||||||
|
endurance_update->spawn_id = GetID();
|
||||||
|
QueuePacket(endurance_packet);
|
||||||
|
entity_list.QueueClientsByXTarget(this, endurance_packet, false);
|
||||||
|
safe_delete(endurance_packet);
|
||||||
|
|
||||||
|
last_reported_endurance_percent = this->GetEndurancePercent();
|
||||||
|
}
|
||||||
|
|
||||||
|
last_reported_mana = current_mana;
|
||||||
|
last_reported_endurance = current_endurance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1858,12 +1912,11 @@ void Client::SendManaUpdatePacket() {
|
|||||||
void Client::SendManaUpdate()
|
void Client::SendManaUpdate()
|
||||||
{
|
{
|
||||||
auto mana_app = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct));
|
auto mana_app = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct));
|
||||||
ManaUpdate_Struct* mus = (ManaUpdate_Struct*)mana_app->pBuffer;
|
ManaUpdate_Struct* mana_update = (ManaUpdate_Struct*)mana_app->pBuffer;
|
||||||
mus->cur_mana = GetMana();
|
mana_update->cur_mana = GetMana();
|
||||||
mus->max_mana = GetMaxMana();
|
mana_update->max_mana = GetMaxMana();
|
||||||
mus->spawn_id = GetID();
|
mana_update->spawn_id = GetID();
|
||||||
QueuePacket(mana_app);
|
QueuePacket(mana_app);
|
||||||
entity_list.QueueClientsByXTarget(this, mana_app, false);
|
|
||||||
safe_delete(mana_app);
|
safe_delete(mana_app);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1871,12 +1924,11 @@ void Client::SendManaUpdate()
|
|||||||
void Client::SendEnduranceUpdate()
|
void Client::SendEnduranceUpdate()
|
||||||
{
|
{
|
||||||
auto end_app = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
auto end_app = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||||
EnduranceUpdate_Struct* eus = (EnduranceUpdate_Struct*)end_app->pBuffer;
|
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)end_app->pBuffer;
|
||||||
eus->cur_end = GetEndurance();
|
endurance_update->cur_end = GetEndurance();
|
||||||
eus->max_end = GetMaxEndurance();
|
endurance_update->max_end = GetMaxEndurance();
|
||||||
eus->spawn_id = GetID();
|
endurance_update->spawn_id = GetID();
|
||||||
QueuePacket(end_app);
|
QueuePacket(end_app);
|
||||||
entity_list.QueueClientsByXTarget(this, end_app, false);
|
|
||||||
safe_delete(end_app);
|
safe_delete(end_app);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1892,6 +1944,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.guildID = GuildID();
|
ns->spawn.guildID = GuildID();
|
||||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||||
// ns->spawn.pvp = GetPVP() ? 1 : 0;
|
// ns->spawn.pvp = GetPVP() ? 1 : 0;
|
||||||
|
ns->spawn.show_name = true;
|
||||||
|
|
||||||
|
|
||||||
strcpy(ns->spawn.title, m_pp.title);
|
strcpy(ns->spawn.title, m_pp.title);
|
||||||
@ -1920,7 +1973,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Client::GMHideMe(Client* client) {
|
bool Client::GMHideMe(Client* client) {
|
||||||
if (gmhideme) {
|
if (gm_hide_me) {
|
||||||
if (client == 0)
|
if (client == 0)
|
||||||
return true;
|
return true;
|
||||||
else if (admin > client->Admin())
|
else if (admin > client->Admin())
|
||||||
@ -2339,7 +2392,9 @@ bool Client::CheckIncreaseSkill(EQEmu::skills::SkillType skillid, Mob *against_w
|
|||||||
return false;
|
return false;
|
||||||
int skillval = GetRawSkill(skillid);
|
int skillval = GetRawSkill(skillid);
|
||||||
int maxskill = GetMaxSkillAfterSpecializationRules(skillid, MaxSkill(skillid));
|
int maxskill = GetMaxSkillAfterSpecializationRules(skillid, MaxSkill(skillid));
|
||||||
|
char buffer[24] = { 0 };
|
||||||
|
snprintf(buffer, 23, "%d %d", skillid, skillval);
|
||||||
|
parse->EventPlayer(EVENT_USE_SKILL, this, buffer, 0);
|
||||||
if(against_who)
|
if(against_who)
|
||||||
{
|
{
|
||||||
if(against_who->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() ||
|
if(against_who->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() ||
|
||||||
@ -3187,9 +3242,9 @@ void Client::SetHideMe(bool flag)
|
|||||||
{
|
{
|
||||||
EQApplicationPacket app;
|
EQApplicationPacket app;
|
||||||
|
|
||||||
gmhideme = flag;
|
gm_hide_me = flag;
|
||||||
|
|
||||||
if(gmhideme)
|
if(gm_hide_me)
|
||||||
{
|
{
|
||||||
database.SetHideMe(AccountID(),true);
|
database.SetHideMe(AccountID(),true);
|
||||||
CreateDespawnPacket(&app, false);
|
CreateDespawnPacket(&app, false);
|
||||||
@ -3737,8 +3792,8 @@ void Client::SetEndurance(int32 newEnd)
|
|||||||
newEnd = GetMaxEndurance();
|
newEnd = GetMaxEndurance();
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_end = newEnd;
|
current_endurance = newEnd;
|
||||||
SendManaUpdatePacket();
|
CheckManaEndUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SacrificeConfirm(Client *caster)
|
void Client::SacrificeConfirm(Client *caster)
|
||||||
@ -3931,6 +3986,46 @@ void Client::SendPopupToClient(const char *Title, const char *Text, uint32 Popup
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::SendFullPopup(const char *Title, const char *Text, uint32 PopupID, uint32 NegativeID, uint32 Buttons, uint32 Duration, const char *ButtonName0, const char *ButtonName1, uint32 SoundControls) {
|
||||||
|
auto outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
|
||||||
|
OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *)outapp->pBuffer;
|
||||||
|
|
||||||
|
if((strlen(Text) > (sizeof(olms->Text)-1)) || (strlen(Title) > (sizeof(olms->Title) - 1)) ) {
|
||||||
|
safe_delete(outapp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ButtonName0 && ButtonName1 && ( (strlen(ButtonName0) > (sizeof(olms->ButtonName0) - 1)) || (strlen(ButtonName1) > (sizeof(olms->ButtonName1) - 1)) ) ) {
|
||||||
|
safe_delete(outapp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(olms->Title, Title);
|
||||||
|
strcpy(olms->Text, Text);
|
||||||
|
|
||||||
|
olms->Buttons = Buttons;
|
||||||
|
|
||||||
|
if (ButtonName0 == NULL || ButtonName1 == NULL) {
|
||||||
|
sprintf(olms->ButtonName0, "%s", "Yes");
|
||||||
|
sprintf(olms->ButtonName1, "%s", "No");
|
||||||
|
} else {
|
||||||
|
strcpy(olms->ButtonName0, ButtonName0);
|
||||||
|
strcpy(olms->ButtonName1, ButtonName1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Duration > 0)
|
||||||
|
olms->Duration = Duration * 1000;
|
||||||
|
else
|
||||||
|
olms->Duration = 0xffffffff;
|
||||||
|
|
||||||
|
olms->PopupID = PopupID;
|
||||||
|
olms->NegativeID = NegativeID;
|
||||||
|
olms->SoundControls = SoundControls;
|
||||||
|
|
||||||
|
QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...) {
|
void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...) {
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
@ -4171,7 +4266,7 @@ bool Client::GroupFollow(Client* inviter) {
|
|||||||
RemoveAutoXTargets();
|
RemoveAutoXTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetXTargetAutoMgr(GetXTargetAutoMgr());
|
SetXTargetAutoMgr(raid->GetXTargetAutoMgr());
|
||||||
if (!GetXTargetAutoMgr()->empty())
|
if (!GetXTargetAutoMgr()->empty())
|
||||||
SetDirtyAutoHaters();
|
SetDirtyAutoHaters();
|
||||||
|
|
||||||
@ -4304,7 +4399,7 @@ bool Client::GroupFollow(Client* inviter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
database.RefreshGroupFromDB(this);
|
database.RefreshGroupFromDB(this);
|
||||||
group->SendHPPacketsTo(this);
|
group->SendHPManaEndPacketsTo(this);
|
||||||
//send updates to clients out of zone...
|
//send updates to clients out of zone...
|
||||||
group->SendGroupJoinOOZ(this);
|
group->SendGroupJoinOOZ(this);
|
||||||
return true;
|
return true;
|
||||||
@ -5715,6 +5810,20 @@ void Client::SuspendMinion()
|
|||||||
Message_StringID(clientMessageTell, SUSPEND_MINION_UNSUSPEND, CurrentPet->GetCleanName());
|
Message_StringID(clientMessageTell, SUSPEND_MINION_UNSUSPEND, CurrentPet->GetCleanName());
|
||||||
|
|
||||||
memset(&m_suspendedminion, 0, sizeof(struct PetInfo));
|
memset(&m_suspendedminion, 0, sizeof(struct PetInfo));
|
||||||
|
// TODO: These pet command states need to be synced ...
|
||||||
|
// Will just fix them for now
|
||||||
|
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
|
||||||
|
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_STOP, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_REGROUP, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_FOLLOW, 1);
|
||||||
|
SetPetCommandState(PET_BUTTON_GUARD, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_TAUNT, 1);
|
||||||
|
SetPetCommandState(PET_BUTTON_HOLD, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_GHOLD, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_FOCUS, 0);
|
||||||
|
SetPetCommandState(PET_BUTTON_SPELLHOLD, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@ -6266,7 +6375,7 @@ void Client::LocateCorpse()
|
|||||||
SetHeading(CalculateHeadingToTarget(ClosestCorpse->GetX(), ClosestCorpse->GetY()));
|
SetHeading(CalculateHeadingToTarget(ClosestCorpse->GetX(), ClosestCorpse->GetY()));
|
||||||
SetTarget(ClosestCorpse);
|
SetTarget(ClosestCorpse);
|
||||||
SendTargetCommand(ClosestCorpse->GetID());
|
SendTargetCommand(ClosestCorpse->GetID());
|
||||||
SendPosUpdate(2);
|
SendPositionUpdate(2);
|
||||||
}
|
}
|
||||||
else if(!GetTarget())
|
else if(!GetTarget())
|
||||||
Message_StringID(clientMessageError, SENSE_CORPSE_NONE);
|
Message_StringID(clientMessageError, SENSE_CORPSE_NONE);
|
||||||
@ -8489,7 +8598,7 @@ void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool a
|
|||||||
|
|
||||||
if (type == EQEmu::item::ItemTypeFood)
|
if (type == EQEmu::item::ItemTypeFood)
|
||||||
{
|
{
|
||||||
int hchange = item->CastTime * cons_mod;
|
int hchange = item->CastTime_ * cons_mod;
|
||||||
hchange = mod_food_value(item, hchange);
|
hchange = mod_food_value(item, hchange);
|
||||||
|
|
||||||
if(hchange < 0) { return; }
|
if(hchange < 0) { return; }
|
||||||
@ -8506,7 +8615,7 @@ void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool a
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int tchange = item->CastTime * cons_mod;
|
int tchange = item->CastTime_ * cons_mod;
|
||||||
tchange = mod_drink_value(item, tchange);
|
tchange = mod_drink_value(item, tchange);
|
||||||
|
|
||||||
if(tchange < 0) { return; }
|
if(tchange < 0) { return; }
|
||||||
@ -8660,8 +8769,8 @@ void Client::SendHPUpdateMarquee(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Health Update Marquee Display: Custom*/
|
/* Health Update Marquee Display: Custom*/
|
||||||
uint32 health_percentage = (uint32)(this->cur_hp * 100 / this->max_hp);
|
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
|
||||||
if (health_percentage == 100)
|
if (health_percentage >= 100)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);
|
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);
|
||||||
@ -8937,3 +9046,12 @@ void Client::ProcessAggroMeter()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::SetPetCommandState(int button, int state)
|
||||||
|
{
|
||||||
|
auto app = new EQApplicationPacket(OP_PetCommandState, sizeof(PetCommandState_Struct));
|
||||||
|
auto pcs = (PetCommandState_Struct *)app->pBuffer;
|
||||||
|
pcs->button_id = button;
|
||||||
|
pcs->state = state;
|
||||||
|
FastQueuePacket(&app);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,6 +70,7 @@ namespace EQEmu
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
|
||||||
#define CLIENT_TIMEOUT 90000
|
#define CLIENT_TIMEOUT 90000
|
||||||
@ -221,7 +222,7 @@ public:
|
|||||||
Client(EQStreamInterface * ieqs);
|
Client(EQStreamInterface * ieqs);
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
std::unordered_map<NPC *, float> close_npcs;
|
std::unordered_map<Mob *, float> close_mobs;
|
||||||
bool is_client_moving;
|
bool is_client_moving;
|
||||||
|
|
||||||
//abstract virtual function implementations required by base abstract class
|
//abstract virtual function implementations required by base abstract class
|
||||||
@ -298,6 +299,7 @@ public:
|
|||||||
const char* GetBuyerWelcomeMessage() { return BuyerWelcomeMessage.c_str(); }
|
const char* GetBuyerWelcomeMessage() { return BuyerWelcomeMessage.c_str(); }
|
||||||
|
|
||||||
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||||
|
bool ShouldISpawnFor(Client *c) { return !GMHideMe(c) && !IsHoveringForRespawn(); }
|
||||||
virtual bool Process();
|
virtual bool Process();
|
||||||
void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemData* item, bool buying);
|
void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemData* item, bool buying);
|
||||||
void SendPacketQueue(bool Block = true);
|
void SendPacketQueue(bool Block = true);
|
||||||
@ -307,6 +309,7 @@ public:
|
|||||||
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, const char* message, ...);
|
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, const char* message, ...);
|
||||||
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
|
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
|
||||||
void Message(uint32 type, const char* message, ...);
|
void Message(uint32 type, const char* message, ...);
|
||||||
|
void FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...);
|
||||||
void QuestJournalledMessage(const char *npcname, const char* message);
|
void QuestJournalledMessage(const char *npcname, const char* message);
|
||||||
void VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber);
|
void VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber);
|
||||||
void SendSound();
|
void SendSound();
|
||||||
@ -318,7 +321,7 @@ public:
|
|||||||
bool GetRevoked() const { return revoked; }
|
bool GetRevoked() const { return revoked; }
|
||||||
void SetRevoked(bool rev) { revoked = rev; }
|
void SetRevoked(bool rev) { revoked = rev; }
|
||||||
inline uint32 GetIP() const { return ip; }
|
inline uint32 GetIP() const { return ip; }
|
||||||
inline bool GetHideMe() const { return gmhideme; }
|
inline bool GetHideMe() const { return gm_hide_me; }
|
||||||
void SetHideMe(bool hm);
|
void SetHideMe(bool hm);
|
||||||
inline uint16 GetPort() const { return port; }
|
inline uint16 GetPort() const { return port; }
|
||||||
bool IsDead() const { return(dead); }
|
bool IsDead() const { return(dead); }
|
||||||
@ -351,6 +354,8 @@ public:
|
|||||||
inline InspectMessage_Struct& GetInspectMessage() { return m_inspect_message; }
|
inline InspectMessage_Struct& GetInspectMessage() { return m_inspect_message; }
|
||||||
inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; }
|
inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; }
|
||||||
|
|
||||||
|
void SetPetCommandState(int button, int state);
|
||||||
|
|
||||||
bool CheckAccess(int16 iDBLevel, int16 iDefaultLevel);
|
bool CheckAccess(int16 iDBLevel, int16 iDefaultLevel);
|
||||||
|
|
||||||
void CheckQuests(const char* zonename, const char* message, uint32 npc_id, uint32 item_id, Mob* other);
|
void CheckQuests(const char* zonename, const char* message, uint32 npc_id, uint32 item_id, Mob* other);
|
||||||
@ -536,11 +541,11 @@ public:
|
|||||||
void CalcMaxEndurance(); //This calculates the maximum endurance we can have
|
void CalcMaxEndurance(); //This calculates the maximum endurance we can have
|
||||||
int32 CalcBaseEndurance(); //Calculates Base End
|
int32 CalcBaseEndurance(); //Calculates Base End
|
||||||
int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
|
int32 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
|
||||||
int32 GetEndurance() const {return cur_end;} //This gets our current endurance
|
int32 GetEndurance() const {return current_endurance;} //This gets our current endurance
|
||||||
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
int32 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
||||||
int32 CalcEnduranceRegenCap();
|
int32 CalcEnduranceRegenCap();
|
||||||
int32 CalcHPRegenCap();
|
int32 CalcHPRegenCap();
|
||||||
inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
|
inline uint8 GetEndurancePercent() { return (uint8)((float)current_endurance / (float)max_end * 100.0f); }
|
||||||
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
|
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
|
||||||
void DoEnduranceRegen(); //This Regenerates endurance
|
void DoEnduranceRegen(); //This Regenerates endurance
|
||||||
void DoEnduranceUpkeep(); //does the endurance upkeep
|
void DoEnduranceUpkeep(); //does the endurance upkeep
|
||||||
@ -567,6 +572,7 @@ public:
|
|||||||
void AddCrystals(uint32 Radiant, uint32 Ebon);
|
void AddCrystals(uint32 Radiant, uint32 Ebon);
|
||||||
void SendCrystalCounts();
|
void SendCrystalCounts();
|
||||||
|
|
||||||
|
uint32 GetExperienceForKill(Mob *against);
|
||||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||||
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
||||||
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
||||||
@ -656,7 +662,7 @@ public:
|
|||||||
void RefreshGuildInfo();
|
void RefreshGuildInfo();
|
||||||
|
|
||||||
|
|
||||||
void SendManaUpdatePacket();
|
void CheckManaEndUpdate();
|
||||||
void SendManaUpdate();
|
void SendManaUpdate();
|
||||||
void SendEnduranceUpdate();
|
void SendEnduranceUpdate();
|
||||||
uint8 GetFace() const { return m_pp.face; }
|
uint8 GetFace() const { return m_pp.face; }
|
||||||
@ -792,12 +798,12 @@ public:
|
|||||||
void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); }
|
void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); }
|
||||||
int GetAAPoints() { return m_pp.aapoints; }
|
int GetAAPoints() { return m_pp.aapoints; }
|
||||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||||
|
uint32 GetRequiredAAExperience();
|
||||||
|
|
||||||
//old AA methods that we still use
|
//old AA methods that we still use
|
||||||
void ResetAA();
|
void ResetAA();
|
||||||
void RefundAA();
|
void RefundAA();
|
||||||
void SendClearAA();
|
void SendClearAA();
|
||||||
inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
|
|
||||||
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
||||||
inline uint32 GetAAPercent() const { return m_epp.perAA; }
|
inline uint32 GetAAPercent() const { return m_epp.perAA; }
|
||||||
int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
|
int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
|
||||||
@ -942,6 +948,7 @@ public:
|
|||||||
inline bool HasSpellScribed(int spellid) { return (FindSpellBookSlotBySpellID(spellid) != -1 ? true : false); }
|
inline bool HasSpellScribed(int spellid) { return (FindSpellBookSlotBySpellID(spellid) != -1 ? true : false); }
|
||||||
uint16 GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skillid, uint16 maxSkill);
|
uint16 GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skillid, uint16 maxSkill);
|
||||||
void SendPopupToClient(const char *Title, const char *Text, uint32 PopupID = 0, uint32 Buttons = 0, uint32 Duration = 0);
|
void SendPopupToClient(const char *Title, const char *Text, uint32 PopupID = 0, uint32 Buttons = 0, uint32 Duration = 0);
|
||||||
|
void SendFullPopup(const char *Title, const char *Text, uint32 PopupID = 0, uint32 NegativeID = 0, uint32 Buttons = 0, uint32 Duration = 0, const char *ButtonName0 = 0, const char *ButtonName1 = 0, uint32 SoundControls = 0);
|
||||||
void SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...);
|
void SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...);
|
||||||
bool PendingTranslocate;
|
bool PendingTranslocate;
|
||||||
time_t TranslocateTime;
|
time_t TranslocateTime;
|
||||||
@ -1066,7 +1073,7 @@ public:
|
|||||||
void Signal(uint32 data);
|
void Signal(uint32 data);
|
||||||
Mob *GetBindSightTarget() { return bind_sight_target; }
|
Mob *GetBindSightTarget() { return bind_sight_target; }
|
||||||
void SetBindSightTarget(Mob *n) { bind_sight_target = n; }
|
void SetBindSightTarget(Mob *n) { bind_sight_target = n; }
|
||||||
const uint16 GetBoatID() const { return BoatID; }
|
const uint16 GetBoatID() const { return controlling_boat_id; }
|
||||||
void SendRewards();
|
void SendRewards();
|
||||||
bool TryReward(uint32 claim_id);
|
bool TryReward(uint32 claim_id);
|
||||||
QGlobalCache *GetQGlobals() { return qGlobals; }
|
QGlobalCache *GetQGlobals() { return qGlobals; }
|
||||||
@ -1257,6 +1264,8 @@ public:
|
|||||||
|
|
||||||
void CheckRegionTypeChanges();
|
void CheckRegionTypeChanges();
|
||||||
|
|
||||||
|
int32 CalcATK();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mob;
|
friend class Mob;
|
||||||
void CalcItemBonuses(StatBonuses* newbon);
|
void CalcItemBonuses(StatBonuses* newbon);
|
||||||
@ -1316,7 +1325,6 @@ private:
|
|||||||
|
|
||||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
||||||
|
|
||||||
int32 CalcATK();
|
|
||||||
int32 CalcItemATKCap();
|
int32 CalcItemATKCap();
|
||||||
int32 CalcHaste();
|
int32 CalcHaste();
|
||||||
|
|
||||||
@ -1369,7 +1377,7 @@ private:
|
|||||||
bool duelaccepted;
|
bool duelaccepted;
|
||||||
std::list<uint32> keyring;
|
std::list<uint32> keyring;
|
||||||
bool tellsoff; // GM /toggle
|
bool tellsoff; // GM /toggle
|
||||||
bool gmhideme;
|
bool gm_hide_me;
|
||||||
bool LFG;
|
bool LFG;
|
||||||
bool LFP;
|
bool LFP;
|
||||||
uint8 LFGFromLevel;
|
uint8 LFGFromLevel;
|
||||||
@ -1389,7 +1397,7 @@ private:
|
|||||||
uint32 weight;
|
uint32 weight;
|
||||||
bool berserk;
|
bool berserk;
|
||||||
bool dead;
|
bool dead;
|
||||||
uint16 BoatID;
|
uint16 controlling_boat_id;
|
||||||
uint16 TrackingID;
|
uint16 TrackingID;
|
||||||
uint16 CustomerID;
|
uint16 CustomerID;
|
||||||
uint16 TraderID;
|
uint16 TraderID;
|
||||||
@ -1404,7 +1412,7 @@ private:
|
|||||||
int Haste; //precalced value
|
int Haste; //precalced value
|
||||||
|
|
||||||
int32 max_end;
|
int32 max_end;
|
||||||
int32 cur_end;
|
int32 current_endurance;
|
||||||
|
|
||||||
PlayerProfile_Struct m_pp;
|
PlayerProfile_Struct m_pp;
|
||||||
ExtendedProfile_Struct m_epp;
|
ExtendedProfile_Struct m_epp;
|
||||||
@ -1424,7 +1432,7 @@ private:
|
|||||||
bool AddPacket(const EQApplicationPacket *, bool);
|
bool AddPacket(const EQApplicationPacket *, bool);
|
||||||
bool AddPacket(EQApplicationPacket**, bool);
|
bool AddPacket(EQApplicationPacket**, bool);
|
||||||
bool SendAllPackets();
|
bool SendAllPackets();
|
||||||
LinkedList<CLIENTPACKET *> clientpackets;
|
std::deque<std::unique_ptr<CLIENTPACKET>> clientpackets;
|
||||||
|
|
||||||
//Zoning related stuff
|
//Zoning related stuff
|
||||||
void SendZoneCancel(ZoneChange_Struct *zc);
|
void SendZoneCancel(ZoneChange_Struct *zc);
|
||||||
@ -1478,7 +1486,9 @@ private:
|
|||||||
Timer helm_toggle_timer;
|
Timer helm_toggle_timer;
|
||||||
Timer aggro_meter_timer;
|
Timer aggro_meter_timer;
|
||||||
Timer npc_close_scan_timer;
|
Timer npc_close_scan_timer;
|
||||||
|
Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */
|
||||||
|
Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */
|
||||||
|
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||||
glm::vec3 m_Proximity;
|
glm::vec3 m_Proximity;
|
||||||
|
|
||||||
void BulkSendInventoryItems();
|
void BulkSendInventoryItems();
|
||||||
@ -1487,7 +1497,6 @@ private:
|
|||||||
|
|
||||||
uint32 tribute_master_id;
|
uint32 tribute_master_id;
|
||||||
|
|
||||||
uint32 max_AAXP;
|
|
||||||
bool npcflag;
|
bool npcflag;
|
||||||
uint8 npclevel;
|
uint8 npclevel;
|
||||||
bool feigned;
|
bool feigned;
|
||||||
@ -1495,7 +1504,10 @@ private:
|
|||||||
bool tgb;
|
bool tgb;
|
||||||
bool instalog;
|
bool instalog;
|
||||||
int32 last_reported_mana;
|
int32 last_reported_mana;
|
||||||
int32 last_reported_endur;
|
int32 last_reported_endurance;
|
||||||
|
|
||||||
|
int8 last_reported_mana_percent;
|
||||||
|
int8 last_reported_endurance_percent;
|
||||||
|
|
||||||
unsigned int AggroCount; // How many mobs are aggro on us.
|
unsigned int AggroCount; // How many mobs are aggro on us.
|
||||||
|
|
||||||
|
|||||||
@ -1046,14 +1046,14 @@ int32 Client::CalcMaxMana()
|
|||||||
if (max_mana < 0) {
|
if (max_mana < 0) {
|
||||||
max_mana = 0;
|
max_mana = 0;
|
||||||
}
|
}
|
||||||
if (cur_mana > max_mana) {
|
if (current_mana > max_mana) {
|
||||||
cur_mana = max_mana;
|
current_mana = max_mana;
|
||||||
}
|
}
|
||||||
int mana_perc_cap = spellbonuses.ManaPercCap[0];
|
int mana_perc_cap = spellbonuses.ManaPercCap[0];
|
||||||
if (mana_perc_cap) {
|
if (mana_perc_cap) {
|
||||||
int curMana_cap = (max_mana * mana_perc_cap) / 100;
|
int curMana_cap = (max_mana * mana_perc_cap) / 100;
|
||||||
if (cur_mana > curMana_cap || (spellbonuses.ManaPercCap[1] && cur_mana > spellbonuses.ManaPercCap[1])) {
|
if (current_mana > curMana_cap || (spellbonuses.ManaPercCap[1] && current_mana > spellbonuses.ManaPercCap[1])) {
|
||||||
cur_mana = curMana_cap;
|
current_mana = curMana_cap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log(Logs::Detail, Logs::Spells, "Client::CalcMaxMana() called for %s - returning %d", GetName(), max_mana);
|
Log(Logs::Detail, Logs::Spells, "Client::CalcMaxMana() called for %s - returning %d", GetName(), max_mana);
|
||||||
@ -2034,14 +2034,14 @@ void Client::CalcMaxEndurance()
|
|||||||
if (max_end < 0) {
|
if (max_end < 0) {
|
||||||
max_end = 0;
|
max_end = 0;
|
||||||
}
|
}
|
||||||
if (cur_end > max_end) {
|
if (current_endurance > max_end) {
|
||||||
cur_end = max_end;
|
current_endurance = max_end;
|
||||||
}
|
}
|
||||||
int end_perc_cap = spellbonuses.EndPercCap[0];
|
int end_perc_cap = spellbonuses.EndPercCap[0];
|
||||||
if (end_perc_cap) {
|
if (end_perc_cap) {
|
||||||
int curEnd_cap = (max_end * end_perc_cap) / 100;
|
int curEnd_cap = (max_end * end_perc_cap) / 100;
|
||||||
if (cur_end > curEnd_cap || (spellbonuses.EndPercCap[1] && cur_end > spellbonuses.EndPercCap[1])) {
|
if (current_endurance > curEnd_cap || (spellbonuses.EndPercCap[1] && current_endurance > spellbonuses.EndPercCap[1])) {
|
||||||
cur_end = curEnd_cap;
|
current_endurance = curEnd_cap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -236,6 +236,7 @@
|
|||||||
void Handle_OP_RecipesSearch(const EQApplicationPacket *app);
|
void Handle_OP_RecipesSearch(const EQApplicationPacket *app);
|
||||||
void Handle_OP_ReloadUI(const EQApplicationPacket *app);
|
void Handle_OP_ReloadUI(const EQApplicationPacket *app);
|
||||||
void Handle_OP_RemoveBlockedBuffs(const EQApplicationPacket *app);
|
void Handle_OP_RemoveBlockedBuffs(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_RemoveTrap(const EQApplicationPacket *app);
|
||||||
void Handle_OP_Report(const EQApplicationPacket *app);
|
void Handle_OP_Report(const EQApplicationPacket *app);
|
||||||
void Handle_OP_RequestDuel(const EQApplicationPacket *app);
|
void Handle_OP_RequestDuel(const EQApplicationPacket *app);
|
||||||
void Handle_OP_RequestTitles(const EQApplicationPacket *app);
|
void Handle_OP_RequestTitles(const EQApplicationPacket *app);
|
||||||
@ -288,6 +289,7 @@
|
|||||||
void Handle_OP_TributeNPC(const EQApplicationPacket *app);
|
void Handle_OP_TributeNPC(const EQApplicationPacket *app);
|
||||||
void Handle_OP_TributeToggle(const EQApplicationPacket *app);
|
void Handle_OP_TributeToggle(const EQApplicationPacket *app);
|
||||||
void Handle_OP_TributeUpdate(const EQApplicationPacket *app);
|
void Handle_OP_TributeUpdate(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_UpdateAura(const EQApplicationPacket *app);
|
||||||
void Handle_OP_VetClaimRequest(const EQApplicationPacket *app);
|
void Handle_OP_VetClaimRequest(const EQApplicationPacket *app);
|
||||||
void Handle_OP_VoiceMacroIn(const EQApplicationPacket *app);
|
void Handle_OP_VoiceMacroIn(const EQApplicationPacket *app);
|
||||||
void Handle_OP_WearChange(const EQApplicationPacket *app);
|
void Handle_OP_WearChange(const EQApplicationPacket *app);
|
||||||
|
|||||||
@ -63,64 +63,49 @@ extern EntityList entity_list;
|
|||||||
bool Client::Process() {
|
bool Client::Process() {
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
if (Connected() || IsLD())
|
if (Connected() || IsLD()) {
|
||||||
{
|
|
||||||
// try to send all packets that weren't sent before
|
// try to send all packets that weren't sent before
|
||||||
if (!IsLD() && zoneinpacket_timer.Check())
|
if (!IsLD() && zoneinpacket_timer.Check()) {
|
||||||
{
|
|
||||||
SendAllPackets();
|
SendAllPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_request_timer)
|
if (adventure_request_timer) {
|
||||||
{
|
if (adventure_request_timer->Check()) {
|
||||||
if (adventure_request_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_request_timer);
|
safe_delete(adventure_request_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_create_timer)
|
if (adventure_create_timer) {
|
||||||
{
|
if (adventure_create_timer->Check()) {
|
||||||
if (adventure_create_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_create_timer);
|
safe_delete(adventure_create_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_leave_timer)
|
if (adventure_leave_timer) {
|
||||||
{
|
if (adventure_leave_timer->Check()) {
|
||||||
if (adventure_leave_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_leave_timer);
|
safe_delete(adventure_leave_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_door_timer)
|
if (adventure_door_timer) {
|
||||||
{
|
if (adventure_door_timer->Check()) {
|
||||||
if (adventure_door_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_door_timer);
|
safe_delete(adventure_door_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_stats_timer)
|
if (adventure_stats_timer) {
|
||||||
{
|
if (adventure_stats_timer->Check()) {
|
||||||
if (adventure_stats_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_stats_timer);
|
safe_delete(adventure_stats_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adventure_leaderboard_timer)
|
if (adventure_leaderboard_timer) {
|
||||||
{
|
if (adventure_leaderboard_timer->Check()) {
|
||||||
if (adventure_leaderboard_timer->Check())
|
|
||||||
{
|
|
||||||
safe_delete(adventure_leaderboard_timer);
|
safe_delete(adventure_leaderboard_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dead)
|
if (dead) {
|
||||||
{
|
|
||||||
SetHP(-100);
|
SetHP(-100);
|
||||||
if (RespawnFromHoverTimer.Check())
|
if (RespawnFromHoverTimer.Check())
|
||||||
HandleRespawnFromHover(0);
|
HandleRespawnFromHover(0);
|
||||||
@ -134,8 +119,13 @@ bool Client::Process() {
|
|||||||
if (hpupdate_timer.Check(false))
|
if (hpupdate_timer.Check(false))
|
||||||
SendHPUpdate();
|
SendHPUpdate();
|
||||||
|
|
||||||
|
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||||
|
if (!is_client_moving && position_update_timer.Check()) {
|
||||||
|
SendPositionUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
if (mana_timer.Check())
|
if (mana_timer.Check())
|
||||||
SendManaUpdatePacket();
|
CheckManaEndUpdate();
|
||||||
|
|
||||||
if (dead && dead_timer.Check()) {
|
if (dead && dead_timer.Check()) {
|
||||||
database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId));
|
database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId));
|
||||||
@ -254,19 +244,22 @@ bool Client::Process() {
|
|||||||
/* Build a close range list of NPC's */
|
/* Build a close range list of NPC's */
|
||||||
if (npc_close_scan_timer.Check()) {
|
if (npc_close_scan_timer.Check()) {
|
||||||
|
|
||||||
close_npcs.clear();
|
close_mobs.clear();
|
||||||
|
|
||||||
auto &npc_list = entity_list.GetNPCList();
|
auto &mob_list = entity_list.GetMobList();
|
||||||
|
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
||||||
|
float client_update_range = (RuleI(Range, MobPositionUpdates) * RuleI(Range, MobPositionUpdates));
|
||||||
|
|
||||||
float scan_range = RuleI(Range, ClientNPCScan);
|
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||||
for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) {
|
Mob* mob = itr->second;
|
||||||
NPC* npc = itr->second;
|
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
||||||
float distance = DistanceNoZ(m_Position, npc->GetPosition());
|
if (mob->IsNPC()) {
|
||||||
if(distance <= scan_range) {
|
if (distance <= scan_range) {
|
||||||
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
}
|
}
|
||||||
else if (npc->GetAggroRange() > scan_range) {
|
else if (mob->GetAggroRange() > scan_range) {
|
||||||
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,14 +441,14 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
animation = 0;
|
animation = 0;
|
||||||
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
||||||
SendPosUpdate(2);
|
SendPositionUpdate(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a position packet every 8 seconds - if not done, other clients
|
// Send a position packet every 8 seconds - if not done, other clients
|
||||||
// see this char disappear after 10-12 seconds of inactivity
|
// see this char disappear after 10-12 seconds of inactivity
|
||||||
if (position_timer_counter >= 36) { // Approx. 4 ticks per second
|
if (position_timer_counter >= 36) { // Approx. 4 ticks per second
|
||||||
entity_list.SendPositionUpdates(this, pLastUpdateWZ, 500, GetTarget(), true);
|
entity_list.SendPositionUpdates(this, pLastUpdateWZ, RuleI(Range, MobPositionUpdates), GetTarget(), true);
|
||||||
pLastUpdate = Timer::GetCurrentTime();
|
pLastUpdate = Timer::GetCurrentTime();
|
||||||
pLastUpdateWZ = pLastUpdate;
|
pLastUpdateWZ = pLastUpdate;
|
||||||
position_timer_counter = 0;
|
position_timer_counter = 0;
|
||||||
@ -619,11 +612,17 @@ bool Client::Process() {
|
|||||||
// only if client is not feigned
|
// only if client is not feigned
|
||||||
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
|
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
|
||||||
int npc_scan_count = 0;
|
int npc_scan_count = 0;
|
||||||
for (auto it = close_npcs.begin(); it != close_npcs.end(); ++it) {
|
for (auto it = close_mobs.begin(); it != close_mobs.end(); ++it) {
|
||||||
NPC *npc = it->first;
|
Mob *mob = it->first;
|
||||||
|
|
||||||
if (npc->CheckWillAggro(this) && !npc->CheckAggro(this)) {
|
if (!mob)
|
||||||
npc->AddToHateList(this, 25);
|
continue;
|
||||||
|
|
||||||
|
if (mob->IsClient())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
|
||||||
|
mob->AddToHateList(this, 25);
|
||||||
}
|
}
|
||||||
npc_scan_count++;
|
npc_scan_count++;
|
||||||
}
|
}
|
||||||
@ -724,6 +723,8 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoveAllAuras();
|
||||||
|
|
||||||
Mob *Other = trade->With();
|
Mob *Other = trade->With();
|
||||||
if(Other)
|
if(Other)
|
||||||
{
|
{
|
||||||
@ -985,8 +986,6 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
|||||||
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName(), handyitem->Name);
|
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName(), handyitem->Name);
|
||||||
else
|
else
|
||||||
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName());
|
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName());
|
||||||
|
|
||||||
merch->CastToNPC()->FaceTarget(this->CastToMob());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// safe_delete_array(cpi);
|
// safe_delete_array(cpi);
|
||||||
@ -1816,7 +1815,7 @@ void Client::DoManaRegen() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
||||||
SendManaUpdatePacket();
|
CheckManaEndUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -173,6 +173,7 @@ int command_init(void)
|
|||||||
command_add("checklos", "- Check for line of sight to your target", 50, command_checklos) ||
|
command_add("checklos", "- Check for line of sight to your target", 50, command_checklos) ||
|
||||||
command_add("clearinvsnapshots", "[use rule] - Clear inventory snapshot history (true - elapsed entries, false - all entries)", 200, command_clearinvsnapshots) ||
|
command_add("clearinvsnapshots", "[use rule] - Clear inventory snapshot history (true - elapsed entries, false - all entries)", 200, command_clearinvsnapshots) ||
|
||||||
command_add("corpse", "- Manipulate corpses, use with no arguments for help", 50, command_corpse) ||
|
command_add("corpse", "- Manipulate corpses, use with no arguments for help", 50, command_corpse) ||
|
||||||
|
command_add("corpsefix", "Attempts to bring corpses from underneath the ground within close proximity of the player", 0, command_corpsefix) ||
|
||||||
command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) ||
|
command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) ||
|
||||||
command_add("cvs", "- Summary of client versions currently online.", 200, command_cvs) ||
|
command_add("cvs", "- Summary of client versions currently online.", 200, command_cvs) ||
|
||||||
command_add("damage", "[amount] - Damage your target", 100, command_damage) ||
|
command_add("damage", "[amount] - Damage your target", 100, command_damage) ||
|
||||||
@ -2977,6 +2978,11 @@ void command_reloadqst(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_corpsefix(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
entity_list.CorpseFix(c);
|
||||||
|
}
|
||||||
|
|
||||||
void command_reloadworld(Client *c, const Seperator *sep)
|
void command_reloadworld(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
c->Message(0, "Reloading quest cache and repopping zones worldwide.");
|
c->Message(0, "Reloading quest cache and repopping zones worldwide.");
|
||||||
@ -7191,7 +7197,7 @@ void command_ginfo(Client *c, const Seperator *sep)
|
|||||||
void command_hp(Client *c, const Seperator *sep)
|
void command_hp(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
c->SendHPUpdate();
|
c->SendHPUpdate();
|
||||||
c->SendManaUpdatePacket();
|
c->CheckManaEndUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_aggro(Client *c, const Seperator *sep)
|
void command_aggro(Client *c, const Seperator *sep)
|
||||||
@ -8734,9 +8740,9 @@ void command_object(Client *c, const Seperator *sep)
|
|||||||
// Verify no other objects already in this spot (accidental double-click of Hotkey?)
|
// Verify no other objects already in this spot (accidental double-click of Hotkey?)
|
||||||
query = StringFormat(
|
query = StringFormat(
|
||||||
"SELECT COUNT(*) FROM object WHERE zoneid = %u "
|
"SELECT COUNT(*) FROM object WHERE zoneid = %u "
|
||||||
"AND version=%u AND (posx BETWEEN %.1f AND %.1f) "
|
"AND version=%u AND (xpos BETWEEN %.1f AND %.1f) "
|
||||||
"AND (posy BETWEEN %.1f AND %.1f) "
|
"AND (ypos BETWEEN %.1f AND %.1f) "
|
||||||
"AND (posz BETWEEN %.1f AND %.1f)",
|
"AND (zpos BETWEEN %.1f AND %.1f)",
|
||||||
zone->GetZoneID(), zone->GetInstanceVersion(), od.x - 0.2f,
|
zone->GetZoneID(), zone->GetInstanceVersion(), od.x - 0.2f,
|
||||||
od.x + 0.2f, // Yes, we're actually using a bounding box instead of a radius.
|
od.x + 0.2f, // Yes, we're actually using a bounding box instead of a radius.
|
||||||
od.y - 0.2f, od.y + 0.2f, // Much less processing power used this way.
|
od.y - 0.2f, od.y + 0.2f, // Much less processing power used this way.
|
||||||
|
|||||||
@ -72,6 +72,7 @@ void command_checklos(Client *c, const Seperator *sep);
|
|||||||
void command_clearinvsnapshots(Client *c, const Seperator *sep);
|
void command_clearinvsnapshots(Client *c, const Seperator *sep);
|
||||||
void command_connectworldserver(Client *c, const Seperator *sep);
|
void command_connectworldserver(Client *c, const Seperator *sep);
|
||||||
void command_corpse(Client *c, const Seperator *sep);
|
void command_corpse(Client *c, const Seperator *sep);
|
||||||
|
void command_corpsefix(Client *c, const Seperator *sep);
|
||||||
void command_crashtest(Client *c, const Seperator *sep);
|
void command_crashtest(Client *c, const Seperator *sep);
|
||||||
void command_cvs(Client *c, const Seperator *sep);
|
void command_cvs(Client *c, const Seperator *sep);
|
||||||
void command_d1(Client *c, const Seperator *sep);
|
void command_d1(Client *c, const Seperator *sep);
|
||||||
|
|||||||
@ -56,6 +56,57 @@
|
|||||||
//Maximum distance from a zone point if zone was specified
|
//Maximum distance from a zone point if zone was specified
|
||||||
#define ZONEPOINT_ZONE_RANGE 40000.0f
|
#define ZONEPOINT_ZONE_RANGE 40000.0f
|
||||||
|
|
||||||
|
// Defines based on the RoF2 Client
|
||||||
|
#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window
|
||||||
|
#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window
|
||||||
|
#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window
|
||||||
|
#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window
|
||||||
|
#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window
|
||||||
|
#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window
|
||||||
|
#define PET_SIT 6 // 0x06 - /pet sit or Pet Window
|
||||||
|
#define PET_SITDOWN 7 // 0x07 - /pet sit on
|
||||||
|
#define PET_STANDUP 8 // 0x08 - /pet sit off
|
||||||
|
#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented
|
||||||
|
#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented
|
||||||
|
#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented
|
||||||
|
#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window
|
||||||
|
#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on
|
||||||
|
#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off
|
||||||
|
#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window, won't add to hate list unless attacking
|
||||||
|
#define PET_HOLD_ON 16 // 0x10 - /pet hold on
|
||||||
|
#define PET_HOLD_OFF 17 // 0x11 - /pet hold off
|
||||||
|
#define PET_GHOLD 18 // 0x12 - /pet ghold, will never add to hate list unless told to
|
||||||
|
#define PET_GHOLD_ON 19 // 0x13 - /pet ghold on
|
||||||
|
#define PET_GHOLD_OFF 20 // 0x14 - /pet ghold off
|
||||||
|
#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window
|
||||||
|
#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on
|
||||||
|
#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off
|
||||||
|
#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window
|
||||||
|
#define PET_FOCUS_ON 25 // 0x19 - /pet focus on
|
||||||
|
#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off
|
||||||
|
#define PET_FEIGN 27 // 0x1b - /pet feign
|
||||||
|
#define PET_BACKOFF 28 // 0x1c - /pet back off
|
||||||
|
#define PET_GETLOST 29 // 0x1d - /pet get lost
|
||||||
|
#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client /pet target in modern clients but doesn't send packet
|
||||||
|
#define PET_REGROUP 31 // 0x1f - /pet regroup, acts like classic hold. Stops attack and moves back to guard/you but doesn't clear hate list
|
||||||
|
#define PET_REGROUP_ON 32 // 0x20 - /pet regroup on, turns on regroup
|
||||||
|
#define PET_REGROUP_OFF 33 // 0x21 - /pet regroup off, turns off regroup
|
||||||
|
#define PET_MAXCOMMANDS PET_REGROUP_OFF + 1
|
||||||
|
|
||||||
|
// can change the state of these buttons with a packet
|
||||||
|
#define PET_BUTTON_SIT 0
|
||||||
|
#define PET_BUTTON_STOP 1
|
||||||
|
#define PET_BUTTON_REGROUP 2
|
||||||
|
#define PET_BUTTON_FOLLOW 3
|
||||||
|
#define PET_BUTTON_GUARD 4
|
||||||
|
#define PET_BUTTON_TAUNT 5
|
||||||
|
#define PET_BUTTON_HOLD 6
|
||||||
|
#define PET_BUTTON_GHOLD 7
|
||||||
|
#define PET_BUTTON_FOCUS 8
|
||||||
|
#define PET_BUTTON_SPELLHOLD 9
|
||||||
|
|
||||||
|
#define AURA_HARDCAP 2
|
||||||
|
|
||||||
typedef enum { //focus types
|
typedef enum { //focus types
|
||||||
focusSpellHaste = 1,
|
focusSpellHaste = 1,
|
||||||
focusSpellDuration,
|
focusSpellDuration,
|
||||||
@ -156,6 +207,16 @@ typedef enum { //fear states
|
|||||||
|
|
||||||
enum { FlyMode0 = 0, FlyMode1 = 1, Flymode2 = 2, FlyMode3 = 3 };
|
enum { FlyMode0 = 0, FlyMode1 = 1, Flymode2 = 2, FlyMode3 = 3 };
|
||||||
|
|
||||||
|
// This is actually FlyMode, from MQ2
|
||||||
|
enum GravityBehavior {
|
||||||
|
Ground,
|
||||||
|
Flying,
|
||||||
|
Levitating,
|
||||||
|
Water,
|
||||||
|
Floating, // boat
|
||||||
|
LevitateWhileRunning
|
||||||
|
};
|
||||||
|
|
||||||
struct TradeEntity;
|
struct TradeEntity;
|
||||||
class Trade;
|
class Trade;
|
||||||
enum TradeState {
|
enum TradeState {
|
||||||
@ -359,7 +420,7 @@ struct StatBonuses {
|
|||||||
uint32 SpellTriggers[MAX_SPELL_TRIGGER]; // Innate/Spell/Item Spells that trigger when you cast
|
uint32 SpellTriggers[MAX_SPELL_TRIGGER]; // Innate/Spell/Item Spells that trigger when you cast
|
||||||
uint32 SpellOnKill[MAX_SPELL_TRIGGER*3]; // Chance to proc after killing a mob
|
uint32 SpellOnKill[MAX_SPELL_TRIGGER*3]; // Chance to proc after killing a mob
|
||||||
uint32 SpellOnDeath[MAX_SPELL_TRIGGER*2]; // Chance to have effect cast when you die
|
uint32 SpellOnDeath[MAX_SPELL_TRIGGER*2]; // Chance to have effect cast when you die
|
||||||
int32 CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
int32 CritDmgMod[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
||||||
int32 SkillReuseTime[EQEmu::skills::HIGHEST_SKILL + 1]; // Reduces skill timers
|
int32 SkillReuseTime[EQEmu::skills::HIGHEST_SKILL + 1]; // Reduces skill timers
|
||||||
int32 SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
int32 SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
||||||
int32 TwoHandBluntBlock; // chance to block when wielding two hand blunt weapon
|
int32 TwoHandBluntBlock; // chance to block when wielding two hand blunt weapon
|
||||||
@ -485,6 +546,10 @@ struct StatBonuses {
|
|||||||
uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill.
|
uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill.
|
||||||
int16 NoBreakAESneak; // Percent value
|
int16 NoBreakAESneak; // Percent value
|
||||||
int16 FeignedCastOnChance; // Percent Value
|
int16 FeignedCastOnChance; // Percent Value
|
||||||
|
bool PetCommands[PET_MAXCOMMANDS]; // SPA 267
|
||||||
|
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
|
||||||
|
int aura_slots;
|
||||||
|
int trap_slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
119
zone/effects.cpp
119
zone/effects.cpp
@ -356,67 +356,15 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
|
|||||||
cost -= mana_back;
|
cost -= mana_back;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This formula was derived from the following resource:
|
int spec = GetSpecializeSkillValue(spell_id);
|
||||||
// http://www.eqsummoners.com/eq1/specialization-library.html
|
int PercentManaReduction = 0;
|
||||||
// WildcardX
|
if (spec)
|
||||||
float PercentManaReduction = 0;
|
PercentManaReduction = 1 + spec / 20; // there seems to be some non-obvious rounding here, let's truncate for now.
|
||||||
float SpecializeSkill = GetSpecializeSkillValue(spell_id);
|
|
||||||
int SuccessChance = zone->random.Int(0, 100);
|
|
||||||
|
|
||||||
float bonus = 1.0;
|
|
||||||
switch(GetAA(aaSpellCastingMastery))
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
bonus += 0.05;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
bonus += 0.15;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
bonus += 0.30;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bonus += 0.05f * GetAA(aaAdvancedSpellCastingMastery);
|
|
||||||
|
|
||||||
if(SuccessChance <= (SpecializeSkill * 0.3 * bonus))
|
|
||||||
{
|
|
||||||
PercentManaReduction = 1 + 0.05f * SpecializeSkill;
|
|
||||||
switch(GetAA(aaSpellCastingMastery))
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
PercentManaReduction += 2.5;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
PercentManaReduction += 5.0;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
PercentManaReduction += 10.0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(GetAA(aaAdvancedSpellCastingMastery))
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
PercentManaReduction += 2.5;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
PercentManaReduction += 5.0;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
PercentManaReduction += 10.0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);
|
int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);
|
||||||
|
PercentManaReduction += focus_redux;
|
||||||
|
|
||||||
if(focus_redux > 0)
|
cost -= cost * PercentManaReduction / 100;
|
||||||
{
|
|
||||||
PercentManaReduction += zone->random.Real(1, (double)focus_redux);
|
|
||||||
}
|
|
||||||
|
|
||||||
cost -= (cost * (PercentManaReduction / 100));
|
|
||||||
|
|
||||||
// Gift of Mana - reduces spell cost to 1 mana
|
// Gift of Mana - reduces spell cost to 1 mana
|
||||||
if(focus_redux >= 100) {
|
if(focus_redux >= 100) {
|
||||||
@ -746,7 +694,7 @@ void EntityList::AETaunt(Client* taunter, float range, int32 bonus_hate)
|
|||||||
// causes caster to hit every mob within dist range of center with
|
// causes caster to hit every mob within dist range of center with
|
||||||
// spell_id.
|
// spell_id.
|
||||||
// NPC spells will only affect other NPCs with compatible faction
|
// NPC spells will only affect other NPCs with compatible faction
|
||||||
void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust)
|
void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust, int *max_targets)
|
||||||
{
|
{
|
||||||
Mob *curmob = nullptr;
|
Mob *curmob = nullptr;
|
||||||
|
|
||||||
@ -755,12 +703,25 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
||||||
float dist_targ = 0;
|
float dist_targ = 0;
|
||||||
|
|
||||||
|
const auto &position = spells[spell_id].targettype == ST_Ring ? caster->GetTargetRingLocation() : static_cast<glm::vec3>(center->GetPosition());
|
||||||
|
glm::vec2 min = { position.x - dist, position.y - dist };
|
||||||
|
glm::vec2 max = { position.x + dist, position.y + dist };
|
||||||
|
|
||||||
bool bad = IsDetrimentalSpell(spell_id);
|
bool bad = IsDetrimentalSpell(spell_id);
|
||||||
bool isnpc = caster->IsNPC();
|
bool isnpc = caster->IsNPC();
|
||||||
int MAX_TARGETS_ALLOWED = 4;
|
|
||||||
|
|
||||||
if (spells[spell_id].aemaxtargets)
|
if (RuleB(Spells, OldRainTargets))
|
||||||
MAX_TARGETS_ALLOWED = spells[spell_id].aemaxtargets;
|
max_targets = nullptr; // ignore it!
|
||||||
|
|
||||||
|
// if we have a passed in value, use it, otherwise default to data
|
||||||
|
// detrimental Target AEs have a default value of 4 for PCs and unlimited for NPCs
|
||||||
|
int max_targets_allowed = 0; // unlimited
|
||||||
|
if (max_targets) // rains pass this in since they need to preserve the count through waves
|
||||||
|
max_targets_allowed = *max_targets;
|
||||||
|
else if (spells[spell_id].aemaxtargets)
|
||||||
|
max_targets_allowed = spells[spell_id].aemaxtargets;
|
||||||
|
else if (IsTargetableAESpell(spell_id) && bad && !isnpc)
|
||||||
|
max_targets_allowed = 4;
|
||||||
|
|
||||||
int iCounter = 0;
|
int iCounter = 0;
|
||||||
|
|
||||||
@ -769,8 +730,6 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
// test to fix possible cause of random zone crashes..external methods accessing client properties before they're initialized
|
// test to fix possible cause of random zone crashes..external methods accessing client properties before they're initialized
|
||||||
if (curmob->IsClient() && !curmob->CastToClient()->ClientFinishedLoading())
|
if (curmob->IsClient() && !curmob->CastToClient()->ClientFinishedLoading())
|
||||||
continue;
|
continue;
|
||||||
if (curmob == center) //do not affect center
|
|
||||||
continue;
|
|
||||||
if (curmob == caster && !affect_caster) //watch for caster too
|
if (curmob == caster && !affect_caster) //watch for caster too
|
||||||
continue;
|
continue;
|
||||||
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && curmob->IsPetOwnerClient())
|
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && curmob->IsPetOwnerClient())
|
||||||
@ -784,13 +743,10 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
continue;
|
continue;
|
||||||
if (spells[spell_id].pcnpc_only_flag == 2 && (curmob->IsClient() || curmob->IsMerc()))
|
if (spells[spell_id].pcnpc_only_flag == 2 && (curmob->IsClient() || curmob->IsMerc()))
|
||||||
continue;
|
continue;
|
||||||
|
if (!IsWithinAxisAlignedBox(static_cast<glm::vec2>(curmob->GetPosition()), min, max))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (spells[spell_id].targettype == ST_Ring) {
|
dist_targ = DistanceSquared(curmob->GetPosition(), position);
|
||||||
dist_targ = DistanceSquared(static_cast<glm::vec3>(curmob->GetPosition()), caster->GetTargetRingLocation());
|
|
||||||
}
|
|
||||||
else if (center) {
|
|
||||||
dist_targ = DistanceSquared(curmob->GetPosition(), center->GetPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dist_targ > dist2) //make sure they are in range
|
if (dist_targ > dist2) //make sure they are in range
|
||||||
continue;
|
continue;
|
||||||
@ -813,7 +769,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
if (bad) {
|
if (bad) {
|
||||||
if (!caster->IsAttackAllowed(curmob, true))
|
if (!caster->IsAttackAllowed(curmob, true))
|
||||||
continue;
|
continue;
|
||||||
if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob))
|
if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob))
|
||||||
continue;
|
continue;
|
||||||
if (!center && !spells[spell_id].npc_no_los && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize()))
|
if (!center && !spells[spell_id].npc_no_los && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize()))
|
||||||
continue;
|
continue;
|
||||||
@ -828,22 +784,17 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
}
|
}
|
||||||
|
|
||||||
curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||||
|
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||||
|
|
||||||
//if we get here... cast the spell.
|
if (max_targets_allowed) { // if we have a limit, increment count
|
||||||
if (IsTargetableAESpell(spell_id) && bad) {
|
|
||||||
if (iCounter < MAX_TARGETS_ALLOWED) {
|
|
||||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
|
||||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
|
||||||
if (!spells[spell_id].aemaxtargets)
|
|
||||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isnpc || spells[spell_id].aemaxtargets) //npcs are not target limited (unless casting a spell with a target limit)...
|
|
||||||
iCounter++;
|
iCounter++;
|
||||||
|
if (iCounter >= max_targets_allowed) // we done
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_targets && max_targets_allowed)
|
||||||
|
*max_targets = *max_targets - iCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster)
|
void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster)
|
||||||
|
|||||||
@ -117,6 +117,7 @@ const char *QuestEventSubroutines[_LargestEventID] = {
|
|||||||
"EVENT_TICK",
|
"EVENT_TICK",
|
||||||
"EVENT_SPAWN_ZONE",
|
"EVENT_SPAWN_ZONE",
|
||||||
"EVENT_DEATH_ZONE",
|
"EVENT_DEATH_ZONE",
|
||||||
|
"EVENT_USE_SKILL",
|
||||||
};
|
};
|
||||||
|
|
||||||
PerlembParser::PerlembParser() : perl(nullptr) {
|
PerlembParser::PerlembParser() : perl(nullptr) {
|
||||||
@ -1441,6 +1442,12 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
|||||||
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
|
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_USE_SKILL:{
|
||||||
|
Seperator sep(data);
|
||||||
|
ExportVar(package_name.c_str(), "skill_id", sep.arg[0]);
|
||||||
|
ExportVar(package_name.c_str(), "skill_level", sep.arg[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -3599,6 +3599,24 @@ XS(XS__crosszonesetentityvariablebynpctypeid)
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS__crosszonesetentityvariablebyclientname);
|
||||||
|
XS(XS__crosszonesetentityvariablebyclientname)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
|
||||||
|
if (items != 3)
|
||||||
|
Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebyclientname(clientname, id, m_var)");
|
||||||
|
|
||||||
|
if (items == 3) {
|
||||||
|
const char *clientname = (const char *)SvPV_nolen(ST(0));
|
||||||
|
const char *id = (const char *)SvPV_nolen(ST(1));
|
||||||
|
const char *m_var = (const char *)SvPV_nolen(ST(2));
|
||||||
|
quest_manager.CrossZoneSetEntityVariableByClientName(clientname, id, m_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
XS(XS__crosszonesignalnpcbynpctypeid);
|
XS(XS__crosszonesignalnpcbynpctypeid);
|
||||||
XS(XS__crosszonesignalnpcbynpctypeid)
|
XS(XS__crosszonesignalnpcbynpctypeid)
|
||||||
{
|
{
|
||||||
@ -3766,6 +3784,7 @@ EXTERN_C XS(boot_quest)
|
|||||||
newXS(strcpy(buf, "createguild"), XS__createguild, file);
|
newXS(strcpy(buf, "createguild"), XS__createguild, file);
|
||||||
newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file);
|
newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file);
|
||||||
newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file);
|
newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file);
|
||||||
|
newXS(strcpy(buf, "crosszonesetentityvariablebyclientname"), XS__crosszonesetentityvariablebyclientname, file);
|
||||||
newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file);
|
newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file);
|
||||||
newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file);
|
newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file);
|
||||||
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
|
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
|
||||||
|
|||||||
112
zone/entity.cpp
112
zone/entity.cpp
@ -659,6 +659,8 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
|||||||
QueueClients(npc, app);
|
QueueClients(npc, app);
|
||||||
npc->SendArmorAppearance();
|
npc->SendArmorAppearance();
|
||||||
npc->SetAppearance(npc->GetGuardPointAnim(),false);
|
npc->SetAppearance(npc->GetGuardPointAnim(),false);
|
||||||
|
if (!npc->IsTargetable())
|
||||||
|
npc->SendTargetable(false);
|
||||||
safe_delete(app);
|
safe_delete(app);
|
||||||
} else {
|
} else {
|
||||||
auto ns = new NewSpawn_Struct;
|
auto ns = new NewSpawn_Struct;
|
||||||
@ -799,6 +801,8 @@ void EntityList::CheckSpawnQueue()
|
|||||||
NPC *pnpc = it->second;
|
NPC *pnpc = it->second;
|
||||||
pnpc->SendArmorAppearance();
|
pnpc->SendArmorAppearance();
|
||||||
pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false);
|
pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false);
|
||||||
|
if (!pnpc->IsTargetable())
|
||||||
|
pnpc->SendTargetable(false);
|
||||||
}
|
}
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
iterator.RemoveCurrent();
|
iterator.RemoveCurrent();
|
||||||
@ -1242,12 +1246,9 @@ void EntityList::SendZoneSpawns(Client *client)
|
|||||||
auto it = mob_list.begin();
|
auto it = mob_list.begin();
|
||||||
while (it != mob_list.end()) {
|
while (it != mob_list.end()) {
|
||||||
Mob *ent = it->second;
|
Mob *ent = it->second;
|
||||||
if (!(ent->InZone()) || (ent->IsClient())) {
|
if (!ent->InZone() || !ent->ShouldISpawnFor(client)) {
|
||||||
if (ent->CastToClient()->GMHideMe(client) ||
|
++it;
|
||||||
ent->CastToClient()->IsHoveringForRespawn()) {
|
continue;
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app = new EQApplicationPacket;
|
app = new EQApplicationPacket;
|
||||||
@ -1275,17 +1276,16 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
|||||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||||
spawn = it->second;
|
spawn = it->second;
|
||||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||||
if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) ||
|
if (!spawn->ShouldISpawnFor(client))
|
||||||
spawn->CastToClient()->IsHoveringForRespawn()))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
const glm::vec4& spos = spawn->GetPosition();
|
const glm::vec4& spos = spawn->GetPosition();
|
||||||
|
|
||||||
delaypkt = false;
|
delaypkt = false;
|
||||||
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
||||||
delaypkt = true;
|
delaypkt = true;
|
||||||
|
|
||||||
if (delaypkt) {
|
if (delaypkt) {
|
||||||
app = new EQApplicationPacket;
|
app = new EQApplicationPacket;
|
||||||
spawn->CreateSpawnPacket(app);
|
spawn->CreateSpawnPacket(app);
|
||||||
@ -2135,6 +2135,25 @@ void EntityList::MessageClose(Mob* sender, bool skipsender, float dist, uint32 t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityList::FilteredMessageClose(Mob *sender, bool skipsender, float dist, uint32 type, eqFilterType filter, const char *message, ...)
|
||||||
|
{
|
||||||
|
va_list argptr;
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
va_start(argptr, message);
|
||||||
|
vsnprintf(buffer, 4095, message, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
float dist2 = dist * dist;
|
||||||
|
|
||||||
|
auto it = client_list.begin();
|
||||||
|
while (it != client_list.end()) {
|
||||||
|
if (DistanceSquared(it->second->GetPosition(), sender->GetPosition()) <= dist2 && (!skipsender || it->second != sender))
|
||||||
|
it->second->FilteredMessage(sender, type, filter, buffer);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EntityList::RemoveAllMobs()
|
void EntityList::RemoveAllMobs()
|
||||||
{
|
{
|
||||||
auto it = mob_list.begin();
|
auto it = mob_list.begin();
|
||||||
@ -2263,6 +2282,9 @@ bool EntityList::RemoveMob(uint16 delete_id)
|
|||||||
|
|
||||||
auto it = mob_list.find(delete_id);
|
auto it = mob_list.find(delete_id);
|
||||||
if (it != mob_list.end()) {
|
if (it != mob_list.end()) {
|
||||||
|
|
||||||
|
RemoveMobFromClientCloseLists(it->second);
|
||||||
|
|
||||||
if (npc_list.count(delete_id))
|
if (npc_list.count(delete_id))
|
||||||
entity_list.RemoveNPC(delete_id);
|
entity_list.RemoveNPC(delete_id);
|
||||||
else if (client_list.count(delete_id))
|
else if (client_list.count(delete_id))
|
||||||
@ -2285,6 +2307,8 @@ bool EntityList::RemoveMob(Mob *delete_mob)
|
|||||||
auto it = mob_list.begin();
|
auto it = mob_list.begin();
|
||||||
while (it != mob_list.end()) {
|
while (it != mob_list.end()) {
|
||||||
if (it->second == delete_mob) {
|
if (it->second == delete_mob) {
|
||||||
|
RemoveMobFromClientCloseLists(it->second);
|
||||||
|
|
||||||
safe_delete(it->second);
|
safe_delete(it->second);
|
||||||
if (!corpse_list.count(it->first))
|
if (!corpse_list.count(it->first))
|
||||||
free_ids.push(it->first);
|
free_ids.push(it->first);
|
||||||
@ -2304,10 +2328,9 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
|||||||
// make sure its proximity is removed
|
// make sure its proximity is removed
|
||||||
RemoveProximity(delete_id);
|
RemoveProximity(delete_id);
|
||||||
// remove from client close lists
|
// remove from client close lists
|
||||||
RemoveNPCFromClientCloseLists(npc);
|
RemoveMobFromClientCloseLists(npc->CastToMob());
|
||||||
// remove from the list
|
// remove from the list
|
||||||
npc_list.erase(it);
|
npc_list.erase(it);
|
||||||
|
|
||||||
|
|
||||||
// remove from limit list if needed
|
// remove from limit list if needed
|
||||||
if (npc_limit_list.count(delete_id))
|
if (npc_limit_list.count(delete_id))
|
||||||
@ -2317,11 +2340,11 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityList::RemoveNPCFromClientCloseLists(NPC *npc)
|
bool EntityList::RemoveMobFromClientCloseLists(Mob *mob)
|
||||||
{
|
{
|
||||||
auto it = client_list.begin();
|
auto it = client_list.begin();
|
||||||
while (it != client_list.end()) {
|
while (it != client_list.end()) {
|
||||||
it->second->close_npcs.erase(npc);
|
it->second->close_mobs.erase(mob);
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -2615,10 +2638,9 @@ void EntityList::RemoveDebuffs(Mob *caster)
|
|||||||
// Currently, a new packet is sent per entity.
|
// Currently, a new packet is sent per entity.
|
||||||
// @todo: Come back and use FLAG_COMBINED to pack
|
// @todo: Come back and use FLAG_COMBINED to pack
|
||||||
// all updates into one packet.
|
// all updates into one packet.
|
||||||
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate,
|
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate, float update_range, Entity *always_send, bool iSendEvenIfNotChanged)
|
||||||
float range, Entity *alwayssend, bool iSendEvenIfNotChanged)
|
|
||||||
{
|
{
|
||||||
range = range * range;
|
update_range = (update_range * update_range);
|
||||||
|
|
||||||
EQApplicationPacket *outapp = 0;
|
EQApplicationPacket *outapp = 0;
|
||||||
PlayerPositionUpdateServer_Struct *ppu = 0;
|
PlayerPositionUpdateServer_Struct *ppu = 0;
|
||||||
@ -2626,27 +2648,37 @@ void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate,
|
|||||||
|
|
||||||
auto it = mob_list.begin();
|
auto it = mob_list.begin();
|
||||||
while (it != mob_list.end()) {
|
while (it != mob_list.end()) {
|
||||||
if (outapp == 0) {
|
|
||||||
outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
|
||||||
ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
|
|
||||||
}
|
|
||||||
mob = it->second;
|
mob = it->second;
|
||||||
if (mob && !mob->IsCorpse() && (it->second != client)
|
|
||||||
|
if (
|
||||||
|
mob && !mob->IsCorpse()
|
||||||
|
&& (it->second != client)
|
||||||
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
|
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
|
||||||
&& (!it->second->IsClient() || !it->second->CastToClient()->GMHideMe(client))) {
|
&& (it->second->ShouldISpawnFor(client))
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
update_range == 0
|
||||||
|
|| (it->second == always_send)
|
||||||
|
|| mob->IsClient()
|
||||||
|
|| (DistanceSquared(mob->GetPosition(), client->GetPosition()) <= update_range)
|
||||||
|
) {
|
||||||
|
if (mob && mob->IsClient() && mob->GetID() > 0) {
|
||||||
|
client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||||
|
|
||||||
//bool Grouped = client->HasGroup() && mob->IsClient() && (client->GetGroup() == mob->CastToClient()->GetGroup());
|
if (outapp == 0) {
|
||||||
|
outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
//if (range == 0 || (iterator.GetData() == alwayssend) || Grouped || (mob->DistNoRootNoZ(*client) <= range)) {
|
mob->MakeSpawnUpdate(ppu);
|
||||||
if (range == 0 || (it->second == alwayssend) || mob->IsClient() || (DistanceSquared(mob->GetPosition(), client->GetPosition()) <= range)) {
|
|
||||||
mob->MakeSpawnUpdate(ppu);
|
safe_delete(outapp);
|
||||||
}
|
outapp = 0;
|
||||||
if(mob && mob->IsClient() && mob->GetID()>0) {
|
}
|
||||||
client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
safe_delete(outapp);
|
|
||||||
outapp = 0;
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2826,6 +2858,22 @@ int32 EntityList::DeleteNPCCorpses()
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityList::CorpseFix(Client* c)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto it = corpse_list.begin();
|
||||||
|
while (it != corpse_list.end()) {
|
||||||
|
Corpse* corpse = it->second;
|
||||||
|
if (corpse->IsNPCCorpse()) {
|
||||||
|
if (DistanceNoZ(c->GetPosition(), corpse->GetPosition()) < 100) {
|
||||||
|
c->Message(15, "Attempting to fix %s", it->second->GetCleanName());
|
||||||
|
corpse->GMMove(corpse->GetX(), corpse->GetY(), c->GetZ() + 2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns the number of corpses deleted. A negative number indicates an error code.
|
// returns the number of corpses deleted. A negative number indicates an error code.
|
||||||
int32 EntityList::DeletePlayerCorpses()
|
int32 EntityList::DeletePlayerCorpses()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -79,6 +79,8 @@ public:
|
|||||||
virtual bool IsTrap() const { return false; }
|
virtual bool IsTrap() const { return false; }
|
||||||
virtual bool IsBeacon() const { return false; }
|
virtual bool IsBeacon() const { return false; }
|
||||||
virtual bool IsEncounter() const { return false; }
|
virtual bool IsEncounter() const { return false; }
|
||||||
|
virtual bool IsBot() const { return false; }
|
||||||
|
virtual bool IsAura() const { return false; }
|
||||||
|
|
||||||
virtual bool Process() { return false; }
|
virtual bool Process() { return false; }
|
||||||
virtual bool Save() { return true; }
|
virtual bool Save() { return true; }
|
||||||
@ -113,7 +115,6 @@ public:
|
|||||||
bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1);
|
bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1);
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
virtual bool IsBot() const { return false; }
|
|
||||||
Bot* CastToBot();
|
Bot* CastToBot();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -279,7 +280,7 @@ public:
|
|||||||
bool RemoveTrap(uint16 delete_id);
|
bool RemoveTrap(uint16 delete_id);
|
||||||
bool RemoveObject(uint16 delete_id);
|
bool RemoveObject(uint16 delete_id);
|
||||||
bool RemoveProximity(uint16 delete_npc_id);
|
bool RemoveProximity(uint16 delete_npc_id);
|
||||||
bool RemoveNPCFromClientCloseLists(NPC *npc);
|
bool RemoveMobFromClientCloseLists(Mob *mob);
|
||||||
void RemoveAllMobs();
|
void RemoveAllMobs();
|
||||||
void RemoveAllClients();
|
void RemoveAllClients();
|
||||||
void RemoveAllNPCs();
|
void RemoveAllNPCs();
|
||||||
@ -315,6 +316,7 @@ public:
|
|||||||
void Message(uint32 to_guilddbid, uint32 type, const char* message, ...);
|
void Message(uint32 to_guilddbid, uint32 type, const char* message, ...);
|
||||||
void MessageStatus(uint32 to_guilddbid, int to_minstatus, uint32 type, const char* message, ...);
|
void MessageStatus(uint32 to_guilddbid, int to_minstatus, uint32 type, const char* message, ...);
|
||||||
void MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...);
|
void MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...);
|
||||||
|
void FilteredMessageClose(Mob* sender, bool skipsender, float dist, uint32 type, eqFilterType filter, const char* message, ...);
|
||||||
void Message_StringID(Mob *sender, bool skipsender, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
void Message_StringID(Mob *sender, bool skipsender, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||||
void FilteredMessage_StringID(Mob *sender, bool skipsender, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
void FilteredMessage_StringID(Mob *sender, bool skipsender, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||||
void MessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
void MessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||||
@ -356,7 +358,7 @@ public:
|
|||||||
|
|
||||||
void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false);
|
void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false);
|
||||||
void AETaunt(Client *caster, float range=0, int32 bonus_hate=0);
|
void AETaunt(Client *caster, float range=0, int32 bonus_hate=0);
|
||||||
void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0);
|
void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0, int *max_targets = nullptr);
|
||||||
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
||||||
void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
||||||
|
|
||||||
@ -369,7 +371,7 @@ public:
|
|||||||
Mob* FindDefenseNPC(uint32 npcid);
|
Mob* FindDefenseNPC(uint32 npcid);
|
||||||
void OpenDoorsNear(NPC* opener);
|
void OpenDoorsNear(NPC* opener);
|
||||||
void UpdateWho(bool iSendFullUpdate = false);
|
void UpdateWho(bool iSendFullUpdate = false);
|
||||||
void SendPositionUpdates(Client* client, uint32 cLastUpdate = 0, float range = 0, Entity* alwayssend = 0, bool iSendEvenIfNotChanged = false);
|
void SendPositionUpdates(Client* client, uint32 cLastUpdate = 0, float update_range = 0, Entity* always_send = 0, bool iSendEvenIfNotChanged = false);
|
||||||
char* MakeNameUnique(char* name);
|
char* MakeNameUnique(char* name);
|
||||||
static char* RemoveNumbers(char* name);
|
static char* RemoveNumbers(char* name);
|
||||||
void SignalMobsByNPCID(uint32 npc_type, int signal_id);
|
void SignalMobsByNPCID(uint32 npc_type, int signal_id);
|
||||||
@ -385,6 +387,7 @@ public:
|
|||||||
void FindPathsToAllNPCs();
|
void FindPathsToAllNPCs();
|
||||||
int32 DeleteNPCCorpses();
|
int32 DeleteNPCCorpses();
|
||||||
int32 DeletePlayerCorpses();
|
int32 DeletePlayerCorpses();
|
||||||
|
void CorpseFix(Client* c);
|
||||||
void WriteEntityIDs();
|
void WriteEntityIDs();
|
||||||
void HalveAggro(Mob* who);
|
void HalveAggro(Mob* who);
|
||||||
void DoubleAggro(Mob* who);
|
void DoubleAggro(Mob* who);
|
||||||
|
|||||||
@ -85,6 +85,7 @@ typedef enum {
|
|||||||
EVENT_TICK,
|
EVENT_TICK,
|
||||||
EVENT_SPAWN_ZONE,
|
EVENT_SPAWN_ZONE,
|
||||||
EVENT_DEATH_ZONE,
|
EVENT_DEATH_ZONE,
|
||||||
|
EVENT_USE_SKILL,
|
||||||
_LargestEventID
|
_LargestEventID
|
||||||
} QuestEventID;
|
} QuestEventID;
|
||||||
|
|
||||||
|
|||||||
66
zone/exp.cpp
66
zone/exp.cpp
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "queryserv.h"
|
#include "queryserv.h"
|
||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
|
#include "lua_parser.h"
|
||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
@ -153,6 +154,26 @@ uint32 Client::CalcEXP(uint8 conlevel) {
|
|||||||
return in_add_exp;
|
return in_add_exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Client::GetExperienceForKill(Mob *against)
|
||||||
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
uint32 lua_ret = 0;
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
lua_ret = LuaParser::Instance()->GetExperienceForKill(this, against, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return lua_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (against && against->IsNPC()) {
|
||||||
|
uint32 level = (uint32)against->GetLevel();
|
||||||
|
return EXP_FORMULA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||||
|
|
||||||
this->EVENT_ITEM_ScriptStopReturn();
|
this->EVENT_ITEM_ScriptStopReturn();
|
||||||
@ -339,8 +360,8 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
|||||||
|
|
||||||
void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||||
Log(Logs::Detail, Logs::None, "Attempting to Set Exp for %s (XP: %u, AAXP: %u, Rez: %s)", this->GetCleanName(), set_exp, set_aaxp, isrezzexp ? "true" : "false");
|
Log(Logs::Detail, Logs::None, "Attempting to Set Exp for %s (XP: %u, AAXP: %u, Rez: %s)", this->GetCleanName(), set_exp, set_aaxp, isrezzexp ? "true" : "false");
|
||||||
//max_AAXP = GetEXPForLevel(52) - GetEXPForLevel(51); //GetEXPForLevel() doesn't depend on class/race, just level, so it shouldn't change between Clients
|
|
||||||
max_AAXP = RuleI(AA, ExpPerPoint); //this may be redundant since we're doing this in Client::FinishConnState2()
|
auto max_AAXP = GetRequiredAAExperience();
|
||||||
if (max_AAXP == 0 || GetEXPForLevel(GetLevel()) == 0xFFFFFFFF) {
|
if (max_AAXP == 0 || GetEXPForLevel(GetLevel()) == 0xFFFFFFFF) {
|
||||||
Message(13, "Error in Client::SetEXP. EXP not set.");
|
Message(13, "Error in Client::SetEXP. EXP not set.");
|
||||||
return; // Must be invalid class/race
|
return; // Must be invalid class/race
|
||||||
@ -377,19 +398,23 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isrezzexp) {
|
if (isrezzexp) {
|
||||||
if (RuleI(Character, ShowExpValues) > 0) Message(MT_Experience, "You regain %s experience from resurrection. %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
if (RuleI(Character, ShowExpValues) > 0)
|
||||||
|
Message(MT_Experience, "You regain %s experience from resurrection. %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
||||||
else Message_StringID(MT_Experience, REZ_REGAIN);
|
else Message_StringID(MT_Experience, REZ_REGAIN);
|
||||||
} else {
|
} else {
|
||||||
if (membercount > 1) {
|
if (membercount > 1) {
|
||||||
if (RuleI(Character, ShowExpValues) > 0) Message(MT_Experience, "You have gained %s party experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
if (RuleI(Character, ShowExpValues) > 0)
|
||||||
|
Message(MT_Experience, "You have gained %s party experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
||||||
else Message_StringID(MT_Experience, GAIN_GROUPXP);
|
else Message_StringID(MT_Experience, GAIN_GROUPXP);
|
||||||
}
|
}
|
||||||
else if (IsRaidGrouped()) {
|
else if (IsRaidGrouped()) {
|
||||||
if (RuleI(Character, ShowExpValues) > 0) Message(MT_Experience, "You have gained %s raid experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
if (RuleI(Character, ShowExpValues) > 0)
|
||||||
|
Message(MT_Experience, "You have gained %s raid experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
||||||
else Message_StringID(MT_Experience, GAIN_RAIDEXP);
|
else Message_StringID(MT_Experience, GAIN_RAIDEXP);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (RuleI(Character, ShowExpValues) > 0) Message(MT_Experience, "You have gained %s experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
if (RuleI(Character, ShowExpValues) > 0)
|
||||||
|
Message(MT_Experience, "You have gained %s experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
|
||||||
else Message_StringID(MT_Experience, GAIN_XP);
|
else Message_StringID(MT_Experience, GAIN_XP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,14 +485,13 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
|||||||
|
|
||||||
//add in how many points we had
|
//add in how many points we had
|
||||||
m_pp.aapoints += last_unspentAA;
|
m_pp.aapoints += last_unspentAA;
|
||||||
//set_aaxp = m_pp.expAA % max_AAXP;
|
|
||||||
|
|
||||||
//figure out how many points were actually gained
|
//figure out how many points were actually gained
|
||||||
/*uint32 gained = m_pp.aapoints - last_unspentAA;*/ //unused
|
/*uint32 gained = m_pp.aapoints - last_unspentAA;*/ //unused
|
||||||
|
|
||||||
//Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
|
//Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
|
||||||
char val1[20]={0};
|
char val1[20]={0};
|
||||||
Message_StringID(MT_Experience, GAIN_ABILITY_POINT,ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
|
Message_StringID(MT_Experience, GAIN_ABILITY_POINT, ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
|
||||||
|
|
||||||
/* QS: PlayerLogAARate */
|
/* QS: PlayerLogAARate */
|
||||||
if (RuleB(QueryServ, PlayerLogAARate)){
|
if (RuleB(QueryServ, PlayerLogAARate)){
|
||||||
@ -571,8 +595,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
|||||||
char val1[20]={0};
|
char val1[20]={0};
|
||||||
char val2[20]={0};
|
char val2[20]={0};
|
||||||
char val3[20]={0};
|
char val3[20]={0};
|
||||||
Message_StringID(MT_Experience, GM_GAINXP,ConvertArray(set_aaxp,val1),ConvertArray(set_exp,val2),ConvertArray(GetEXPForLevel(GetLevel()+1),val3)); //[GM] You have gained %1 AXP and %2 EXP (%3).
|
Message_StringID(MT_Experience, GM_GAINXP, ConvertArray(set_aaxp,val1),ConvertArray(set_exp,val2),ConvertArray(GetEXPForLevel(GetLevel()+1),val3)); //[GM] You have gained %1 AXP and %2 EXP (%3).
|
||||||
//Message(15, "[GM] You now have %d / %d EXP and %d / %d AA exp.", set_exp, GetEXPForLevel(GetLevel()+1), set_aaxp, max_AAXP);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,6 +687,15 @@ void Client::SetLevel(uint8 set_level, bool command)
|
|||||||
// Add: You can set the values you want now, client will be always sync :) - Merkur
|
// Add: You can set the values you want now, client will be always sync :) - Merkur
|
||||||
uint32 Client::GetEXPForLevel(uint16 check_level)
|
uint32 Client::GetEXPForLevel(uint16 check_level)
|
||||||
{
|
{
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
uint32 lua_ret = 0;
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
lua_ret = LuaParser::Instance()->GetEXPForLevel(this, check_level, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return lua_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16 check_levelm1 = check_level-1;
|
uint16 check_levelm1 = check_level-1;
|
||||||
float mod;
|
float mod;
|
||||||
@ -933,3 +965,17 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Client::GetRequiredAAExperience() {
|
||||||
|
#ifdef LUA_EQEMU
|
||||||
|
uint32 lua_ret = 0;
|
||||||
|
bool ignoreDefault = false;
|
||||||
|
lua_ret = LuaParser::Instance()->GetRequiredAAExperience(this, ignoreDefault);
|
||||||
|
|
||||||
|
if (ignoreDefault) {
|
||||||
|
return lua_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return RuleI(AA, ExpPerPoint);
|
||||||
|
}
|
||||||
|
|||||||
@ -154,7 +154,8 @@ void Mob::CalculateNewFearpoint()
|
|||||||
|
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
float ranx, rany, ranz;
|
float ranx, rany, ranz;
|
||||||
currently_fleeing = false;
|
|
||||||
|
currently_fleeing = true;
|
||||||
while (loop < 100) //Max 100 tries
|
while (loop < 100) //Max 100 tries
|
||||||
{
|
{
|
||||||
int ran = 250 - (loop*2);
|
int ran = 250 - (loop*2);
|
||||||
@ -167,13 +168,13 @@ void Mob::CalculateNewFearpoint()
|
|||||||
float fdist = ranz - GetZ();
|
float fdist = ranz - GetZ();
|
||||||
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
||||||
{
|
{
|
||||||
currently_fleeing = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currently_fleeing)
|
|
||||||
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
if (loop <= 100)
|
||||||
else //Break fear
|
{
|
||||||
BuffFadeByEffect(SE_Fear);
|
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -196,7 +196,7 @@ bool Client::CanFish() {
|
|||||||
|
|
||||||
float step_size = RuleR(Watermap, FishingLineStepSize);
|
float step_size = RuleR(Watermap, FishingLineStepSize);
|
||||||
|
|
||||||
for(float i = 0.0f; i < len; i += step_size) {
|
for(float i = 0.0f; i < LineLength; i += step_size) {
|
||||||
glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i);
|
glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i);
|
||||||
|
|
||||||
bool in_lava = zone->watermap->InLava(dest);
|
bool in_lava = zone->watermap->InLava(dest);
|
||||||
|
|||||||
@ -338,6 +338,13 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
|
|||||||
database.SetGroupID(NewMemberName, GetID(), owner->CharacterID(), true);
|
database.SetGroupID(NewMemberName, GetID(), owner->CharacterID(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Group* group = newmember->CastToClient()->GetGroup();
|
||||||
|
if (group) {
|
||||||
|
group->SendHPManaEndPacketsTo(newmember);
|
||||||
|
group->SendHPPacketsFrom(newmember);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -387,31 +394,30 @@ void Group::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
|||||||
|
|
||||||
// Sends the rest of the group's hps to member. this is useful when someone
|
// Sends the rest of the group's hps to member. this is useful when someone
|
||||||
// first joins a group, but otherwise there shouldn't be a need to call it
|
// first joins a group, but otherwise there shouldn't be a need to call it
|
||||||
void Group::SendHPPacketsTo(Mob *member)
|
void Group::SendHPManaEndPacketsTo(Mob *member)
|
||||||
{
|
{
|
||||||
if(member && member->IsClient())
|
if(member && member->IsClient()) {
|
||||||
{
|
|
||||||
EQApplicationPacket hpapp;
|
EQApplicationPacket hpapp;
|
||||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||||
|
|
||||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++)
|
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
{
|
if(members[i] && members[i] != member) {
|
||||||
if(members[i] && members[i] != member)
|
|
||||||
{
|
|
||||||
members[i]->CreateHPPacket(&hpapp);
|
members[i]->CreateHPPacket(&hpapp);
|
||||||
member->CastToClient()->QueuePacket(&hpapp, false);
|
member->CastToClient()->QueuePacket(&hpapp, false);
|
||||||
safe_delete_array(hpapp.pBuffer);
|
safe_delete_array(hpapp.pBuffer);
|
||||||
hpapp.size = 0;
|
hpapp.size = 0;
|
||||||
if (member->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)
|
|
||||||
{
|
if (member->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
outapp.SetOpcode(OP_MobManaUpdate);
|
outapp.SetOpcode(OP_MobManaUpdate);
|
||||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer;
|
|
||||||
mmus->spawn_id = members[i]->GetID();
|
MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||||
mmus->mana = members[i]->GetManaPercent();
|
mana_update->spawn_id = members[i]->GetID();
|
||||||
|
mana_update->mana = members[i]->GetManaPercent();
|
||||||
member->CastToClient()->QueuePacket(&outapp, false);
|
member->CastToClient()->QueuePacket(&outapp, false);
|
||||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
|
||||||
|
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||||
meus->endurance = members[i]->GetEndurancePercent();
|
endurance_update->endurance = members[i]->GetEndurancePercent();
|
||||||
member->CastToClient()->QueuePacket(&outapp, false);
|
member->CastToClient()->QueuePacket(&outapp, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,19 +436,58 @@ void Group::SendHPPacketsFrom(Mob *member)
|
|||||||
|
|
||||||
uint32 i;
|
uint32 i;
|
||||||
for(i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
for(i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
if(members[i] && members[i] != member && members[i]->IsClient())
|
if(members[i] && members[i] != member && members[i]->IsClient()) {
|
||||||
{
|
|
||||||
members[i]->CastToClient()->QueuePacket(&hp_app);
|
members[i]->CastToClient()->QueuePacket(&hp_app);
|
||||||
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)
|
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
{
|
|
||||||
outapp.SetOpcode(OP_MobManaUpdate);
|
outapp.SetOpcode(OP_MobManaUpdate);
|
||||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer;
|
MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||||
mmus->spawn_id = member->GetID();
|
mana_update->spawn_id = member->GetID();
|
||||||
mmus->mana = member->GetManaPercent();
|
mana_update->mana = member->GetManaPercent();
|
||||||
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
||||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
|
||||||
|
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||||
meus->endurance = member->GetEndurancePercent();
|
endurance_update->endurance = member->GetEndurancePercent();
|
||||||
|
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::SendManaPacketFrom(Mob *member)
|
||||||
|
{
|
||||||
|
if (!member)
|
||||||
|
return;
|
||||||
|
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||||
|
|
||||||
|
uint32 i;
|
||||||
|
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
|
if (members[i] && members[i] != member && members[i]->IsClient()) {
|
||||||
|
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
|
outapp.SetOpcode(OP_MobManaUpdate);
|
||||||
|
MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||||
|
mana_update->spawn_id = member->GetID();
|
||||||
|
mana_update->mana = member->GetManaPercent();
|
||||||
|
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::SendEndurancePacketFrom(Mob* member)
|
||||||
|
{
|
||||||
|
if (!member)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EQApplicationPacket outapp(OP_MobEnduranceUpdate, sizeof(MobManaUpdate_Struct));
|
||||||
|
|
||||||
|
uint32 i;
|
||||||
|
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||||
|
if (members[i] && members[i] != member && members[i]->IsClient()) {
|
||||||
|
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||||
|
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||||
|
endurance_update->spawn_id = member->GetID();
|
||||||
|
endurance_update->endurance = member->GetEndurancePercent();
|
||||||
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
members[i]->CastToClient()->QueuePacket(&outapp, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -648,7 +693,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetLeader() == nullptr)
|
if (!GetLeaderName())
|
||||||
{
|
{
|
||||||
DisbandGroup();
|
DisbandGroup();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -80,8 +80,10 @@ public:
|
|||||||
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
||||||
inline Mob* GetLeader() { return leader; };
|
inline Mob* GetLeader() { return leader; };
|
||||||
const char* GetLeaderName() { return membername[0]; };
|
const char* GetLeaderName() { return membername[0]; };
|
||||||
void SendHPPacketsTo(Mob* newmember);
|
void SendHPManaEndPacketsTo(Mob* newmember);
|
||||||
void SendHPPacketsFrom(Mob* newmember);
|
void SendHPPacketsFrom(Mob* member);
|
||||||
|
void SendManaPacketFrom(Mob* member);
|
||||||
|
void SendEndurancePacketFrom(Mob* member);
|
||||||
bool UpdatePlayer(Mob* update);
|
bool UpdatePlayer(Mob* update);
|
||||||
void MemberZoned(Mob* removemob);
|
void MemberZoned(Mob* removemob);
|
||||||
inline bool IsLeader(Mob* leadertest) { return leadertest==leader; };
|
inline bool IsLeader(Mob* leadertest) { return leadertest==leader; };
|
||||||
|
|||||||
@ -1172,6 +1172,11 @@ uint64 Lua_Client::GetAllMoney() {
|
|||||||
return self->GetAllMoney();
|
return self->GetAllMoney();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Lua_Client::GetMoney(uint8 type, uint8 subtype) {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetMoney(type, subtype);
|
||||||
|
}
|
||||||
|
|
||||||
void Lua_Client::OpenLFGuildWindow() {
|
void Lua_Client::OpenLFGuildWindow() {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->OpenLFGuildWindow();
|
self->OpenLFGuildWindow();
|
||||||
@ -1414,9 +1419,25 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) {
|
|||||||
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction);
|
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Lua_Client::GetMoney(uint8 type, uint8 subtype) {
|
bool Lua_Client::IsDead() {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsDead();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Client::CalcCurrentWeight() {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->GetMoney(type, subtype);
|
return self->CalcCurrentWeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Client::CalcATK() {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->CalcATK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::FilteredMessage(Mob *sender, uint32 type, int filter, const char *message)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->FilteredMessage(sender, type, (eqFilterType)filter, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
@ -1653,6 +1674,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("GetAggroCount", (int(Lua_Client::*)(void))&Lua_Client::GetAggroCount)
|
.def("GetAggroCount", (int(Lua_Client::*)(void))&Lua_Client::GetAggroCount)
|
||||||
.def("GetCarriedMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetCarriedMoney)
|
.def("GetCarriedMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetCarriedMoney)
|
||||||
.def("GetAllMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetAllMoney)
|
.def("GetAllMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetAllMoney)
|
||||||
|
.def("GetMoney", (uint32(Lua_Client::*)(uint8, uint8))&Lua_Client::GetMoney)
|
||||||
.def("OpenLFGuildWindow", (void(Lua_Client::*)(void))&Lua_Client::OpenLFGuildWindow)
|
.def("OpenLFGuildWindow", (void(Lua_Client::*)(void))&Lua_Client::OpenLFGuildWindow)
|
||||||
.def("Signal", (void(Lua_Client::*)(uint32))&Lua_Client::Signal)
|
.def("Signal", (void(Lua_Client::*)(uint32))&Lua_Client::Signal)
|
||||||
.def("AddAlternateCurrencyValue", (void(Lua_Client::*)(uint32,int))&Lua_Client::AddAlternateCurrencyValue)
|
.def("AddAlternateCurrencyValue", (void(Lua_Client::*)(uint32,int))&Lua_Client::AddAlternateCurrencyValue)
|
||||||
@ -1687,7 +1709,10 @@ luabind::scope lua_register_client() {
|
|||||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
||||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Lua_Client::QuestReward)
|
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Lua_Client::QuestReward)
|
||||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, luabind::adl::object))&Lua_Client::QuestReward)
|
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, luabind::adl::object))&Lua_Client::QuestReward)
|
||||||
.def("GetMoney", (uint32(Lua_Client::*)(uint8, uint8))&Lua_Client::GetMoney);
|
.def("IsDead", &Lua_Client::IsDead)
|
||||||
|
.def("CalcCurrentWeight", &Lua_Client::CalcCurrentWeight)
|
||||||
|
.def("CalcATK", &Lua_Client::CalcATK)
|
||||||
|
.def("FilteredMessage", &Lua_Client::FilteredMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_inventory_where() {
|
luabind::scope lua_register_inventory_where() {
|
||||||
|
|||||||
@ -297,6 +297,10 @@ public:
|
|||||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp);
|
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp);
|
||||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction);
|
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction);
|
||||||
void QuestReward(Lua_Mob target, luabind::adl::object reward);
|
void QuestReward(Lua_Mob target, luabind::adl::object reward);
|
||||||
|
bool IsDead();
|
||||||
|
int CalcCurrentWeight();
|
||||||
|
int CalcATK();
|
||||||
|
void FilteredMessage(Mob *sender, uint32 type, int filter, const char* message);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -67,6 +67,16 @@ bool Lua_Entity::IsBeacon() {
|
|||||||
return self->IsBeacon();
|
return self->IsBeacon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Lua_Entity::IsEncounter() {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsEncounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Entity::IsBot() {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsBot();
|
||||||
|
}
|
||||||
|
|
||||||
int Lua_Entity::GetID() {
|
int Lua_Entity::GetID() {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
return self->GetID();
|
return self->GetID();
|
||||||
@ -124,6 +134,8 @@ luabind::scope lua_register_entity() {
|
|||||||
.def("IsDoor", &Lua_Entity::IsDoor)
|
.def("IsDoor", &Lua_Entity::IsDoor)
|
||||||
.def("IsTrap", &Lua_Entity::IsTrap)
|
.def("IsTrap", &Lua_Entity::IsTrap)
|
||||||
.def("IsBeacon", &Lua_Entity::IsBeacon)
|
.def("IsBeacon", &Lua_Entity::IsBeacon)
|
||||||
|
.def("IsEncounter", &Lua_Entity::IsEncounter)
|
||||||
|
.def("IsBot", &Lua_Entity::IsBot)
|
||||||
.def("GetID", &Lua_Entity::GetID)
|
.def("GetID", &Lua_Entity::GetID)
|
||||||
.def("CastToClient", &Lua_Entity::CastToClient)
|
.def("CastToClient", &Lua_Entity::CastToClient)
|
||||||
.def("CastToNPC", &Lua_Entity::CastToNPC)
|
.def("CastToNPC", &Lua_Entity::CastToNPC)
|
||||||
|
|||||||
@ -44,6 +44,8 @@ public:
|
|||||||
bool IsDoor();
|
bool IsDoor();
|
||||||
bool IsTrap();
|
bool IsTrap();
|
||||||
bool IsBeacon();
|
bool IsBeacon();
|
||||||
|
bool IsEncounter();
|
||||||
|
bool IsBot();
|
||||||
int GetID();
|
int GetID();
|
||||||
|
|
||||||
Lua_Client CastToClient();
|
Lua_Client CastToClient();
|
||||||
|
|||||||
@ -210,6 +210,12 @@ void Lua_EntityList::MessageClose(Lua_Mob sender, bool skip_sender, float dist,
|
|||||||
self->MessageClose(sender, skip_sender, dist, type, message);
|
self->MessageClose(sender, skip_sender, dist, type, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_EntityList::FilteredMessageClose(Lua_Mob sender, bool skip_sender, float dist, uint32 type, int filter, const char *message)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->FilteredMessageClose(sender, skip_sender, dist, type, (eqFilterType)filter, message);
|
||||||
|
}
|
||||||
|
|
||||||
void Lua_EntityList::RemoveFromTargets(Lua_Mob mob) {
|
void Lua_EntityList::RemoveFromTargets(Lua_Mob mob) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->RemoveFromTargets(mob);
|
self->RemoveFromTargets(mob);
|
||||||
@ -450,16 +456,17 @@ luabind::scope lua_register_entity_list() {
|
|||||||
.def("GetSpawnByID", (Lua_Spawn(Lua_EntityList::*)(uint32))&Lua_EntityList::GetSpawnByID)
|
.def("GetSpawnByID", (Lua_Spawn(Lua_EntityList::*)(uint32))&Lua_EntityList::GetSpawnByID)
|
||||||
.def("ClearClientPetitionQueue", (void(Lua_EntityList::*)(void))&Lua_EntityList::ClearClientPetitionQueue)
|
.def("ClearClientPetitionQueue", (void(Lua_EntityList::*)(void))&Lua_EntityList::ClearClientPetitionQueue)
|
||||||
.def("CanAddHateForMob", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::CanAddHateForMob)
|
.def("CanAddHateForMob", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::CanAddHateForMob)
|
||||||
.def("Message", (void(Lua_EntityList::*)(uint32,uint32,const char*))&Lua_EntityList::Message)
|
.def("Message", (void(Lua_EntityList::*)(uint32, uint32, const char*))&Lua_EntityList::Message)
|
||||||
.def("MessageStatus", (void(Lua_EntityList::*)(uint32,uint32,uint32,const char*))&Lua_EntityList::MessageStatus)
|
.def("MessageStatus", (void(Lua_EntityList::*)(uint32, uint32, uint32, const char*))&Lua_EntityList::MessageStatus)
|
||||||
.def("MessageClose", (void(Lua_EntityList::*)(Lua_Mob,bool,float,uint32,const char*))&Lua_EntityList::MessageClose)
|
.def("MessageClose", (void(Lua_EntityList::*)(Lua_Mob, bool, float, uint32, const char*))&Lua_EntityList::MessageClose)
|
||||||
|
.def("FilteredMessageClose", &Lua_EntityList::FilteredMessageClose)
|
||||||
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromTargets)
|
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromTargets)
|
||||||
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob,bool))&Lua_EntityList::RemoveFromTargets)
|
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob, bool))&Lua_EntityList::RemoveFromTargets)
|
||||||
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob,Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
|
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob, Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
|
||||||
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_NPC))&Lua_EntityList::OpenDoorsNear)
|
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_NPC))&Lua_EntityList::OpenDoorsNear)
|
||||||
.def("MakeNameUnique", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::MakeNameUnique)
|
.def("MakeNameUnique", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::MakeNameUnique)
|
||||||
.def("RemoveNumbers", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::RemoveNumbers)
|
.def("RemoveNumbers", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::RemoveNumbers)
|
||||||
.def("SignalMobsByNPCID", (void(Lua_EntityList::*)(uint32,int))&Lua_EntityList::SignalMobsByNPCID)
|
.def("SignalMobsByNPCID", (void(Lua_EntityList::*)(uint32, int))&Lua_EntityList::SignalMobsByNPCID)
|
||||||
.def("DeleteNPCCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeleteNPCCorpses)
|
.def("DeleteNPCCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeleteNPCCorpses)
|
||||||
.def("DeletePlayerCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeletePlayerCorpses)
|
.def("DeletePlayerCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeletePlayerCorpses)
|
||||||
.def("HalveAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::HalveAggro)
|
.def("HalveAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::HalveAggro)
|
||||||
@ -467,10 +474,10 @@ luabind::scope lua_register_entity_list() {
|
|||||||
.def("ClearFeignAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::ClearFeignAggro)
|
.def("ClearFeignAggro", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::ClearFeignAggro)
|
||||||
.def("Fighting", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::Fighting)
|
.def("Fighting", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::Fighting)
|
||||||
.def("RemoveFromHateLists", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromHateLists)
|
.def("RemoveFromHateLists", (void(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::RemoveFromHateLists)
|
||||||
.def("RemoveFromHateLists", (void(Lua_EntityList::*)(Lua_Mob,bool))&Lua_EntityList::RemoveFromHateLists)
|
.def("RemoveFromHateLists", (void(Lua_EntityList::*)(Lua_Mob, bool))&Lua_EntityList::RemoveFromHateLists)
|
||||||
.def("MessageGroup", (void(Lua_EntityList::*)(Lua_Mob,bool,uint32,const char*))&Lua_EntityList::MessageGroup)
|
.def("MessageGroup", (void(Lua_EntityList::*)(Lua_Mob, bool, uint32, const char*))&Lua_EntityList::MessageGroup)
|
||||||
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float,float,float,float))&Lua_EntityList::GetRandomClient)
|
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float, float, float, float))&Lua_EntityList::GetRandomClient)
|
||||||
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float,float,float,float,Lua_Client))&Lua_EntityList::GetRandomClient)
|
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float, float, float, float, Lua_Client))&Lua_EntityList::GetRandomClient)
|
||||||
.def("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList)
|
.def("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList)
|
||||||
.def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList)
|
.def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList)
|
||||||
.def("GetNPCList", (Lua_NPC_List(Lua_EntityList::*)(void))&Lua_EntityList::GetNPCList)
|
.def("GetNPCList", (Lua_NPC_List(Lua_EntityList::*)(void))&Lua_EntityList::GetNPCList)
|
||||||
@ -479,7 +486,7 @@ luabind::scope lua_register_entity_list() {
|
|||||||
.def("GetDoorsList", (Lua_Doors_List(Lua_EntityList::*)(void))&Lua_EntityList::GetDoorsList)
|
.def("GetDoorsList", (Lua_Doors_List(Lua_EntityList::*)(void))&Lua_EntityList::GetDoorsList)
|
||||||
.def("GetSpawnList", (Lua_Spawn_List(Lua_EntityList::*)(void))&Lua_EntityList::GetSpawnList)
|
.def("GetSpawnList", (Lua_Spawn_List(Lua_EntityList::*)(void))&Lua_EntityList::GetSpawnList)
|
||||||
.def("SignalAllClients", (void(Lua_EntityList::*)(int))&Lua_EntityList::SignalAllClients)
|
.def("SignalAllClients", (void(Lua_EntityList::*)(int))&Lua_EntityList::SignalAllClients)
|
||||||
.def("ChannelMessage", (void(Lua_EntityList::*)(Lua_Mob,int,int,const char*))&Lua_EntityList::ChannelMessage);
|
.def("ChannelMessage", (void(Lua_EntityList::*)(Lua_Mob, int, int, const char*))&Lua_EntityList::ChannelMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_mob_list() {
|
luabind::scope lua_register_mob_list() {
|
||||||
|
|||||||
@ -80,6 +80,7 @@ public:
|
|||||||
void Message(uint32 guild_dbid, uint32 type, const char *message);
|
void Message(uint32 guild_dbid, uint32 type, const char *message);
|
||||||
void MessageStatus(uint32 guild_dbid, int min_status, uint32 type, const char *message);
|
void MessageStatus(uint32 guild_dbid, int min_status, uint32 type, const char *message);
|
||||||
void MessageClose(Lua_Mob sender, bool skip_sender, float dist, uint32 type, const char *message);
|
void MessageClose(Lua_Mob sender, bool skip_sender, float dist, uint32 type, const char *message);
|
||||||
|
void FilteredMessageClose(Lua_Mob sender, bool skip_sender, float dist, uint32 type, int filter, const char *message);
|
||||||
void RemoveFromTargets(Lua_Mob mob);
|
void RemoveFromTargets(Lua_Mob mob);
|
||||||
void RemoveFromTargets(Lua_Mob mob, bool RemoveFromXTargets);
|
void RemoveFromTargets(Lua_Mob mob, bool RemoveFromXTargets);
|
||||||
void ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target);
|
void ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target);
|
||||||
|
|||||||
@ -7,6 +7,10 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "../common/timer.h"
|
||||||
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/classes.h"
|
||||||
|
#include "../common/rulesys.h"
|
||||||
#include "lua_parser.h"
|
#include "lua_parser.h"
|
||||||
#include "lua_item.h"
|
#include "lua_item.h"
|
||||||
#include "lua_iteminst.h"
|
#include "lua_iteminst.h"
|
||||||
@ -16,8 +20,6 @@
|
|||||||
#include "quest_parser_collection.h"
|
#include "quest_parser_collection.h"
|
||||||
#include "questmgr.h"
|
#include "questmgr.h"
|
||||||
#include "qglobals.h"
|
#include "qglobals.h"
|
||||||
#include "../common/timer.h"
|
|
||||||
#include "../common/eqemu_logsys.h"
|
|
||||||
#include "encounter.h"
|
#include "encounter.h"
|
||||||
#include "lua_encounter.h"
|
#include "lua_encounter.h"
|
||||||
|
|
||||||
@ -27,6 +29,12 @@ struct Slots { };
|
|||||||
struct Materials { };
|
struct Materials { };
|
||||||
struct ClientVersions { };
|
struct ClientVersions { };
|
||||||
struct Appearances { };
|
struct Appearances { };
|
||||||
|
struct Classes { };
|
||||||
|
struct Skills { };
|
||||||
|
struct BodyTypes { };
|
||||||
|
struct Filters { };
|
||||||
|
struct MessageTypes { };
|
||||||
|
struct Rule { };
|
||||||
|
|
||||||
struct lua_registered_event {
|
struct lua_registered_event {
|
||||||
std::string encounter_name;
|
std::string encounter_name;
|
||||||
@ -892,6 +900,10 @@ void lua_cross_zone_message_player_by_name(uint32 type, const char *player, cons
|
|||||||
quest_manager.CrossZoneMessagePlayerByName(type, player, message);
|
quest_manager.CrossZoneMessagePlayerByName(type, player, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_cross_zone_set_entity_variable_by_client_name(const char *player, const char *id, const char *m_var) {
|
||||||
|
quest_manager.CrossZoneSetEntityVariableByClientName(player, id, m_var);
|
||||||
|
}
|
||||||
|
|
||||||
void lua_world_wide_marquee(uint32 type, uint32 priority, uint32 fadein, uint32 fadeout, uint32 duration, const char *message) {
|
void lua_world_wide_marquee(uint32 type, uint32 priority, uint32 fadein, uint32 fadeout, uint32 duration, const char *message) {
|
||||||
quest_manager.WorldWideMarquee(type, priority, fadein, fadeout, duration, message);
|
quest_manager.WorldWideMarquee(type, priority, fadein, fadeout, duration, message);
|
||||||
}
|
}
|
||||||
@ -1458,6 +1470,39 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
|||||||
npc->GiveNPCTypeData(npc_type);
|
npc->GiveNPCTypeData(npc_type);
|
||||||
entity_list.AddNPC(npc);
|
entity_list.AddNPC(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int random_int(int low, int high) {
|
||||||
|
return zone->random.Int(low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
double random_real(double low, double high) {
|
||||||
|
return zone->random.Real(low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool random_roll_int(int required) {
|
||||||
|
return zone->random.Roll(required);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool random_roll_real(double required) {
|
||||||
|
return zone->random.Roll(required);
|
||||||
|
}
|
||||||
|
|
||||||
|
int random_roll0(int max) {
|
||||||
|
return zone->random.Roll0(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_rulei(int rule) {
|
||||||
|
return RuleManager::Instance()->GetIntRule((RuleManager::IntType)rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_ruler(int rule) {
|
||||||
|
return RuleManager::Instance()->GetRealRule((RuleManager::RealType)rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_ruleb(int rule) {
|
||||||
|
return RuleManager::Instance()->GetBoolRule((RuleManager::BoolType)rule);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_general() {
|
luabind::scope lua_register_general() {
|
||||||
return luabind::namespace_("eq")
|
return luabind::namespace_("eq")
|
||||||
[
|
[
|
||||||
@ -1617,6 +1662,7 @@ luabind::scope lua_register_general() {
|
|||||||
luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id),
|
luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id),
|
||||||
luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name),
|
luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name),
|
||||||
luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name),
|
luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name),
|
||||||
|
luabind::def("cross_zone_set_entity_variable_by_client_name", &lua_cross_zone_set_entity_variable_by_client_name),
|
||||||
luabind::def("world_wide_marquee", &lua_world_wide_marquee),
|
luabind::def("world_wide_marquee", &lua_world_wide_marquee),
|
||||||
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals),
|
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals),
|
||||||
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_Client))&lua_get_qglobals),
|
luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_Client))&lua_get_qglobals),
|
||||||
@ -1658,6 +1704,18 @@ luabind::scope lua_register_general() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_random() {
|
||||||
|
return luabind::namespace_("Random")
|
||||||
|
[
|
||||||
|
luabind::def("Int", &random_int),
|
||||||
|
luabind::def("Real", &random_real),
|
||||||
|
luabind::def("Roll", &random_roll_int),
|
||||||
|
luabind::def("RollReal", &random_roll_real),
|
||||||
|
luabind::def("Roll0", &random_roll0)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
luabind::scope lua_register_events() {
|
luabind::scope lua_register_events() {
|
||||||
return luabind::class_<Events>("Event")
|
return luabind::class_<Events>("Event")
|
||||||
.enum_("constants")
|
.enum_("constants")
|
||||||
@ -1738,7 +1796,8 @@ luabind::scope lua_register_events() {
|
|||||||
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
|
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
|
||||||
luabind::value("tick", static_cast<int>(EVENT_TICK)),
|
luabind::value("tick", static_cast<int>(EVENT_TICK)),
|
||||||
luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
|
luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
|
||||||
luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE))
|
luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE)),
|
||||||
|
luabind::value("use_skill", static_cast<int>(EVENT_USE_SKILL))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1857,4 +1916,355 @@ luabind::scope lua_register_appearance() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_classes() {
|
||||||
|
return luabind::class_<Classes>("Class")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
luabind::value("WARRIOR", WARRIOR),
|
||||||
|
luabind::value("CLERIC", CLERIC),
|
||||||
|
luabind::value("PALADIN", PALADIN),
|
||||||
|
luabind::value("RANGER", RANGER),
|
||||||
|
luabind::value("SHADOWKNIGHT", SHADOWKNIGHT),
|
||||||
|
luabind::value("DRUID", DRUID),
|
||||||
|
luabind::value("MONK", MONK),
|
||||||
|
luabind::value("BARD", BARD),
|
||||||
|
luabind::value("ROGUE", ROGUE),
|
||||||
|
luabind::value("SHAMAN", SHAMAN),
|
||||||
|
luabind::value("NECROMANCER", NECROMANCER),
|
||||||
|
luabind::value("WIZARD", WIZARD),
|
||||||
|
luabind::value("MAGICIAN", MAGICIAN),
|
||||||
|
luabind::value("ENCHANTER", ENCHANTER),
|
||||||
|
luabind::value("BEASTLORD", BEASTLORD),
|
||||||
|
luabind::value("BERSERKER", BERSERKER),
|
||||||
|
luabind::value("WARRIORGM", WARRIORGM),
|
||||||
|
luabind::value("CLERICGM", CLERICGM),
|
||||||
|
luabind::value("PALADINGM", PALADINGM),
|
||||||
|
luabind::value("RANGERGM", RANGERGM),
|
||||||
|
luabind::value("SHADOWKNIGHTGM", SHADOWKNIGHTGM),
|
||||||
|
luabind::value("DRUIDGM", DRUIDGM),
|
||||||
|
luabind::value("MONKGM", MONKGM),
|
||||||
|
luabind::value("BARDGM", BARDGM),
|
||||||
|
luabind::value("ROGUEGM", ROGUEGM),
|
||||||
|
luabind::value("SHAMANGM", SHAMANGM),
|
||||||
|
luabind::value("NECROMANCERGM", NECROMANCERGM),
|
||||||
|
luabind::value("WIZARDGM", WIZARDGM),
|
||||||
|
luabind::value("MAGICIANGM", MAGICIANGM),
|
||||||
|
luabind::value("ENCHANTERGM", ENCHANTERGM),
|
||||||
|
luabind::value("BEASTLORDGM", BEASTLORDGM),
|
||||||
|
luabind::value("BERSERKERGM", BERSERKERGM),
|
||||||
|
luabind::value("BANKER", BANKER),
|
||||||
|
luabind::value("MERCHANT", MERCHANT),
|
||||||
|
luabind::value("DISCORD_MERCHANT", DISCORD_MERCHANT),
|
||||||
|
luabind::value("ADVENTURERECRUITER", ADVENTURERECRUITER),
|
||||||
|
luabind::value("ADVENTUREMERCHANT", ADVENTUREMERCHANT),
|
||||||
|
luabind::value("LDON_TREASURE", LDON_TREASURE),
|
||||||
|
luabind::value("CORPSE_CLASS", CORPSE_CLASS),
|
||||||
|
luabind::value("TRIBUTE_MASTER", TRIBUTE_MASTER),
|
||||||
|
luabind::value("GUILD_TRIBUTE_MASTER", GUILD_TRIBUTE_MASTER),
|
||||||
|
luabind::value("NORRATHS_KEEPERS_MERCHANT", NORRATHS_KEEPERS_MERCHANT),
|
||||||
|
luabind::value("DARK_REIGN_MERCHANT", DARK_REIGN_MERCHANT),
|
||||||
|
luabind::value("FELLOWSHIP_MASTER", FELLOWSHIP_MASTER),
|
||||||
|
luabind::value("ALT_CURRENCY_MERCHANT", ALT_CURRENCY_MERCHANT),
|
||||||
|
luabind::value("MERCERNARY_MASTER", MERCERNARY_MASTER)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_skills() {
|
||||||
|
return luabind::class_<Skills>("Skill")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
luabind::value("1HBlunt", EQEmu::skills::Skill1HBlunt),
|
||||||
|
luabind::value("1HSlashing", EQEmu::skills::Skill1HSlashing),
|
||||||
|
luabind::value("2HBlunt", EQEmu::skills::Skill2HBlunt),
|
||||||
|
luabind::value("2HSlashing", EQEmu::skills::Skill2HSlashing),
|
||||||
|
luabind::value("Abjuration", EQEmu::skills::SkillAbjuration),
|
||||||
|
luabind::value("Alteration", EQEmu::skills::SkillAlteration),
|
||||||
|
luabind::value("ApplyPoison", EQEmu::skills::SkillApplyPoison),
|
||||||
|
luabind::value("Archery", EQEmu::skills::SkillArchery),
|
||||||
|
luabind::value("Backstab", EQEmu::skills::SkillBackstab),
|
||||||
|
luabind::value("BindWound", EQEmu::skills::SkillBindWound),
|
||||||
|
luabind::value("Bash", EQEmu::skills::SkillBash),
|
||||||
|
luabind::value("Block", EQEmu::skills::SkillBlock),
|
||||||
|
luabind::value("BrassInstruments", EQEmu::skills::SkillBrassInstruments),
|
||||||
|
luabind::value("Channeling", EQEmu::skills::SkillChanneling),
|
||||||
|
luabind::value("Conjuration", EQEmu::skills::SkillConjuration),
|
||||||
|
luabind::value("Defense", EQEmu::skills::SkillDefense),
|
||||||
|
luabind::value("Disarm", EQEmu::skills::SkillDisarm),
|
||||||
|
luabind::value("DisarmTraps", EQEmu::skills::SkillDisarmTraps),
|
||||||
|
luabind::value("Divination", EQEmu::skills::SkillDivination),
|
||||||
|
luabind::value("Dodge", EQEmu::skills::SkillDodge),
|
||||||
|
luabind::value("DoubleAttack", EQEmu::skills::SkillDoubleAttack),
|
||||||
|
luabind::value("DragonPunch", EQEmu::skills::SkillDragonPunch),
|
||||||
|
luabind::value("TailRake", EQEmu::skills::SkillTailRake),
|
||||||
|
luabind::value("DualWield", EQEmu::skills::SkillDualWield),
|
||||||
|
luabind::value("EagleStrike", EQEmu::skills::SkillEagleStrike),
|
||||||
|
luabind::value("Evocation", EQEmu::skills::SkillEvocation),
|
||||||
|
luabind::value("FeignDeath", EQEmu::skills::SkillFeignDeath),
|
||||||
|
luabind::value("FlyingKick", EQEmu::skills::SkillFlyingKick),
|
||||||
|
luabind::value("Forage", EQEmu::skills::SkillForage),
|
||||||
|
luabind::value("HandtoHand", EQEmu::skills::SkillHandtoHand),
|
||||||
|
luabind::value("Hide", EQEmu::skills::SkillHide),
|
||||||
|
luabind::value("Kick", EQEmu::skills::SkillKick),
|
||||||
|
luabind::value("Meditate", EQEmu::skills::SkillMeditate),
|
||||||
|
luabind::value("Mend", EQEmu::skills::SkillMend),
|
||||||
|
luabind::value("Offense", EQEmu::skills::SkillOffense),
|
||||||
|
luabind::value("Parry", EQEmu::skills::SkillParry),
|
||||||
|
luabind::value("PickLock", EQEmu::skills::SkillPickLock),
|
||||||
|
luabind::value("1HPiercing", EQEmu::skills::Skill1HPiercing),
|
||||||
|
luabind::value("Riposte", EQEmu::skills::SkillRiposte),
|
||||||
|
luabind::value("RoundKick", EQEmu::skills::SkillRoundKick),
|
||||||
|
luabind::value("SafeFall", EQEmu::skills::SkillSafeFall),
|
||||||
|
luabind::value("SenseHeading", EQEmu::skills::SkillSenseHeading),
|
||||||
|
luabind::value("Singing", EQEmu::skills::SkillSinging),
|
||||||
|
luabind::value("Sneak", EQEmu::skills::SkillSneak),
|
||||||
|
luabind::value("SpecializeAbjure", EQEmu::skills::SkillSpecializeAbjure),
|
||||||
|
luabind::value("SpecializeAlteration", EQEmu::skills::SkillSpecializeAlteration),
|
||||||
|
luabind::value("SpecializeConjuration", EQEmu::skills::SkillSpecializeConjuration),
|
||||||
|
luabind::value("SpecializeDivination", EQEmu::skills::SkillSpecializeDivination),
|
||||||
|
luabind::value("SpecializeEvocation", EQEmu::skills::SkillSpecializeEvocation),
|
||||||
|
luabind::value("PickPockets", EQEmu::skills::SkillPickPockets),
|
||||||
|
luabind::value("StringedInstruments", EQEmu::skills::SkillStringedInstruments),
|
||||||
|
luabind::value("Swimming", EQEmu::skills::SkillSwimming),
|
||||||
|
luabind::value("Throwing", EQEmu::skills::SkillThrowing),
|
||||||
|
luabind::value("TigerClaw", EQEmu::skills::SkillTigerClaw),
|
||||||
|
luabind::value("Tracking", EQEmu::skills::SkillTracking),
|
||||||
|
luabind::value("WindInstruments", EQEmu::skills::SkillWindInstruments),
|
||||||
|
luabind::value("Fishing", EQEmu::skills::SkillFishing),
|
||||||
|
luabind::value("MakePoison", EQEmu::skills::SkillMakePoison),
|
||||||
|
luabind::value("Tinkering", EQEmu::skills::SkillTinkering),
|
||||||
|
luabind::value("Research", EQEmu::skills::SkillResearch),
|
||||||
|
luabind::value("Alchemy", EQEmu::skills::SkillAlchemy),
|
||||||
|
luabind::value("Baking", EQEmu::skills::SkillBaking),
|
||||||
|
luabind::value("Tailoring", EQEmu::skills::SkillTailoring),
|
||||||
|
luabind::value("SenseTraps", EQEmu::skills::SkillSenseTraps),
|
||||||
|
luabind::value("Blacksmithing", EQEmu::skills::SkillBlacksmithing),
|
||||||
|
luabind::value("Fletching", EQEmu::skills::SkillFletching),
|
||||||
|
luabind::value("Brewing", EQEmu::skills::SkillBrewing),
|
||||||
|
luabind::value("AlcoholTolerance", EQEmu::skills::SkillAlcoholTolerance),
|
||||||
|
luabind::value("Begging", EQEmu::skills::SkillBegging),
|
||||||
|
luabind::value("JewelryMaking", EQEmu::skills::SkillJewelryMaking),
|
||||||
|
luabind::value("Pottery", EQEmu::skills::SkillPottery),
|
||||||
|
luabind::value("PercussionInstruments", EQEmu::skills::SkillPercussionInstruments),
|
||||||
|
luabind::value("Intimidation", EQEmu::skills::SkillIntimidation),
|
||||||
|
luabind::value("Berserking", EQEmu::skills::SkillBerserking),
|
||||||
|
luabind::value("Taunt", EQEmu::skills::SkillTaunt),
|
||||||
|
luabind::value("Frenzy", EQEmu::skills::SkillFrenzy),
|
||||||
|
luabind::value("RemoveTraps", EQEmu::skills::SkillRemoveTraps),
|
||||||
|
luabind::value("TripleAttack", EQEmu::skills::SkillTripleAttack),
|
||||||
|
luabind::value("2HPiercing", EQEmu::skills::Skill2HPiercing),
|
||||||
|
luabind::value("HIGHEST_SKILL", EQEmu::skills::HIGHEST_SKILL)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_bodytypes() {
|
||||||
|
return luabind::class_<BodyTypes>("BT")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
luabind::value("Humanoid", 1),
|
||||||
|
luabind::value("Lycanthrope", 2),
|
||||||
|
luabind::value("Undead", 3),
|
||||||
|
luabind::value("Giant", 4),
|
||||||
|
luabind::value("Construct", 5),
|
||||||
|
luabind::value("Extraplanar", 6),
|
||||||
|
luabind::value("Magical", 7),
|
||||||
|
luabind::value("SummonedUndead", 8),
|
||||||
|
luabind::value("RaidGiant", 9),
|
||||||
|
luabind::value("NoTarget", 11),
|
||||||
|
luabind::value("Vampire", 12),
|
||||||
|
luabind::value("Atenha_Ra", 13),
|
||||||
|
luabind::value("Greater_Akheva", 14),
|
||||||
|
luabind::value("Khati_Sha", 15),
|
||||||
|
luabind::value("Seru", 16),
|
||||||
|
luabind::value("Draz_Nurakk", 18),
|
||||||
|
luabind::value("Zek", 19),
|
||||||
|
luabind::value("Luggald", 20),
|
||||||
|
luabind::value("Animal", 21),
|
||||||
|
luabind::value("Insect", 22),
|
||||||
|
luabind::value("Monster", 23),
|
||||||
|
luabind::value("Summoned", 24),
|
||||||
|
luabind::value("Plant", 25),
|
||||||
|
luabind::value("Dragon", 26),
|
||||||
|
luabind::value("Summoned2", 27),
|
||||||
|
luabind::value("Summoned3", 28),
|
||||||
|
luabind::value("VeliousDragon", 30),
|
||||||
|
luabind::value("Dragon3", 32),
|
||||||
|
luabind::value("Boxes", 33),
|
||||||
|
luabind::value("Muramite", 34),
|
||||||
|
luabind::value("NoTarget2", 60),
|
||||||
|
luabind::value("SwarmPet", 63),
|
||||||
|
luabind::value("InvisMan", 66),
|
||||||
|
luabind::value("Special", 67)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_filters() {
|
||||||
|
return luabind::class_<Filters>("Filter")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
luabind::value("None", FilterNone),
|
||||||
|
luabind::value("GuildChat", FilterGuildChat),
|
||||||
|
luabind::value("Socials", FilterSocials),
|
||||||
|
luabind::value("GroupChat", FilterGroupChat),
|
||||||
|
luabind::value("Shouts", FilterShouts),
|
||||||
|
luabind::value("Auctions", FilterAuctions),
|
||||||
|
luabind::value("OOC", FilterOOC),
|
||||||
|
luabind::value("BadWords", FilterBadWords),
|
||||||
|
luabind::value("PCSpells", FilterPCSpells),
|
||||||
|
luabind::value("NPCSpells", FilterNPCSpells),
|
||||||
|
luabind::value("BardSongs", FilterBardSongs),
|
||||||
|
luabind::value("SpellCrits", FilterSpellCrits),
|
||||||
|
luabind::value("MeleeCrits", FilterMeleeCrits),
|
||||||
|
luabind::value("SpellDamage", FilterSpellDamage),
|
||||||
|
luabind::value("MyMisses", FilterMyMisses),
|
||||||
|
luabind::value("OthersMiss", FilterOthersMiss),
|
||||||
|
luabind::value("OthersHit", FilterOthersHit),
|
||||||
|
luabind::value("MissedMe", FilterMissedMe),
|
||||||
|
luabind::value("DamageShields", FilterDamageShields),
|
||||||
|
luabind::value("DOT", FilterDOT),
|
||||||
|
luabind::value("PetHits", FilterPetHits),
|
||||||
|
luabind::value("PetMisses", FilterPetMisses),
|
||||||
|
luabind::value("FocusEffects", FilterFocusEffects),
|
||||||
|
luabind::value("PetSpells", FilterPetSpells),
|
||||||
|
luabind::value("HealOverTime", FilterHealOverTime),
|
||||||
|
luabind::value("Unknown25", FilterUnknown25),
|
||||||
|
luabind::value("Unknown26", FilterUnknown26),
|
||||||
|
luabind::value("Unknown27", FilterUnknown27),
|
||||||
|
luabind::value("Unknown28", FilterUnknown28)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_message_types() {
|
||||||
|
return luabind::class_<MessageTypes>("MT")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
luabind::value("Say", MT_Say),
|
||||||
|
luabind::value("Tell", MT_Tell),
|
||||||
|
luabind::value("Group", MT_Group),
|
||||||
|
luabind::value("Guild", MT_Guild),
|
||||||
|
luabind::value("OOC", MT_OOC),
|
||||||
|
luabind::value("Auction", MT_Auction),
|
||||||
|
luabind::value("Shout", MT_Shout),
|
||||||
|
luabind::value("Emote", MT_Emote),
|
||||||
|
luabind::value("Spells", MT_Spells),
|
||||||
|
luabind::value("YouHitOther", MT_YouHitOther),
|
||||||
|
luabind::value("OtherHitsYou", MT_OtherHitsYou),
|
||||||
|
luabind::value("YouMissOther", MT_YouMissOther),
|
||||||
|
luabind::value("OtherMissesYou", MT_OtherMissesYou),
|
||||||
|
luabind::value("Broadcasts", MT_Broadcasts),
|
||||||
|
luabind::value("Skills", MT_Skills),
|
||||||
|
luabind::value("Disciplines", MT_Disciplines),
|
||||||
|
luabind::value("Unused1", MT_Unused1),
|
||||||
|
luabind::value("DefaultText", MT_DefaultText),
|
||||||
|
luabind::value("Unused2", MT_Unused2),
|
||||||
|
luabind::value("MerchantOffer", MT_MerchantOffer),
|
||||||
|
luabind::value("MerchantBuySell", MT_MerchantBuySell),
|
||||||
|
luabind::value("YourDeath", MT_YourDeath),
|
||||||
|
luabind::value("OtherDeath", MT_OtherDeath),
|
||||||
|
luabind::value("OtherHits", MT_OtherHits),
|
||||||
|
luabind::value("OtherMisses", MT_OtherMisses),
|
||||||
|
luabind::value("Who", MT_Who),
|
||||||
|
luabind::value("YellForHelp", MT_YellForHelp),
|
||||||
|
luabind::value("NonMelee", MT_NonMelee),
|
||||||
|
luabind::value("WornOff", MT_WornOff),
|
||||||
|
luabind::value("MoneySplit", MT_MoneySplit),
|
||||||
|
luabind::value("LootMessages", MT_LootMessages),
|
||||||
|
luabind::value("DiceRoll", MT_DiceRoll),
|
||||||
|
luabind::value("OtherSpells", MT_OtherSpells),
|
||||||
|
luabind::value("SpellFailure", MT_SpellFailure),
|
||||||
|
luabind::value("Chat", MT_Chat),
|
||||||
|
luabind::value("Channel1", MT_Channel1),
|
||||||
|
luabind::value("Channel2", MT_Channel2),
|
||||||
|
luabind::value("Channel3", MT_Channel3),
|
||||||
|
luabind::value("Channel4", MT_Channel4),
|
||||||
|
luabind::value("Channel5", MT_Channel5),
|
||||||
|
luabind::value("Channel6", MT_Channel6),
|
||||||
|
luabind::value("Channel7", MT_Channel7),
|
||||||
|
luabind::value("Channel8", MT_Channel8),
|
||||||
|
luabind::value("Channel9", MT_Channel9),
|
||||||
|
luabind::value("Channel10", MT_Channel10),
|
||||||
|
luabind::value("CritMelee", MT_CritMelee),
|
||||||
|
luabind::value("SpellCrits", MT_SpellCrits),
|
||||||
|
luabind::value("TooFarAway", MT_TooFarAway),
|
||||||
|
luabind::value("NPCRampage", MT_NPCRampage),
|
||||||
|
luabind::value("NPCFlurry", MT_NPCFlurry),
|
||||||
|
luabind::value("NPCEnrage", MT_NPCEnrage),
|
||||||
|
luabind::value("SayEcho", MT_SayEcho),
|
||||||
|
luabind::value("TellEcho", MT_TellEcho),
|
||||||
|
luabind::value("GroupEcho", MT_GroupEcho),
|
||||||
|
luabind::value("GuildEcho", MT_GuildEcho),
|
||||||
|
luabind::value("OOCEcho", MT_OOCEcho),
|
||||||
|
luabind::value("AuctionEcho", MT_AuctionEcho),
|
||||||
|
luabind::value("ShoutECho", MT_ShoutECho),
|
||||||
|
luabind::value("EmoteEcho", MT_EmoteEcho),
|
||||||
|
luabind::value("Chat1Echo", MT_Chat1Echo),
|
||||||
|
luabind::value("Chat2Echo", MT_Chat2Echo),
|
||||||
|
luabind::value("Chat3Echo", MT_Chat3Echo),
|
||||||
|
luabind::value("Chat4Echo", MT_Chat4Echo),
|
||||||
|
luabind::value("Chat5Echo", MT_Chat5Echo),
|
||||||
|
luabind::value("Chat6Echo", MT_Chat6Echo),
|
||||||
|
luabind::value("Chat7Echo", MT_Chat7Echo),
|
||||||
|
luabind::value("Chat8Echo", MT_Chat8Echo),
|
||||||
|
luabind::value("Chat9Echo", MT_Chat9Echo),
|
||||||
|
luabind::value("Chat10Echo", MT_Chat10Echo),
|
||||||
|
luabind::value("DoTDamage", MT_DoTDamage),
|
||||||
|
luabind::value("ItemLink", MT_ItemLink),
|
||||||
|
luabind::value("RaidSay", MT_RaidSay),
|
||||||
|
luabind::value("MyPet", MT_MyPet),
|
||||||
|
luabind::value("DS", MT_DS),
|
||||||
|
luabind::value("Leadership", MT_Leadership),
|
||||||
|
luabind::value("PetFlurry", MT_PetFlurry),
|
||||||
|
luabind::value("PetCrit", MT_PetCrit),
|
||||||
|
luabind::value("FocusEffect", MT_FocusEffect),
|
||||||
|
luabind::value("Experience", MT_Experience),
|
||||||
|
luabind::value("System", MT_System),
|
||||||
|
luabind::value("PetSpell", MT_PetSpell),
|
||||||
|
luabind::value("PetResponse", MT_PetResponse),
|
||||||
|
luabind::value("ItemSpeech", MT_ItemSpeech),
|
||||||
|
luabind::value("StrikeThrough", MT_StrikeThrough),
|
||||||
|
luabind::value("Stun", MT_Stun)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_rules_const() {
|
||||||
|
return luabind::class_<Rule>("Rule")
|
||||||
|
.enum_("constants")
|
||||||
|
[
|
||||||
|
#define RULE_INT(cat, rule, default_value) \
|
||||||
|
luabind::value(#rule, RuleManager::Int__##rule),
|
||||||
|
#include "../common/ruletypes.h"
|
||||||
|
luabind::value("_IntRuleCount", RuleManager::_IntRuleCount),
|
||||||
|
#undef RULE_INT
|
||||||
|
#define RULE_REAL(cat, rule, default_value) \
|
||||||
|
luabind::value(#rule, RuleManager::Real__##rule),
|
||||||
|
#include "../common/ruletypes.h"
|
||||||
|
luabind::value("_RealRuleCount", RuleManager::_RealRuleCount),
|
||||||
|
#undef RULE_REAL
|
||||||
|
#define RULE_BOOL(cat, rule, default_value) \
|
||||||
|
luabind::value(#rule, RuleManager::Bool__##rule),
|
||||||
|
#include "../common/ruletypes.h"
|
||||||
|
luabind::value("_BoolRuleCount", RuleManager::_BoolRuleCount)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_rulei() {
|
||||||
|
return luabind::namespace_("RuleI")
|
||||||
|
[
|
||||||
|
luabind::def("Get", &get_rulei)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_ruler() {
|
||||||
|
return luabind::namespace_("RuleR")
|
||||||
|
[
|
||||||
|
luabind::def("Get", &get_ruler)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
luabind::scope lua_register_ruleb() {
|
||||||
|
return luabind::namespace_("RuleB")
|
||||||
|
[
|
||||||
|
luabind::def("Get", &get_ruleb)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -3,12 +3,22 @@
|
|||||||
#ifdef LUA_EQEMU
|
#ifdef LUA_EQEMU
|
||||||
|
|
||||||
luabind::scope lua_register_general();
|
luabind::scope lua_register_general();
|
||||||
|
luabind::scope lua_register_random();
|
||||||
luabind::scope lua_register_events();
|
luabind::scope lua_register_events();
|
||||||
luabind::scope lua_register_faction();
|
luabind::scope lua_register_faction();
|
||||||
luabind::scope lua_register_slot();
|
luabind::scope lua_register_slot();
|
||||||
luabind::scope lua_register_material();
|
luabind::scope lua_register_material();
|
||||||
luabind::scope lua_register_client_version();
|
luabind::scope lua_register_client_version();
|
||||||
luabind::scope lua_register_appearance();
|
luabind::scope lua_register_appearance();
|
||||||
|
luabind::scope lua_register_classes();
|
||||||
|
luabind::scope lua_register_skills();
|
||||||
|
luabind::scope lua_register_bodytypes();
|
||||||
|
luabind::scope lua_register_filters();
|
||||||
|
luabind::scope lua_register_message_types();
|
||||||
|
luabind::scope lua_register_rules_const();
|
||||||
|
luabind::scope lua_register_rulei();
|
||||||
|
luabind::scope lua_register_ruler();
|
||||||
|
luabind::scope lua_register_ruleb();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
115
zone/lua_mob.cpp
115
zone/lua_mob.cpp
@ -10,6 +10,7 @@
|
|||||||
#include "lua_mob.h"
|
#include "lua_mob.h"
|
||||||
#include "lua_hate_list.h"
|
#include "lua_hate_list.h"
|
||||||
#include "lua_client.h"
|
#include "lua_client.h"
|
||||||
|
#include "lua_stat_bonuses.h"
|
||||||
|
|
||||||
struct SpecialAbilities { };
|
struct SpecialAbilities { };
|
||||||
|
|
||||||
@ -1725,6 +1726,18 @@ int Lua_Mob::GetSkillDmgTaken(int skill) {
|
|||||||
return self->GetSkillDmgTaken(static_cast<EQEmu::skills::SkillType>(skill));
|
return self->GetSkillDmgTaken(static_cast<EQEmu::skills::SkillType>(skill));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetFcDamageAmtIncoming(Lua_Mob caster, uint32 spell_id, bool use_skill, uint16 skill)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetFcDamageAmtIncoming(caster, spell_id, use_skill, skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetSkillDmgAmt(uint16 skill)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetSkillDmgAmt(skill);
|
||||||
|
}
|
||||||
|
|
||||||
void Lua_Mob::SetAllowBeneficial(bool value) {
|
void Lua_Mob::SetAllowBeneficial(bool value) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->SetAllowBeneficial(value);
|
self->SetAllowBeneficial(value);
|
||||||
@ -1985,6 +1998,89 @@ int32 Lua_Mob::GetMeleeMitigation() {
|
|||||||
return self->GetMeleeMitigation();
|
return self->GetMeleeMitigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetWeaponDamageBonus(Lua_Item weapon, bool offhand) {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetWeaponDamageBonus(weapon, offhand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lua_StatBonuses Lua_Mob::GetItemBonuses()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Class(Lua_StatBonuses);
|
||||||
|
return self->GetItemBonusesPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Lua_StatBonuses Lua_Mob::GetSpellBonuses()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Class(Lua_StatBonuses);
|
||||||
|
return self->GetSpellBonusesPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Lua_StatBonuses Lua_Mob::GetAABonuses()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Class(Lua_StatBonuses);
|
||||||
|
return self->GetAABonusesPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 Lua_Mob::GetMeleeDamageMod_SE(uint16 skill)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetMeleeDamageMod_SE(skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 Lua_Mob::GetMeleeMinDamageMod_SE(uint16 skill)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetMeleeMinDamageMod_SE(skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Mob::IsAttackAllowed(Lua_Mob target, bool isSpellAttack) {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsAttackAllowed(target, isSpellAttack);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Mob::IsCasting() {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsCasting();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::AttackAnimation(int Hand, Lua_ItemInst weapon) {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return (int)self->AttackAnimation(Hand, weapon);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetWeaponDamage(Lua_Mob against, Lua_ItemInst weapon) {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetWeaponDamage(against, weapon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Mob::IsBerserk() {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsBerserk();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Mob::TryFinishingBlow(Lua_Mob defender, int &damage) {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->TryFinishingBlow(defender, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetBodyType()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return (int)self->GetBodyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_Mob::GetOrigBodyType()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return (int)self->GetOrigBodyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Mob::CheckNumHitsRemaining(int type, int32 buff_slot, uint16 spell_id)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->CheckNumHitsRemaining((NumHit)type, buff_slot, spell_id);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_mob() {
|
luabind::scope lua_register_mob() {
|
||||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -2281,6 +2377,8 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("ModSkillDmgTaken", (void(Lua_Mob::*)(int,int))&Lua_Mob::ModSkillDmgTaken)
|
.def("ModSkillDmgTaken", (void(Lua_Mob::*)(int,int))&Lua_Mob::ModSkillDmgTaken)
|
||||||
.def("GetModSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetModSkillDmgTaken)
|
.def("GetModSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetModSkillDmgTaken)
|
||||||
.def("GetSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetSkillDmgTaken)
|
.def("GetSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetSkillDmgTaken)
|
||||||
|
.def("GetFcDamageAmtIncoming", &Lua_Mob::GetFcDamageAmtIncoming)
|
||||||
|
.def("GetSkillDmgAmt", (int(Lua_Mob::*)(int))&Lua_Mob::GetSkillDmgAmt)
|
||||||
.def("SetAllowBeneficial", (void(Lua_Mob::*)(bool))&Lua_Mob::SetAllowBeneficial)
|
.def("SetAllowBeneficial", (void(Lua_Mob::*)(bool))&Lua_Mob::SetAllowBeneficial)
|
||||||
.def("GetAllowBeneficial", (bool(Lua_Mob::*)(void))&Lua_Mob::GetAllowBeneficial)
|
.def("GetAllowBeneficial", (bool(Lua_Mob::*)(void))&Lua_Mob::GetAllowBeneficial)
|
||||||
.def("IsBeneficialAllowed", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsBeneficialAllowed)
|
.def("IsBeneficialAllowed", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsBeneficialAllowed)
|
||||||
@ -2330,7 +2428,22 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet)
|
.def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet)
|
||||||
.def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced)
|
.def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced)
|
||||||
.def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad)
|
.def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad)
|
||||||
.def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation);
|
.def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation)
|
||||||
|
.def("GetWeaponDamageBonus", &Lua_Mob::GetWeaponDamageBonus)
|
||||||
|
.def("GetItemBonuses", &Lua_Mob::GetItemBonuses)
|
||||||
|
.def("GetSpellBonuses", &Lua_Mob::GetSpellBonuses)
|
||||||
|
.def("GetAABonuses", &Lua_Mob::GetAABonuses)
|
||||||
|
.def("GetMeleeDamageMod_SE", &Lua_Mob::GetMeleeDamageMod_SE)
|
||||||
|
.def("GetMeleeMinDamageMod_SE", &Lua_Mob::GetMeleeMinDamageMod_SE)
|
||||||
|
.def("IsAttackAllowed", &Lua_Mob::IsAttackAllowed)
|
||||||
|
.def("IsCasting", &Lua_Mob::IsCasting)
|
||||||
|
.def("AttackAnimation", &Lua_Mob::AttackAnimation)
|
||||||
|
.def("GetWeaponDamage", &Lua_Mob::GetWeaponDamage)
|
||||||
|
.def("IsBerserk", &Lua_Mob::IsBerserk)
|
||||||
|
.def("TryFinishingBlow", &Lua_Mob::TryFinishingBlow)
|
||||||
|
.def("GetBodyType", &Lua_Mob::GetBodyType)
|
||||||
|
.def("GetOrigBodyType", &Lua_Mob::GetOrigBodyType)
|
||||||
|
.def("CheckNumHitsRemaining", &Lua_Mob::CheckNumHitsRemaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_special_abilities() {
|
luabind::scope lua_register_special_abilities() {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ class Mob;
|
|||||||
struct Lua_HateList;
|
struct Lua_HateList;
|
||||||
class Lua_Item;
|
class Lua_Item;
|
||||||
class Lua_ItemInst;
|
class Lua_ItemInst;
|
||||||
|
class Lua_StatBonuses;
|
||||||
|
|
||||||
namespace luabind {
|
namespace luabind {
|
||||||
struct scope;
|
struct scope;
|
||||||
@ -330,6 +331,8 @@ public:
|
|||||||
void ModSkillDmgTaken(int skill, int value);
|
void ModSkillDmgTaken(int skill, int value);
|
||||||
int GetModSkillDmgTaken(int skill);
|
int GetModSkillDmgTaken(int skill);
|
||||||
int GetSkillDmgTaken(int skill);
|
int GetSkillDmgTaken(int skill);
|
||||||
|
int GetFcDamageAmtIncoming(Lua_Mob caster, uint32 spell_id, bool use_skill, uint16 skill);
|
||||||
|
int GetSkillDmgAmt(uint16 skill);
|
||||||
void SetAllowBeneficial(bool value);
|
void SetAllowBeneficial(bool value);
|
||||||
bool GetAllowBeneficial();
|
bool GetAllowBeneficial();
|
||||||
bool IsBeneficialAllowed(Lua_Mob target);
|
bool IsBeneficialAllowed(Lua_Mob target);
|
||||||
@ -340,7 +343,6 @@ public:
|
|||||||
void SetFlurryChance(int value);
|
void SetFlurryChance(int value);
|
||||||
int GetFlurryChance();
|
int GetFlurryChance();
|
||||||
int GetSkill(int skill_id);
|
int GetSkill(int skill_id);
|
||||||
void CalcBonuses();
|
|
||||||
int GetSpecialAbility(int ability);
|
int GetSpecialAbility(int ability);
|
||||||
int GetSpecialAbilityParam(int ability, int param);
|
int GetSpecialAbilityParam(int ability, int param);
|
||||||
void SetSpecialAbility(int ability, int level);
|
void SetSpecialAbility(int ability, int level);
|
||||||
@ -381,6 +383,21 @@ public:
|
|||||||
bool IsSilenced();
|
bool IsSilenced();
|
||||||
bool IsAmnesiad();
|
bool IsAmnesiad();
|
||||||
int32 GetMeleeMitigation();
|
int32 GetMeleeMitigation();
|
||||||
|
int GetWeaponDamageBonus(Lua_Item weapon, bool offhand);
|
||||||
|
Lua_StatBonuses GetItemBonuses();
|
||||||
|
Lua_StatBonuses GetSpellBonuses();
|
||||||
|
Lua_StatBonuses GetAABonuses();
|
||||||
|
int16 GetMeleeDamageMod_SE(uint16 skill);
|
||||||
|
int16 GetMeleeMinDamageMod_SE(uint16 skill);
|
||||||
|
bool IsAttackAllowed(Lua_Mob target, bool isSpellAttack);
|
||||||
|
bool IsCasting();
|
||||||
|
int AttackAnimation(int Hand, Lua_ItemInst weapon);
|
||||||
|
int GetWeaponDamage(Lua_Mob against, Lua_ItemInst weapon);
|
||||||
|
bool IsBerserk();
|
||||||
|
bool TryFinishingBlow(Lua_Mob defender, int &damage);
|
||||||
|
int GetBodyType();
|
||||||
|
int GetOrigBodyType();
|
||||||
|
void CheckNumHitsRemaining(int type, int32 buff_slot, uint16 spell_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
631
zone/lua_mod.cpp
Normal file
631
zone/lua_mod.cpp
Normal file
@ -0,0 +1,631 @@
|
|||||||
|
#include "lua.hpp"
|
||||||
|
#include <luabind/luabind.hpp>
|
||||||
|
#include <luabind/object.hpp>
|
||||||
|
|
||||||
|
#include "../common/spdat.h"
|
||||||
|
#include "masterentity.h"
|
||||||
|
#include "questmgr.h"
|
||||||
|
#include "zone.h"
|
||||||
|
#include "zone_config.h"
|
||||||
|
|
||||||
|
#include "lua_parser.h"
|
||||||
|
#include "lua_mod.h"
|
||||||
|
#include "lua_bit.h"
|
||||||
|
#include "lua_entity.h"
|
||||||
|
#include "lua_item.h"
|
||||||
|
#include "lua_iteminst.h"
|
||||||
|
#include "lua_mob.h"
|
||||||
|
#include "lua_hate_list.h"
|
||||||
|
#include "lua_client.h"
|
||||||
|
#include "lua_inventory.h"
|
||||||
|
#include "lua_npc.h"
|
||||||
|
#include "lua_spell.h"
|
||||||
|
#include "lua_entity_list.h"
|
||||||
|
#include "lua_group.h"
|
||||||
|
#include "lua_raid.h"
|
||||||
|
#include "lua_corpse.h"
|
||||||
|
#include "lua_object.h"
|
||||||
|
#include "lua_door.h"
|
||||||
|
#include "lua_spawn.h"
|
||||||
|
#include "lua_packet.h"
|
||||||
|
#include "lua_general.h"
|
||||||
|
#include "lua_encounter.h"
|
||||||
|
#include "lua_stat_bonuses.h"
|
||||||
|
|
||||||
|
void LuaMod::Init()
|
||||||
|
{
|
||||||
|
m_has_melee_mitigation = parser_->HasFunction("MeleeMitigation", package_name_);
|
||||||
|
m_has_apply_damage_table = parser_->HasFunction("ApplyDamageTable", package_name_);
|
||||||
|
m_has_avoid_damage = parser_->HasFunction("AvoidDamage", package_name_);
|
||||||
|
m_has_check_hit_chance = parser_->HasFunction("CheckHitChance", package_name_);
|
||||||
|
m_has_try_critical_hit = parser_->HasFunction("TryCriticalHit", package_name_);
|
||||||
|
m_has_get_required_aa_experience = parser_->HasFunction("GetRequiredAAExperience", package_name_);
|
||||||
|
m_has_get_exp_for_level = parser_->HasFunction("GetEXPForLevel", package_name_);
|
||||||
|
m_has_get_experience_for_kill = parser_->HasFunction("GetExperienceForKill", package_name_);
|
||||||
|
m_has_common_outgoing_hit_success = parser_->HasFunction("CommonOutgoingHitSuccess", package_name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutDamageHitInfo(lua_State *L, luabind::adl::object &e, DamageHitInfo &hit) {
|
||||||
|
luabind::adl::object lua_hit = luabind::newtable(L);
|
||||||
|
lua_hit["base_damage"] = hit.base_damage;
|
||||||
|
lua_hit["min_damage"] = hit.min_damage;
|
||||||
|
lua_hit["damage_done"] = hit.damage_done;
|
||||||
|
lua_hit["offense"] = hit.offense;
|
||||||
|
lua_hit["tohit"] = hit.tohit;
|
||||||
|
lua_hit["hand"] = hit.hand;
|
||||||
|
lua_hit["skill"] = (int)hit.skill;
|
||||||
|
e["hit"] = lua_hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDamageHitInfo(luabind::adl::object &ret, DamageHitInfo &hit) {
|
||||||
|
auto luaHitTable = ret["hit"];
|
||||||
|
if (luabind::type(luaHitTable) == LUA_TTABLE) {
|
||||||
|
auto base_damage = luaHitTable["base_damage"];
|
||||||
|
auto min_damage = luaHitTable["min_damage"];
|
||||||
|
auto damage_done = luaHitTable["damage_done"];
|
||||||
|
auto offense = luaHitTable["offense"];
|
||||||
|
auto tohit = luaHitTable["tohit"];
|
||||||
|
auto hand = luaHitTable["hand"];
|
||||||
|
auto skill = luaHitTable["skill"];
|
||||||
|
|
||||||
|
if (luabind::type(base_damage) == LUA_TNUMBER) {
|
||||||
|
hit.base_damage = luabind::object_cast<int>(base_damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(min_damage) == LUA_TNUMBER) {
|
||||||
|
hit.min_damage = luabind::object_cast<int>(min_damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(damage_done) == LUA_TNUMBER) {
|
||||||
|
hit.damage_done = luabind::object_cast<int>(damage_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(offense) == LUA_TNUMBER) {
|
||||||
|
hit.offense = luabind::object_cast<int>(offense);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(tohit) == LUA_TNUMBER) {
|
||||||
|
hit.tohit = luabind::object_cast<int>(tohit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(hand) == LUA_TNUMBER) {
|
||||||
|
hit.hand = luabind::object_cast<int>(hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(skill) == LUA_TNUMBER) {
|
||||||
|
hit.skill = (EQEmu::skills::SkillType)luabind::object_cast<int>(skill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutExtraAttackOptions(lua_State *L, luabind::adl::object &e, ExtraAttackOptions *opts) {
|
||||||
|
if (opts) {
|
||||||
|
luabind::adl::object lua_opts = luabind::newtable(L);
|
||||||
|
lua_opts["damage_percent"] = opts->damage_percent;
|
||||||
|
lua_opts["damage_flat"] = opts->damage_flat;
|
||||||
|
lua_opts["armor_pen_percent"] = opts->armor_pen_percent;
|
||||||
|
lua_opts["armor_pen_flat"] = opts->armor_pen_flat;
|
||||||
|
lua_opts["crit_percent"] = opts->crit_percent;
|
||||||
|
lua_opts["crit_flat"] = opts->crit_flat;
|
||||||
|
lua_opts["hate_percent"] = opts->hate_percent;
|
||||||
|
lua_opts["hate_flat"] = opts->hate_flat;
|
||||||
|
lua_opts["hit_chance"] = opts->hit_chance;
|
||||||
|
lua_opts["melee_damage_bonus_flat"] = opts->melee_damage_bonus_flat;
|
||||||
|
lua_opts["skilldmgtaken_bonus_flat"] = opts->skilldmgtaken_bonus_flat;
|
||||||
|
e["opts"] = lua_opts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetExtraAttackOptions(luabind::adl::object &ret, ExtraAttackOptions *opts) {
|
||||||
|
if (opts) {
|
||||||
|
auto luaOptsTable = ret["opts"];
|
||||||
|
if (luabind::type(luaOptsTable) == LUA_TTABLE) {
|
||||||
|
auto damage_percent = luaOptsTable["damage_percent"];
|
||||||
|
auto damage_flat = luaOptsTable["damage_flat"];
|
||||||
|
auto armor_pen_percent = luaOptsTable["armor_pen_percent"];
|
||||||
|
auto armor_pen_flat = luaOptsTable["armor_pen_flat"];
|
||||||
|
auto crit_percent = luaOptsTable["crit_percent"];
|
||||||
|
auto crit_flat = luaOptsTable["crit_flat"];
|
||||||
|
auto hate_percent = luaOptsTable["hate_percent"];
|
||||||
|
auto hate_flat = luaOptsTable["hate_flat"];
|
||||||
|
auto hit_chance = luaOptsTable["hit_chance"];
|
||||||
|
auto melee_damage_bonus_flat = luaOptsTable["melee_damage_bonus_flat"];
|
||||||
|
auto skilldmgtaken_bonus_flat = luaOptsTable["skilldmgtaken_bonus_flat"];
|
||||||
|
|
||||||
|
if (luabind::type(damage_percent) == LUA_TNUMBER) {
|
||||||
|
opts->damage_percent = luabind::object_cast<float>(damage_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(damage_flat) == LUA_TNUMBER) {
|
||||||
|
opts->damage_flat = luabind::object_cast<int>(damage_flat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(armor_pen_percent) == LUA_TNUMBER) {
|
||||||
|
opts->armor_pen_percent = luabind::object_cast<float>(armor_pen_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(armor_pen_flat) == LUA_TNUMBER) {
|
||||||
|
opts->armor_pen_flat = luabind::object_cast<int>(armor_pen_flat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(crit_percent) == LUA_TNUMBER) {
|
||||||
|
opts->crit_percent = luabind::object_cast<float>(crit_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(crit_flat) == LUA_TNUMBER) {
|
||||||
|
opts->crit_flat = luabind::object_cast<float>(crit_flat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(hate_percent) == LUA_TNUMBER) {
|
||||||
|
opts->hate_percent = luabind::object_cast<float>(hate_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(hate_flat) == LUA_TNUMBER) {
|
||||||
|
opts->hate_flat = luabind::object_cast<int>(hate_flat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(hit_chance) == LUA_TNUMBER) {
|
||||||
|
opts->hit_chance = luabind::object_cast<int>(hit_chance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(melee_damage_bonus_flat) == LUA_TNUMBER) {
|
||||||
|
opts->melee_damage_bonus_flat = luabind::object_cast<int>(melee_damage_bonus_flat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (luabind::type(skilldmgtaken_bonus_flat) == LUA_TNUMBER) {
|
||||||
|
opts->skilldmgtaken_bonus_flat = luabind::object_cast<int>(skilldmgtaken_bonus_flat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_melee_mitigation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "MeleeMitigation");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
Lua_Mob l_other(attacker);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
PutExtraAttackOptions(L, e, opts);
|
||||||
|
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
GetExtraAttackOptions(ret, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_apply_damage_table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "ApplyDamageTable");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &returnValue, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_avoid_damage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "AvoidDamage");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
Lua_Mob l_other(other);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnValueObj = ret["ReturnValue"];
|
||||||
|
if (luabind::type(returnValueObj) == LUA_TBOOLEAN) {
|
||||||
|
returnValue = luabind::object_cast<bool>(returnValueObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &returnValue, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_check_hit_chance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "CheckHitChance");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
Lua_Mob l_other(other);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnValueObj = ret["ReturnValue"];
|
||||||
|
if (luabind::type(returnValueObj) == LUA_TBOOLEAN) {
|
||||||
|
returnValue = luabind::object_cast<bool>(returnValueObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::CommonOutgoingHitSuccess(Mob *self, Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault)
|
||||||
|
{
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_common_outgoing_hit_success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "CommonOutgoingHitSuccess");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
Lua_Mob l_other(other);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
PutExtraAttackOptions(L, e, opts);
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
GetExtraAttackOptions(ret, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::TryCriticalHit(Mob *self, Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_try_critical_hit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "TryCriticalHit");
|
||||||
|
|
||||||
|
Lua_Mob l_self(self);
|
||||||
|
Lua_Mob l_other(defender);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
|
||||||
|
PutDamageHitInfo(L, e, hit);
|
||||||
|
PutExtraAttackOptions(L, e, opts);
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDamageHitInfo(ret, hit);
|
||||||
|
GetExtraAttackOptions(ret, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::GetRequiredAAExperience(Client *self, uint32 &returnValue, bool &ignoreDefault)
|
||||||
|
{
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_get_required_aa_experience) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "GetRequiredAAExperience");
|
||||||
|
|
||||||
|
Lua_Client l_self(self);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnValueObj = ret["ReturnValue"];
|
||||||
|
if (luabind::type(returnValueObj) == LUA_TNUMBER) {
|
||||||
|
returnValue = luabind::object_cast<uint32>(returnValueObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::GetEXPForLevel(Client *self, uint16 level, uint32 &returnValue, bool &ignoreDefault) {
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_get_exp_for_level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "GetEXPForLevel");
|
||||||
|
|
||||||
|
Lua_Client l_self(self);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["level"] = level;
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnValueObj = ret["ReturnValue"];
|
||||||
|
if (luabind::type(returnValueObj) == LUA_TNUMBER) {
|
||||||
|
returnValue = luabind::object_cast<uint32>(returnValueObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaMod::GetExperienceForKill(Client *self, Mob *against, uint32 &returnValue, bool &ignoreDefault)
|
||||||
|
{
|
||||||
|
int start = lua_gettop(L);
|
||||||
|
uint32 retval = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!m_has_get_experience_for_kill) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
|
||||||
|
lua_getfield(L, -1, "GetExperienceForKill");
|
||||||
|
|
||||||
|
Lua_Client l_self(self);
|
||||||
|
Lua_Mob l_other(against);
|
||||||
|
luabind::adl::object e = luabind::newtable(L);
|
||||||
|
e["self"] = l_self;
|
||||||
|
e["other"] = l_other;
|
||||||
|
e.push(L);
|
||||||
|
|
||||||
|
if (lua_pcall(L, 1, 1, 0)) {
|
||||||
|
std::string error = lua_tostring(L, -1);
|
||||||
|
parser_->AddError(error);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, -1) == LUA_TTABLE) {
|
||||||
|
luabind::adl::object ret(luabind::from_stack(L, -1));
|
||||||
|
auto IgnoreDefaultObj = ret["IgnoreDefault"];
|
||||||
|
if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) {
|
||||||
|
ignoreDefault = ignoreDefault || luabind::object_cast<bool>(IgnoreDefaultObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnValueObj = ret["ReturnValue"];
|
||||||
|
if (luabind::type(returnValueObj) == LUA_TNUMBER) {
|
||||||
|
returnValue = luabind::object_cast<uint32>(returnValueObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
parser_->AddError(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = lua_gettop(L);
|
||||||
|
int n = end - start;
|
||||||
|
if (n > 0) {
|
||||||
|
lua_pop(L, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
zone/lua_mod.h
Normal file
43
zone/lua_mod.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
class LuaParser;
|
||||||
|
class LuaMod
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LuaMod(lua_State *ls, LuaParser *lp, const std::string &package_name) {
|
||||||
|
L = ls;
|
||||||
|
parser_ = lp;
|
||||||
|
package_name_ = package_name;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
~LuaMod() { }
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
void MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault);
|
||||||
|
void ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault);
|
||||||
|
void AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &returnValue, bool &ignoreDefault);
|
||||||
|
void CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &returnValue, bool &ignoreDefault);
|
||||||
|
void CommonOutgoingHitSuccess(Mob *self, Mob* other, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault);
|
||||||
|
void TryCriticalHit(Mob *self, Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault);
|
||||||
|
void GetRequiredAAExperience(Client *self, uint32 &returnValue, bool &ignoreDefault);
|
||||||
|
void GetEXPForLevel(Client *self, uint16 level, uint32 &returnValue, bool &ignoreDefault);
|
||||||
|
void GetExperienceForKill(Client *self, Mob *against, uint32 &returnValue, bool &ignoreDefault);
|
||||||
|
private:
|
||||||
|
LuaParser *parser_;
|
||||||
|
lua_State *L;
|
||||||
|
std::string package_name_;
|
||||||
|
|
||||||
|
bool m_has_melee_mitigation;
|
||||||
|
bool m_has_apply_damage_table;
|
||||||
|
bool m_has_avoid_damage;
|
||||||
|
bool m_has_check_hit_chance;
|
||||||
|
bool m_has_common_outgoing_hit_success;
|
||||||
|
bool m_has_try_critical_hit;
|
||||||
|
bool m_has_get_required_aa_experience;
|
||||||
|
bool m_has_get_exp_for_level;
|
||||||
|
bool m_has_get_experience_for_kill;
|
||||||
|
};
|
||||||
@ -498,6 +498,17 @@ uint8 Lua_NPC::GetMerchantProbability() {
|
|||||||
return self->GetMerchantProbability();
|
return self->GetMerchantProbability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Lua_NPC::GetRawAC() {
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetRawAC();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Lua_NPC::GetAvoidanceRating()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Int();
|
||||||
|
return self->GetAvoidanceRating();
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_npc() {
|
luabind::scope lua_register_npc() {
|
||||||
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -598,7 +609,9 @@ luabind::scope lua_register_npc() {
|
|||||||
.def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop)
|
.def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop)
|
||||||
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
||||||
.def("SetMerchantProbability", (void(Lua_NPC::*)(void))&Lua_NPC::SetMerchantProbability)
|
.def("SetMerchantProbability", (void(Lua_NPC::*)(void))&Lua_NPC::SetMerchantProbability)
|
||||||
.def("GetMerchantProbability", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetMerchantProbability);
|
.def("GetMerchantProbability", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetMerchantProbability)
|
||||||
|
.def("GetRawAC", (int(Lua_NPC::*)(void))&Lua_NPC::GetRawAC)
|
||||||
|
.def("GetAvoidanceRating", &Lua_NPC::GetAvoidanceRating);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user