mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 16:41:29 +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,5 +1,51 @@
|
||||
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).
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -139,9 +139,9 @@ void EQ::Net::DaybreakConnectionManager::Process()
|
||||
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
||||
if ((size_t)time_since_last_send.count() > m_options.connect_delay_ms) {
|
||||
connection->SendConnect();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StatusConnected: {
|
||||
if (m_options.keepalive_delay_ms != 0) {
|
||||
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - connection->m_last_send);
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -407,10 +402,16 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
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;
|
||||
@ -425,7 +426,10 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
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;
|
||||
@ -1187,24 +1191,21 @@ 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);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
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,8 +81,13 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ack_req) {
|
||||
m_connection->QueuePacket(out);
|
||||
}
|
||||
else {
|
||||
m_connection->QueuePacket(out, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req) {
|
||||
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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`;
|
||||
$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,8 +114,23 @@ 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
|
||||
@ -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)) {
|
||||
|
||||
113
zone/attack.cpp
113
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
|
||||
// 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
|
||||
|
||||
// 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 (IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && GetOwner()->GetAA(aaAdvancedPetDiscipline) >= 1 && IsFocused()) {
|
||||
if (!targetmob)
|
||||
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))
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3188,6 +3210,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
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;
|
||||
}
|
||||
|
||||
26
zone/bot.cpp
26
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,8 +3854,8 @@ 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) {
|
||||
@ -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; }
|
||||
|
||||
282
zone/client.cpp
282
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 (last_reported_mana != current_mana || last_reported_endurance != current_endurance) {
|
||||
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
SendManaUpdate();
|
||||
SendEnduranceUpdate();
|
||||
}
|
||||
|
||||
if (last_reported_mana != cur_mana || last_reported_endur != cur_end) {
|
||||
|
||||
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));
|
||||
|
||||
MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp->pBuffer;
|
||||
MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp2->pBuffer;
|
||||
|
||||
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);
|
||||
if (raid) {
|
||||
raid->SendManaPacketFrom(this);
|
||||
}
|
||||
else if (group) {
|
||||
group->SendManaPacketFrom(this);
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete(outapp2);
|
||||
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);
|
||||
|
||||
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());
|
||||
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_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
else if (mob->GetAggroRange() > scan_range) {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
else if (npc->GetAggroRange() > scan_range) {
|
||||
close_npcs.insert(std::pair<NPC *, float>(npc, 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
|
||||
|
||||
117
zone/effects.cpp
117
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;
|
||||
@ -828,24 +784,19 @@ 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)
|
||||
{
|
||||
Mob *curmob = nullptr;
|
||||
|
||||
@ -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);
|
||||
|
||||
100
zone/entity.cpp
100
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,13 +1246,10 @@ 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()) {
|
||||
if (!ent->InZone() || !ent->ShouldISpawnFor(client)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
app = new EQApplicationPacket;
|
||||
it->second->CastToMob()->CreateSpawnPacket(app); // TODO: Use zonespawns opcode instead
|
||||
@ -1275,8 +1276,7 @@ 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
|
||||
@ -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,11 +2328,10 @@ 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))
|
||||
npc_limit_list.erase(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()) {
|
||||
|
||||
mob = it->second;
|
||||
|
||||
if (
|
||||
mob && !mob->IsCorpse()
|
||||
&& (it->second != client)
|
||||
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
|
||||
&& (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);
|
||||
|
||||
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)
|
||||
&& (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate))
|
||||
&& (!it->second->IsClient() || !it->second->CastToClient()->GMHideMe(client))) {
|
||||
|
||||
//bool Grouped = client->HasGroup() && mob->IsClient() && (client->GetGroup() == mob->CastToClient()->GetGroup());
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
62
zone/exp.cpp
62
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,7 +485,6 @@ 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
|
||||
@ -572,7 +596,6 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
if (loop <= 100)
|
||||
{
|
||||
m_FearWalkTarget = glm::vec3(ranx, rany, ranz);
|
||||
else //Break fear
|
||||
BuffFadeByEffect(SE_Fear);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
if(member && member->IsClient())
|
||||
void Group::SendHPManaEndPacketsTo(Mob *member)
|
||||
{
|
||||
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);
|
||||
@ -453,6 +459,7 @@ luabind::scope lua_register_entity_list() {
|
||||
.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)
|
||||
|
||||
@ -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
|
||||
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