mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-14 15:41:30 +00:00
commit
519c049902
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,5 +33,7 @@ Build_32/
|
||||
build_32/
|
||||
Build_64/
|
||||
build_64/
|
||||
x64/
|
||||
x86/
|
||||
log/
|
||||
logs/
|
||||
|
||||
@ -13,12 +13,6 @@
|
||||
#EQEMU_LOG_LEVEL_QUEST
|
||||
#EQEMU_LOG_LEVEL_COMMANDS
|
||||
#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_ENABLE_BOTS
|
||||
#EQEMU_DISABLE_LOGSYS
|
||||
@ -78,7 +72,7 @@ IF(MSVC)
|
||||
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
|
||||
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
|
||||
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)
|
||||
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
|
||||
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)
|
||||
|
||||
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
|
||||
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(-DFIELD_ITEMS)
|
||||
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_NORMAL=${EQEMU_LOG_LEVEL_NORMAL})
|
||||
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(-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_PACKAGE(ZLIB 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++**
|
||||
* 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
|
||||
* 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
|
||||
* 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)
|
||||
* [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
|
||||
|
||||
### > 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
|
||||
|
||||
|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)
|
||||
-------------------------------------------------------
|
||||
|
||||
== 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 ==
|
||||
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).
|
||||
-TCP Server to Server connection stack completely rewritten.
|
||||
-Server connections reconnect much more reliably and quickly now.
|
||||
-Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/).
|
||||
-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.
|
||||
-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.
|
||||
-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).
|
||||
- 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.
|
||||
- Server connections reconnect much more reliably and quickly now.
|
||||
- Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/).
|
||||
- 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.
|
||||
- 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.
|
||||
- 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).
|
||||
|
||||
-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%/
|
||||
-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.
|
||||
-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.
|
||||
-To enable telnet you need to add a telnet tag in the world section of configuration such as:
|
||||
- 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%/
|
||||
- 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.
|
||||
- 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.
|
||||
- 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"/>
|
||||
|
||||
== 4/1/2017 ==
|
||||
|
||||
@ -103,6 +103,7 @@ SET(common_sources
|
||||
tinyxml/tinyxml.cpp
|
||||
tinyxml/tinyxmlerror.cpp
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
util/directory.cpp
|
||||
util/uuid.cpp
|
||||
)
|
||||
|
||||
@ -257,6 +258,7 @@ SET(common_headers
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
util/memory_stream.h
|
||||
util/directory.h
|
||||
util/uuid.h
|
||||
)
|
||||
|
||||
@ -366,6 +368,8 @@ SOURCE_GROUP(TinyXML FILES
|
||||
|
||||
SOURCE_GROUP(Util FILES
|
||||
util/memory_stream.h
|
||||
util/directory.cpp
|
||||
util/directory.h
|
||||
util/uuid.cpp
|
||||
util/uuid.h
|
||||
)
|
||||
|
||||
@ -355,6 +355,7 @@ N(OP_OpenTributeMaster),
|
||||
N(OP_PDeletePetition),
|
||||
N(OP_PetBuffWindow),
|
||||
N(OP_PetCommands),
|
||||
N(OP_PetCommandState),
|
||||
N(OP_PetHoTT),
|
||||
N(OP_Petition),
|
||||
N(OP_PetitionBug),
|
||||
@ -407,6 +408,7 @@ N(OP_ReloadUI),
|
||||
N(OP_RemoveAllDoors),
|
||||
N(OP_RemoveBlockedBuffs),
|
||||
N(OP_RemoveNimbusEffect),
|
||||
N(OP_RemoveTrap),
|
||||
N(OP_Report),
|
||||
N(OP_ReqClientSpawn),
|
||||
N(OP_ReqNewZone),
|
||||
@ -522,6 +524,7 @@ N(OP_TributeToggle),
|
||||
N(OP_TributeUpdate),
|
||||
N(OP_Untargetable),
|
||||
N(OP_UpdateAA),
|
||||
N(OP_UpdateAura),
|
||||
N(OP_UpdateLeadershipAA),
|
||||
N(OP_VetClaimReply),
|
||||
N(OP_VetClaimRequest),
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
//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_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_PVP 4 // 0 = blue, 1 = pvp (red)
|
||||
#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_HP 17 // Client->Server, my HP has changed (like regen tic)
|
||||
#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_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
||||
#define AT_GuildID 22
|
||||
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
||||
#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_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_Size 29 // spawn's size (present: SoF, absent: RoF2)
|
||||
//#define AT_30 30 // unknown
|
||||
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name
|
||||
//#define AT_32 32 // unknown
|
||||
//#define AT_33 33 // 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, Trader on RoF2?
|
||||
#define AT_AARank 32 // AA Rank Title ID thingy, does is this the title in /who?
|
||||
#define AT_CancelSneakHide 33 // Turns off Hide and Sneak
|
||||
//#define AT_34 34 // unknown (present: SoF, absent: RoF2)
|
||||
//#define AT_35 35 // unknown
|
||||
//#define AT_36 36 // unknown
|
||||
//#define AT_37 37 // unknown
|
||||
//#define AT_38 38 // unknown
|
||||
//#define AT_39 39 // unknown
|
||||
#define AT_AreaHPRegen 35 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_AreaManaRegen 36 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_AreaEndRegen 37 // guild hall regen pool sets to value * 0.001
|
||||
#define AT_FreezeBuffs 38 // Freezes beneficial buff timers
|
||||
#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_DamageState 44 // The damage state of a destructible object (0 through 4)
|
||||
//#define AT_46 46 // unknown
|
||||
//#define AT_48 48 // unknown
|
||||
//#define AT_49 49 // unknown
|
||||
//#define AT_52 52 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
||||
//#define AT_53 53 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
||||
#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_EQPlayers 45 // /eqplayersupdate
|
||||
#define AT_FindBits 46 // set FindBits, whatever those are!
|
||||
#define AT_TextureType 48 // TextureType
|
||||
#define AT_FacePick 49 // Turns off face pick window? maybe ...
|
||||
#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)
|
||||
|
||||
|
||||
@ -305,6 +305,7 @@ union
|
||||
uint8 DestructibleUnk8;
|
||||
uint32 DestructibleUnk9;
|
||||
bool targetable_with_hotkey;
|
||||
bool show_name;
|
||||
|
||||
};
|
||||
|
||||
@ -1116,6 +1117,11 @@ struct PetCommand_Struct {
|
||||
/*004*/ uint32 target;
|
||||
};
|
||||
|
||||
struct PetCommandState_Struct {
|
||||
/*00*/ uint32 button_id;
|
||||
/*04*/ uint32 state;
|
||||
};
|
||||
|
||||
/*
|
||||
** Delete Spawn
|
||||
** Length: 4 Bytes
|
||||
@ -1690,6 +1696,7 @@ struct OnLevelMessage_Struct
|
||||
uint32 Duration;
|
||||
uint32 PopupID;
|
||||
uint32 NegativeID;
|
||||
uint32 SoundControls;
|
||||
char ButtonName0[25];
|
||||
char ButtonName1[25];
|
||||
};
|
||||
@ -5326,6 +5333,24 @@ struct fling_struct {
|
||||
/* 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
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include "global_define.h"
|
||||
#include "eq_stream_proxy.h"
|
||||
#include "struct_strategy.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "opcodemgr.h"
|
||||
|
||||
|
||||
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)
|
||||
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();
|
||||
FastQueuePacket(&newp, ack_req);
|
||||
}
|
||||
|
||||
@ -86,6 +86,8 @@ enum LogCategory {
|
||||
Login_Server,
|
||||
Client_Login,
|
||||
Headless_Client,
|
||||
HP_Update,
|
||||
FixZ,
|
||||
MaxCategoryID /* Don't Remove this*/
|
||||
};
|
||||
|
||||
@ -135,7 +137,10 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
|
||||
"Packet :: Server -> Client (Dump)",
|
||||
"Packet :: Client -> Server (Dump)",
|
||||
"Login Server",
|
||||
"Client Login"
|
||||
"Client Login",
|
||||
"Headless Client",
|
||||
"HP Update",
|
||||
"FixZ"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -332,7 +332,7 @@ namespace EQEmu
|
||||
};
|
||||
|
||||
struct ItemEffect_Struct {
|
||||
int16 Effect;
|
||||
int32 Effect;
|
||||
uint8 Type;
|
||||
uint8 Level;
|
||||
uint8 Level2;
|
||||
|
||||
@ -25,6 +25,23 @@ void EQ::Net::ConsoleServer::RegisterLogin(ConsoleServerLoginCallback 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)
|
||||
{
|
||||
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 RegisterLogin(ConsoleServerLoginCallback fn);
|
||||
|
||||
ConsoleServerConnection *FindByAccountName(const std::string &acct_name);
|
||||
void SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell);
|
||||
private:
|
||||
void ConnectionDisconnected(ConsoleServerConnection *c);
|
||||
void ProcessCommand(ConsoleServerConnection *c, const std::string& cmd);
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include "../common/util/uuid.h"
|
||||
#include "../common/net/packet.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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
struct ServerChannelMessage_Struct;
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
@ -42,6 +44,7 @@ namespace EQ
|
||||
bool AcceptMessages() const { return m_accept_messages; }
|
||||
void SetAcceptMessages(bool v) { m_accept_messages = v; }
|
||||
void QueueMessage(const std::string &msg);
|
||||
bool SendChannelMessage(const ServerChannelMessage_Struct* scm, std::function<void(void)> onTell);
|
||||
private:
|
||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||
void OnDisconnect(TCPConnection* c);
|
||||
|
||||
@ -135,26 +135,26 @@ void EQ::Net::DaybreakConnectionManager::Process()
|
||||
|
||||
switch (status)
|
||||
{
|
||||
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) {
|
||||
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.keepalive_delay_ms) {
|
||||
connection->SendKeepAlive();
|
||||
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);
|
||||
if ((size_t)time_since_last_send.count() > m_options.keepalive_delay_ms) {
|
||||
connection->SendKeepAlive();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case StatusDisconnecting:
|
||||
connection->Process();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case StatusDisconnecting:
|
||||
connection->Process();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iter++;
|
||||
@ -170,12 +170,12 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend()
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case StatusConnected:
|
||||
case StatusDisconnecting:
|
||||
connection->ProcessResend();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case StatusConnected:
|
||||
case StatusDisconnecting:
|
||||
connection->ProcessResend();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iter++;
|
||||
@ -382,13 +382,8 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
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);
|
||||
if (opcode == OP_KeepAlive || opcode == OP_OutboundPing) {
|
||||
if (p.GetInt8(0) == 0 && (opcode == OP_KeepAlive || opcode == OP_OutboundPing)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -406,14 +401,20 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeCompression:
|
||||
Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
break;
|
||||
case EncodeXOR:
|
||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EncodeCompression:
|
||||
if(temp.GetInt8(0) == 0)
|
||||
Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Decompress(temp, 1, temp.Length() - 1);
|
||||
break;
|
||||
case EncodeXOR:
|
||||
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) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeXOR:
|
||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EncodeXOR:
|
||||
if (temp.GetInt8(0) == 0)
|
||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
else
|
||||
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)) {
|
||||
case OP_Combined: {
|
||||
if (m_status == StatusDisconnecting) {
|
||||
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) {
|
||||
case OP_Combined: {
|
||||
if (m_status == StatusDisconnecting) {
|
||||
SendDisconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||
current += subpacket_length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
||||
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");
|
||||
if (end < current + subpacket_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*(current + 1) == 0xFF && *(current + 2) == 0xFF) {
|
||||
if (end < current + 7) {
|
||||
throw std::out_of_range("Error in OP_AppCombined, end < current + 7");
|
||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||
current += subpacket_length;
|
||||
}
|
||||
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)(
|
||||
(*(current + 3) << 24) |
|
||||
(*(current + 4) << 16) |
|
||||
(*(current + 5) << 8) |
|
||||
(*(current + 6))
|
||||
);
|
||||
current += 7;
|
||||
if (*(current + 1) == 0xFF && *(current + 2) == 0xFF) {
|
||||
if (end < current + 7) {
|
||||
throw std::out_of_range("Error in OP_AppCombined, end < current + 7");
|
||||
}
|
||||
|
||||
subpacket_length = (uint32_t)(
|
||||
(*(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 {
|
||||
subpacket_length = (uint32_t)(
|
||||
(*(current + 1) << 8) |
|
||||
(*(current + 2))
|
||||
);
|
||||
current += 3;
|
||||
subpacket_length = (uint32_t)((*(current + 0)));
|
||||
current += 1;
|
||||
}
|
||||
|
||||
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 {
|
||||
subpacket_length = (uint32_t)((*(current + 0)));
|
||||
current += 1;
|
||||
}
|
||||
|
||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||
current += subpacket_length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case OP_SessionRequest:
|
||||
{
|
||||
if (m_status == StatusConnected) {
|
||||
auto request = p.GetSerialize<DaybreakConnect>(0);
|
||||
|
||||
if (NetworkToHost(request.connect_code) != m_connect_code) {
|
||||
case OP_Packet:
|
||||
case OP_Packet2:
|
||||
case OP_Packet3:
|
||||
case OP_Packet4:
|
||||
{
|
||||
if (m_status == StatusDisconnecting) {
|
||||
SendDisconnect();
|
||||
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);
|
||||
}
|
||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||
auto sequence = NetworkToHost(header.sequence);
|
||||
auto stream_id = header.opcode - OP_Packet;
|
||||
auto stream = &m_streams[stream_id];
|
||||
|
||||
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);
|
||||
auto order = CompareSequence(stream->sequence_in, sequence);
|
||||
if (order == SequenceFuture) {
|
||||
SendOutOfOrderAck(stream_id, sequence);
|
||||
AddToQueue(stream_id, sequence, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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 if (order == SequencePast) {
|
||||
SendAck(stream_id, stream->sequence_in - 1);
|
||||
}
|
||||
else {
|
||||
stream->fragment_packet.PutData(
|
||||
stream->fragment_current_bytes,
|
||||
(char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size());
|
||||
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);
|
||||
}
|
||||
|
||||
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableHeader::size());
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream->fragment_current_bytes >= stream->fragment_total_bytes) {
|
||||
ProcessDecodedPacket(stream->fragment_packet);
|
||||
stream->fragment_packet.Clear();
|
||||
stream->fragment_total_bytes = 0;
|
||||
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 {
|
||||
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_Ack4:
|
||||
{
|
||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||
auto sequence = NetworkToHost(header.sequence);
|
||||
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();
|
||||
case OP_Ack:
|
||||
case OP_Ack2:
|
||||
case OP_Ack3:
|
||||
case OP_Ack4:
|
||||
{
|
||||
auto header = p.GetSerialize<DaybreakReliableHeader>(0);
|
||||
auto sequence = NetworkToHost(header.sequence);
|
||||
auto stream_id = header.opcode - OP_Ack;
|
||||
Ack(stream_id, sequence);
|
||||
break;
|
||||
}
|
||||
|
||||
ChangeStatus(StatusDisconnecting);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_Padding:
|
||||
{
|
||||
auto self = m_self.lock();
|
||||
if (m_owner->m_on_packet_recv && self) {
|
||||
m_owner->m_on_packet_recv(self, StaticPacket((char*)p.Data() + 1, p.Length() - 1));
|
||||
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;
|
||||
}
|
||||
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;
|
||||
case OP_SessionDisconnect:
|
||||
{
|
||||
if (m_status == StatusConnected || m_status == StatusDisconnecting) {
|
||||
FlushBuffer();
|
||||
SendDisconnect();
|
||||
}
|
||||
|
||||
ChangeStatus(StatusDisconnecting);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_Padding:
|
||||
{
|
||||
auto self = m_self.lock();
|
||||
if (m_owner->m_on_packet_recv && self) {
|
||||
m_owner->m_on_packet_recv(self, StaticPacket((char*)p.Data() + 1, p.Length() - 1));
|
||||
}
|
||||
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 {
|
||||
@ -782,16 +786,16 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
|
||||
int calculated = 0;
|
||||
int actual = 0;
|
||||
switch (m_crc_bytes) {
|
||||
case 2:
|
||||
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;
|
||||
break;
|
||||
case 4:
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
case 2:
|
||||
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;
|
||||
break;
|
||||
case 4:
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actual == calculated) {
|
||||
@ -809,14 +813,14 @@ void EQ::Net::DaybreakConnection::AppendCRC(Packet &p)
|
||||
|
||||
int calculated = 0;
|
||||
switch (m_crc_bytes) {
|
||||
case 2:
|
||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key) & 0xffff;
|
||||
p.PutInt16(p.Length(), EQ::Net::HostToNetwork((int16_t)calculated));
|
||||
break;
|
||||
case 4:
|
||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key);
|
||||
p.PutInt32(p.Length(), EQ::Net::HostToNetwork(calculated));
|
||||
break;
|
||||
case 2:
|
||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key) & 0xffff;
|
||||
p.PutInt16(p.Length(), EQ::Net::HostToNetwork((int16_t)calculated));
|
||||
break;
|
||||
case 4:
|
||||
calculated = Crc32(p.Data(), (int)p.Length(), m_encode_key);
|
||||
p.PutInt32(p.Length(), EQ::Net::HostToNetwork(calculated));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1055,7 +1059,7 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
|
||||
while (iter != s->sent_packets.end()) {
|
||||
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();
|
||||
|
||||
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)) {
|
||||
DynamicPacket out;
|
||||
|
||||
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);
|
||||
}
|
||||
out.PutPacket(0, p);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeCompression:
|
||||
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
break;
|
||||
case EncodeXOR:
|
||||
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EncodeCompression:
|
||||
if(out.GetInt8(0) == 0)
|
||||
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Compress(out, 1, out.Length() - 1);
|
||||
break;
|
||||
case EncodeXOR:
|
||||
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;
|
||||
port = 0;
|
||||
hold_size = 448;
|
||||
hold_length_ms = 10;
|
||||
hold_length_ms = 50;
|
||||
simulated_in_packet_loss = 0;
|
||||
simulated_out_packet_loss = 0;
|
||||
tic_rate_hertz = 60.0;
|
||||
|
||||
@ -81,7 +81,12 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
|
||||
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)
|
||||
{
|
||||
if (p.Length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Length() < 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.");
|
||||
@ -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)
|
||||
{
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Length() < offset + length) {
|
||||
if (!Resize(offset + length)) {
|
||||
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;
|
||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||
OUT(Buttons);
|
||||
OUT(SoundControls);
|
||||
OUT(Duration);
|
||||
OUT(PopupID);
|
||||
OUT(NegativeID);
|
||||
@ -3929,7 +3930,7 @@ namespace RoF
|
||||
if (strlen(emu->suffix))
|
||||
PacketSize += strlen(emu->suffix) + 1;
|
||||
|
||||
bool ShowName = 1;
|
||||
bool ShowName = emu->show_name;
|
||||
if (emu->bodytype >= 66)
|
||||
{
|
||||
emu->race = 127;
|
||||
|
||||
@ -1927,6 +1927,7 @@ namespace RoF2
|
||||
eq->Text_Count = 4096;
|
||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||
OUT(Buttons);
|
||||
OUT(SoundControls);
|
||||
OUT(Duration);
|
||||
OUT(PopupID);
|
||||
OUT(NegativeID);
|
||||
@ -4085,7 +4086,7 @@ namespace RoF2
|
||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||
}
|
||||
|
||||
bool ShowName = 1;
|
||||
bool ShowName = emu->show_name;
|
||||
if (emu->bodytype >= 66)
|
||||
{
|
||||
emu->race = 127;
|
||||
@ -4119,6 +4120,7 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||
// actually melee range variable, this probably screws the shit out of melee ranges :D
|
||||
if (emu->DestructibleObject)
|
||||
{
|
||||
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(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;
|
||||
|
||||
@ -4158,6 +4160,7 @@ namespace RoF2
|
||||
|
||||
Buffer += sizeof(structs::Spawn_Struct_Bitfields);
|
||||
|
||||
// actually part of bitfields
|
||||
uint8 OtherData = 0;
|
||||
|
||||
if (emu->class_ == 62) //LDoN Chest
|
||||
@ -4173,6 +4176,7 @@ namespace RoF2
|
||||
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||
// float EmitterScalingRadius
|
||||
|
||||
if (emu->DestructibleObject)
|
||||
{
|
||||
@ -4182,6 +4186,7 @@ namespace RoF2
|
||||
{
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3
|
||||
}
|
||||
// int DefaultEmitterID
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
|
||||
|
||||
if (emu->DestructibleObject || emu->class_ == 62)
|
||||
@ -4191,8 +4196,9 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleString);
|
||||
|
||||
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->DestructibleID2);
|
||||
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->DestructibleUnk6);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk7);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructibleUnk8);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk9);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructibleUnk8); // bInteractiveObjectCollidable
|
||||
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
|
||||
// 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(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_details);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown9
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown10
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // unknown11
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); // InNonPCRaceIllusion
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // material
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // variation
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // headtype
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->size);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->face);
|
||||
@ -4243,6 +4250,7 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->runspeed);
|
||||
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(uint32, Buffer, emu->deity);
|
||||
if (emu->NPC)
|
||||
@ -4275,19 +4283,19 @@ namespace RoF2
|
||||
|
||||
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, 0); // unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // TempPet
|
||||
|
||||
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, 0); // unknown15
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // NpcTintIndex
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // PrimaryTintIndex
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // SecondaryTintIndex
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
|
||||
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))
|
||||
{
|
||||
@ -4355,12 +4363,16 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->suffix);
|
||||
}
|
||||
|
||||
// skipping two ints
|
||||
// unknown, maybe some sort of spawn ID
|
||||
// SplineID -- no idea
|
||||
Buffer += 8;
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->IsMercenary);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, "0000000000000000");
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, "0000000000000000"); // RealEstateItemGuid
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // RealEstateID
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // RealEstateItemID
|
||||
// 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;
|
||||
if (Buffer != (BufferStart + PacketSize))
|
||||
{
|
||||
|
||||
@ -328,38 +328,43 @@ showeq -> eqemu
|
||||
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
|
||||
{
|
||||
// byte 1
|
||||
/*00*/ unsigned gender:2; // Gender (0=male, 1=female, 2=monster)
|
||||
/*02*/ unsigned ispet:1; // Guessed based on observing live spawns
|
||||
/*03*/ unsigned afk:1; // 0=no, 1=afk
|
||||
/*04*/ unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||
/*06*/ unsigned gm:1;
|
||||
/*06*/ unsigned sneak:1;
|
||||
/*07*/ unsigned sneak:1;
|
||||
// byte 2
|
||||
/*08*/ unsigned lfg: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
|
||||
/*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
|
||||
/*09*/ unsigned betabuffed:1;
|
||||
/*10*/ unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF2
|
||||
/*23*/ unsigned showhelm:1;
|
||||
// byte 4
|
||||
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
||||
/*25*/ unsigned trader:1;
|
||||
/*26*/ unsigned unknown26:1;
|
||||
/*26*/ unsigned animationonpop:1;
|
||||
/*27*/ unsigned targetable:1;
|
||||
/*28*/ unsigned targetable_with_hotkey:1;
|
||||
/*29*/ unsigned showname:1;
|
||||
/*30*/ unsigned unknown30:1;
|
||||
/*30*/ unsigned untargetable:1; // Untargetable with mouse
|
||||
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
|
||||
/*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
|
||||
unsigned betabuffed:1;
|
||||
@ -498,7 +503,7 @@ struct Spawn_Struct
|
||||
|
||||
/*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4)
|
||||
/*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.
|
||||
/*0000*/ char unknown21[55];
|
||||
};
|
||||
@ -2092,7 +2097,7 @@ struct OnLevelMessage_Struct {
|
||||
/*0000*/ uint32 ButtonName1_Count;
|
||||
/*0000*/ char ButtonName1[25];
|
||||
/*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 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
|
||||
|
||||
@ -339,18 +339,7 @@ struct Spawn_Struct_Bitfields
|
||||
/*06*/ unsigned sneak:1;
|
||||
/*08*/ unsigned lfg: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
|
||||
/*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
|
||||
/*10*/ unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||
/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF
|
||||
/*23*/ unsigned showhelm:1;
|
||||
/*24*/ unsigned unknown24:1; // Prefixes name with !
|
||||
@ -2122,7 +2111,7 @@ struct OnLevelMessage_Struct {
|
||||
/*0000*/ uint32 ButtonName1_Count;
|
||||
/*0000*/ char ButtonName1[25];
|
||||
/*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 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
|
||||
|
||||
@ -1373,6 +1373,7 @@ namespace SoD
|
||||
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||
OUT(Buttons);
|
||||
OUT(SoundControls);
|
||||
OUT(Duration);
|
||||
OUT(PopupID);
|
||||
OUT(NegativeID);
|
||||
@ -2559,7 +2560,7 @@ namespace SoD
|
||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||
}
|
||||
|
||||
bool ShowName = 1;
|
||||
bool ShowName = emu->show_name;
|
||||
if (emu->bodytype >= 66)
|
||||
{
|
||||
emu->race = 127;
|
||||
@ -3291,73 +3292,60 @@ namespace SoD
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
case 1: // back off
|
||||
emu->command = 28;
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
case 2: // get lost
|
||||
emu->command = 29;
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
case 3: // as you were ???
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
case 4: // report HP
|
||||
emu->command = 0;
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
case 5: // guard here
|
||||
emu->command = 5;
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
case 6: // guard me
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
case 7: // attack
|
||||
emu->command = 2;
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
case 8: // follow
|
||||
emu->command = 4;
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // /pet stop
|
||||
case 9: // sit down
|
||||
emu->command = 7;
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
case 10: // stand up
|
||||
emu->command = 8;
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
case 11: // taunt toggle
|
||||
emu->command = 12;
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
case 12: // hold toggle
|
||||
emu->command = 15;
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
case 13: // taunt on
|
||||
emu->command = 13;
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
case 14: // no taunt
|
||||
emu->command = 14;
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
// 15 is target, doesn't send packet
|
||||
case 16: // leader
|
||||
emu->command = 1;
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
case 17: // feign
|
||||
emu->command = 27;
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
case 18: // no cast toggle
|
||||
emu->command = 21;
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
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
|
||||
case 19: // focus toggle
|
||||
emu->command = 24;
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
|
||||
@ -250,8 +250,7 @@ struct Spawn_Struct_Bitfields
|
||||
unsigned sneak:1;
|
||||
unsigned lfg:1;
|
||||
unsigned padding5:1;
|
||||
unsigned invis:1; // 0 = visible, 1 = invis/sneaking
|
||||
unsigned padding7:11;
|
||||
unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||
unsigned gm:1;
|
||||
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||
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
|
||||
/*4249*/ char ButtonName1[25];
|
||||
/*4274*/ uint8 Buttons;
|
||||
/*4275*/ uint8 Unknown4275; // Something to do with audio controls
|
||||
/*4275*/ uint8 SoundControls; // Something to do with audio controls
|
||||
/*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
|
||||
/*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;
|
||||
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->statue = 0; //New Field - 1 freezes animation
|
||||
eq->showhelm = emu->showhelm;
|
||||
@ -2136,10 +2136,10 @@ namespace SoF
|
||||
eq->findable = emu->findable;
|
||||
if (emu->bodytype >= 66)
|
||||
{
|
||||
eq->bodytype = 11; //non-targetable
|
||||
eq->showname = 0; //no visible name
|
||||
eq->race = 127; //invisible man
|
||||
eq->gender = 0; //invisible men are gender 0
|
||||
eq->bodytype = 11; //non-targetable
|
||||
eq->showname = 0; //no visible name
|
||||
eq->race = 127; //invisible man
|
||||
eq->gender = 0; //invisible men are gender 0
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2675,73 +2675,60 @@ namespace SoF
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
case 1: // back off
|
||||
emu->command = 28;
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
case 2: // get lost
|
||||
emu->command = 29;
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
case 3: // as you were ???
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
case 4: // report HP
|
||||
emu->command = 0;
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
case 5: // guard here
|
||||
emu->command = 5;
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
case 6: // guard me
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
case 7: // attack
|
||||
emu->command = 2;
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
case 8: // follow
|
||||
emu->command = 4;
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // Stop?
|
||||
case 9: // sit down
|
||||
emu->command = 7;
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
case 10: // stand up
|
||||
emu->command = 8;
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
case 11: // taunt toggle
|
||||
emu->command = 12;
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
case 12: // hold toggle
|
||||
emu->command = 15;
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
case 13: // taunt on
|
||||
emu->command = 13;
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
case 14: // no taunt
|
||||
emu->command = 14;
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
// 15 is target, doesn't send packet
|
||||
case 16: // leader
|
||||
emu->command = 1;
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
case 17: // feign
|
||||
emu->command = 27;
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
case 18: // no cast toggle
|
||||
emu->command = 21;
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
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
|
||||
case 19: // focus toggle
|
||||
emu->command = 24;
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
|
||||
@ -2030,73 +2030,60 @@ namespace Titanium
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
case 1: // back off
|
||||
emu->command = 28;
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
case 2: // get lost
|
||||
emu->command = 29;
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
case 3: // as you were ???
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
case 4: // report HP
|
||||
emu->command = 0;
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
case 5: // guard here
|
||||
emu->command = 5;
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
case 6: // guard me
|
||||
emu->command = 4; // fuck it follow
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
case 7: // attack
|
||||
emu->command = 2;
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
case 8: // follow
|
||||
emu->command = 4;
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // Stop?
|
||||
case 9: // sit down
|
||||
emu->command = 7;
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
case 10: // stand up
|
||||
emu->command = 8;
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
case 11: // taunt toggle
|
||||
emu->command = 12;
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
case 12: // hold toggle
|
||||
emu->command = 15;
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
case 13: // taunt on
|
||||
emu->command = 13;
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
case 14: // no taunt
|
||||
emu->command = 14;
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
// 15 is target, doesn't send packet
|
||||
case 16: // leader
|
||||
emu->command = 1;
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
case 17: // feign
|
||||
emu->command = 27;
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
case 18: // no cast toggle
|
||||
emu->command = 21;
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
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
|
||||
case 19: // focus toggle
|
||||
emu->command = 24;
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
|
||||
@ -1607,6 +1607,7 @@ namespace UF
|
||||
memcpy(eq->Title, emu->Title, sizeof(eq->Title));
|
||||
memcpy(eq->Text, emu->Text, sizeof(eq->Text));
|
||||
OUT(Buttons);
|
||||
OUT(SoundControls);
|
||||
OUT(Duration);
|
||||
OUT(PopupID);
|
||||
OUT(NegativeID);
|
||||
@ -2843,7 +2844,7 @@ namespace UF
|
||||
PacketSize += strlen(emu->DestructibleString) + 1;
|
||||
}
|
||||
|
||||
bool ShowName = 1;
|
||||
bool ShowName = emu->show_name;
|
||||
if (emu->bodytype >= 66)
|
||||
{
|
||||
emu->race = 127;
|
||||
|
||||
@ -250,8 +250,7 @@ struct Spawn_Struct_Bitfields
|
||||
unsigned sneak:1;
|
||||
unsigned lfg:1;
|
||||
unsigned padding5:1;
|
||||
unsigned invis:1; // 0 = visible, 1 = invis/sneaking
|
||||
unsigned padding7:11;
|
||||
unsigned invis:12; // there are 3000 different (non-GM) invis levels
|
||||
unsigned gm:1;
|
||||
unsigned anon:2; // 0=normal, 1=anon, 2=roleplay
|
||||
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
|
||||
/*4249*/ char ButtonName1[25];
|
||||
/*4274*/ uint8 Buttons;
|
||||
/*4275*/ uint8 Unknown4275; // Something to do with audio controls
|
||||
/*4275*/ uint8 SoundControls; // Something to do with audio controls
|
||||
/*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
|
||||
/*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, TradeskillUpResearch, 1) // Research 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_INT(Character, IksarCommonTongue, 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, 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, OPClientUpdateVisualDebug, false) // Shows a pulse and forward directional particle each time the client sends its position to server
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@ -235,7 +235,6 @@ RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone AL
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
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, 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.
|
||||
@ -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, 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, 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, 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.
|
||||
@ -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, Find, true) // Enable pathing for FindPerson requests from the client.
|
||||
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, 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.
|
||||
@ -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_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_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_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.
|
||||
@ -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, 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, OldRainTargets, false) // use old incorrectly implemented max targets for rains
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
|
||||
@ -189,6 +189,7 @@
|
||||
#define ServerOP_ReloadWorld 0x4009
|
||||
#define ServerOP_ReloadLogs 0x4010
|
||||
#define ServerOP_ReloadPerlExportSettings 0x4011
|
||||
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
||||
/* Query Server OP Codes */
|
||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
||||
@ -1263,6 +1264,12 @@ struct CZSetEntVarByNPCTypeID_Struct {
|
||||
char m_var[256];
|
||||
};
|
||||
|
||||
struct CZSetEntVarByClientName_Struct {
|
||||
char CharName[64];
|
||||
char id[256];
|
||||
char m_var[256];
|
||||
};
|
||||
|
||||
struct ReloadWorld_Struct{
|
||||
uint32 Option;
|
||||
};
|
||||
|
||||
@ -1674,6 +1674,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
for (y = 0; y < 16; 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].ResistDiff=atoi(row[147]);
|
||||
sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
|
||||
|
||||
@ -468,7 +468,7 @@ typedef enum {
|
||||
#define SE_Blank 254 // implemented
|
||||
#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
|
||||
#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_CombatStability 259 // implemented[AA] - damage mitigation
|
||||
#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_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_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_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)
|
||||
@ -562,9 +562,9 @@ typedef enum {
|
||||
#define SE_LimitManaMin 348 // implemented
|
||||
#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_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_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect
|
||||
#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_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_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758)
|
||||
//#define SE_ChangeTriggerType 356 // not used
|
||||
@ -757,7 +757,7 @@ struct SPDat_Spell_Struct
|
||||
// -- DIETY_BERTOXXULOUS ... DIETY_VEESHAN
|
||||
/* 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
|
||||
/* 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
|
||||
/* 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
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9110
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9114
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
|
||||
#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_AutoFire=0x314e
|
||||
OP_PetCommands=0x0093
|
||||
OP_PetCommandState=0x74ed
|
||||
OP_PetHoTT=0x0df4
|
||||
OP_DeleteSpell=0x305c
|
||||
OP_Surname=0x1a87
|
||||
@ -671,3 +672,7 @@ OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||
OP_InitialHPUpdate=0x0000
|
||||
|
||||
OP_ItemRecastDelay=0x57ed
|
||||
|
||||
#aura related
|
||||
OP_UpdateAura=0x1fa9
|
||||
OP_RemoveTrap=0x6a4d
|
||||
|
||||
@ -195,6 +195,7 @@ OP_Consent=0x1fd1
|
||||
OP_ConsentDeny=0x7a45
|
||||
OP_AutoFire=0x241e
|
||||
OP_PetCommands=0x0159
|
||||
OP_PetCommandState=0x1dc8
|
||||
OP_PetHoTT=0x794a
|
||||
OP_DeleteSpell=0x3358
|
||||
OP_Surname=0x0423
|
||||
@ -674,3 +675,7 @@ OP_RAWOutOfSession=0x0000
|
||||
# we need to document the differences between these packets to make identifying them easier
|
||||
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||
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_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_Zone_MissingName01=0x0000 #
|
||||
#new titles avaliable: #
|
||||
|
||||
#aura related
|
||||
OP_UpdateAura=0x62a9
|
||||
OP_RemoveTrap=0x7bd9
|
||||
|
||||
@ -198,6 +198,7 @@ OP_Consent=0x6bb9 # C
|
||||
OP_ConsentDeny=0x4cd1 # C
|
||||
OP_AutoFire=0x5db5 # C
|
||||
OP_PetCommands=0x7706 # C
|
||||
OP_PetCommandState=0x1a79
|
||||
OP_PetHoTT=0x2528
|
||||
OP_DeleteSpell=0x0698 # C
|
||||
OP_Surname=0x44ae # C
|
||||
@ -684,3 +685,7 @@ OP_ItemRecastDelay=0x82d7
|
||||
|
||||
# unhandled
|
||||
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
|
||||
do_self_update_check_routine() if !$skip_self_update_check;
|
||||
get_windows_wget();
|
||||
get_perl_version();
|
||||
read_eqemu_config_xml();
|
||||
get_mysql_path();
|
||||
@ -200,7 +201,7 @@ sub new_server {
|
||||
}
|
||||
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";
|
||||
<>;
|
||||
exit;
|
||||
@ -280,6 +281,8 @@ sub new_server {
|
||||
|
||||
show_install_summary_info();
|
||||
|
||||
rmtree('updates_staged');
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
@ -517,6 +520,13 @@ sub get_perl_version {
|
||||
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 {
|
||||
|
||||
#::: 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";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#::: 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);
|
||||
|
||||
@ -997,68 +1007,14 @@ sub get_remote_file{
|
||||
}
|
||||
}
|
||||
|
||||
if($OS eq "Windows"){
|
||||
#::: For non-text type requests...
|
||||
if($content_type == 1){
|
||||
$break = 0;
|
||||
while($break == 0) {
|
||||
eval "use LWP::Simple qw(getstore);";
|
||||
# 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;
|
||||
}
|
||||
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
|
||||
$wget = `wget -N --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
|
||||
@ -1498,7 +1454,7 @@ sub map_files_fetch_bulk{
|
||||
get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
|
||||
unzip('maps/maps.zip', 'maps/');
|
||||
my @files;
|
||||
my $start_dir = "maps/EQEmuMaps-master/maps";
|
||||
my $start_dir = "maps/EQEmuMaps-master/";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
@ -1551,12 +1507,12 @@ sub map_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";
|
||||
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";
|
||||
mkdir('updates_staged');
|
||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
||||
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||
}
|
||||
|
||||
$fc = 0;
|
||||
@ -1564,7 +1520,7 @@ sub quest_files_fetch{
|
||||
use File::Compare;
|
||||
|
||||
my @files;
|
||||
my $start_dir = "updates_staged/Quests-Plugins-master/quests/";
|
||||
my $start_dir = "updates_staged/projecteqquests-master/";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
@ -1573,7 +1529,7 @@ sub quest_files_fetch{
|
||||
if($file=~/\.pl|\.lua|\.ext/i){
|
||||
$staged_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) {
|
||||
copy_file($staged_file, $destination_file);
|
||||
@ -1603,27 +1559,28 @@ sub quest_files_fetch{
|
||||
}
|
||||
}
|
||||
|
||||
rmtree('updates_staged');
|
||||
|
||||
if($fc == 0){
|
||||
print "[Update] No Quest Updates found... \n\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub lua_modules_fetch {
|
||||
if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") {
|
||||
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);
|
||||
print "[Update] Fetched latest LUA Modules...\n";
|
||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
||||
if (!-e "updates_staged/projecteqquests-master/") {
|
||||
print "[Update] Fetching Latest lua modules --- \n";
|
||||
get_remote_file("https://codeload.github.com/ProjectEQ/projecteqquests/zip/master", "updates_staged/projecteqquests-master.zip", 1);
|
||||
print "[Install] Fetched latest lua modules...\n";
|
||||
mkdir('updates_staged');
|
||||
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||
}
|
||||
|
||||
$fc = 0;
|
||||
use File::Find;
|
||||
use File::Compare;
|
||||
|
||||
mkdir('lua_modules');
|
||||
|
||||
my @files;
|
||||
my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/";
|
||||
my $start_dir = "updates_staged/projecteqquests-master/lua_modules/";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
@ -1632,7 +1589,7 @@ sub lua_modules_fetch {
|
||||
if($file=~/\.pl|\.lua|\.ext/i){
|
||||
$staged_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) {
|
||||
copy_file($staged_file, $destination_file);
|
||||
@ -1667,19 +1624,22 @@ sub lua_modules_fetch {
|
||||
}
|
||||
|
||||
sub plugins_fetch{
|
||||
if (!-e "updates_staged/Quests-Plugins-master/plugins/") {
|
||||
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);
|
||||
print "[Update] Fetched latest plugins\n";
|
||||
unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
|
||||
if (!-e "updates_staged/projecteqquests-master/") {
|
||||
print "[Update] Fetching Latest plugins --- \n";
|
||||
get_remote_file("https://codeload.github.com/ProjectEQ/projecteqquests/zip/master", "updates_staged/projecteqquests-master.zip", 1);
|
||||
print "[Install] Fetched latest plugins...\n";
|
||||
mkdir('updates_staged');
|
||||
unzip('updates_staged/projecteqquests-master.zip', 'updates_staged/');
|
||||
}
|
||||
|
||||
$fc = 0;
|
||||
use File::Find;
|
||||
use File::Compare;
|
||||
|
||||
mkdir('plugins');
|
||||
|
||||
my @files;
|
||||
my $start_dir = "updates_staged/Quests-Plugins-master/plugins/";
|
||||
my $start_dir = "updates_staged/projecteqquests-master/plugins/";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
@ -1688,7 +1648,7 @@ sub plugins_fetch{
|
||||
if($file=~/\.pl|\.lua|\.ext/i){
|
||||
$staged_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) {
|
||||
copy_file($staged_file, $destination_file);
|
||||
@ -2220,3 +2180,4 @@ sub generate_random_password {
|
||||
|
||||
return $randpassword;
|
||||
}
|
||||
|
||||
|
||||
@ -114,9 +114,24 @@ if [[ "$OS" == "Debian" ]]; then
|
||||
apt-get $apt_options install open-vm-tools
|
||||
apt-get $apt_options install unzip
|
||||
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 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
|
||||
echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections
|
||||
apt-get -y -q install proftpd
|
||||
@ -149,8 +164,35 @@ EOF
|
||||
|
||||
elif [[ "$OS" == "fedora_core" ]]; then
|
||||
# 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 groupinstall "Development Tools" "Basic Web Server" "C Development Tools and Libraries"
|
||||
dnf -y install open-vm-tools
|
||||
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
|
||||
|
||||
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|
|
||||
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|
|
||||
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:
|
||||
# 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;
|
||||
}
|
||||
|
||||
cle->SetOnline();
|
||||
|
||||
if(minilogin){
|
||||
cle->SetOnline();
|
||||
WorldConfig::DisableStats();
|
||||
Log(Logs::General, Logs::World_Server, "MiniLogin Account #%d",cle->AccountID());
|
||||
}
|
||||
else {
|
||||
if (!is_player_zoning) {
|
||||
Log(Logs::General, Logs::World_Server,
|
||||
"Account (%s) Logging in :: LSID: %d ", cle->AccountName(), cle->LSID());
|
||||
else if (!is_player_zoning) {
|
||||
// Track who is in and who is out of the game
|
||||
char *inout= (char *) "";
|
||||
|
||||
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();
|
||||
@ -1021,6 +1040,7 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
case OP_WorldLogout:
|
||||
{
|
||||
// I don't see this getting executed on logout
|
||||
eqs->Close();
|
||||
cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction.
|
||||
return false;
|
||||
@ -1261,6 +1281,10 @@ void Client::Clearance(int8 response)
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
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 int16 WorldAdmin() const { return pworldadmin; }
|
||||
inline const char* GetLSKey() const { return plskey; }
|
||||
inline const int8 GetOnline() const { return pOnline; }
|
||||
|
||||
// Account stuff
|
||||
inline uint32 AccountID() const { return paccountid; }
|
||||
|
||||
@ -332,6 +332,8 @@ int main(int argc, char** argv) {
|
||||
database.ClearMerchantTemp();
|
||||
}
|
||||
|
||||
RuleManager::Instance()->SaveRules(&database);
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Loading EQ time of day..");
|
||||
TimeOfDay_Struct eqTime;
|
||||
time_t realtime;
|
||||
@ -392,12 +394,12 @@ int main(int argc, char** argv) {
|
||||
server_connection->Listen(server_opts);
|
||||
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}",
|
||||
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
|
||||
|
||||
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) {
|
||||
|
||||
@ -46,7 +46,7 @@ extern UCSConnection UCSLink;
|
||||
extern QueryServConnection QSLink;
|
||||
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) {
|
||||
|
||||
/* Set Process tracking variable defaults */
|
||||
@ -73,6 +73,8 @@ ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> conn
|
||||
zone_boot_timer.Disable();
|
||||
}
|
||||
}));
|
||||
|
||||
this->console = console;
|
||||
}
|
||||
|
||||
ZoneServer::~ZoneServer() {
|
||||
@ -412,6 +414,27 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
|
||||
(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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
@ -1248,6 +1285,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_CZSignalNPC:
|
||||
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
||||
case ServerOP_CZSignalClient:
|
||||
case ServerOP_CZSetEntityVariableByClientName:
|
||||
case ServerOP_WWMarquee:
|
||||
case ServerOP_DepopAllPlayersCorpses:
|
||||
case ServerOP_DepopPlayerCorpse:
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "../net/servertalk_server.h"
|
||||
#include "../event/timer.h"
|
||||
#include "../timer.h"
|
||||
#include "console.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
@ -31,7 +32,7 @@ class ServerPacket;
|
||||
|
||||
class ZoneServer : public WorldTCPConnection {
|
||||
public:
|
||||
ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console);
|
||||
~ZoneServer();
|
||||
virtual inline bool IsZoneServer() { return true; }
|
||||
|
||||
@ -97,6 +98,7 @@ private:
|
||||
uint32 zone_os_process_id;
|
||||
std::string launcher_name; //the launcher which started us
|
||||
std::string launched_name; //the name of the zone we launched.
|
||||
EQ::Net::ConsoleServer *console;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,6 +5,7 @@ SET(zone_sources
|
||||
aa_ability.cpp
|
||||
aggro.cpp
|
||||
aggromanager.cpp
|
||||
aura.cpp
|
||||
attack.cpp
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
@ -51,6 +52,7 @@ SET(zone_sources
|
||||
lua_item.cpp
|
||||
lua_iteminst.cpp
|
||||
lua_mob.cpp
|
||||
lua_mod.cpp
|
||||
lua_npc.cpp
|
||||
lua_object.cpp
|
||||
lua_packet.cpp
|
||||
@ -59,6 +61,7 @@ SET(zone_sources
|
||||
lua_raid.cpp
|
||||
lua_spawn.cpp
|
||||
lua_spell.cpp
|
||||
lua_stat_bonuses.cpp
|
||||
embperl.cpp
|
||||
embxs.cpp
|
||||
entity.cpp
|
||||
@ -134,6 +137,7 @@ SET(zone_headers
|
||||
aa.h
|
||||
aa_ability.h
|
||||
aggromanager.h
|
||||
aura.h
|
||||
basic_functions.h
|
||||
beacon.h
|
||||
bot.h
|
||||
@ -173,6 +177,7 @@ SET(zone_headers
|
||||
lua_item.h
|
||||
lua_iteminst.h
|
||||
lua_mob.h
|
||||
lua_mod.h
|
||||
lua_npc.h
|
||||
lua_object.h
|
||||
lua_packet.h
|
||||
@ -182,6 +187,7 @@ SET(zone_headers
|
||||
lua_raid.h
|
||||
lua_spawn.h
|
||||
lua_spell.h
|
||||
lua_stat_bonuses.h
|
||||
map.h
|
||||
masterentity.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())
|
||||
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;
|
||||
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);
|
||||
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() {
|
||||
auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct));
|
||||
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->percentage = m_epp.perAA;
|
||||
QueuePacket(outapp);
|
||||
@ -1194,6 +1202,11 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||
Message_StringID(MT_SpellFailure, SNEAK_RESTRICT);
|
||||
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
|
||||
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)) {
|
||||
|
||||
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 "worldserver.h"
|
||||
#include "zone.h"
|
||||
#include "lua_parser.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
@ -52,7 +53,7 @@ extern WorldServer worldserver;
|
||||
extern EntityList entity_list;
|
||||
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
|
||||
int type = 0;
|
||||
@ -137,7 +138,8 @@ bool Mob::AttackAnimation(EQEmu::skills::SkillType &skillinuse, int Hand, const
|
||||
type = animDualWield;
|
||||
|
||||
DoAnim(type, 0, false);
|
||||
return true;
|
||||
|
||||
return 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.
|
||||
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 *defender = this;
|
||||
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)
|
||||
{
|
||||
#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
|
||||
* 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)
|
||||
{
|
||||
#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)
|
||||
return;
|
||||
|
||||
@ -1237,6 +1268,7 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||
return;
|
||||
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);
|
||||
|
||||
// check to see if we hit..
|
||||
if (other->AvoidDamage(this, hit)) {
|
||||
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;
|
||||
// calculate attack_skill and skillinuse depending on hand and weapon
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
int16 charges = 0;
|
||||
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
|
||||
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);
|
||||
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);
|
||||
|
||||
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.RemoveNPC(GetID());
|
||||
|
||||
this->SetID(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;
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
return;
|
||||
}
|
||||
// Pet that is /pet hold on will not add to their hate list if they're not engaged
|
||||
// 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()) {
|
||||
if (!targetmob)
|
||||
return;
|
||||
// we skip these checks if it's forced through a pet command
|
||||
if (!pet_command) {
|
||||
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))
|
||||
@ -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))
|
||||
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 0;
|
||||
}
|
||||
|
||||
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`
|
||||
|
||||
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()) {
|
||||
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);
|
||||
|
||||
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
|
||||
this->CastToClient()->SendHPUpdateMarquee();
|
||||
|
||||
if (HasDied()) {
|
||||
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 (IsNPC()) {
|
||||
// Is this adequate?
|
||||
|
||||
Teleport(new_pos);
|
||||
SendPosUpdate();
|
||||
if (position_update_melee_push_timer.Check()) {
|
||||
SendPositionUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -4056,7 +4100,7 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
|
||||
|
||||
if (critChance > 0) {
|
||||
if (zone->random.Roll(critChance)) {
|
||||
critMod += GetCritDmgMob(hit.skill);
|
||||
critMod += GetCritDmgMod(hit.skill);
|
||||
hit.damage_done += 5;
|
||||
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)
|
||||
{
|
||||
#ifdef LUA_EQEMU
|
||||
bool ignoreDefault = false;
|
||||
LuaParser::Instance()->TryCriticalHit(this, defender, hit, opts, ignoreDefault);
|
||||
|
||||
if (ignoreDefault) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hit.damage_done < 1 || !defender)
|
||||
return;
|
||||
|
||||
@ -4185,7 +4238,11 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
||||
// step 2: calculate damage
|
||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||
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;
|
||||
Log(Logs::Detail, Logs::Combat,
|
||||
"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
|
||||
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
||||
// staggers message.
|
||||
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(IMMUNE_STUN)) {
|
||||
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(UNSTUNABLE)) {
|
||||
defender->Emote("staggers.");
|
||||
defender->Stun(2000);
|
||||
}
|
||||
@ -4527,6 +4584,15 @@ const DamageTable &Mob::GetDamageTable() const
|
||||
|
||||
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
|
||||
if (!IsClient()
|
||||
#ifdef BOTS
|
||||
@ -4862,6 +4928,15 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
if (!defender)
|
||||
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
|
||||
if (hit.skill == EQEmu::skills::SkillArchery ||
|
||||
(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;
|
||||
spell_iterations = 0;
|
||||
caster_id = 0;
|
||||
max_targets = 4; // default
|
||||
|
||||
if(lifetime)
|
||||
remove_timer.Start();
|
||||
@ -93,10 +94,12 @@ bool Beacon::Process()
|
||||
)
|
||||
{
|
||||
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
|
||||
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust);
|
||||
// NPCs should never be affected by an AE they cast. PB AEs shouldn't affect caster either
|
||||
// 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
|
||||
{
|
||||
@ -126,6 +129,8 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 resist_adj
|
||||
this->resist_adjust = resist_adjust;
|
||||
spell_iterations = spells[spell_id].AEDuration / 2500;
|
||||
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.Trigger();
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ protected:
|
||||
int16 resist_adjust;
|
||||
int spell_iterations;
|
||||
Timer spell_timer;
|
||||
int max_targets;
|
||||
|
||||
uint16 caster_id;
|
||||
private:
|
||||
|
||||
@ -48,6 +48,14 @@ void Mob::CalcBonuses()
|
||||
SetAttackTimer();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1084,9 +1092,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] += base1;
|
||||
newbon->CritDmgMod[EQEmu::skills::HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
newbon->CritDmgMob[base2] += base1;
|
||||
newbon->CritDmgMod[base2] += base1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1442,11 +1450,27 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->FeignedCastOnChance = base1;
|
||||
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
|
||||
case SE_PetDiscipline:
|
||||
break;
|
||||
case SE_PetDiscipline2:
|
||||
break;
|
||||
case SE_PotionBeltSlots:
|
||||
break;
|
||||
case SE_BandolierSlots:
|
||||
@ -1465,8 +1489,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
case SE_TrapCircumvention:
|
||||
break;
|
||||
case SE_FeignedMinion:
|
||||
break;
|
||||
|
||||
// not handled here
|
||||
case SE_HastenedAASkill:
|
||||
@ -2435,9 +2457,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
if (base2 > EQEmu::skills::HIGHEST_SKILL)
|
||||
break;
|
||||
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
|
||||
new_bonus->CritDmgMob[base2] += effect_value;
|
||||
new_bonus->CritDmgMod[base2] += effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3187,6 +3209,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
if (new_bonus->FeignedCastOnChance < effect_value)
|
||||
new_bonus->FeignedCastOnChance = effect_value;
|
||||
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
|
||||
if (IsAISpellEffect) {
|
||||
@ -4197,9 +4229,9 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
{
|
||||
for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++)
|
||||
{
|
||||
spellbonuses.CritDmgMob[e] = effect_value;
|
||||
aabonuses.CritDmgMob[e] = effect_value;
|
||||
itembonuses.CritDmgMob[e] = effect_value;
|
||||
spellbonuses.CritDmgMod[e] = effect_value;
|
||||
aabonuses.CritDmgMod[e] = effect_value;
|
||||
itembonuses.CritDmgMod[e] = effect_value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
28
zone/bot.cpp
28
zone/bot.cpp
@ -22,6 +22,7 @@
|
||||
#include "object.h"
|
||||
#include "doors.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "lua_parser.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/say_link.h"
|
||||
|
||||
@ -83,7 +84,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
|
||||
GenerateBaseStats();
|
||||
// Calculate HitPoints Last As It Uses Base Stats
|
||||
cur_hp = GenerateBaseHitPoints();
|
||||
cur_mana = GenerateBaseManaPoints();
|
||||
current_mana = GenerateBaseManaPoints();
|
||||
cur_end = CalcBaseEndurance();
|
||||
hp_regen = CalcHPRegen();
|
||||
mana_regen = CalcManaRegen();
|
||||
@ -128,7 +129,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
_baseRace = npcTypeData.race;
|
||||
_baseGender = npcTypeData.gender;
|
||||
cur_hp = npcTypeData.cur_hp;
|
||||
cur_mana = npcTypeData.Mana;
|
||||
current_mana = npcTypeData.Mana;
|
||||
RestRegenHP = 0;
|
||||
RestRegenMana = 0;
|
||||
RestRegenEndurance = 0;
|
||||
@ -205,8 +206,8 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
SpellOnTarget(756, this); // Rezz effects
|
||||
}
|
||||
|
||||
if(cur_mana > max_mana)
|
||||
cur_mana = max_mana;
|
||||
if(current_mana > max_mana)
|
||||
current_mana = max_mana;
|
||||
|
||||
cur_end = max_end;
|
||||
}
|
||||
@ -2171,7 +2172,7 @@ void Bot::AI_Process() {
|
||||
}
|
||||
|
||||
if(IsMoving())
|
||||
SendPosUpdate();
|
||||
SendPositionUpdate();
|
||||
else
|
||||
SendPosition();
|
||||
}
|
||||
@ -2382,7 +2383,7 @@ void Bot::AI_Process() {
|
||||
|
||||
// TODO: Test RuleB(Bots, UpdatePositionWithTimer)
|
||||
if(IsMoving())
|
||||
SendPosUpdate();
|
||||
SendPositionUpdate();
|
||||
else
|
||||
SendPosition();
|
||||
}
|
||||
@ -2504,7 +2505,7 @@ void Bot::AI_Process() {
|
||||
}
|
||||
|
||||
if(IsMoving())
|
||||
SendPosUpdate();
|
||||
SendPositionUpdate();
|
||||
else
|
||||
SendPosition();
|
||||
}
|
||||
@ -2928,6 +2929,7 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
|
||||
ns->spawn.helm = helmtexture; //(GetShowHelm() ? helmtexture : 0); //0xFF;
|
||||
ns->spawn.equip_chest2 = texture; //0xFF;
|
||||
ns->spawn.show_name = true;
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = nullptr;
|
||||
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, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
|
||||
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, 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, 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) {
|
||||
SetTarget(nullptr);
|
||||
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
|
||||
// also send Packet to near clients
|
||||
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);
|
||||
|
||||
// Now figure out damage
|
||||
@ -5556,8 +5558,8 @@ int32 Bot::CalcMaxMana() {
|
||||
}
|
||||
}
|
||||
|
||||
if(cur_mana > max_mana)
|
||||
cur_mana = max_mana;
|
||||
if(current_mana > max_mana)
|
||||
current_mana = max_mana;
|
||||
else if(max_mana < 0)
|
||||
max_mana = 0;
|
||||
|
||||
|
||||
@ -325,7 +325,7 @@ public:
|
||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
|
||||
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
||||
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 Zone();
|
||||
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
|
||||
),
|
||||
//these must be listed in the order they appear in client.h
|
||||
position_timer(250),
|
||||
hpupdate_timer(2000),
|
||||
camp_timer(29000),
|
||||
@ -158,10 +157,15 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
|
||||
last_region_type(RegionTypeUnsupported),
|
||||
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;
|
||||
conn_state = NoPacketsReceived;
|
||||
client_data_loaded = false;
|
||||
@ -190,8 +194,10 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
strcpy(account_name, "");
|
||||
tellsoff = false;
|
||||
last_reported_mana = 0;
|
||||
last_reported_endur = 0;
|
||||
gmhideme = false;
|
||||
last_reported_endurance = 0;
|
||||
last_reported_endurance_percent = 0;
|
||||
last_reported_mana_percent = 0;
|
||||
gm_hide_me = false;
|
||||
AFK = false;
|
||||
LFG = false;
|
||||
LFGFromLevel = 0;
|
||||
@ -255,7 +261,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
memset(&m_epp, 0, sizeof(m_epp));
|
||||
PendingTranslocate = false;
|
||||
PendingSacrifice = false;
|
||||
BoatID = 0;
|
||||
controlling_boat_id = 0;
|
||||
|
||||
KarmaUpdateTimer = new Timer(RuleI(Chat, KarmaUpdateIntervalMS));
|
||||
GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS));
|
||||
@ -268,7 +274,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
RestRegenMana = 0;
|
||||
RestRegenEndurance = 0;
|
||||
XPRate = 100;
|
||||
cur_end = 0;
|
||||
current_endurance = 0;
|
||||
|
||||
m_TimeSinceLastPositionCheck = 0;
|
||||
m_DistanceSinceLastPositionCheck = 0.0f;
|
||||
@ -286,7 +292,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
HideCorpseMode = HideCorpseNone;
|
||||
PendingGuildInvitation = false;
|
||||
|
||||
cur_end = 0;
|
||||
current_endurance = 0;
|
||||
|
||||
InitializeBuffSlots();
|
||||
|
||||
@ -357,7 +363,7 @@ Client::~Client() {
|
||||
m_tradeskill_object = nullptr;
|
||||
}
|
||||
|
||||
close_npcs.clear();
|
||||
close_mobs.clear();
|
||||
|
||||
if(IsDueling() && GetDuelTarget() != 0) {
|
||||
Entity* entity = entity_list.GetID(GetDuelTarget());
|
||||
@ -598,8 +604,8 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
m_pp.cur_hp = GetHP();
|
||||
}
|
||||
|
||||
m_pp.mana = cur_mana;
|
||||
m_pp.endurance = cur_end;
|
||||
m_pp.mana = current_mana;
|
||||
m_pp.endurance = current_endurance;
|
||||
|
||||
/* Save Character Currency */
|
||||
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.
|
||||
return(false);
|
||||
}
|
||||
auto c = new CLIENTPACKET;
|
||||
|
||||
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
|
||||
|
||||
c->ack_req = bAckreq;
|
||||
c->app = pApp->Copy();
|
||||
|
||||
clientpackets.Append(c);
|
||||
clientpackets.push_back(std::move(c));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -714,26 +721,23 @@ bool Client::AddPacket(EQApplicationPacket** pApp, bool bAckreq) {
|
||||
//drop the packet because it will never get sent.
|
||||
return(false);
|
||||
}
|
||||
auto c = new CLIENTPACKET;
|
||||
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
|
||||
|
||||
c->ack_req = bAckreq;
|
||||
c->app = *pApp;
|
||||
*pApp = nullptr;
|
||||
|
||||
clientpackets.Append(c);
|
||||
clientpackets.push_back(std::move(c));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::SendAllPackets() {
|
||||
LinkedListIterator<CLIENTPACKET*> iterator(clientpackets);
|
||||
|
||||
CLIENTPACKET* cp = nullptr;
|
||||
iterator.Reset();
|
||||
while(iterator.MoreElements()) {
|
||||
cp = iterator.GetData();
|
||||
while (!clientpackets.empty()) {
|
||||
cp = clientpackets.front().get();
|
||||
if(eqs)
|
||||
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
|
||||
iterator.RemoveCurrent();
|
||||
clientpackets.pop_front();
|
||||
Log(Logs::Moderate, Logs::Client_Server_Packet, "Transmitting a packet");
|
||||
}
|
||||
return true;
|
||||
@ -1257,6 +1261,37 @@ void Client::Message(uint32 type, const char* message, ...) {
|
||||
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) {
|
||||
|
||||
// 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;
|
||||
if (amount > GetMaxMana())
|
||||
amount = GetMaxMana();
|
||||
if (amount != cur_mana)
|
||||
if (amount != current_mana)
|
||||
update = true;
|
||||
cur_mana = amount;
|
||||
current_mana = amount;
|
||||
if (update)
|
||||
Mob::SetMana(amount);
|
||||
SendManaUpdatePacket();
|
||||
return cur_mana;
|
||||
CheckManaEndUpdate();
|
||||
return current_mana;
|
||||
}
|
||||
|
||||
void Client::SendManaUpdatePacket() {
|
||||
void Client::CheckManaEndUpdate() {
|
||||
if (!Connected())
|
||||
return;
|
||||
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
SendManaUpdate();
|
||||
SendEnduranceUpdate();
|
||||
}
|
||||
if (last_reported_mana != current_mana || last_reported_endurance != current_endurance) {
|
||||
|
||||
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));
|
||||
ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer;
|
||||
manachange->new_mana = cur_mana;
|
||||
manachange->stamina = cur_end;
|
||||
manachange->spell_id = casting_spell_id;
|
||||
manachange->keepcasting = 1;
|
||||
ManaChange_Struct* mana_change = (ManaChange_Struct*)outapp->pBuffer;
|
||||
mana_change->new_mana = current_mana;
|
||||
mana_change->stamina = current_endurance;
|
||||
mana_change->spell_id = casting_spell_id;
|
||||
mana_change->keepcasting = 1;
|
||||
outapp->priority = 6;
|
||||
QueuePacket(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)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
auto outapp2 =
|
||||
new EQApplicationPacket(OP_MobEnduranceUpdate, sizeof(MobEnduranceUpdate_Struct));
|
||||
if (raid) {
|
||||
raid->SendManaPacketFrom(this);
|
||||
}
|
||||
else if (group) {
|
||||
group->SendManaPacketFrom(this);
|
||||
}
|
||||
|
||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp->pBuffer;
|
||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp2->pBuffer;
|
||||
auto mana_packet = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct));
|
||||
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();
|
||||
|
||||
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);
|
||||
last_reported_mana_percent = this->GetManaPercent();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
last_reported_endur = cur_end;
|
||||
if (raid) {
|
||||
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()
|
||||
{
|
||||
auto mana_app = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct));
|
||||
ManaUpdate_Struct* mus = (ManaUpdate_Struct*)mana_app->pBuffer;
|
||||
mus->cur_mana = GetMana();
|
||||
mus->max_mana = GetMaxMana();
|
||||
mus->spawn_id = GetID();
|
||||
ManaUpdate_Struct* mana_update = (ManaUpdate_Struct*)mana_app->pBuffer;
|
||||
mana_update->cur_mana = GetMana();
|
||||
mana_update->max_mana = GetMaxMana();
|
||||
mana_update->spawn_id = GetID();
|
||||
QueuePacket(mana_app);
|
||||
entity_list.QueueClientsByXTarget(this, mana_app, false);
|
||||
safe_delete(mana_app);
|
||||
}
|
||||
|
||||
@ -1871,12 +1924,11 @@ void Client::SendManaUpdate()
|
||||
void Client::SendEnduranceUpdate()
|
||||
{
|
||||
auto end_app = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||
EnduranceUpdate_Struct* eus = (EnduranceUpdate_Struct*)end_app->pBuffer;
|
||||
eus->cur_end = GetEndurance();
|
||||
eus->max_end = GetMaxEndurance();
|
||||
eus->spawn_id = GetID();
|
||||
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)end_app->pBuffer;
|
||||
endurance_update->cur_end = GetEndurance();
|
||||
endurance_update->max_end = GetMaxEndurance();
|
||||
endurance_update->spawn_id = GetID();
|
||||
QueuePacket(end_app);
|
||||
entity_list.QueueClientsByXTarget(this, end_app, false);
|
||||
safe_delete(end_app);
|
||||
}
|
||||
|
||||
@ -1892,6 +1944,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.guildID = GuildID();
|
||||
// ns->spawn.linkdead = IsLD() ? 1 : 0;
|
||||
// ns->spawn.pvp = GetPVP() ? 1 : 0;
|
||||
ns->spawn.show_name = true;
|
||||
|
||||
|
||||
strcpy(ns->spawn.title, m_pp.title);
|
||||
@ -1920,7 +1973,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
}
|
||||
|
||||
bool Client::GMHideMe(Client* client) {
|
||||
if (gmhideme) {
|
||||
if (gm_hide_me) {
|
||||
if (client == 0)
|
||||
return true;
|
||||
else if (admin > client->Admin())
|
||||
@ -2339,7 +2392,9 @@ bool Client::CheckIncreaseSkill(EQEmu::skills::SkillType skillid, Mob *against_w
|
||||
return false;
|
||||
int skillval = GetRawSkill(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->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() ||
|
||||
@ -3187,9 +3242,9 @@ void Client::SetHideMe(bool flag)
|
||||
{
|
||||
EQApplicationPacket app;
|
||||
|
||||
gmhideme = flag;
|
||||
gm_hide_me = flag;
|
||||
|
||||
if(gmhideme)
|
||||
if(gm_hide_me)
|
||||
{
|
||||
database.SetHideMe(AccountID(),true);
|
||||
CreateDespawnPacket(&app, false);
|
||||
@ -3737,8 +3792,8 @@ void Client::SetEndurance(int32 newEnd)
|
||||
newEnd = GetMaxEndurance();
|
||||
}
|
||||
|
||||
cur_end = newEnd;
|
||||
SendManaUpdatePacket();
|
||||
current_endurance = newEnd;
|
||||
CheckManaEndUpdate();
|
||||
}
|
||||
|
||||
void Client::SacrificeConfirm(Client *caster)
|
||||
@ -3931,6 +3986,46 @@ void Client::SendPopupToClient(const char *Title, const char *Text, uint32 Popup
|
||||
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, ...) {
|
||||
va_list argptr;
|
||||
char buffer[4096];
|
||||
@ -4171,7 +4266,7 @@ bool Client::GroupFollow(Client* inviter) {
|
||||
RemoveAutoXTargets();
|
||||
}
|
||||
|
||||
SetXTargetAutoMgr(GetXTargetAutoMgr());
|
||||
SetXTargetAutoMgr(raid->GetXTargetAutoMgr());
|
||||
if (!GetXTargetAutoMgr()->empty())
|
||||
SetDirtyAutoHaters();
|
||||
|
||||
@ -4304,7 +4399,7 @@ bool Client::GroupFollow(Client* inviter) {
|
||||
}
|
||||
|
||||
database.RefreshGroupFromDB(this);
|
||||
group->SendHPPacketsTo(this);
|
||||
group->SendHPManaEndPacketsTo(this);
|
||||
//send updates to clients out of zone...
|
||||
group->SendGroupJoinOOZ(this);
|
||||
return true;
|
||||
@ -5715,6 +5810,20 @@ void Client::SuspendMinion()
|
||||
Message_StringID(clientMessageTell, SUSPEND_MINION_UNSUSPEND, CurrentPet->GetCleanName());
|
||||
|
||||
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
|
||||
return;
|
||||
@ -6266,7 +6375,7 @@ void Client::LocateCorpse()
|
||||
SetHeading(CalculateHeadingToTarget(ClosestCorpse->GetX(), ClosestCorpse->GetY()));
|
||||
SetTarget(ClosestCorpse);
|
||||
SendTargetCommand(ClosestCorpse->GetID());
|
||||
SendPosUpdate(2);
|
||||
SendPositionUpdate(2);
|
||||
}
|
||||
else if(!GetTarget())
|
||||
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)
|
||||
{
|
||||
int hchange = item->CastTime * cons_mod;
|
||||
int hchange = item->CastTime_ * cons_mod;
|
||||
hchange = mod_food_value(item, hchange);
|
||||
|
||||
if(hchange < 0) { return; }
|
||||
@ -8506,7 +8615,7 @@ void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool a
|
||||
}
|
||||
else
|
||||
{
|
||||
int tchange = item->CastTime * cons_mod;
|
||||
int tchange = item->CastTime_ * cons_mod;
|
||||
tchange = mod_drink_value(item, tchange);
|
||||
|
||||
if(tchange < 0) { return; }
|
||||
@ -8660,8 +8769,8 @@ void Client::SendHPUpdateMarquee(){
|
||||
return;
|
||||
|
||||
/* Health Update Marquee Display: Custom*/
|
||||
uint32 health_percentage = (uint32)(this->cur_hp * 100 / this->max_hp);
|
||||
if (health_percentage == 100)
|
||||
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
|
||||
if (health_percentage >= 100)
|
||||
return;
|
||||
|
||||
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 <algorithm>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
|
||||
#define CLIENT_TIMEOUT 90000
|
||||
@ -221,7 +222,7 @@ public:
|
||||
Client(EQStreamInterface * ieqs);
|
||||
~Client();
|
||||
|
||||
std::unordered_map<NPC *, float> close_npcs;
|
||||
std::unordered_map<Mob *, float> close_mobs;
|
||||
bool is_client_moving;
|
||||
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
@ -298,6 +299,7 @@ public:
|
||||
const char* GetBuyerWelcomeMessage() { return BuyerWelcomeMessage.c_str(); }
|
||||
|
||||
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
bool ShouldISpawnFor(Client *c) { return !GMHideMe(c) && !IsHoveringForRespawn(); }
|
||||
virtual bool Process();
|
||||
void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemData* item, bool buying);
|
||||
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, uint8 lang_skill, 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 VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber);
|
||||
void SendSound();
|
||||
@ -318,7 +321,7 @@ public:
|
||||
bool GetRevoked() const { return revoked; }
|
||||
void SetRevoked(bool rev) { revoked = rev; }
|
||||
inline uint32 GetIP() const { return ip; }
|
||||
inline bool GetHideMe() const { return gmhideme; }
|
||||
inline bool GetHideMe() const { return gm_hide_me; }
|
||||
void SetHideMe(bool hm);
|
||||
inline uint16 GetPort() const { return port; }
|
||||
bool IsDead() const { return(dead); }
|
||||
@ -351,6 +354,8 @@ public:
|
||||
inline InspectMessage_Struct& GetInspectMessage() { 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);
|
||||
|
||||
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
|
||||
int32 CalcBaseEndurance(); //Calculates Base End
|
||||
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 CalcEnduranceRegenCap();
|
||||
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 DoEnduranceRegen(); //This Regenerates endurance
|
||||
void DoEnduranceUpkeep(); //does the endurance upkeep
|
||||
@ -567,6 +572,7 @@ public:
|
||||
void AddCrystals(uint32 Radiant, uint32 Ebon);
|
||||
void SendCrystalCounts();
|
||||
|
||||
uint32 GetExperienceForKill(Mob *against);
|
||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
||||
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
||||
@ -656,7 +662,7 @@ public:
|
||||
void RefreshGuildInfo();
|
||||
|
||||
|
||||
void SendManaUpdatePacket();
|
||||
void CheckManaEndUpdate();
|
||||
void SendManaUpdate();
|
||||
void SendEnduranceUpdate();
|
||||
uint8 GetFace() const { return m_pp.face; }
|
||||
@ -792,12 +798,12 @@ public:
|
||||
void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); }
|
||||
int GetAAPoints() { return m_pp.aapoints; }
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
uint32 GetRequiredAAExperience();
|
||||
|
||||
//old AA methods that we still use
|
||||
void ResetAA();
|
||||
void RefundAA();
|
||||
void SendClearAA();
|
||||
inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
|
||||
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
||||
inline uint32 GetAAPercent() const { return m_epp.perAA; }
|
||||
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); }
|
||||
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 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, ...);
|
||||
bool PendingTranslocate;
|
||||
time_t TranslocateTime;
|
||||
@ -1066,7 +1073,7 @@ public:
|
||||
void Signal(uint32 data);
|
||||
Mob *GetBindSightTarget() { return bind_sight_target; }
|
||||
void SetBindSightTarget(Mob *n) { bind_sight_target = n; }
|
||||
const uint16 GetBoatID() const { return BoatID; }
|
||||
const uint16 GetBoatID() const { return controlling_boat_id; }
|
||||
void SendRewards();
|
||||
bool TryReward(uint32 claim_id);
|
||||
QGlobalCache *GetQGlobals() { return qGlobals; }
|
||||
@ -1257,6 +1264,8 @@ public:
|
||||
|
||||
void CheckRegionTypeChanges();
|
||||
|
||||
int32 CalcATK();
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
@ -1316,7 +1325,6 @@ private:
|
||||
|
||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
||||
|
||||
int32 CalcATK();
|
||||
int32 CalcItemATKCap();
|
||||
int32 CalcHaste();
|
||||
|
||||
@ -1369,7 +1377,7 @@ private:
|
||||
bool duelaccepted;
|
||||
std::list<uint32> keyring;
|
||||
bool tellsoff; // GM /toggle
|
||||
bool gmhideme;
|
||||
bool gm_hide_me;
|
||||
bool LFG;
|
||||
bool LFP;
|
||||
uint8 LFGFromLevel;
|
||||
@ -1389,7 +1397,7 @@ private:
|
||||
uint32 weight;
|
||||
bool berserk;
|
||||
bool dead;
|
||||
uint16 BoatID;
|
||||
uint16 controlling_boat_id;
|
||||
uint16 TrackingID;
|
||||
uint16 CustomerID;
|
||||
uint16 TraderID;
|
||||
@ -1404,7 +1412,7 @@ private:
|
||||
int Haste; //precalced value
|
||||
|
||||
int32 max_end;
|
||||
int32 cur_end;
|
||||
int32 current_endurance;
|
||||
|
||||
PlayerProfile_Struct m_pp;
|
||||
ExtendedProfile_Struct m_epp;
|
||||
@ -1424,7 +1432,7 @@ private:
|
||||
bool AddPacket(const EQApplicationPacket *, bool);
|
||||
bool AddPacket(EQApplicationPacket**, bool);
|
||||
bool SendAllPackets();
|
||||
LinkedList<CLIENTPACKET *> clientpackets;
|
||||
std::deque<std::unique_ptr<CLIENTPACKET>> clientpackets;
|
||||
|
||||
//Zoning related stuff
|
||||
void SendZoneCancel(ZoneChange_Struct *zc);
|
||||
@ -1478,7 +1486,9 @@ private:
|
||||
Timer helm_toggle_timer;
|
||||
Timer aggro_meter_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;
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
@ -1487,7 +1497,6 @@ private:
|
||||
|
||||
uint32 tribute_master_id;
|
||||
|
||||
uint32 max_AAXP;
|
||||
bool npcflag;
|
||||
uint8 npclevel;
|
||||
bool feigned;
|
||||
@ -1495,7 +1504,10 @@ private:
|
||||
bool tgb;
|
||||
bool instalog;
|
||||
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.
|
||||
|
||||
|
||||
@ -1046,14 +1046,14 @@ int32 Client::CalcMaxMana()
|
||||
if (max_mana < 0) {
|
||||
max_mana = 0;
|
||||
}
|
||||
if (cur_mana > max_mana) {
|
||||
cur_mana = max_mana;
|
||||
if (current_mana > max_mana) {
|
||||
current_mana = max_mana;
|
||||
}
|
||||
int mana_perc_cap = spellbonuses.ManaPercCap[0];
|
||||
if (mana_perc_cap) {
|
||||
int curMana_cap = (max_mana * mana_perc_cap) / 100;
|
||||
if (cur_mana > curMana_cap || (spellbonuses.ManaPercCap[1] && cur_mana > spellbonuses.ManaPercCap[1])) {
|
||||
cur_mana = curMana_cap;
|
||||
if (current_mana > curMana_cap || (spellbonuses.ManaPercCap[1] && current_mana > spellbonuses.ManaPercCap[1])) {
|
||||
current_mana = curMana_cap;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
max_end = 0;
|
||||
}
|
||||
if (cur_end > max_end) {
|
||||
cur_end = max_end;
|
||||
if (current_endurance > max_end) {
|
||||
current_endurance = max_end;
|
||||
}
|
||||
int end_perc_cap = spellbonuses.EndPercCap[0];
|
||||
if (end_perc_cap) {
|
||||
int curEnd_cap = (max_end * end_perc_cap) / 100;
|
||||
if (cur_end > curEnd_cap || (spellbonuses.EndPercCap[1] && cur_end > spellbonuses.EndPercCap[1])) {
|
||||
cur_end = curEnd_cap;
|
||||
if (current_endurance > curEnd_cap || (spellbonuses.EndPercCap[1] && current_endurance > spellbonuses.EndPercCap[1])) {
|
||||
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_ReloadUI(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_RequestDuel(const EQApplicationPacket *app);
|
||||
void Handle_OP_RequestTitles(const EQApplicationPacket *app);
|
||||
@ -288,6 +289,7 @@
|
||||
void Handle_OP_TributeNPC(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeToggle(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_VoiceMacroIn(const EQApplicationPacket *app);
|
||||
void Handle_OP_WearChange(const EQApplicationPacket *app);
|
||||
|
||||
@ -63,64 +63,49 @@ extern EntityList entity_list;
|
||||
bool Client::Process() {
|
||||
bool ret = true;
|
||||
|
||||
if (Connected() || IsLD())
|
||||
{
|
||||
if (Connected() || IsLD()) {
|
||||
// try to send all packets that weren't sent before
|
||||
if (!IsLD() && zoneinpacket_timer.Check())
|
||||
{
|
||||
if (!IsLD() && zoneinpacket_timer.Check()) {
|
||||
SendAllPackets();
|
||||
}
|
||||
|
||||
if (adventure_request_timer)
|
||||
{
|
||||
if (adventure_request_timer->Check())
|
||||
{
|
||||
if (adventure_request_timer) {
|
||||
if (adventure_request_timer->Check()) {
|
||||
safe_delete(adventure_request_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (adventure_create_timer)
|
||||
{
|
||||
if (adventure_create_timer->Check())
|
||||
{
|
||||
if (adventure_create_timer) {
|
||||
if (adventure_create_timer->Check()) {
|
||||
safe_delete(adventure_create_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (adventure_leave_timer)
|
||||
{
|
||||
if (adventure_leave_timer->Check())
|
||||
{
|
||||
if (adventure_leave_timer) {
|
||||
if (adventure_leave_timer->Check()) {
|
||||
safe_delete(adventure_leave_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (adventure_door_timer)
|
||||
{
|
||||
if (adventure_door_timer->Check())
|
||||
{
|
||||
if (adventure_door_timer) {
|
||||
if (adventure_door_timer->Check()) {
|
||||
safe_delete(adventure_door_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (adventure_stats_timer)
|
||||
{
|
||||
if (adventure_stats_timer->Check())
|
||||
{
|
||||
if (adventure_stats_timer) {
|
||||
if (adventure_stats_timer->Check()) {
|
||||
safe_delete(adventure_stats_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (adventure_leaderboard_timer)
|
||||
{
|
||||
if (adventure_leaderboard_timer->Check())
|
||||
{
|
||||
if (adventure_leaderboard_timer) {
|
||||
if (adventure_leaderboard_timer->Check()) {
|
||||
safe_delete(adventure_leaderboard_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (dead)
|
||||
{
|
||||
if (dead) {
|
||||
SetHP(-100);
|
||||
if (RespawnFromHoverTimer.Check())
|
||||
HandleRespawnFromHover(0);
|
||||
@ -134,8 +119,13 @@ bool Client::Process() {
|
||||
if (hpupdate_timer.Check(false))
|
||||
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())
|
||||
SendManaUpdatePacket();
|
||||
CheckManaEndUpdate();
|
||||
|
||||
if (dead && dead_timer.Check()) {
|
||||
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 */
|
||||
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 = npc_list.begin(); itr != npc_list.end(); ++itr) {
|
||||
NPC* npc = itr->second;
|
||||
float distance = DistanceNoZ(m_Position, npc->GetPosition());
|
||||
if(distance <= scan_range) {
|
||||
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
||||
}
|
||||
else if (npc->GetAggroRange() > scan_range) {
|
||||
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
||||
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||
Mob* mob = itr->second;
|
||||
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
||||
if (mob->IsNPC()) {
|
||||
if (distance <= scan_range) {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
else if (mob->GetAggroRange() > scan_range) {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -448,14 +441,14 @@ bool Client::Process() {
|
||||
{
|
||||
animation = 0;
|
||||
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
|
||||
// see this char disappear after 10-12 seconds of inactivity
|
||||
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();
|
||||
pLastUpdateWZ = pLastUpdate;
|
||||
position_timer_counter = 0;
|
||||
@ -619,11 +612,17 @@ bool Client::Process() {
|
||||
// only if client is not feigned
|
||||
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
|
||||
int npc_scan_count = 0;
|
||||
for (auto it = close_npcs.begin(); it != close_npcs.end(); ++it) {
|
||||
NPC *npc = it->first;
|
||||
for (auto it = close_mobs.begin(); it != close_mobs.end(); ++it) {
|
||||
Mob *mob = it->first;
|
||||
|
||||
if (npc->CheckWillAggro(this) && !npc->CheckAggro(this)) {
|
||||
npc->AddToHateList(this, 25);
|
||||
if (!mob)
|
||||
continue;
|
||||
|
||||
if (mob->IsClient())
|
||||
continue;
|
||||
|
||||
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
|
||||
mob->AddToHateList(this, 25);
|
||||
}
|
||||
npc_scan_count++;
|
||||
}
|
||||
@ -724,6 +723,8 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
}
|
||||
}
|
||||
|
||||
RemoveAllAuras();
|
||||
|
||||
Mob *Other = trade->With();
|
||||
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);
|
||||
else
|
||||
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName());
|
||||
|
||||
merch->CastToNPC()->FaceTarget(this->CastToMob());
|
||||
}
|
||||
|
||||
// safe_delete_array(cpi);
|
||||
@ -1816,7 +1815,7 @@ void Client::DoManaRegen() {
|
||||
return;
|
||||
|
||||
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("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("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("cvs", "- Summary of client versions currently online.", 200, command_cvs) ||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
c->SendHPUpdate();
|
||||
c->SendManaUpdatePacket();
|
||||
c->CheckManaEndUpdate();
|
||||
}
|
||||
|
||||
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?)
|
||||
query = StringFormat(
|
||||
"SELECT COUNT(*) FROM object WHERE zoneid = %u "
|
||||
"AND version=%u AND (posx BETWEEN %.1f AND %.1f) "
|
||||
"AND (posy BETWEEN %.1f AND %.1f) "
|
||||
"AND (posz BETWEEN %.1f AND %.1f)",
|
||||
"AND version=%u AND (xpos BETWEEN %.1f AND %.1f) "
|
||||
"AND (ypos BETWEEN %.1f AND %.1f) "
|
||||
"AND (zpos BETWEEN %.1f AND %.1f)",
|
||||
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.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_connectworldserver(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_cvs(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
|
||||
#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
|
||||
focusSpellHaste = 1,
|
||||
focusSpellDuration,
|
||||
@ -156,6 +207,16 @@ typedef enum { //fear states
|
||||
|
||||
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;
|
||||
class Trade;
|
||||
enum TradeState {
|
||||
@ -359,7 +420,7 @@ struct StatBonuses {
|
||||
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 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 SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
||||
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.
|
||||
int16 NoBreakAESneak; // 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
|
||||
|
||||
119
zone/effects.cpp
119
zone/effects.cpp
@ -356,67 +356,15 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
|
||||
cost -= mana_back;
|
||||
}
|
||||
|
||||
// This formula was derived from the following resource:
|
||||
// http://www.eqsummoners.com/eq1/specialization-library.html
|
||||
// WildcardX
|
||||
float PercentManaReduction = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
int spec = GetSpecializeSkillValue(spell_id);
|
||||
int PercentManaReduction = 0;
|
||||
if (spec)
|
||||
PercentManaReduction = 1 + spec / 20; // there seems to be some non-obvious rounding here, let's truncate for now.
|
||||
|
||||
int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);
|
||||
PercentManaReduction += focus_redux;
|
||||
|
||||
if(focus_redux > 0)
|
||||
{
|
||||
PercentManaReduction += zone->random.Real(1, (double)focus_redux);
|
||||
}
|
||||
|
||||
cost -= (cost * (PercentManaReduction / 100));
|
||||
cost -= cost * PercentManaReduction / 100;
|
||||
|
||||
// Gift of Mana - reduces spell cost to 1 mana
|
||||
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
|
||||
// spell_id.
|
||||
// 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;
|
||||
|
||||
@ -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 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 isnpc = caster->IsNPC();
|
||||
int MAX_TARGETS_ALLOWED = 4;
|
||||
|
||||
if (spells[spell_id].aemaxtargets)
|
||||
MAX_TARGETS_ALLOWED = spells[spell_id].aemaxtargets;
|
||||
if (RuleB(Spells, OldRainTargets))
|
||||
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;
|
||||
|
||||
@ -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
|
||||
if (curmob->IsClient() && !curmob->CastToClient()->ClientFinishedLoading())
|
||||
continue;
|
||||
if (curmob == center) //do not affect center
|
||||
continue;
|
||||
if (curmob == caster && !affect_caster) //watch for caster too
|
||||
continue;
|
||||
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;
|
||||
if (spells[spell_id].pcnpc_only_flag == 2 && (curmob->IsClient() || curmob->IsMerc()))
|
||||
continue;
|
||||
if (!IsWithinAxisAlignedBox(static_cast<glm::vec2>(curmob->GetPosition()), min, max))
|
||||
continue;
|
||||
|
||||
if (spells[spell_id].targettype == ST_Ring) {
|
||||
dist_targ = DistanceSquared(static_cast<glm::vec3>(curmob->GetPosition()), caster->GetTargetRingLocation());
|
||||
}
|
||||
else if (center) {
|
||||
dist_targ = DistanceSquared(curmob->GetPosition(), center->GetPosition());
|
||||
}
|
||||
dist_targ = DistanceSquared(curmob->GetPosition(), position);
|
||||
|
||||
if (dist_targ > dist2) //make sure they are in range
|
||||
continue;
|
||||
@ -813,7 +769,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
if (bad) {
|
||||
if (!caster->IsAttackAllowed(curmob, true))
|
||||
continue;
|
||||
if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob))
|
||||
if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob))
|
||||
continue;
|
||||
if (!center && !spells[spell_id].npc_no_los && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize()))
|
||||
continue;
|
||||
@ -828,22 +784,17 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
}
|
||||
|
||||
curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
|
||||
//if we get here... cast the spell.
|
||||
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)...
|
||||
if (max_targets_allowed) { // if we have a limit, increment count
|
||||
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)
|
||||
|
||||
@ -117,6 +117,7 @@ const char *QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_TICK",
|
||||
"EVENT_SPAWN_ZONE",
|
||||
"EVENT_DEATH_ZONE",
|
||||
"EVENT_USE_SKILL",
|
||||
};
|
||||
|
||||
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]);
|
||||
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: {
|
||||
break;
|
||||
|
||||
@ -3599,6 +3599,24 @@ XS(XS__crosszonesetentityvariablebynpctypeid)
|
||||
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)
|
||||
{
|
||||
@ -3766,6 +3784,7 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "createguild"), XS__createguild, file);
|
||||
newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, 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, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, 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);
|
||||
npc->SendArmorAppearance();
|
||||
npc->SetAppearance(npc->GetGuardPointAnim(),false);
|
||||
if (!npc->IsTargetable())
|
||||
npc->SendTargetable(false);
|
||||
safe_delete(app);
|
||||
} else {
|
||||
auto ns = new NewSpawn_Struct;
|
||||
@ -799,6 +801,8 @@ void EntityList::CheckSpawnQueue()
|
||||
NPC *pnpc = it->second;
|
||||
pnpc->SendArmorAppearance();
|
||||
pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false);
|
||||
if (!pnpc->IsTargetable())
|
||||
pnpc->SendTargetable(false);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
iterator.RemoveCurrent();
|
||||
@ -1242,12 +1246,9 @@ void EntityList::SendZoneSpawns(Client *client)
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
Mob *ent = it->second;
|
||||
if (!(ent->InZone()) || (ent->IsClient())) {
|
||||
if (ent->CastToClient()->GMHideMe(client) ||
|
||||
ent->CastToClient()->IsHoveringForRespawn()) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
if (!ent->InZone() || !ent->ShouldISpawnFor(client)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
app = new EQApplicationPacket;
|
||||
@ -1275,17 +1276,16 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
spawn = it->second;
|
||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||
if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) ||
|
||||
spawn->CastToClient()->IsHoveringForRespawn()))
|
||||
if (!spawn->ShouldISpawnFor(client))
|
||||
continue;
|
||||
|
||||
#if 1
|
||||
const glm::vec4& spos = spawn->GetPosition();
|
||||
|
||||
|
||||
delaypkt = false;
|
||||
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
||||
delaypkt = true;
|
||||
|
||||
|
||||
if (delaypkt) {
|
||||
app = new EQApplicationPacket;
|
||||
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()
|
||||
{
|
||||
auto it = mob_list.begin();
|
||||
@ -2263,6 +2282,9 @@ bool EntityList::RemoveMob(uint16 delete_id)
|
||||
|
||||
auto it = mob_list.find(delete_id);
|
||||
if (it != mob_list.end()) {
|
||||
|
||||
RemoveMobFromClientCloseLists(it->second);
|
||||
|
||||
if (npc_list.count(delete_id))
|
||||
entity_list.RemoveNPC(delete_id);
|
||||
else if (client_list.count(delete_id))
|
||||
@ -2285,6 +2307,8 @@ bool EntityList::RemoveMob(Mob *delete_mob)
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
if (it->second == delete_mob) {
|
||||
RemoveMobFromClientCloseLists(it->second);
|
||||
|
||||
safe_delete(it->second);
|
||||
if (!corpse_list.count(it->first))
|
||||
free_ids.push(it->first);
|
||||
@ -2304,10 +2328,9 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
||||
// make sure its proximity is removed
|
||||
RemoveProximity(delete_id);
|
||||
// remove from client close lists
|
||||
RemoveNPCFromClientCloseLists(npc);
|
||||
RemoveMobFromClientCloseLists(npc->CastToMob());
|
||||
// remove from the list
|
||||
npc_list.erase(it);
|
||||
|
||||
|
||||
// remove from limit list if needed
|
||||
if (npc_limit_list.count(delete_id))
|
||||
@ -2317,11 +2340,11 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityList::RemoveNPCFromClientCloseLists(NPC *npc)
|
||||
bool EntityList::RemoveMobFromClientCloseLists(Mob *mob)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
it->second->close_npcs.erase(npc);
|
||||
it->second->close_mobs.erase(mob);
|
||||
++it;
|
||||
}
|
||||
return false;
|
||||
@ -2615,10 +2638,9 @@ void EntityList::RemoveDebuffs(Mob *caster)
|
||||
// Currently, a new packet is sent per entity.
|
||||
// @todo: Come back and use FLAG_COMBINED to pack
|
||||
// all updates into one packet.
|
||||
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate,
|
||||
float range, Entity *alwayssend, bool iSendEvenIfNotChanged)
|
||||
void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate, float update_range, Entity *always_send, bool iSendEvenIfNotChanged)
|
||||
{
|
||||
range = range * range;
|
||||
update_range = (update_range * update_range);
|
||||
|
||||
EQApplicationPacket *outapp = 0;
|
||||
PlayerPositionUpdateServer_Struct *ppu = 0;
|
||||
@ -2626,27 +2648,37 @@ void EntityList::SendPositionUpdates(Client *client, uint32 cLastUpdate,
|
||||
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
if (outapp == 0) {
|
||||
outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
|
||||
}
|
||||
|
||||
mob = it->second;
|
||||
if (mob && !mob->IsCorpse() && (it->second != client)
|
||||
|
||||
if (
|
||||
mob && !mob->IsCorpse()
|
||||
&& (it->second != client)
|
||||
&& (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)) {
|
||||
if (range == 0 || (it->second == alwayssend) || mob->IsClient() || (DistanceSquared(mob->GetPosition(), client->GetPosition()) <= range)) {
|
||||
mob->MakeSpawnUpdate(ppu);
|
||||
}
|
||||
if(mob && mob->IsClient() && mob->GetID()>0) {
|
||||
client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
mob->MakeSpawnUpdate(ppu);
|
||||
|
||||
safe_delete(outapp);
|
||||
outapp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_delete(outapp);
|
||||
outapp = 0;
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
@ -2826,6 +2858,22 @@ int32 EntityList::DeleteNPCCorpses()
|
||||
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.
|
||||
int32 EntityList::DeletePlayerCorpses()
|
||||
{
|
||||
|
||||
@ -79,6 +79,8 @@ public:
|
||||
virtual bool IsTrap() const { return false; }
|
||||
virtual bool IsBeacon() 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 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);
|
||||
|
||||
#ifdef BOTS
|
||||
virtual bool IsBot() const { return false; }
|
||||
Bot* CastToBot();
|
||||
#endif
|
||||
|
||||
@ -279,7 +280,7 @@ public:
|
||||
bool RemoveTrap(uint16 delete_id);
|
||||
bool RemoveObject(uint16 delete_id);
|
||||
bool RemoveProximity(uint16 delete_npc_id);
|
||||
bool RemoveNPCFromClientCloseLists(NPC *npc);
|
||||
bool RemoveMobFromClientCloseLists(Mob *mob);
|
||||
void RemoveAllMobs();
|
||||
void RemoveAllClients();
|
||||
void RemoveAllNPCs();
|
||||
@ -315,6 +316,7 @@ public:
|
||||
void Message(uint32 to_guilddbid, 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 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 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);
|
||||
@ -356,7 +358,7 @@ public:
|
||||
|
||||
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 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 AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
||||
|
||||
@ -369,7 +371,7 @@ public:
|
||||
Mob* FindDefenseNPC(uint32 npcid);
|
||||
void OpenDoorsNear(NPC* opener);
|
||||
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);
|
||||
static char* RemoveNumbers(char* name);
|
||||
void SignalMobsByNPCID(uint32 npc_type, int signal_id);
|
||||
@ -385,6 +387,7 @@ public:
|
||||
void FindPathsToAllNPCs();
|
||||
int32 DeleteNPCCorpses();
|
||||
int32 DeletePlayerCorpses();
|
||||
void CorpseFix(Client* c);
|
||||
void WriteEntityIDs();
|
||||
void HalveAggro(Mob* who);
|
||||
void DoubleAggro(Mob* who);
|
||||
|
||||
@ -85,6 +85,7 @@ typedef enum {
|
||||
EVENT_TICK,
|
||||
EVENT_SPAWN_ZONE,
|
||||
EVENT_DEATH_ZONE,
|
||||
EVENT_USE_SKILL,
|
||||
_LargestEventID
|
||||
} QuestEventID;
|
||||
|
||||
|
||||
66
zone/exp.cpp
66
zone/exp.cpp
@ -28,6 +28,7 @@
|
||||
|
||||
#include "queryserv.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "lua_parser.h"
|
||||
#include "string_ids.h"
|
||||
|
||||
#ifdef BOTS
|
||||
@ -153,6 +154,26 @@ uint32 Client::CalcEXP(uint8 conlevel) {
|
||||
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) {
|
||||
|
||||
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) {
|
||||
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) {
|
||||
Message(13, "Error in Client::SetEXP. EXP not set.");
|
||||
return; // Must be invalid class/race
|
||||
@ -377,19 +398,23 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool 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 {
|
||||
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 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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -460,14 +485,13 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
|
||||
//add in how many points we had
|
||||
m_pp.aapoints += last_unspentAA;
|
||||
//set_aaxp = m_pp.expAA % max_AAXP;
|
||||
|
||||
//figure out how many points were actually gained
|
||||
/*uint32 gained = m_pp.aapoints - last_unspentAA;*/ //unused
|
||||
|
||||
//Message(15, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
|
||||
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 */
|
||||
if (RuleB(QueryServ, PlayerLogAARate)){
|
||||
@ -571,8 +595,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
char val1[20]={0};
|
||||
char val2[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(15, "[GM] You now have %d / %d EXP and %d / %d AA exp.", set_exp, GetEXPForLevel(GetLevel()+1), set_aaxp, max_AAXP);
|
||||
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).
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
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;
|
||||
float mod;
|
||||
@ -933,3 +965,17 @@ uint32 Client::GetCharMaxLevelFromQGlobal() {
|
||||
|
||||
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;
|
||||
float ranx, rany, ranz;
|
||||
currently_fleeing = false;
|
||||
|
||||
currently_fleeing = true;
|
||||
while (loop < 100) //Max 100 tries
|
||||
{
|
||||
int ran = 250 - (loop*2);
|
||||
@ -167,13 +168,13 @@ void Mob::CalculateNewFearpoint()
|
||||
float fdist = ranz - GetZ();
|
||||
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
|
||||
{
|
||||
currently_fleeing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currently_fleeing)
|
||||
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
||||
else //Break fear
|
||||
BuffFadeByEffect(SE_Fear);
|
||||
|
||||
if (loop <= 100)
|
||||
{
|
||||
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -196,7 +196,7 @@ bool Client::CanFish() {
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Group* group = newmember->CastToClient()->GetGroup();
|
||||
if (group) {
|
||||
group->SendHPManaEndPacketsTo(newmember);
|
||||
group->SendHPPacketsFrom(newmember);
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
// 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 outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++)
|
||||
{
|
||||
if(members[i] && members[i] != member)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if(members[i] && members[i] != member) {
|
||||
members[i]->CreateHPPacket(&hpapp);
|
||||
member->CastToClient()->QueuePacket(&hpapp, false);
|
||||
safe_delete_array(hpapp.pBuffer);
|
||||
hpapp.size = 0;
|
||||
if (member->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)
|
||||
{
|
||||
|
||||
if (member->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobManaUpdate);
|
||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||
mmus->spawn_id = members[i]->GetID();
|
||||
mmus->mana = members[i]->GetManaPercent();
|
||||
|
||||
MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||
mana_update->spawn_id = members[i]->GetID();
|
||||
mana_update->mana = members[i]->GetManaPercent();
|
||||
member->CastToClient()->QueuePacket(&outapp, false);
|
||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||
|
||||
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||
meus->endurance = members[i]->GetEndurancePercent();
|
||||
endurance_update->endurance = members[i]->GetEndurancePercent();
|
||||
member->CastToClient()->QueuePacket(&outapp, false);
|
||||
}
|
||||
}
|
||||
@ -430,19 +436,58 @@ void Group::SendHPPacketsFrom(Mob *member)
|
||||
|
||||
uint32 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);
|
||||
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)
|
||||
{
|
||||
if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobManaUpdate);
|
||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer;
|
||||
mmus->spawn_id = member->GetID();
|
||||
mmus->mana = member->GetManaPercent();
|
||||
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);
|
||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||
|
||||
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -648,7 +693,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
}
|
||||
}
|
||||
|
||||
if (GetLeader() == nullptr)
|
||||
if (!GetLeaderName())
|
||||
{
|
||||
DisbandGroup();
|
||||
return true;
|
||||
|
||||
@ -80,8 +80,10 @@ public:
|
||||
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
||||
inline Mob* GetLeader() { return leader; };
|
||||
const char* GetLeaderName() { return membername[0]; };
|
||||
void SendHPPacketsTo(Mob* newmember);
|
||||
void SendHPPacketsFrom(Mob* newmember);
|
||||
void SendHPManaEndPacketsTo(Mob* newmember);
|
||||
void SendHPPacketsFrom(Mob* member);
|
||||
void SendManaPacketFrom(Mob* member);
|
||||
void SendEndurancePacketFrom(Mob* member);
|
||||
bool UpdatePlayer(Mob* update);
|
||||
void MemberZoned(Mob* removemob);
|
||||
inline bool IsLeader(Mob* leadertest) { return leadertest==leader; };
|
||||
|
||||
@ -1172,6 +1172,11 @@ uint64 Lua_Client::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() {
|
||||
Lua_Safe_Call_Void();
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
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() {
|
||||
@ -1653,6 +1674,7 @@ luabind::scope lua_register_client() {
|
||||
.def("GetAggroCount", (int(Lua_Client::*)(void))&Lua_Client::GetAggroCount)
|
||||
.def("GetCarriedMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetCarriedMoney)
|
||||
.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("Signal", (void(Lua_Client::*)(uint32))&Lua_Client::Signal)
|
||||
.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, bool))&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() {
|
||||
|
||||
@ -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, bool faction);
|
||||
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
|
||||
|
||||
@ -67,6 +67,16 @@ bool Lua_Entity::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() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetID();
|
||||
@ -124,6 +134,8 @@ luabind::scope lua_register_entity() {
|
||||
.def("IsDoor", &Lua_Entity::IsDoor)
|
||||
.def("IsTrap", &Lua_Entity::IsTrap)
|
||||
.def("IsBeacon", &Lua_Entity::IsBeacon)
|
||||
.def("IsEncounter", &Lua_Entity::IsEncounter)
|
||||
.def("IsBot", &Lua_Entity::IsBot)
|
||||
.def("GetID", &Lua_Entity::GetID)
|
||||
.def("CastToClient", &Lua_Entity::CastToClient)
|
||||
.def("CastToNPC", &Lua_Entity::CastToNPC)
|
||||
|
||||
@ -44,6 +44,8 @@ public:
|
||||
bool IsDoor();
|
||||
bool IsTrap();
|
||||
bool IsBeacon();
|
||||
bool IsEncounter();
|
||||
bool IsBot();
|
||||
int GetID();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RemoveFromTargets(mob);
|
||||
@ -450,16 +456,17 @@ luabind::scope lua_register_entity_list() {
|
||||
.def("GetSpawnByID", (Lua_Spawn(Lua_EntityList::*)(uint32))&Lua_EntityList::GetSpawnByID)
|
||||
.def("ClearClientPetitionQueue", (void(Lua_EntityList::*)(void))&Lua_EntityList::ClearClientPetitionQueue)
|
||||
.def("CanAddHateForMob", (bool(Lua_EntityList::*)(Lua_Mob))&Lua_EntityList::CanAddHateForMob)
|
||||
.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("MessageClose", (void(Lua_EntityList::*)(Lua_Mob,bool,float,uint32,const char*))&Lua_EntityList::MessageClose)
|
||||
.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("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,bool))&Lua_EntityList::RemoveFromTargets)
|
||||
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob,Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
|
||||
.def("RemoveFromTargets", (void(Lua_EntityList::*)(Lua_Mob, bool))&Lua_EntityList::RemoveFromTargets)
|
||||
.def("ReplaceWithTarget", (void(Lua_EntityList::*)(Lua_Mob, Lua_Mob))&Lua_EntityList::ReplaceWithTarget)
|
||||
.def("OpenDoorsNear", (void(Lua_EntityList::*)(Lua_NPC))&Lua_EntityList::OpenDoorsNear)
|
||||
.def("MakeNameUnique", (std::string(Lua_EntityList::*)(const char*))&Lua_EntityList::MakeNameUnique)
|
||||
.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("DeletePlayerCorpses", (int(Lua_EntityList::*)(void))&Lua_EntityList::DeletePlayerCorpses)
|
||||
.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("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,bool))&Lua_EntityList::RemoveFromHateLists)
|
||||
.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_Client))&Lua_EntityList::GetRandomClient)
|
||||
.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("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("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList)
|
||||
.def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList)
|
||||
.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("GetSpawnList", (Lua_Spawn_List(Lua_EntityList::*)(void))&Lua_EntityList::GetSpawnList)
|
||||
.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() {
|
||||
|
||||
@ -80,6 +80,7 @@ public:
|
||||
void Message(uint32 guild_dbid, 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 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, bool RemoveFromXTargets);
|
||||
void ReplaceWithTarget(Lua_Mob target, Lua_Mob new_target);
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
#include <list>
|
||||
#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_item.h"
|
||||
#include "lua_iteminst.h"
|
||||
@ -16,8 +20,6 @@
|
||||
#include "quest_parser_collection.h"
|
||||
#include "questmgr.h"
|
||||
#include "qglobals.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "encounter.h"
|
||||
#include "lua_encounter.h"
|
||||
|
||||
@ -27,6 +29,12 @@ struct Slots { };
|
||||
struct Materials { };
|
||||
struct ClientVersions { };
|
||||
struct Appearances { };
|
||||
struct Classes { };
|
||||
struct Skills { };
|
||||
struct BodyTypes { };
|
||||
struct Filters { };
|
||||
struct MessageTypes { };
|
||||
struct Rule { };
|
||||
|
||||
struct lua_registered_event {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
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() {
|
||||
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_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_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("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),
|
||||
@ -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() {
|
||||
return luabind::class_<Events>("Event")
|
||||
.enum_("constants")
|
||||
@ -1738,7 +1796,8 @@ luabind::scope lua_register_events() {
|
||||
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
|
||||
luabind::value("tick", static_cast<int>(EVENT_TICK)),
|
||||
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
|
||||
|
||||
@ -3,12 +3,22 @@
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
luabind::scope lua_register_general();
|
||||
luabind::scope lua_register_random();
|
||||
luabind::scope lua_register_events();
|
||||
luabind::scope lua_register_faction();
|
||||
luabind::scope lua_register_slot();
|
||||
luabind::scope lua_register_material();
|
||||
luabind::scope lua_register_client_version();
|
||||
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
|
||||
|
||||
115
zone/lua_mob.cpp
115
zone/lua_mob.cpp
@ -10,6 +10,7 @@
|
||||
#include "lua_mob.h"
|
||||
#include "lua_hate_list.h"
|
||||
#include "lua_client.h"
|
||||
#include "lua_stat_bonuses.h"
|
||||
|
||||
struct SpecialAbilities { };
|
||||
|
||||
@ -1725,6 +1726,18 @@ int Lua_Mob::GetSkillDmgTaken(int 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) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAllowBeneficial(value);
|
||||
@ -1985,6 +1998,89 @@ int32 Lua_Mob::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() {
|
||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||
.def(luabind::constructor<>())
|
||||
@ -2281,6 +2377,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("ModSkillDmgTaken", (void(Lua_Mob::*)(int,int))&Lua_Mob::ModSkillDmgTaken)
|
||||
.def("GetModSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetModSkillDmgTaken)
|
||||
.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("GetAllowBeneficial", (bool(Lua_Mob::*)(void))&Lua_Mob::GetAllowBeneficial)
|
||||
.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("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced)
|
||||
.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() {
|
||||
|
||||
@ -8,6 +8,7 @@ class Mob;
|
||||
struct Lua_HateList;
|
||||
class Lua_Item;
|
||||
class Lua_ItemInst;
|
||||
class Lua_StatBonuses;
|
||||
|
||||
namespace luabind {
|
||||
struct scope;
|
||||
@ -330,6 +331,8 @@ public:
|
||||
void ModSkillDmgTaken(int skill, int value);
|
||||
int GetModSkillDmgTaken(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);
|
||||
bool GetAllowBeneficial();
|
||||
bool IsBeneficialAllowed(Lua_Mob target);
|
||||
@ -340,7 +343,6 @@ public:
|
||||
void SetFlurryChance(int value);
|
||||
int GetFlurryChance();
|
||||
int GetSkill(int skill_id);
|
||||
void CalcBonuses();
|
||||
int GetSpecialAbility(int ability);
|
||||
int GetSpecialAbilityParam(int ability, int param);
|
||||
void SetSpecialAbility(int ability, int level);
|
||||
@ -381,6 +383,21 @@ public:
|
||||
bool IsSilenced();
|
||||
bool IsAmnesiad();
|
||||
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
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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() {
|
||||
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
||||
.def(luabind::constructor<>())
|
||||
@ -598,7 +609,9 @@ luabind::scope lua_register_npc() {
|
||||
.def("MerchantOpenShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantOpenShop)
|
||||
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
||||
.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
|
||||
|
||||
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