mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-05 13:32:26 +00:00
Merge branch 'master' into loot
This commit is contained in:
commit
54fae508c5
@ -1,5 +1,12 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 10/01/2014 ==
|
||||||
|
Kayen: Exported to PERL $client->SendColoredText(color, msg)
|
||||||
|
demonstar55: Exported SendColoredText to lua
|
||||||
|
|
||||||
|
== 09/30/2014 ==
|
||||||
|
Uleat: Implemented click-casting from bag slots for clients that natively support it (RoF)
|
||||||
|
|
||||||
== 09/28/2014 ==
|
== 09/28/2014 ==
|
||||||
demonstar55: Add support for post June 18, 2014 Hundred Hands Effect spells (they changed the formula and stuff)
|
demonstar55: Add support for post June 18, 2014 Hundred Hands Effect spells (they changed the formula and stuff)
|
||||||
set Spells:Jun182014HundredHandsRevamp to true if you're using a spell file from June 18, 2014+
|
set Spells:Jun182014HundredHandsRevamp to true if you're using a spell file from June 18, 2014+
|
||||||
|
|||||||
@ -17,7 +17,8 @@ static const uint32 BIT_RoFAndLater = 0xFFFFFFE0;
|
|||||||
static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0;
|
static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0;
|
||||||
static const uint32 BIT_AllClients = 0xFFFFFFFF;
|
static const uint32 BIT_AllClients = 0xFFFFFFFF;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
EQClientUnknown = 0,
|
EQClientUnknown = 0,
|
||||||
EQClient62, // Build: 'Aug 4 2005 15:40:59'
|
EQClient62, // Build: 'Aug 4 2005 15:40:59'
|
||||||
EQClientTitanium, // Build: 'Oct 31 2005 10:33:37'
|
EQClientTitanium, // Build: 'Oct 31 2005 10:33:37'
|
||||||
@ -26,17 +27,50 @@ typedef enum {
|
|||||||
EQClientUnderfoot, // Build: 'Jun 8 2010 16:44:32'
|
EQClientUnderfoot, // Build: 'Jun 8 2010 16:44:32'
|
||||||
EQClientRoF, // Build: 'Dec 10 2012 17:35:44'
|
EQClientRoF, // Build: 'Dec 10 2012 17:35:44'
|
||||||
EQClientRoF2, // Build: 'May 10 2013 23:30:08'
|
EQClientRoF2, // Build: 'May 10 2013 23:30:08'
|
||||||
|
|
||||||
_EQClientCount, // place new clients before this point (preferably, in release/attribute order)
|
_EQClientCount, // place new clients before this point (preferably, in release/attribute order)
|
||||||
|
|
||||||
// Values below are not implemented, as yet...
|
// Values below are not implemented, as yet...
|
||||||
|
|
||||||
EmuNPC = _EQClientCount,
|
EmuNPC = _EQClientCount,
|
||||||
EmuMerc,
|
EmuMerc,
|
||||||
EmuBot,
|
EmuBot,
|
||||||
EmuPet,
|
EmuPet,
|
||||||
|
|
||||||
_EmuClientCount // array size for EQLimits
|
_EmuClientCount // array size for EQLimits
|
||||||
} EQClientVersion;
|
} EQClientVersion;
|
||||||
|
|
||||||
|
static const char* EQClientVersionName(EQClientVersion version)
|
||||||
|
{
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case EQClientUnknown:
|
||||||
|
return "EQClientUnknown";
|
||||||
|
case EQClient62:
|
||||||
|
return "EQClient62";
|
||||||
|
case EQClientTitanium:
|
||||||
|
return "EQClientTitanium";
|
||||||
|
case EQClientSoF:
|
||||||
|
return "EQClientSoF";
|
||||||
|
case EQClientSoD:
|
||||||
|
return "EQClientSoD";
|
||||||
|
case EQClientUnderfoot:
|
||||||
|
return "EQClientUnderfoot";
|
||||||
|
case EQClientRoF:
|
||||||
|
return "EQClientRoF";
|
||||||
|
case EQClientRoF2:
|
||||||
|
return "EQClientRoF2";
|
||||||
|
case EmuNPC:
|
||||||
|
return "EmuNPC";
|
||||||
|
case EmuMerc:
|
||||||
|
return "EmuMerc";
|
||||||
|
case EmuBot:
|
||||||
|
return "EmuBot";
|
||||||
|
case EmuPet:
|
||||||
|
return "EmuPet";
|
||||||
|
default:
|
||||||
|
return "ERROR: Invalid EQClientVersion";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CLIENTVERSIONS_H */
|
#endif /* CLIENTVERSIONS_H */
|
||||||
|
|||||||
@ -254,6 +254,7 @@ N(OP_ItemLinkText),
|
|||||||
N(OP_ItemName),
|
N(OP_ItemName),
|
||||||
N(OP_ItemPacket),
|
N(OP_ItemPacket),
|
||||||
N(OP_ItemPreview),
|
N(OP_ItemPreview),
|
||||||
|
N(OP_ItemRecastDelay),
|
||||||
N(OP_ItemVerifyReply),
|
N(OP_ItemVerifyReply),
|
||||||
N(OP_ItemVerifyRequest),
|
N(OP_ItemVerifyRequest),
|
||||||
N(OP_ItemViewUnknown),
|
N(OP_ItemViewUnknown),
|
||||||
|
|||||||
@ -1024,6 +1024,26 @@ bool EQLimits::AllowsEmptyBagInBag(uint32 version) {
|
|||||||
//return local[ValidateMobVersion(version)];
|
//return local[ValidateMobVersion(version)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EQLimits::AllowsClickCastFromBag(uint32 version) {
|
||||||
|
static const bool local[_EmuClientCount] = {
|
||||||
|
/*Unknown*/ false,
|
||||||
|
/*62*/ Client62::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*Titanium*/ Titanium::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*SoF*/ SoF::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*SoD*/ SoD::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*Underfoot*/ Underfoot::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*RoF*/ RoF::limits::ALLOWS_CLICK_CAST_FROM_BAG,
|
||||||
|
/*RoF2*/ false,
|
||||||
|
|
||||||
|
/*NPC*/ false,
|
||||||
|
/*Merc*/ false,
|
||||||
|
/*Bot*/ false,
|
||||||
|
/*Pet*/ false
|
||||||
|
};
|
||||||
|
|
||||||
|
return local[ValidateMobVersion(version)];
|
||||||
|
}
|
||||||
|
|
||||||
// items
|
// items
|
||||||
uint16 EQLimits::ItemCommonSize(uint32 version) {
|
uint16 EQLimits::ItemCommonSize(uint32 version) {
|
||||||
static const uint16 local[_EmuClientCount] = {
|
static const uint16 local[_EmuClientCount] = {
|
||||||
|
|||||||
@ -184,6 +184,7 @@ public:
|
|||||||
static uint64 CursorBitmask(uint32 version);
|
static uint64 CursorBitmask(uint32 version);
|
||||||
|
|
||||||
static bool AllowsEmptyBagInBag(uint32 version);
|
static bool AllowsEmptyBagInBag(uint32 version);
|
||||||
|
static bool AllowsClickCastFromBag(uint32 version);
|
||||||
|
|
||||||
// items
|
// items
|
||||||
static uint16 ItemCommonSize(uint32 version);
|
static uint16 ItemCommonSize(uint32 version);
|
||||||
|
|||||||
@ -4264,6 +4264,13 @@ struct ItemVerifyReply_Struct {
|
|||||||
/*012*/
|
/*012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ItemRecastDelay_Struct {
|
||||||
|
/*000*/ uint32 recast_delay; // in seconds
|
||||||
|
/*004*/ uint32 recast_type;
|
||||||
|
/*008*/ uint32 unknown008;
|
||||||
|
/*012*/
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shroud yourself. For yourself shrouding, this has your spawnId, spawnStruct,
|
* Shroud yourself. For yourself shrouding, this has your spawnId, spawnStruct,
|
||||||
* bits of your charProfileStruct (no checksum, then charProfile up till
|
* bits of your charProfileStruct (no checksum, then charProfile up till
|
||||||
|
|||||||
@ -911,6 +911,30 @@ bool Inventory::CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_S
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Inventory::SupportsClickCasting(int16 slot_id)
|
||||||
|
{
|
||||||
|
// there are a few non-potion items that identify as ItemTypePotion..so, we still need to ubiquitously include the equipment range
|
||||||
|
if ((uint16)slot_id <= EmuConstants::GENERAL_END || slot_id == MainPowerSource)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END)
|
||||||
|
{
|
||||||
|
if (EQLimits::AllowsClickCastFromBag(m_version))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Inventory::SupportsPotionBeltCasting(int16 slot_id)
|
||||||
|
{
|
||||||
|
if ((uint16)slot_id <= EmuConstants::GENERAL_END || slot_id == MainPowerSource || (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Test whether a given slot can support a container item
|
// Test whether a given slot can support a container item
|
||||||
bool Inventory::SupportsContainers(int16 slot_id)
|
bool Inventory::SupportsContainers(int16 slot_id)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -121,8 +121,22 @@ public:
|
|||||||
// Public Methods
|
// Public Methods
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
Inventory() { m_version = EQClientUnknown; m_versionset = false; }
|
||||||
~Inventory();
|
~Inventory();
|
||||||
|
|
||||||
|
// Inventory v2 creep
|
||||||
|
bool SetInventoryVersion(EQClientVersion version) {
|
||||||
|
if (!m_versionset) {
|
||||||
|
m_version = version;
|
||||||
|
return (m_versionset = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EQClientVersion GetInventoryVersion() { return m_version; }
|
||||||
|
|
||||||
static void CleanDirty();
|
static void CleanDirty();
|
||||||
static void MarkDirty(ItemInst *inst);
|
static void MarkDirty(ItemInst *inst);
|
||||||
|
|
||||||
@ -132,7 +146,7 @@ public:
|
|||||||
|
|
||||||
inline iter_queue cursor_begin() { return m_cursor.begin(); }
|
inline iter_queue cursor_begin() { return m_cursor.begin(); }
|
||||||
inline iter_queue cursor_end() { return m_cursor.end(); }
|
inline iter_queue cursor_end() { return m_cursor.end(); }
|
||||||
inline bool CursorEmpty() { return (m_cursor.size() == 0); }
|
inline bool CursorEmpty() { return (m_cursor.size() == 0); }
|
||||||
|
|
||||||
// Retrieve a read-only item from inventory
|
// Retrieve a read-only item from inventory
|
||||||
inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
|
inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
|
||||||
@ -183,6 +197,10 @@ public:
|
|||||||
|
|
||||||
static bool CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container);
|
static bool CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container);
|
||||||
|
|
||||||
|
// Test for valid inventory casting slot
|
||||||
|
bool SupportsClickCasting(int16 slot_id);
|
||||||
|
bool SupportsPotionBeltCasting(int16 slot_id);
|
||||||
|
|
||||||
// Test whether a given slot can support a container item
|
// Test whether a given slot can support a container item
|
||||||
static bool SupportsContainers(int16 slot_id);
|
static bool SupportsContainers(int16 slot_id);
|
||||||
|
|
||||||
@ -229,7 +247,12 @@ protected:
|
|||||||
std::map<int16, ItemInst*> m_bank; // Items in character bank
|
std::map<int16, ItemInst*> m_bank; // Items in character bank
|
||||||
std::map<int16, ItemInst*> m_shbank; // Items in character shared bank
|
std::map<int16, ItemInst*> m_shbank; // Items in character shared bank
|
||||||
std::map<int16, ItemInst*> m_trade; // Items in a trade session
|
std::map<int16, ItemInst*> m_trade; // Items in a trade session
|
||||||
ItemInstQueue m_cursor; // Items on cursor: FIFO
|
ItemInstQueue m_cursor; // Items on cursor: FIFO
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Active inventory version
|
||||||
|
EQClientVersion m_version;
|
||||||
|
bool m_versionset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedDatabase;
|
class SharedDatabase;
|
||||||
|
|||||||
@ -306,6 +306,7 @@ OUTz(OP_FinishWindow2);
|
|||||||
//OUTv(OP_AdventureMerchantResponse, strlen(msg)+2);
|
//OUTv(OP_AdventureMerchantResponse, strlen(msg)+2);
|
||||||
OUTv(OP_ItemPacket, ItemPacket_Struct);
|
OUTv(OP_ItemPacket, ItemPacket_Struct);
|
||||||
OUTv(OP_ColoredText, ColoredText_Struct);
|
OUTv(OP_ColoredText, ColoredText_Struct);
|
||||||
|
OUTv(OP_ItemRecastDelay, ItemRecastDelay_Struct);
|
||||||
OUTv(OP_FormattedMessage, FormattedMessage_Struct);
|
OUTv(OP_FormattedMessage, FormattedMessage_Struct);
|
||||||
OUTv(OP_GuildMemberList, uint32); //variable length, but nasty
|
OUTv(OP_GuildMemberList, uint32); //variable length, but nasty
|
||||||
OUTv(OP_InterruptCast, InterruptCast_Struct);
|
OUTv(OP_InterruptCast, InterruptCast_Struct);
|
||||||
|
|||||||
@ -180,6 +180,7 @@ namespace Client62 {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = false;
|
||||||
static const bool COIN_HAS_WEIGHT = true;
|
static const bool COIN_HAS_WEIGHT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -184,6 +184,7 @@ namespace RoF {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = true;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = true;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = true;
|
||||||
static const bool COIN_HAS_WEIGHT = false;
|
static const bool COIN_HAS_WEIGHT = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,6 +181,7 @@ namespace SoD {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = false;
|
||||||
static const bool COIN_HAS_WEIGHT = false;
|
static const bool COIN_HAS_WEIGHT = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,6 +181,7 @@ namespace SoF {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = false;
|
||||||
static const bool COIN_HAS_WEIGHT = true;
|
static const bool COIN_HAS_WEIGHT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -180,6 +180,7 @@ namespace Titanium {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = false;
|
||||||
static const bool COIN_HAS_WEIGHT = true;
|
static const bool COIN_HAS_WEIGHT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,6 +181,7 @@ namespace Underfoot {
|
|||||||
|
|
||||||
namespace limits {
|
namespace limits {
|
||||||
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
static const bool ALLOWS_EMPTY_BAG_IN_BAG = false;
|
||||||
|
static const bool ALLOWS_CLICK_CAST_FROM_BAG = false;
|
||||||
static const bool COIN_HAS_WEIGHT = false;
|
static const bool COIN_HAS_WEIGHT = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -523,9 +523,9 @@ void Database::ExpireMail() {
|
|||||||
time(nullptr) - RuleI(Mail, ExpireTrash));
|
time(nullptr) - RuleI(Mail, ExpireTrash));
|
||||||
results = QueryDatabase(query);
|
results = QueryDatabase(query);
|
||||||
if(results.Success())
|
if(results.Success())
|
||||||
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
|
|
||||||
else
|
|
||||||
_log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected());
|
_log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected());
|
||||||
|
else
|
||||||
|
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -653,3 +653,5 @@ OP_RAWOutOfSession=0x0000
|
|||||||
# we need to document the differences between these packets to make identifying them easier
|
# we need to document the differences between these packets to make identifying them easier
|
||||||
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||||
OP_InitialHPUpdate=0x0000
|
OP_InitialHPUpdate=0x0000
|
||||||
|
|
||||||
|
OP_ItemRecastDelay=0x57ed
|
||||||
|
|||||||
@ -660,3 +660,5 @@ OP_RAWOutOfSession=0x0000 #
|
|||||||
# we need to document the differences between these packets to make identifying them easier
|
# we need to document the differences between these packets to make identifying them easier
|
||||||
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||||
OP_InitialHPUpdate=0x0000 #
|
OP_InitialHPUpdate=0x0000 #
|
||||||
|
|
||||||
|
OP_ItemRecastDelay=0x15c4
|
||||||
|
|||||||
@ -654,3 +654,5 @@ OP_RAWOutOfSession=0x0000 #
|
|||||||
# we need to document the differences between these packets to make identifying them easier
|
# we need to document the differences between these packets to make identifying them easier
|
||||||
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
|
||||||
OP_InitialHPUpdate=0x0000 #
|
OP_InitialHPUpdate=0x0000 #
|
||||||
|
|
||||||
|
OP_ItemRecastDelay=0x82d7
|
||||||
|
|||||||
2079
zone/bot.cpp
2079
zone/bot.cpp
File diff suppressed because it is too large
Load Diff
@ -1307,7 +1307,13 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
conn_state = ReceivedZoneEntry;
|
conn_state = ReceivedZoneEntry;
|
||||||
|
|
||||||
ClientVersion = Connection()->ClientVersion();
|
ClientVersion = Connection()->ClientVersion();
|
||||||
ClientVersionBit = 1 << (ClientVersion - 1);
|
if (ClientVersion != EQClientUnknown)
|
||||||
|
ClientVersionBit = 1 << (ClientVersion - 1);
|
||||||
|
else
|
||||||
|
ClientVersionBit = 0;
|
||||||
|
|
||||||
|
bool siv = m_inv.SetInventoryVersion(ClientVersion);
|
||||||
|
LogFile->write(EQEMuLog::Debug, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), EQClientVersionName(ClientVersion), ClientVersion);
|
||||||
|
|
||||||
/* Antighost code
|
/* Antighost code
|
||||||
tmp var is so the search doesnt find this object
|
tmp var is so the search doesnt find this object
|
||||||
@ -3999,15 +4005,16 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
else if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // ITEM or POTION cast
|
else if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // ITEM or POTION cast
|
||||||
{
|
{
|
||||||
//discipline, using the item spell slot
|
//discipline, using the item spell slot
|
||||||
if (castspell->inventoryslot == 0xFFFFFFFF) {
|
if (castspell->inventoryslot == INVALID_INDEX) {
|
||||||
if (!UseDiscipline(castspell->spell_id, castspell->target_id)) {
|
if (!UseDiscipline(castspell->spell_id, castspell->target_id)) {
|
||||||
LogFile->write(EQEMuLog::Debug, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id);
|
LogFile->write(EQEMuLog::Debug, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id);
|
||||||
InterruptSpell(castspell->spell_id);
|
InterruptSpell(castspell->spell_id);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ((castspell->inventoryslot <= EmuConstants::GENERAL_END) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // sanity check
|
else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // sanity check
|
||||||
{
|
{
|
||||||
|
// packet field types will be reviewed as packet transistions occur -U
|
||||||
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
||||||
//bool cancast = true;
|
//bool cancast = true;
|
||||||
if (inst && inst->IsType(ItemClassCommon))
|
if (inst && inst->IsType(ItemClassCommon))
|
||||||
@ -8555,7 +8562,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
LogFile->write(EQEMuLog::Debug, "OP ItemVerifyRequest: spell=%i, target=%i, inv=%i", spell_id, target_id, slot_id);
|
LogFile->write(EQEMuLog::Debug, "OP ItemVerifyRequest: spell=%i, target=%i, inv=%i", spell_id, target_id, slot_id);
|
||||||
|
|
||||||
if ((slot_id < MainCursor) || (slot_id == MainPowerSource) || (slot_id > 250 && slot_id < 331 && ((item->ItemType == ItemTypePotion) || item->PotionBelt))) // sanity check
|
if (m_inv.SupportsClickCasting(slot_id) || ((item->ItemType == ItemTypePotion || item->PotionBelt) && m_inv.SupportsPotionBeltCasting(slot_id))) // sanity check
|
||||||
{
|
{
|
||||||
ItemInst* p_inst = (ItemInst*)inst;
|
ItemInst* p_inst = (ItemInst*)inst;
|
||||||
|
|
||||||
@ -10686,7 +10693,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
|||||||
Client *i = entity_list.GetClientByName(ri->player_name);
|
Client *i = entity_list.GetClientByName(ri->player_name);
|
||||||
if (i){
|
if (i){
|
||||||
if (IsRaidGrouped()){
|
if (IsRaidGrouped()){
|
||||||
i->Message_StringID(0, 5060); //group failed, must invite members not in raid...
|
i->Message_StringID(0, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Raid *r = entity_list.GetRaidByClient(i);
|
Raid *r = entity_list.GetRaidByClient(i);
|
||||||
|
|||||||
@ -1239,6 +1239,11 @@ void Lua_Client::SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in
|
|||||||
self->SendMarqueeMessage(type, priority, fade_in, fade_out, duration, msg);
|
self->SendMarqueeMessage(type, priority, fade_in, fade_out, duration, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Client::SendColoredText(uint32 type, std::string msg) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->SendColoredText(type, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void Lua_Client::PlayMP3(std::string file)
|
void Lua_Client::PlayMP3(std::string file)
|
||||||
{
|
{
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
@ -1492,6 +1497,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("SetThirst", (void(Lua_Client::*)(int))&Lua_Client::SetThirst)
|
.def("SetThirst", (void(Lua_Client::*)(int))&Lua_Client::SetThirst)
|
||||||
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
|
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
|
||||||
.def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage)
|
.def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage)
|
||||||
|
.def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText)
|
||||||
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3);
|
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -275,6 +275,7 @@ public:
|
|||||||
void SetThirst(int in_thirst);
|
void SetThirst(int in_thirst);
|
||||||
void SetConsumption(int in_hunger, int in_thirst);
|
void SetConsumption(int in_hunger, int in_thirst);
|
||||||
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
|
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
|
||||||
|
void SendColoredText(uint32 type, std::string msg);
|
||||||
void PlayMP3(std::string file);
|
void PlayMP3(std::string file);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
554
zone/npc.cpp
554
zone/npc.cpp
@ -965,240 +965,352 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn, uint32 extra) {
|
uint32 ZoneDatabase::CreateNewNPCCommand(const char* zone, uint32 zone_version,Client *client, NPC* spawn, uint32 extra) {
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
||||||
char *query = 0;
|
uint32 npc_type_id = 0;
|
||||||
MYSQL_RES *result;
|
|
||||||
MYSQL_ROW row;
|
if (extra && client && client->GetZoneID())
|
||||||
uint32 tmp = 0;
|
{
|
||||||
uint32 tmp2 = 0;
|
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
|
||||||
|
int starting_npc_id = client->GetZoneID() * 1000;
|
||||||
|
|
||||||
|
std::string query = StringFormat("SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i",
|
||||||
|
starting_npc_id, starting_npc_id + 1000);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (results.Success()) {
|
||||||
|
if (results.RowCount() != 0)
|
||||||
|
{
|
||||||
|
auto row = results.begin();
|
||||||
|
npc_type_id = atoi(row[0]) + 1;
|
||||||
|
// Prevent the npc_type id from exceeding the range for this zone
|
||||||
|
if (npc_type_id >= (starting_npc_id + 1000))
|
||||||
|
npc_type_id = 0;
|
||||||
|
}
|
||||||
|
else // No npc_type IDs set in this range yet
|
||||||
|
npc_type_id = starting_npc_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char tmpstr[64];
|
||||||
|
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
||||||
|
std::string query;
|
||||||
|
if (npc_type_id)
|
||||||
|
{
|
||||||
|
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
|
||||||
|
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||||
|
"runspeed, prim_melee_type, sec_melee_type) "
|
||||||
|
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||||
|
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||||
|
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||||
|
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||||
|
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
npc_type_id = results.LastInsertedID();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
|
||||||
|
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||||
|
"runspeed, prim_melee_type, sec_melee_type) "
|
||||||
|
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||||
|
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||||
|
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||||
|
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||||
|
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
npc_type_id = results.LastInsertedID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("INSERT INTO spawngroup (id, name) VALUES(%i, '%s-%s')", 0, zone, spawn->GetName());
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32 spawngroupid = results.LastInsertedID();
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||||
|
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||||
|
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200,
|
||||||
|
spawn->GetHeading(), spawngroupid);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
|
||||||
|
spawngroupid, npc_type_id, 100);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime) {
|
||||||
|
uint32 last_insert_id = 0;
|
||||||
|
|
||||||
|
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')",
|
||||||
|
zone, spawn->GetName(), Timer::GetCurrentTime());
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
last_insert_id = results.LastInsertedID();
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
uint32 respawntime = 0;
|
||||||
|
uint32 spawnid = 0;
|
||||||
|
if (respawnTime)
|
||||||
|
respawntime = respawnTime;
|
||||||
|
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
|
||||||
|
respawntime = spawn->respawn2->RespawnTimer();
|
||||||
|
else
|
||||||
|
respawntime = 1200;
|
||||||
|
|
||||||
|
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||||
|
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||||
|
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
|
||||||
|
spawn->GetHeading(), last_insert_id);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
spawnid = results.LastInsertedID();
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
|
||||||
|
last_insert_id, spawn->GetNPCTypeID(), 100);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return spawnid;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC* spawn) {
|
||||||
|
|
||||||
|
std::string query = StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
|
||||||
|
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
|
||||||
|
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
|
||||||
|
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||||
|
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||||
|
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||||
|
spawn->MerchantType, spawn->GetNPCTypeID());
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success() && client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return results.Success() == true? 1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn) {
|
||||||
|
uint32 id = 0;
|
||||||
|
uint32 spawngroupID = 0;
|
||||||
|
|
||||||
|
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE "
|
||||||
|
"zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2());
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (results.RowCount() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (row[0])
|
||||||
|
id = atoi(row[0]);
|
||||||
|
|
||||||
|
if (row[1])
|
||||||
|
spawngroupID = atoi(row[1]);
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn) {
|
||||||
|
|
||||||
|
uint32 id = 0;
|
||||||
|
uint32 spawngroupID = 0;
|
||||||
|
|
||||||
|
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' "
|
||||||
|
"AND version = %u AND spawngroupID = %i",
|
||||||
|
zone, zone_version, spawn->GetSp2());
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (results.RowCount() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
|
||||||
|
if (row[0])
|
||||||
|
id = atoi(row[0]);
|
||||||
|
|
||||||
|
if (row[1])
|
||||||
|
spawngroupID = atoi(row[1]);
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
|
||||||
|
|
||||||
uint32 last_insert_id = 0;
|
uint32 last_insert_id = 0;
|
||||||
|
std::string query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||||
|
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||||
|
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(),
|
||||||
|
120, client->GetHeading(), spawnGroupID);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
|
||||||
|
|
||||||
|
uint32 npc_type_id;
|
||||||
|
char numberlessName[64];
|
||||||
|
|
||||||
|
EntityList::RemoveNumbers(strn0cpy(numberlessName, spawn->GetName(), sizeof(numberlessName)));
|
||||||
|
std::string query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
|
||||||
|
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||||
|
"runspeed, prim_melee_type, sec_melee_type) "
|
||||||
|
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||||
|
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||||
|
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||||
|
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||||
|
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success())
|
||||||
|
return 0;
|
||||||
|
npc_type_id = results.LastInsertedID();
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->LogSQL(query.c_str());
|
||||||
|
|
||||||
|
if(client)
|
||||||
|
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn, uint32 extra) {
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 0: { // Create a new NPC and add all spawn related data
|
case 0: { // Create a new NPC and add all spawn related data
|
||||||
uint32 npc_type_id = 0;
|
return CreateNewNPCCommand(zone, zone_version, c, spawn, extra);
|
||||||
uint32 spawngroupid;
|
|
||||||
if (extra && c && c->GetZoneID())
|
|
||||||
{
|
|
||||||
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
|
|
||||||
int starting_npc_id = c->GetZoneID() * 1000;
|
|
||||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i", starting_npc_id, (starting_npc_id + 1000)), errbuf, &result)) {
|
|
||||||
row = mysql_fetch_row(result);
|
|
||||||
if(row)
|
|
||||||
{
|
|
||||||
if (row[0])
|
|
||||||
{
|
|
||||||
npc_type_id = atoi(row[0]) + 1;
|
|
||||||
// Prevent the npc_type id from exceeding the range for this zone
|
|
||||||
if (npc_type_id >= (starting_npc_id + 1000))
|
|
||||||
{
|
|
||||||
npc_type_id = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// row[0] is nullptr - No npc_type IDs set in this range yet
|
|
||||||
npc_type_id = starting_npc_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_delete_array(query);
|
|
||||||
mysql_free_result(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char tmpstr[64];
|
|
||||||
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
|
||||||
if (npc_type_id)
|
|
||||||
{
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (id, name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(%i,\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
snprintf(tmpstr, sizeof(tmpstr), "%s-%s", zone, spawn->GetName());
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawngroup (id, name) values(%i, '%s')", tmp, tmpstr), errbuf, 0, 0, &spawngroupid)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200, spawn->GetHeading(), spawngroupid), errbuf, 0, 0, &tmp)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawnentry (spawngroupID, npcID, chance) values(%i, %i, %i)", spawngroupid, npc_type_id, 100), errbuf, 0)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 1:{ // Add new spawn group and spawn point for an existing NPC Type ID
|
case 1:{ // Add new spawn group and spawn point for an existing NPC Type ID
|
||||||
tmp2 = spawn->GetNPCTypeID();
|
return AddNewNPCSpawnGroupCommand(zone, zone_version, c, spawn, extra);
|
||||||
char tmpstr[64];
|
|
||||||
snprintf(tmpstr, sizeof(tmpstr), "%s%s%i", zone, spawn->GetName(),Timer::GetCurrentTime());
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawngroup (name) values('%s')", tmpstr), errbuf, 0, 0, &last_insert_id)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
|
|
||||||
uint32 respawntime = 0;
|
|
||||||
uint32 spawnid = 0;
|
|
||||||
if (extra)
|
|
||||||
respawntime = extra;
|
|
||||||
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
|
|
||||||
respawntime = spawn->respawn2->RespawnTimer();
|
|
||||||
else
|
|
||||||
respawntime = 1200;
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime, spawn->GetHeading(), last_insert_id), errbuf, 0, 0, &spawnid)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawnentry (spawngroupID, npcID, chance) values(%i, %i, %i)", last_insert_id, tmp2, 100), errbuf, 0)) {
|
|
||||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
return spawnid;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 2: { // Update npc_type appearance and other data on targeted spawn
|
case 2: { // Update npc_type appearance and other data on targeted spawn
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE npc_types SET name=\"%s\", level=%i, race=%i, class=%i, hp=%i, gender=%i, texture=%i, helmtexture=%i, size=%i, loottable_id=%i, merchant_id=%i, face=%i, WHERE id=%i", spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, spawn->GetNPCTypeID()), errbuf, 0)) {
|
return UpdateNPCTypeAppearance(c, spawn);
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
safe_delete_array(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 3: { // delete spawn from spawning, but leave in npc_types table
|
case 3: { // delete spawn from spawning, but leave in npc_types table
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id,spawngroupID from spawn2 where zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2()), errbuf, &result)) {
|
return DeleteSpawnLeaveInNPCTypeTable(zone, c, spawn);
|
||||||
safe_delete_array(query);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
safe_delete_array(query);
|
|
||||||
|
|
||||||
row = mysql_fetch_row(result);
|
|
||||||
if (row == nullptr) return false;
|
|
||||||
if (row[0]) tmp = atoi(row[0]);
|
|
||||||
if (row[1]) tmp2 = atoi(row[1]);
|
|
||||||
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawn2 WHERE id='%i'", tmp), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawngroup WHERE id='%i'", tmp2), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawnentry WHERE spawngroupID='%i'", tmp2), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 4: { //delete spawn from DB (including npc_type)
|
case 4: { //delete spawn from DB (including npc_type)
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id,spawngroupID from spawn2 where zone='%s' AND version=%u AND spawngroupID=%i", zone, zone_version, spawn->GetSp2()), errbuf, &result)) {
|
return DeleteSpawnRemoveFromNPCTypeTable(zone, zone_version, c, spawn);
|
||||||
safe_delete_array(query);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
safe_delete_array(query);
|
|
||||||
|
|
||||||
row = mysql_fetch_row(result);
|
|
||||||
if (row == nullptr) return false;
|
|
||||||
if (row[0]) tmp = atoi(row[0]);
|
|
||||||
if (row[1]) tmp2 = atoi(row[1]);
|
|
||||||
mysql_free_result(result);
|
|
||||||
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawn2 WHERE id='%i'", tmp), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawngroup WHERE id='%i'", tmp2), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawnentry WHERE spawngroupID='%i'", tmp2), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM npc_types WHERE id='%i'", spawn->GetNPCTypeID()), errbuf,0)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 5: { // add a spawn from spawngroup
|
case 5: { // add a spawn from spawngroup
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, c->GetX(), c->GetY(), c->GetZ(), 120, c->GetHeading(), extra), errbuf, 0, 0, &tmp)) {
|
return AddSpawnFromSpawnGroup(zone, zone_version, c, spawn, extra);
|
||||||
safe_delete(query);
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6: { // add npc_type
|
case 6: { // add npc_type
|
||||||
uint32 npc_type_id;
|
return AddNPCTypes(zone, zone_version, c, spawn, extra);
|
||||||
char tmpstr[64];
|
|
||||||
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
|
||||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
|
||||||
safe_delete(query);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(c) c->LogSQL(query);
|
|
||||||
safe_delete_array(query);
|
|
||||||
if(c) c->Message(0, "%s npc_type ID %i created successfully!", tmpstr, npc_type_id);
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1743,7 +1855,7 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
else
|
else
|
||||||
ns->spawn.IsMercenary = 0;
|
ns->spawn.IsMercenary = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Not recommended if using above (However, this will work better on older clients).
|
//Not recommended if using above (However, this will work better on older clients).
|
||||||
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
||||||
if(GetOwnerID() || GetSwarmOwner()) {
|
if(GetOwnerID() || GetSwarmOwner()) {
|
||||||
|
|||||||
@ -6020,6 +6020,32 @@ XS(XS_Client_SendMarqueeMessage)
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS_Client_SendColoredText); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_Client_SendColoredText)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 3)
|
||||||
|
Perl_croak(aTHX_ "Usage: Client::SendColoredText(color, message)");
|
||||||
|
{
|
||||||
|
Client * THIS;
|
||||||
|
uint32 color = (uint32)SvUV(ST(1));
|
||||||
|
std::string msg = (std::string)SvPV_nolen(ST(2));
|
||||||
|
dXSTARG;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "Client")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(Client *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||||
|
if(THIS == NULL)
|
||||||
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->SendColoredText(color, msg);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
#endif
|
#endif
|
||||||
@ -6259,6 +6285,7 @@ XS(boot_Client)
|
|||||||
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
|
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
|
||||||
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
|
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
|
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
|
||||||
|
newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$");
|
||||||
XSRETURN_YES;
|
XSRETURN_YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
|
||||||
int Mob::GetKickDamage() {
|
int Mob::GetKickDamage() {
|
||||||
@ -346,15 +347,23 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
|||||||
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
||||||
|
|
||||||
//Live AA - Technique of Master Wu
|
//Live AA - Technique of Master Wu
|
||||||
uint16 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||||
if (bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > MakeRandomInt(0, 99))) {
|
if (wuchance) {
|
||||||
|
if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) {
|
||||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||||
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
int extra = 1;
|
||||||
|
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
if (wuchance / 4 > MakeRandomInt(0, 99))
|
||||||
if ((bDoubleSpecialAttack / 4) > MakeRandomInt(0, 99))
|
extra++;
|
||||||
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
// They didn't add a string ID for this.
|
||||||
|
std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra);
|
||||||
|
// live uses 400 here -- not sure if it's the best for all clients though
|
||||||
|
SendColoredText(400, msg);
|
||||||
|
while (extra) {
|
||||||
|
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
||||||
|
extra--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ReuseTime < 100) {
|
if(ReuseTime < 100) {
|
||||||
@ -1743,18 +1752,21 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
//Live AA - Technique of Master Wu
|
//Live AA - Technique of Master Wu
|
||||||
uint16 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||||
if( bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > MakeRandomInt(0,100))) {
|
if (wuchance) {
|
||||||
|
if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) {
|
||||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
|
int extra = 1;
|
||||||
|
if (wuchance / 4 > MakeRandomInt(0, 99))
|
||||||
int TripleChance = 25;
|
extra++;
|
||||||
if (bDoubleSpecialAttack > 100)
|
// They didn't add a string ID for this.
|
||||||
TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100;
|
std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra);
|
||||||
|
// live uses 400 here -- not sure if it's the best for all clients though
|
||||||
if(TripleChance > MakeRandomInt(0,100)) {
|
SendColoredText(400, msg);
|
||||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
|
while (extra) {
|
||||||
|
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0, 4)]);
|
||||||
|
extra--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3205,55 +3205,55 @@ snare has both of them negative, yet their range should work the same:
|
|||||||
case 124: // check sign
|
case 124: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += caster_level - 50;
|
result += updownsign * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 125: // check sign
|
case 125: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 2 * (caster_level - 50);
|
result += updownsign * 2 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 126: // check sign
|
case 126: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 3 * (caster_level - 50);
|
result += updownsign * 3 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 127: // check sign
|
case 127: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 4 * (caster_level - 50);
|
result += updownsign * 4 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 128: // check sign
|
case 128: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 5 * (caster_level - 50);
|
result += updownsign * 5 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 129: // check sign
|
case 129: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 10 * (caster_level - 50);
|
result += updownsign * 10 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 130: // check sign
|
case 130: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 15 * (caster_level - 50);
|
result += updownsign * 15 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 131: // check sign
|
case 131: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 20 * (caster_level - 50);
|
result += updownsign * 20 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 132: // check sign
|
case 132: // check sign
|
||||||
result = ubase;
|
result = ubase;
|
||||||
if (caster_level > 50)
|
if (caster_level > 50)
|
||||||
result += 25 * (caster_level - 50);
|
result += updownsign * 25 * (caster_level - 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 137: // used in berserker AA desperation
|
case 137: // used in berserker AA desperation
|
||||||
|
|||||||
@ -484,6 +484,19 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This needs a bit more work for saving timer to PP for zoning etc
|
||||||
|
if (IsClient() && item_slot != INVALID_INDEX && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT))) {
|
||||||
|
ItemInst *itm = CastToClient()->GetInv().GetItem(item_slot);
|
||||||
|
if (itm && itm->GetItem()->RecastDelay) {
|
||||||
|
outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
|
||||||
|
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
|
||||||
|
ird->recast_delay = itm->GetItem()->RecastDelay;
|
||||||
|
ird->recast_type = itm->GetItem()->RecastType;
|
||||||
|
CastToClient()->QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -275,6 +275,7 @@
|
|||||||
#define TOLD_NOT_ONLINE 5046 //%1 is not online at this time.
|
#define TOLD_NOT_ONLINE 5046 //%1 is not online at this time.
|
||||||
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
||||||
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
||||||
|
#define ALREADY_IN_RAID 5060 //%1 is already in a raid.
|
||||||
#define GAIN_RAIDEXP 5085 //You gained raid experience!
|
#define GAIN_RAIDEXP 5085 //You gained raid experience!
|
||||||
#define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there.
|
#define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there.
|
||||||
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
||||||
|
|||||||
@ -1615,36 +1615,36 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendBazaarWelcome(){
|
void Client::SendBazaarWelcome()
|
||||||
|
{
|
||||||
const std::string query = "SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader";
|
const std::string query = "SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader";
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
if (results.Success() && results.RowCount() == 1){
|
if (results.Success() && results.RowCount() == 1){
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||||
|
|
||||||
memset(outapp->pBuffer,0,outapp->size);
|
memset(outapp->pBuffer,0,outapp->size);
|
||||||
|
|
||||||
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
|
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
bws->Beginning.Action = BazaarWelcome;
|
bws->Beginning.Action = BazaarWelcome;
|
||||||
|
|
||||||
bws->Traders = atoi(row[0]);
|
bws->Traders = atoi(row[0]);
|
||||||
bws->Items = atoi(row[1]);
|
bws->Items = atoi(row[1]);
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
|
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string buyerCountQuery = "SELECT COUNT(DISTINCT charid) FROM buyer";
|
const std::string buyerCountQuery = "SELECT COUNT(DISTINCT charid) FROM buyer";
|
||||||
results = database.QueryDatabase(query);
|
results = database.QueryDatabase(buyerCountQuery);
|
||||||
if (!results.Success() || results.RowCount() != 1)
|
if (!results.Success() || results.RowCount() != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them, "
|
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them, "
|
||||||
"or use /buyer to set up your own Buy Lines.", atoi(row[0]));
|
"or use /buyer to set up your own Buy Lines.", atoi(row[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -376,6 +376,13 @@ public:
|
|||||||
/* NPCs */
|
/* NPCs */
|
||||||
const NPCType* GetNPCType(uint32 id);
|
const NPCType* GetNPCType(uint32 id);
|
||||||
uint32 NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn = 0, uint32 extra = 0); // 0 = Create 1 = Add; 2 = Update; 3 = Remove; 4 = Delete
|
uint32 NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn = 0, uint32 extra = 0); // 0 = Create 1 = Add; 2 = Update; 3 = Remove; 4 = Delete
|
||||||
|
uint32 CreateNewNPCCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 extra);
|
||||||
|
uint32 AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime);
|
||||||
|
uint32 DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn);
|
||||||
|
uint32 DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn);
|
||||||
|
uint32 AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID);
|
||||||
|
uint32 AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID);
|
||||||
|
uint32 UpdateNPCTypeAppearance(Client *client, NPC* spawn);
|
||||||
bool SetSpecialAttkFlag(uint8 id, const char* flag);
|
bool SetSpecialAttkFlag(uint8 id, const char* flag);
|
||||||
bool GetPetEntry(const char *pet_type, PetRecord *into);
|
bool GetPetEntry(const char *pet_type, PetRecord *into);
|
||||||
bool GetPoweredPetEntry(const char *pet_type, int16 petpower, PetRecord *into);
|
bool GetPoweredPetEntry(const char *pet_type, int16 petpower, PetRecord *into);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user