mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-26 02:41:28 +00:00
Merge remote-tracking branch 'remotes/origin/master' into web_interface
Conflicts: common/shareddb.cpp
This commit is contained in:
commit
fa5dedec11
@ -1,5 +1,55 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 01/03/2015 ==
|
||||
Trevius: (RoF2) /shield (shielding) and /key (key ring) are both now functional after opcode updates.
|
||||
|
||||
== 01/02/2015 ==
|
||||
Trevius: (RoF2) *Hopefully* Fixed looting incorrect items from NPCs. Please report any issues!
|
||||
Trevius: (RoF2) Now able to loot items past the 10th slot on NPC corpses.
|
||||
Trevius: Attuned Items can now be auto-looted and will equip properly.
|
||||
Trevius: Mercenaries and Bots will no longer take a share from /split or /autosplit.
|
||||
|
||||
== 12/30/2014 ==
|
||||
Trevius: (RoF2) Aug Type 21 no longer shows the "Buy Now" button in the aug slot of items.
|
||||
Trevius: (RoF2) Identified the "Copied" item flag with the help of Uleat.
|
||||
|
||||
== 12/29/2014 ==
|
||||
Trevius: (RoF2) Identified a few Item Fields and resolved an issue with cloth armor not accepting certain augments that they should.
|
||||
Akkadius: Updated $client->UpdateTaskActivity to have optional argument ignore_quest_update IE: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update])
|
||||
Akkadius: Also updated internal UpdateTaskActivity methods to optionally ignore quest based task updates to prevent feedback
|
||||
|
||||
== 12/28/2014 ==
|
||||
Uleat: Implemented class Client::TextLink as a replacement for the dozens of individual link formatters.
|
||||
|
||||
== 12/27/2014 ==
|
||||
Akkadius: Add option to automatic database upgrade script 5) Download latest Opcodes from Github
|
||||
Trevius: (RoF2) Fixed dropping items on the ground so they go to ground level instead of camera height.
|
||||
Trevius: Show Helm Option should be functional again.
|
||||
Kayen: Implemened npc special ability (43) CASTING_RESIST_DIFF which sets innate resist modifier on
|
||||
ALL spells used by that NPC. Ie. 43,1,-200 will set a -200 innate resist diff, so if your npc cast
|
||||
a spell that has a -10 resist modifier the final resist diff would be -210.
|
||||
|
||||
== 12/25/2014 ==
|
||||
Uleat: Updated 'links' code for all clients
|
||||
|
||||
== 12/24/2014 ==
|
||||
Trevius: (RoF+) Added herosforgemodel field to the npc_types table.
|
||||
Trevius: (RoF2) Updated item links from #npcstat command output.
|
||||
Trevius: (RoF+) Implemented Hero's Forge Armor for NPCs. Set the herosforgemodel field in npc_types table to the model (example: 84 for full set, or 12107 for robe).
|
||||
Trevius: (RoF+) Hero's Forge Armor now overrides NPC texture settings. To display Hero's Forge Armor Helms, set helmtexture field to anything other than 0.
|
||||
|
||||
== 12/23/2014 ==
|
||||
Uleat: Tidied up some ItemInst* declarations and added some nullptr checks.
|
||||
Trevius: (RoF+) Added support for Hero's Forge Robe Models. Set herosforgemodel field in items table to exact model such as 11607, 11707, etc.
|
||||
|
||||
== 12/22/2014 ==
|
||||
Trevius: (RoF2) Fixed Tracking.
|
||||
Trevius: (RoF+) Added a work-around for the cursor buffer issue.
|
||||
|
||||
== 12/21/2014 ==
|
||||
Trevius: (RoF2) Fixed Extended Targets Window by correcting opcodes.
|
||||
Trevius: (RoF/RoF2) Fixed Guild Rank in the Player Profile, which prevents the guild rank message on login/zone.
|
||||
|
||||
== 12/20/2014 ==
|
||||
Akkadius: Updated #cvs to display RoF2 Client Stream count
|
||||
|
||||
|
||||
@ -1509,7 +1509,8 @@ enum ItemPacketType
|
||||
ItemPacketTributeItem = 0x6C,
|
||||
ItemPacketMerchant = 0x64,
|
||||
ItemPacketWorldContainer = 0x6B,
|
||||
ItemPacketCharmUpdate = 0x6E
|
||||
ItemPacketCharmUpdate = 0x6E,
|
||||
ItemPacketInvalid = 0xFF
|
||||
};
|
||||
struct ItemPacket_Struct
|
||||
{
|
||||
@ -3015,14 +3016,14 @@ struct ClientError_Struct
|
||||
};
|
||||
|
||||
struct Track_Struct {
|
||||
uint16 entityid;
|
||||
uint16 padding002;
|
||||
uint32 entityid;
|
||||
float distance;
|
||||
// Fields for SoD and later
|
||||
uint8 level;
|
||||
uint8 NPC;
|
||||
uint8 GroupMember;
|
||||
uint8 is_npc;
|
||||
char name[64];
|
||||
uint8 is_pet;
|
||||
uint8 is_merc;
|
||||
};
|
||||
|
||||
struct Tracking_Struct {
|
||||
|
||||
@ -89,6 +89,17 @@ ItemInst* ItemInstQueue::pop()
|
||||
return inst;
|
||||
}
|
||||
|
||||
// Remove item from back of queue
|
||||
ItemInst* ItemInstQueue::pop_back()
|
||||
{
|
||||
if (m_list.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
ItemInst* inst = m_list.back();
|
||||
m_list.pop_back();
|
||||
return inst;
|
||||
}
|
||||
|
||||
// Look at item at front of queue
|
||||
ItemInst* ItemInstQueue::peek_front() const
|
||||
{
|
||||
@ -259,6 +270,11 @@ int16 Inventory::PushCursor(const ItemInst& inst)
|
||||
return MainCursor;
|
||||
}
|
||||
|
||||
ItemInst* Inventory::GetCursorItem()
|
||||
{
|
||||
return m_cursor.peek_front();
|
||||
}
|
||||
|
||||
// Swap items in inventory
|
||||
bool Inventory::SwapItem(int16 slot_a, int16 slot_b)
|
||||
{
|
||||
@ -1170,13 +1186,13 @@ int16 Inventory::_HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, ui
|
||||
|
||||
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
|
||||
ItemInst* baginst = itb->second;
|
||||
if (baginst->GetID() == item_id) {
|
||||
if (baginst && baginst->GetID() == item_id) {
|
||||
quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges();
|
||||
if (quantity_found >= quantity)
|
||||
return Inventory::CalcSlotId(it->first, itb->first);
|
||||
}
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
|
||||
if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT; // Only one augment per slot.
|
||||
}
|
||||
}
|
||||
@ -1214,13 +1230,13 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
||||
|
||||
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
|
||||
ItemInst* baginst = itb->second;
|
||||
if (baginst->GetID() == item_id) {
|
||||
if (baginst && baginst->GetID() == item_id) {
|
||||
quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges();
|
||||
if (quantity_found >= quantity)
|
||||
return Inventory::CalcSlotId(MainCursor, itb->first);
|
||||
}
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
|
||||
if (baginst && baginst->GetAugmentItemID(i) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT; // Only one augment per slot.
|
||||
}
|
||||
|
||||
@ -1314,7 +1330,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
||||
if (inst->GetItem()->LoreGroup == loregroup)
|
||||
return it->first;
|
||||
|
||||
ItemInst* Aug;
|
||||
ItemInst* Aug = nullptr;
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
Aug = inst->GetAugment(i);
|
||||
if (Aug && Aug->GetItem()->LoreGroup == loregroup)
|
||||
@ -1329,7 +1345,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
||||
if (baginst && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup)
|
||||
return Inventory::CalcSlotId(it->first, itb->first);
|
||||
|
||||
ItemInst* Aug2;
|
||||
ItemInst* Aug2 = nullptr;
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
Aug2 = baginst->GetAugment(i);
|
||||
if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
|
||||
@ -1357,7 +1373,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||
if (inst->GetItem()->LoreGroup == loregroup)
|
||||
return MainCursor;
|
||||
|
||||
ItemInst* Aug;
|
||||
ItemInst* Aug = nullptr;
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
Aug = inst->GetAugment(i);
|
||||
if (Aug && Aug->GetItem()->LoreGroup == loregroup)
|
||||
@ -1373,7 +1389,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||
return Inventory::CalcSlotId(MainCursor, itb->first);
|
||||
|
||||
|
||||
ItemInst* Aug2;
|
||||
ItemInst* Aug2 = nullptr;
|
||||
for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
Aug2 = baginst->GetAugment(i);
|
||||
if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
|
||||
@ -1703,6 +1719,8 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
|
||||
end = m_contents.end();
|
||||
for (; cur != end;) {
|
||||
ItemInst* inst = cur->second;
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
const Item_Struct* item = inst->GetItem();
|
||||
del = cur;
|
||||
++cur;
|
||||
|
||||
@ -93,6 +93,7 @@ public:
|
||||
void push(ItemInst* inst);
|
||||
void push_front(ItemInst* inst);
|
||||
ItemInst* pop();
|
||||
ItemInst* pop_back();
|
||||
ItemInst* peek_front() const;
|
||||
inline int size() { return static_cast<int>(m_list.size()); }
|
||||
|
||||
@ -152,6 +153,9 @@ public:
|
||||
// Add item to cursor queue
|
||||
int16 PushCursor(const ItemInst& inst);
|
||||
|
||||
// Get cursor item in front of queue
|
||||
ItemInst* GetCursorItem();
|
||||
|
||||
// Swap items in inventory
|
||||
bool SwapItem(int16 slot_a, int16 slot_b);
|
||||
|
||||
|
||||
@ -2315,7 +2315,7 @@ namespace RoF
|
||||
outapp->WriteUInt8(emu->gm);
|
||||
|
||||
outapp->WriteUInt32(emu->guild_id);
|
||||
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet.
|
||||
outapp->WriteUInt8(emu->guildrank); // guildrank
|
||||
outapp->WriteUInt32(0); // Unknown - observed 1 in a live packet.
|
||||
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet.
|
||||
outapp->WriteUInt32(0); // Unknown
|
||||
@ -2576,7 +2576,7 @@ namespace RoF
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
@ -2643,7 +2643,7 @@ namespace RoF
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
@ -2900,7 +2900,7 @@ namespace RoF
|
||||
{
|
||||
eq->entries[i] = emu->entries[i];
|
||||
}
|
||||
eq->entries[21] = 0;
|
||||
eq->entries[21] = 1;
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -3294,9 +3294,9 @@ namespace RoF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
@ -4854,27 +4854,8 @@ namespace RoF
|
||||
ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem));
|
||||
}
|
||||
//ORNAMENT IDFILE / ICON
|
||||
uint16 ornaIcon = 0;
|
||||
int32 heroModel = 0;
|
||||
/*
|
||||
if (inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
//Mainhand
|
||||
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
|
||||
ss.write((const char*)&null_term, sizeof(uint8));
|
||||
//Offhand
|
||||
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
|
||||
ss.write((const char*)&null_term, sizeof(uint8));
|
||||
//Icon
|
||||
ornaIcon = aug_weap->Icon;
|
||||
if (aug_weap->HerosForgeModel > 0)
|
||||
{
|
||||
heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in);
|
||||
}
|
||||
}
|
||||
else
|
||||
*/
|
||||
uint32 ornaIcon = 0;
|
||||
uint32 heroModel = 0;
|
||||
|
||||
if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon())
|
||||
{
|
||||
@ -4896,8 +4877,6 @@ namespace RoF
|
||||
|
||||
RoF::structs::ItemSerializationHeaderFinish hdrf;
|
||||
hdrf.ornamentIcon = ornaIcon;
|
||||
hdrf.unknown061 = 0;
|
||||
hdrf.unknown062 = 0;
|
||||
hdrf.unknowna1 = 0xffffffff;
|
||||
hdrf.ornamentHeroModel = heroModel;
|
||||
hdrf.unknown063 = 0;
|
||||
@ -5506,7 +5485,6 @@ namespace RoF
|
||||
|
||||
static inline uint32 ServerToRoFCorpseSlot(uint32 ServerCorpse)
|
||||
{
|
||||
//uint32 RoFCorpse;
|
||||
return (ServerCorpse + 1);
|
||||
}
|
||||
|
||||
@ -5647,7 +5625,6 @@ namespace RoF
|
||||
|
||||
static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return (RoFCorpse - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,15 +21,15 @@ namespace RoF2
|
||||
static OpcodeManager *opcodes = nullptr;
|
||||
static Strategy struct_strategy;
|
||||
|
||||
char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth);
|
||||
char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type);
|
||||
|
||||
// server to client inventory location converters
|
||||
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot);
|
||||
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType = ItemPacketInvalid);
|
||||
static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 ServerSlot);
|
||||
static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse);
|
||||
|
||||
// client to server inventory location converters
|
||||
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot);
|
||||
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType = ItemPacketInvalid);
|
||||
static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot);
|
||||
static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse);
|
||||
|
||||
@ -116,6 +116,72 @@ namespace RoF2
|
||||
#include "ss_define.h"
|
||||
|
||||
// ENCODE methods
|
||||
|
||||
|
||||
// RoF2 Specific Encodes Begin
|
||||
ENCODE(OP_SendMembershipDetails)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Membership_Details_Struct);
|
||||
SETUP_DIRECT_ENCODE(Membership_Details_Struct, structs::Membership_Details_Struct);
|
||||
|
||||
eq->membership_setting_count = 72;
|
||||
for (uint32 i = 0; i < emu->membership_setting_count; ++i) // 66
|
||||
{
|
||||
OUT(settings[i].setting_index);
|
||||
OUT(settings[i].setting_id);
|
||||
OUT(settings[i].setting_value);
|
||||
}
|
||||
// Last 6 new settings fields are all 0s on Live as of 12/29/14
|
||||
|
||||
eq->race_entry_count = emu->race_entry_count;
|
||||
for (uint32 i = 0; i < emu->race_entry_count; ++i) // 15
|
||||
{
|
||||
OUT(membership_races[i].purchase_id);
|
||||
OUT(membership_races[i].bitwise_entry);
|
||||
}
|
||||
|
||||
eq->class_entry_count = emu->class_entry_count;
|
||||
for (uint32 i = 0; i < emu->class_entry_count; ++i) // 15
|
||||
{
|
||||
OUT(membership_classes[i].purchase_id);
|
||||
OUT(membership_classes[i].bitwise_entry);
|
||||
}
|
||||
|
||||
eq->exit_url_length = emu->exit_url_length;
|
||||
eq->exit_url_length2 = emu->exit_url_length2;
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SendMembership)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Membership_Struct);
|
||||
SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct);
|
||||
|
||||
eq->membership = emu->membership;
|
||||
eq->races = emu->races;
|
||||
eq->classes = emu->classes;
|
||||
eq->entrysize = 25; //emu->entrysize;
|
||||
|
||||
for (uint32 i = 0; i < emu->entrysize; ++i) // 21
|
||||
{
|
||||
OUT(entries[i]);
|
||||
}
|
||||
// Last 4 new entries are 0s on Live Silver as of 12/29/14
|
||||
// Setting them each to 1 for now.
|
||||
// This removes the "Buy Now" button from aug type 21 slots on items.
|
||||
for (uint32 i = 21; i < 25; ++i) // 4
|
||||
{
|
||||
eq->entries[i] = 1;
|
||||
}
|
||||
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
// RoF2 Specific Encodes End
|
||||
|
||||
|
||||
ENCODE(OP_Action)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Action_Struct);
|
||||
@ -556,7 +622,7 @@ namespace RoF2
|
||||
|
||||
uint32 Length = 0;
|
||||
|
||||
char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0);
|
||||
char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory);
|
||||
|
||||
if (Serialized) {
|
||||
|
||||
@ -1370,7 +1436,7 @@ namespace RoF2
|
||||
InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem);
|
||||
|
||||
uint32 length;
|
||||
char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0);
|
||||
char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType);
|
||||
|
||||
if (!serialized) {
|
||||
_log(NET__STRUCTS, "Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
@ -1676,8 +1742,15 @@ namespace RoF2
|
||||
eq->FogDensity = emu->fog_density;
|
||||
|
||||
/*fill in some unknowns with observed values, hopefully it will help */
|
||||
eq->unknown569 = 0;
|
||||
eq->unknown571 = 0;
|
||||
eq->unknown572 = 4;
|
||||
eq->unknown576 = 2;
|
||||
eq->unknown580 = 0;
|
||||
|
||||
eq->unknown800 = -1;
|
||||
eq->unknown844 = 600;
|
||||
eq->unknown848 = 2008; // Guild Lobby observed value
|
||||
eq->unknown880 = 50;
|
||||
eq->unknown884 = 10;
|
||||
eq->unknown888 = 1;
|
||||
@ -1987,17 +2060,17 @@ namespace RoF2
|
||||
outapp->WriteUInt32(emu->drakkin_tattoo);
|
||||
outapp->WriteUInt32(emu->drakkin_details);
|
||||
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown 0
|
||||
outapp->WriteUInt8(0xff); // Unknown 0xff
|
||||
outapp->WriteUInt8(1); // Unknown 1
|
||||
outapp->WriteUInt8(0xff); // Unknown 0xff
|
||||
outapp->WriteUInt8(1); // Unknown 1
|
||||
|
||||
outapp->WriteFloat(5.0f); // Height ?
|
||||
outapp->WriteFloat(5.0f); // Height
|
||||
|
||||
outapp->WriteFloat(3.0f); // Unknown
|
||||
outapp->WriteFloat(2.5f); // Unknown
|
||||
outapp->WriteFloat(5.5f); // Unknown
|
||||
outapp->WriteFloat(3.0f); // Unknown 3.0
|
||||
outapp->WriteFloat(2.5f); // Unknown 2.5
|
||||
outapp->WriteFloat(5.5f); // Unknown 5.5
|
||||
|
||||
outapp->WriteUInt32(0); // Primary ?
|
||||
outapp->WriteUInt32(0); // Secondary ?
|
||||
@ -2316,14 +2389,14 @@ namespace RoF2
|
||||
outapp->WriteUInt8(emu->gm);
|
||||
outapp->WriteUInt32(emu->guild_id);
|
||||
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt8(emu->guildrank); // guildrank
|
||||
outapp->WriteUInt32(0); // Unknown
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
outapp->WriteUInt32(0); // Unknown
|
||||
|
||||
outapp->WriteUInt64(emu->exp); // int32 in client
|
||||
|
||||
outapp->WriteUInt8(0); // Unknown - Seen 5 on Live
|
||||
outapp->WriteUInt8(5); // Unknown - Seen 5 on Live - Eye Height?
|
||||
|
||||
outapp->WriteUInt32(emu->platinum_bank);
|
||||
outapp->WriteUInt32(emu->gold_bank);
|
||||
@ -2587,7 +2660,7 @@ namespace RoF2
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
@ -2654,7 +2727,7 @@ namespace RoF2
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
@ -2898,24 +2971,6 @@ namespace RoF2
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SendMembership)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Membership_Struct);
|
||||
SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct);
|
||||
|
||||
eq->membership = emu->membership;
|
||||
eq->races = emu->races;
|
||||
eq->classes = emu->classes;
|
||||
eq->entrysize = 22;
|
||||
for (int i = 0; i<21; i++)
|
||||
{
|
||||
eq->entries[i] = emu->entries[i];
|
||||
}
|
||||
eq->entries[21] = 0;
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SendZonepoints)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ZonePoints);
|
||||
@ -3289,7 +3344,7 @@ namespace RoF2
|
||||
int PacketSize = 2;
|
||||
|
||||
for (int i = 0; i < EntryCount; ++i, ++emu)
|
||||
PacketSize += (12 + strlen(emu->name));
|
||||
PacketSize += (13 + strlen(emu->name));
|
||||
|
||||
emu = (Track_Struct *)__emu_buffer;
|
||||
|
||||
@ -3305,9 +3360,10 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_pet);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
@ -3734,7 +3790,7 @@ 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); // unknown8
|
||||
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
|
||||
@ -4811,7 +4867,7 @@ namespace RoF2
|
||||
return NextItemInstSerialNumber;
|
||||
}
|
||||
|
||||
char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth)
|
||||
char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth, ItemPacketType packet_type)
|
||||
{
|
||||
int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
uint8 null_term = 0;
|
||||
@ -4835,15 +4891,14 @@ namespace RoF2
|
||||
hdr.stacksize = stackable ? charges : 1;
|
||||
hdr.unknown004 = 0;
|
||||
|
||||
structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in);
|
||||
structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in, packet_type);
|
||||
|
||||
hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items?
|
||||
hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot;
|
||||
hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff;
|
||||
hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
|
||||
hdr.aug_slot = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
|
||||
hdr.price = inst->GetPrice();
|
||||
hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount();
|
||||
//hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff;
|
||||
hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0;
|
||||
hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot;
|
||||
hdr.unknown028 = 0;
|
||||
@ -4869,28 +4924,9 @@ namespace RoF2
|
||||
ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
|
||||
}
|
||||
//ORNAMENT IDFILE / ICON
|
||||
uint16 ornaIcon = 0;
|
||||
int32 heroModel = 0;
|
||||
/*
|
||||
if (inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
//Mainhand
|
||||
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
|
||||
ss.write((const char*)&null_term, sizeof(uint8));
|
||||
//Offhand
|
||||
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
|
||||
ss.write((const char*)&null_term, sizeof(uint8));
|
||||
//Icon
|
||||
ornaIcon = aug_weap->Icon;
|
||||
if (aug_weap->HerosForgeModel > 0)
|
||||
{
|
||||
heroModel = (aug_weap->HerosForgeModel * 100) + Inventory::CalcMaterialFromSlot(slot_id_in);
|
||||
}
|
||||
}
|
||||
else
|
||||
*/
|
||||
|
||||
uint32 ornaIcon = 0;
|
||||
uint32 heroModel = 0;
|
||||
|
||||
if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon())
|
||||
{
|
||||
char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile());
|
||||
@ -4911,12 +4947,10 @@ namespace RoF2
|
||||
|
||||
RoF2::structs::ItemSerializationHeaderFinish hdrf;
|
||||
hdrf.ornamentIcon = ornaIcon;
|
||||
hdrf.unknown061 = 0;
|
||||
hdrf.unknown062 = 0;
|
||||
hdrf.unknowna1 = 0xffffffff;
|
||||
hdrf.ornamentHeroModel = heroModel;
|
||||
hdrf.unknown063 = 0;
|
||||
hdrf.unknowna3 = 0;
|
||||
hdrf.Copied = 0;
|
||||
hdrf.unknowna4 = 0xffffffff;
|
||||
hdrf.unknowna5 = 0;
|
||||
hdrf.ItemClass = item->ItemClass;
|
||||
@ -5066,7 +5100,7 @@ namespace RoF2
|
||||
memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct));
|
||||
|
||||
isbs.augtype = item->AugType;
|
||||
isbs.augdistiller = 65535;
|
||||
isbs.augrestrict2 = -1;
|
||||
isbs.augrestrict = item->AugRestrict;
|
||||
|
||||
for (int x = AUG_BEGIN; x < consts::ITEM_COMMON_SIZE; x++)
|
||||
@ -5310,9 +5344,21 @@ namespace RoF2
|
||||
iqbs.HealAmt = item->HealAmt;
|
||||
iqbs.SpellDmg = item->SpellDmg;
|
||||
iqbs.clairvoyance = item->Clairvoyance;
|
||||
iqbs.unknown28 = 0;
|
||||
iqbs.unknown30 = 0;
|
||||
iqbs.unknown37a = 0;
|
||||
|
||||
//unknown18; //Power Source Capacity or evolve filename?
|
||||
//evolve_string; // Some String, but being evolution related is just a guess
|
||||
|
||||
iqbs.Heirloom = 0;
|
||||
iqbs.Placeable = 0;
|
||||
|
||||
iqbs.unknown28 = -1;
|
||||
iqbs.unknown30 = -1;
|
||||
|
||||
iqbs.NoZone = 0;
|
||||
iqbs.NoGround = 0;
|
||||
iqbs.unknown37a = 0; // (guessed position) New to RoF2
|
||||
iqbs.unknown38 = 0;
|
||||
|
||||
iqbs.unknown39 = 1;
|
||||
|
||||
iqbs.subitem_count = 0;
|
||||
@ -5350,7 +5396,7 @@ namespace RoF2
|
||||
SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x);
|
||||
*/
|
||||
|
||||
SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1);
|
||||
SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1, packet_type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5376,7 +5422,7 @@ namespace RoF2
|
||||
return item_serial;
|
||||
}
|
||||
|
||||
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot)
|
||||
static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot, ItemPacketType PacketType)
|
||||
{
|
||||
structs::ItemSlotStruct RoF2Slot;
|
||||
RoF2Slot.SlotType = INVALID_INDEX;
|
||||
@ -5389,13 +5435,21 @@ namespace RoF2
|
||||
uint32 TempSlot = 0;
|
||||
|
||||
if (ServerSlot < 56 || ServerSlot == MainPowerSource) { // Main Inventory and Cursor
|
||||
RoF2Slot.SlotType = maps::MapPossessions;
|
||||
RoF2Slot.MainSlot = ServerSlot;
|
||||
|
||||
if (PacketType == ItemPacketLoot)
|
||||
{
|
||||
RoF2Slot.SlotType = maps::MapCorpse;
|
||||
RoF2Slot.MainSlot = ServerSlot - EmuConstants::CORPSE_BEGIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
RoF2Slot.SlotType = maps::MapPossessions;
|
||||
RoF2Slot.MainSlot = ServerSlot;
|
||||
}
|
||||
|
||||
if (ServerSlot == MainPowerSource)
|
||||
RoF2Slot.MainSlot = slots::MainPowerSource;
|
||||
|
||||
else if (ServerSlot >= MainCursor) // Cursor and Extended Corpse Inventory
|
||||
else if (ServerSlot >= MainCursor && PacketType != ItemPacketLoot) // Cursor and Extended Corpse Inventory
|
||||
RoF2Slot.MainSlot += 3;
|
||||
|
||||
else if (ServerSlot >= MainAmmo) // (> 20)
|
||||
@ -5522,11 +5576,10 @@ namespace RoF2
|
||||
|
||||
static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse)
|
||||
{
|
||||
//uint32 RoF2Corpse;
|
||||
return (ServerCorpse + 1);
|
||||
return (ServerCorpse - EmuConstants::CORPSE_BEGIN + 1);
|
||||
}
|
||||
|
||||
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot)
|
||||
static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot, ItemPacketType PacketType)
|
||||
{
|
||||
uint32 ServerSlot = INVALID_INDEX;
|
||||
uint32 TempSlot = 0;
|
||||
@ -5621,6 +5674,10 @@ namespace RoF2
|
||||
ServerSlot = INVALID_INDEX;
|
||||
}
|
||||
|
||||
else if (RoF2Slot.SlotType == maps::MapCorpse) {
|
||||
ServerSlot = RoF2Slot.MainSlot + EmuConstants::CORPSE_BEGIN;
|
||||
}
|
||||
|
||||
_log(NET__ERROR, "Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
@ -5663,8 +5720,7 @@ namespace RoF2
|
||||
|
||||
static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return (RoF2Corpse - 1);
|
||||
return (RoF2Corpse + EmuConstants::CORPSE_BEGIN - 1);
|
||||
}
|
||||
}
|
||||
// end namespace RoF2
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
// out-going packets that require an ENCODE translation:
|
||||
// Begin RoF2 Encodes
|
||||
|
||||
E(OP_SendMembershipDetails)
|
||||
|
||||
// incoming packets that require a DECODE translation:
|
||||
// Begin RoF2 Decodes
|
||||
|
||||
|
||||
@ -243,11 +243,11 @@ struct Membership_Setting_Struct
|
||||
struct Membership_Details_Struct
|
||||
{
|
||||
/*0000*/ uint32 membership_setting_count; // Seen 66
|
||||
/*0016*/ Membership_Setting_Struct settings[66];
|
||||
/*0016*/ Membership_Setting_Struct settings[72]; // 864 Bytes
|
||||
/*0012*/ uint32 race_entry_count; // Seen 15
|
||||
/*1044*/ Membership_Entry_Struct membership_races[15];
|
||||
/*1044*/ Membership_Entry_Struct membership_races[15]; // 120 Bytes
|
||||
/*0012*/ uint32 class_entry_count; // Seen 15
|
||||
/*1044*/ Membership_Entry_Struct membership_classes[15];
|
||||
/*1044*/ Membership_Entry_Struct membership_classes[15]; // 120 Bytes
|
||||
/*1044*/ uint32 exit_url_length; // Length of the exit_url string (0 for none)
|
||||
/*1048*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL
|
||||
/*1048*/ uint32 exit_url_length2; // Length of the exit_url2 string (0 for none)
|
||||
@ -260,7 +260,7 @@ struct Membership_Struct
|
||||
/*004*/ uint32 races; // Seen ff ff 01 00
|
||||
/*008*/ uint32 classes; // Seen ff ff 01 01
|
||||
/*012*/ uint32 entrysize; // Seen 22
|
||||
/*016*/ int32 entries[22]; // Most -1, 1, and 0 for Gold Status
|
||||
/*016*/ int32 entries[25]; // Most -1, 1, and 0 for Gold Status
|
||||
/*104*/
|
||||
};
|
||||
|
||||
@ -537,9 +537,13 @@ struct NewZone_Struct {
|
||||
/*0525*/ uint8 rain_duration[4];
|
||||
/*0529*/ uint8 snow_chance[4];
|
||||
/*0533*/ uint8 snow_duration[4];
|
||||
/*0537*/ uint8 unknown537[33];
|
||||
/*0537*/ uint8 unknown537[32]; // Seen all 0xff
|
||||
/*0569*/ uint8 unknown569; // Unknown - Seen 0
|
||||
/*0570*/ uint8 sky; // Sky Type
|
||||
/*0571*/ uint8 unknown571[13]; // ***Placeholder
|
||||
/*0571*/ uint8 unknown571; // Unknown - Seen 0
|
||||
/*0572*/ uint32 unknown572; // Unknown - Seen 4 in Guild Lobby
|
||||
/*0576*/ uint32 unknown576; // Unknown - Seen 2 in Guild Lobby
|
||||
/*0580*/ uint32 unknown580; // Unknown - Seen 0 in Guild Lobby
|
||||
/*0584*/ float zone_exp_multiplier; // Experience Multiplier
|
||||
/*0588*/ float safe_y; // Zone Safe Y
|
||||
/*0592*/ float safe_x; // Zone Safe X
|
||||
@ -554,7 +558,7 @@ struct NewZone_Struct {
|
||||
/*0800*/ int32 unknown800; //seen -1
|
||||
/*0804*/ char unknown804[40]; //
|
||||
/*0844*/ int32 unknown844; //seen 600
|
||||
/*0848*/ int32 unknown848;
|
||||
/*0848*/ int32 unknown848; //seen 2008
|
||||
/*0852*/ uint16 zone_id;
|
||||
/*0854*/ uint16 zone_instance;
|
||||
/*0856*/ char unknown856[20];
|
||||
@ -581,7 +585,7 @@ struct NewZone_Struct {
|
||||
/*0932*/ int32 unknown932; // Seen -1
|
||||
/*0936*/ int32 unknown936; // Seen -1
|
||||
/*0940*/ uint32 unknown940; // Seen 0
|
||||
/*0944*/ float unknown944; // Seen 1.0
|
||||
/*0944*/ float unknown944; // Seen 1.0 in PoK, and 0.25 in Guild Lobby
|
||||
/*0948*/ uint32 unknown948; // Seen 0 - New on Live as of Dec 15 2014
|
||||
/*0952*/ uint32 unknown952; // Seen 100 - New on Live as of Dec 15 2014
|
||||
/*0956*/
|
||||
@ -1219,64 +1223,17 @@ union
|
||||
|
||||
/*
|
||||
///////////////////// - Haven't identified the below fields in the PP yet
|
||||
uint8 pvp; // 1=pvp, 0=not pvp
|
||||
uint8 anon; // 2=roleplay, 1=anon, 0=not anon
|
||||
uint8 gm; // 0=no, 1=yes (guessing!)
|
||||
uint32 guild_id; // guildid
|
||||
uint8 guildrank; // 0=member, 1=officer, 2=guildleader -1=no guild
|
||||
uint32 guildbanker;
|
||||
uint32 available_slots;
|
||||
uint32 endurance; // Current endurance
|
||||
uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 bytes Each * 16 = 64 bytes
|
||||
uint32 abilitySlotRefresh;
|
||||
///////////////////////
|
||||
|
||||
uint32 platinum_bank; // Platinum Pieces in Bank
|
||||
uint32 gold_bank; // Gold Pieces in Bank
|
||||
uint32 silver_bank; // Silver Pieces in Bank
|
||||
uint32 copper_bank; // Copper Pieces in Bank
|
||||
uint32 platinum_shared; // Shared platinum pieces
|
||||
|
||||
uint32 autosplit; // 0 = off, 1 = on
|
||||
|
||||
char groupMembers[MAX_GROUP_MEMBERS][64];// 384 all the members in group, including self
|
||||
char groupLeader[64]; // Leader of the group ?
|
||||
uint32 entityid;
|
||||
|
||||
uint32 leadAAActive; // 0 = leader AA off, 1 = leader AA on
|
||||
int32 ldon_points_guk; // Earned GUK points
|
||||
int32 ldon_points_mir; // Earned MIR points
|
||||
int32 ldon_points_mmc; // Earned MMC points
|
||||
int32 ldon_points_ruj; // Earned RUJ points
|
||||
int32 ldon_points_tak; // Earned TAK points
|
||||
int32 ldon_points_available;// Available LDON points
|
||||
float tribute_time_remaining;// Time remaining on tribute (millisecs)
|
||||
uint32 career_tribute_points;// Total favor points for this char
|
||||
uint32 tribute_points; // Current tribute points
|
||||
uint32 tribute_active; // 0 = off, 1=on
|
||||
Tribute_Struct tributes[MAX_PLAYER_TRIBUTES]; // [40] Current tribute loadout
|
||||
double group_leadership_exp; // Current group lead exp points
|
||||
double raid_leadership_exp; // Current raid lead AA exp points
|
||||
uint32 group_leadership_points; // Unspent group lead AA points
|
||||
uint32 raid_leadership_points; // Unspent raid lead AA points
|
||||
LeadershipAA_Struct leader_abilities; // [128]Leader AA ranks 19332
|
||||
|
||||
uint32 PVPKills;
|
||||
uint32 PVPDeaths;
|
||||
uint32 PVPCurrentPoints;
|
||||
uint32 PVPCareerPoints;
|
||||
uint32 PVPBestKillStreak;
|
||||
uint32 PVPWorstDeathStreak;
|
||||
uint32 PVPCurrentKillStreak;
|
||||
PVPStatsEntry_Struct PVPLastKill; // size 88
|
||||
PVPStatsEntry_Struct PVPLastDeath; // size 88
|
||||
uint32 PVPNumberOfKillsInLast24Hours;
|
||||
PVPStatsEntry_Struct PVPRecentKills[50]; // size 4400 - 88 each
|
||||
uint32 expAA; // Exp earned in current AA point
|
||||
uint32 currentRadCrystals; // Current count of radiant crystals
|
||||
uint32 careerRadCrystals; // Total count of radiant crystals ever
|
||||
uint32 currentEbonCrystals; // Current count of ebon crystals
|
||||
uint32 careerEbonCrystals; // Total count of ebon crystals ever
|
||||
*/
|
||||
|
||||
};
|
||||
@ -1886,8 +1843,8 @@ struct LootingItem_Struct {
|
||||
/*000*/ uint32 lootee;
|
||||
/*004*/ uint32 looter;
|
||||
/*008*/ uint16 slot_id;
|
||||
/*010*/ uint16 unknown10;
|
||||
/*012*/ uint32 auto_loot;
|
||||
/*010*/ uint16 unknown10; // slot_id is probably uint32
|
||||
/*012*/ int32 auto_loot;
|
||||
/*016*/ uint32 unknown16;
|
||||
/*020*/
|
||||
};
|
||||
@ -2892,7 +2849,8 @@ struct Resurrect_Struct
|
||||
/*160*/ char corpse_name[64];
|
||||
/*224*/ uint32 action;
|
||||
/*228*/ uint32 unknown228;
|
||||
/*232*/
|
||||
/*232*/ uint32 unknown232;
|
||||
/*236*/
|
||||
};
|
||||
|
||||
struct SetRunMode_Struct {
|
||||
@ -3111,29 +3069,24 @@ struct MobHealth
|
||||
};
|
||||
|
||||
struct Track_Struct {
|
||||
uint16 entityid;
|
||||
uint16 y;
|
||||
uint16 x;
|
||||
uint16 z;
|
||||
uint32 entityid;
|
||||
float distance;
|
||||
// Fields for SoD and later
|
||||
uint8 level;
|
||||
uint8 is_npc;
|
||||
char name[64];
|
||||
uint8 is_pet;
|
||||
uint8 is_merc;
|
||||
};
|
||||
|
||||
struct Tracking_Struct {
|
||||
uint16 entry_count;
|
||||
Track_Struct Entrys[0];
|
||||
};
|
||||
|
||||
// Looks like new tracking structures - Opcode: 0x57a7
|
||||
struct Tracking_Struct_New {
|
||||
uint16 totalcount; // Total Count of mobs within tracking range
|
||||
Track_Struct Entrys[0];
|
||||
};
|
||||
|
||||
struct Track_Struct_New {
|
||||
uint16 entityid; // Entity ID
|
||||
uint16 unknown002; // 00 00
|
||||
uint32 unknown004; //
|
||||
uint8 level; // level of mob
|
||||
uint8 unknown009; // 01 maybe type of mob? player/npc?
|
||||
char name[1]; // name of mob
|
||||
struct TrackTarget_Struct
|
||||
{
|
||||
uint32 EntityID;
|
||||
};
|
||||
|
||||
|
||||
@ -4399,7 +4352,7 @@ struct ItemSerializationHeader
|
||||
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
||||
/*026*/ uint16 main_slot;
|
||||
/*028*/ uint16 sub_slot;
|
||||
/*030*/ uint16 unknown013; // 0xffff
|
||||
/*030*/ uint16 aug_slot; // 0xffff
|
||||
/*032*/ uint32 price;
|
||||
/*036*/ uint32 merchant_slot; //1 if not a merchant item
|
||||
/*040*/ uint32 scaled_value; //0
|
||||
@ -4428,17 +4381,14 @@ struct EvolvingItem {
|
||||
|
||||
struct ItemSerializationHeaderFinish
|
||||
{
|
||||
/*079*/ uint16 ornamentIcon;
|
||||
/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0?
|
||||
/*082*/ uint8 unknown062; // 0
|
||||
/*083*/ int32 unknowna1; // 0xffffffff
|
||||
/*087*/ uint32 ornamentHeroModel; // 0
|
||||
/*091*/ uint8 unknown063; // 0
|
||||
/*092*/ uint32 unknowna3; // 0
|
||||
/*096*/ int32 unknowna4; // 0xffffffff
|
||||
/*100*/ uint32 unknowna5; // 0
|
||||
/*104*/ uint8 ItemClass; //0, 1, or 2
|
||||
/*105*/
|
||||
uint32 ornamentIcon;
|
||||
int32 unknowna1; // 0xffffffff
|
||||
uint32 ornamentHeroModel;
|
||||
int32 unknown063; // 0
|
||||
uint8 Copied; // Copied Flag - Possibly for items copied during server transfer?
|
||||
int32 unknowna4; // 0xffffffff
|
||||
int32 unknowna5; // 0
|
||||
uint8 ItemClass; //0, 1, or 2
|
||||
};
|
||||
|
||||
struct ItemBodyStruct
|
||||
@ -4542,7 +4492,7 @@ struct ItemSecondaryBodyStruct
|
||||
// swapped augrestrict and augdistiller positions
|
||||
// (this swap does show the proper augment restrictions in Item Information window now)
|
||||
// unsure what the purpose of augdistiller is at this time -U 3/17/2014
|
||||
uint32 augdistiller; // New to December 10th 2012 client - NEW
|
||||
int32 augrestrict2; // New to December 10th 2012 client - Hidden Aug Restriction
|
||||
uint32 augrestrict;
|
||||
AugSlotStruct augslots[6];
|
||||
|
||||
@ -4647,7 +4597,7 @@ struct ItemQuaternaryBodyStruct
|
||||
uint8 quest_item;
|
||||
uint32 Power; // Enables "Power" percentage field used by Power Sources
|
||||
uint32 Purity;
|
||||
uint8 unknown16; // RoF2
|
||||
uint8 unknown16; // RoF
|
||||
uint32 BackstabDmg;
|
||||
uint32 DSMitigation;
|
||||
int32 HeroicStr;
|
||||
@ -4669,15 +4619,19 @@ struct ItemQuaternaryBodyStruct
|
||||
uint8 unknown18; //Power Source Capacity or evolve filename?
|
||||
uint32 evolve_string; // Some String, but being evolution related is just a guess
|
||||
uint8 unknown19;
|
||||
uint32 unknown20; // Bard Stuff?
|
||||
//uint32 unknown21;
|
||||
uint8 unknown22;
|
||||
uint16 unknown20;
|
||||
uint8 unknown21;
|
||||
uint8 Heirloom; // Heirloom Flag
|
||||
uint8 Placeable; // Placeable Flag
|
||||
uint8 unknown22b;
|
||||
uint8 unknown22c;
|
||||
uint8 unknown22d;
|
||||
uint32 unknown23;
|
||||
uint32 unknown24;
|
||||
uint32 unknown25;
|
||||
float unknown26;
|
||||
float unknown27;
|
||||
uint32 unknown_RoF26; // 0 New to March 21 2012 client
|
||||
uint32 unknown_RoF_6; // 0 New to March 21 2012 client
|
||||
uint32 unknown28; // 0xffffffff
|
||||
uint16 unknown29;
|
||||
uint32 unknown30; // 0xffffffff
|
||||
@ -4688,9 +4642,15 @@ struct ItemQuaternaryBodyStruct
|
||||
uint32 unknown35;
|
||||
uint32 unknown36;
|
||||
uint32 unknown37;
|
||||
uint32 unknown_RoF27;
|
||||
uint32 unknown_RoF28;
|
||||
uint8 unknown37a; // (guessed position) New to RoF2
|
||||
uint8 NoZone; // No Zone Flag - Item will disappear upon zoning?
|
||||
uint8 unknown_RoF_7b; // Maybe Uint32 ?
|
||||
uint8 unknown_RoF_7c;
|
||||
uint8 unknown_RoF_7d;
|
||||
uint8 unknown_RoF_8a;
|
||||
uint8 NoGround; // No Ground Flag - Item cannot be dropped on the ground?
|
||||
uint8 unknown_RoF_8c;
|
||||
uint8 unknown_RoF_8d;
|
||||
uint8 unknown37a; // New to RoF2 - Probably variable length string
|
||||
uint8 unknown38; // 0
|
||||
uint8 unknown39; // 1
|
||||
uint32 subitem_count;
|
||||
|
||||
@ -3103,32 +3103,25 @@ struct MobHealth
|
||||
};
|
||||
|
||||
struct Track_Struct {
|
||||
uint16 entityid;
|
||||
uint16 y;
|
||||
uint16 x;
|
||||
uint16 z;
|
||||
uint32 entityid;
|
||||
float distance;
|
||||
// Fields for SoD and later
|
||||
uint8 level;
|
||||
uint8 is_npc;
|
||||
char name[64];
|
||||
uint8 is_merc;
|
||||
};
|
||||
|
||||
struct Tracking_Struct {
|
||||
uint16 entry_count;
|
||||
Track_Struct Entrys[0];
|
||||
};
|
||||
|
||||
// Looks like new tracking structures - Opcode: 0x57a7
|
||||
struct Tracking_Struct_New {
|
||||
uint16 totalcount; // Total Count of mobs within tracking range
|
||||
Track_Struct Entrys[0];
|
||||
struct TrackTarget_Struct
|
||||
{
|
||||
uint32 EntityID;
|
||||
};
|
||||
|
||||
struct Track_Struct_New {
|
||||
uint16 entityid; // Entity ID
|
||||
uint16 unknown002; // 00 00
|
||||
uint32 unknown004; //
|
||||
uint8 level; // level of mob
|
||||
uint8 unknown009; // 01 maybe type of mob? player/npc?
|
||||
char name[1]; // name of mob
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** ZoneServerInfo_Struct
|
||||
** Zone server information
|
||||
@ -4420,9 +4413,7 @@ struct EvolvingItem {
|
||||
|
||||
struct ItemSerializationHeaderFinish
|
||||
{
|
||||
/*079*/ uint16 ornamentIcon;
|
||||
/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0?
|
||||
/*082*/ uint8 unknown062; // 0
|
||||
/*079*/ uint32 ornamentIcon;
|
||||
/*083*/ int32 unknowna1; // 0xffffffff
|
||||
/*087*/ uint32 ornamentHeroModel; // 0
|
||||
/*091*/ uint8 unknown063; // 0
|
||||
|
||||
@ -1638,7 +1638,7 @@ namespace SoD
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
@ -1705,7 +1705,7 @@ namespace SoD
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
@ -2058,9 +2058,9 @@ namespace SoD
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
|
||||
@ -1296,7 +1296,7 @@ namespace SoF
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
@ -1363,7 +1363,7 @@ namespace SoF
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
@ -1645,7 +1645,7 @@ namespace SoF
|
||||
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
|
||||
{
|
||||
OUT(entityid);
|
||||
OUT(padding002);
|
||||
//OUT(padding002);
|
||||
OUT(distance);
|
||||
}
|
||||
|
||||
|
||||
@ -2624,8 +2624,8 @@ struct MobHealth
|
||||
};
|
||||
|
||||
struct Track_Struct {
|
||||
uint16 entityid;
|
||||
uint16 padding002;
|
||||
uint32 entityid;
|
||||
//uint16 padding002;
|
||||
float distance;
|
||||
};
|
||||
|
||||
|
||||
@ -1094,7 +1094,7 @@ namespace Titanium
|
||||
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
|
||||
{
|
||||
OUT(entityid);
|
||||
OUT(padding002);
|
||||
//OUT(padding002);
|
||||
OUT(distance);
|
||||
}
|
||||
|
||||
|
||||
@ -2319,8 +2319,8 @@ struct MobHealth
|
||||
};
|
||||
|
||||
struct Track_Struct {
|
||||
uint16 entityid;
|
||||
uint16 padding002;
|
||||
uint32 entityid;
|
||||
//uint16 padding002;
|
||||
float distance;
|
||||
};
|
||||
|
||||
|
||||
@ -1924,7 +1924,7 @@ namespace Underfoot
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
@ -1991,7 +1991,7 @@ namespace Underfoot
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
@ -2348,9 +2348,9 @@ namespace Underfoot
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid);
|
||||
VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_npc);
|
||||
VARSTRUCT_ENCODE_STRING(Buffer, emu->name);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->is_merc);
|
||||
}
|
||||
|
||||
delete[] __emu_buffer;
|
||||
|
||||
@ -177,6 +177,7 @@ bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 s
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, int16 slot_id) {
|
||||
// need to check 'inst' argument for valid pointer
|
||||
|
||||
uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM };
|
||||
if (inst->IsType(ItemClassCommon))
|
||||
@ -221,6 +222,7 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, int16 slot_id) {
|
||||
// need to check 'inst' argument for valid pointer
|
||||
|
||||
uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM };
|
||||
if (inst->IsType(ItemClassCommon))
|
||||
@ -429,10 +431,6 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
|
||||
|
||||
int16 put_slot_id = INVALID_INDEX;
|
||||
|
||||
ItemInst* inst = CreateBaseItem(item, charges);
|
||||
if (item->ItemClass == ItemClassCommon) {
|
||||
for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
if (aug[i]) {
|
||||
inst->PutAugment(this, i, aug[i]);
|
||||
}
|
||||
}
|
||||
@ -527,6 +525,9 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
|
||||
|
||||
ItemInst* inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
|
||||
if(row[11]) {
|
||||
std::string data_str(row[11]);
|
||||
std::string idAsString;
|
||||
@ -635,6 +636,10 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
|
||||
continue;
|
||||
|
||||
ItemInst* inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
|
||||
inst->SetAttuned(instnodrop);
|
||||
|
||||
if(row[11]) {
|
||||
@ -1193,9 +1198,17 @@ ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1,
|
||||
{
|
||||
const Item_Struct* item = nullptr;
|
||||
ItemInst* inst = nullptr;
|
||||
|
||||
item = GetItem(item_id);
|
||||
if (item) {
|
||||
inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()");
|
||||
LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inst->PutAugment(this, 0, aug1);
|
||||
inst->PutAugment(this, 1, aug2);
|
||||
inst->PutAugment(this, 2, aug3);
|
||||
@ -1215,6 +1228,13 @@ ItemInst* SharedDatabase::CreateItem(const Item_Struct* item, int16 charges, uin
|
||||
ItemInst* inst = nullptr;
|
||||
if (item) {
|
||||
inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateItem()");
|
||||
LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inst->PutAugment(this, 0, aug1);
|
||||
inst->PutAugment(this, 1, aug2);
|
||||
inst->PutAugment(this, 2, aug3);
|
||||
@ -1240,6 +1260,12 @@ ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, int16 charges)
|
||||
|
||||
inst = new ItemInst(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "Error: valid item data returned a null reference for ItemInst creation in SharedDatabase::CreateBaseItem()");
|
||||
LogFile->write(EQEMuLog::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(item->CharmFileID != 0 || (item->LoreGroup >= 1000 && item->LoreGroup != -1)) {
|
||||
inst->Initialize(this);
|
||||
}
|
||||
|
||||
@ -141,11 +141,13 @@ uint32 Timer::GetRemainingTime() {
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled) {
|
||||
void Timer::SetAtTrigger(uint32 in_set_at_trigger, bool iEnableIfDisabled, bool ChangeTimerTime) {
|
||||
set_at_trigger = in_set_at_trigger;
|
||||
if (!Enabled() && iEnableIfDisabled) {
|
||||
Enable();
|
||||
}
|
||||
if (ChangeTimerTime)
|
||||
timer_time = set_at_trigger;
|
||||
}
|
||||
|
||||
void Timer::Trigger()
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
inline const uint32& GetTimerTime() { return timer_time; }
|
||||
inline const uint32& GetSetAtTrigger() { return set_at_trigger; }
|
||||
void Trigger();
|
||||
void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false);
|
||||
void SetAtTrigger(uint32 set_at_trigger, bool iEnableIfDisabled = false, bool ChangeTimerTime = false);
|
||||
|
||||
inline bool Enabled() { return enabled; }
|
||||
inline uint32 GetStartTime() { return(start_time); }
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9062
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9066
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
#ifndef WIN32
|
||||
|
||||
@ -193,7 +193,7 @@ OP_Consent=0x1fd1
|
||||
OP_ConsentDeny=0x7a45
|
||||
OP_AutoFire=0x241e
|
||||
OP_PetCommands=0x0159
|
||||
OP_DeleteSpell=0x52e5
|
||||
OP_DeleteSpell=0x3358
|
||||
OP_Surname=0x0423
|
||||
OP_ClearSurname=0x3fb0
|
||||
OP_FaceChange=0x5578
|
||||
@ -205,14 +205,14 @@ OP_CorpseDrag=0x0904
|
||||
OP_CorpseDrop=0x7037
|
||||
OP_Bug=0x73f4
|
||||
OP_Feedback=0x5602
|
||||
OP_Report=0x1414
|
||||
OP_Report=0x6f14
|
||||
OP_Damage=0x6f15
|
||||
OP_ChannelMessage=0x2b2d
|
||||
OP_Assist=0x4478
|
||||
OP_AssistGroup=0x27f8
|
||||
OP_MoveCoin=0x0bcf
|
||||
OP_ZonePlayerToBind=0x08d8
|
||||
OP_KeyRing=0x6857
|
||||
OP_KeyRing=0x1219
|
||||
OP_WhoAllRequest=0x674b
|
||||
OP_WhoAllResponse=0x578c
|
||||
OP_FriendsWho=0x3956
|
||||
@ -230,10 +230,10 @@ OP_TargetMouse=0x075d
|
||||
OP_MobHealth=0x37b1
|
||||
OP_InitialMobHealth=0x0000 # Unused?
|
||||
OP_TargetHoTT=0x0272
|
||||
OP_XTargetResponse=0x672f
|
||||
OP_XTargetRequest=0x45be
|
||||
OP_XTargetAutoAddHaters=0x792c
|
||||
OP_TargetBuffs=0x4f4b
|
||||
OP_XTargetResponse=0x4d59
|
||||
OP_XTargetRequest=0x3763
|
||||
OP_XTargetAutoAddHaters=0x672f
|
||||
OP_BuffCreate=0x3377
|
||||
OP_BuffRemoveRequest=0x64f2
|
||||
OP_DeleteSpawn=0x7280
|
||||
@ -249,7 +249,7 @@ OP_ItemLinkClick=0x4cef
|
||||
OP_ItemPreview=0x6b5c
|
||||
OP_NewSpawn=0x6097
|
||||
OP_Track=0x17e5
|
||||
OP_TrackTarget=0x0029
|
||||
OP_TrackTarget=0x695e
|
||||
OP_TrackUnknown=0x4577
|
||||
OP_ClickDoor=0x3a8f
|
||||
OP_MoveDoor=0x08e8
|
||||
@ -263,7 +263,7 @@ OP_SafeFallSuccess=0x2219
|
||||
OP_RezzComplete=0x760d
|
||||
OP_RezzRequest=0x3c21
|
||||
OP_RezzAnswer=0x701c
|
||||
OP_Shielding=0x48c1
|
||||
OP_Shielding=0x52e5
|
||||
OP_RequestDuel=0x3af1
|
||||
OP_MobRename=0x2c57
|
||||
OP_AugmentItem=0x661b
|
||||
@ -309,7 +309,7 @@ OP_Sacrifice=0x1821
|
||||
OP_PopupResponse=0x08a6
|
||||
OP_OnLevelMessage=0x575b
|
||||
OP_AugmentInfo=0x0afb
|
||||
OP_Petition=0x1901
|
||||
OP_Petition=0x3de3
|
||||
OP_SomeItemPacketMaybe=0x747c
|
||||
OP_PVPStats=0x4b15
|
||||
OP_PVPLeaderBoardRequest=0x04aa
|
||||
@ -433,7 +433,7 @@ OP_ItemVerifyRequest=0x189c
|
||||
OP_ItemVerifyReply=0x097b
|
||||
|
||||
# merchant stuff
|
||||
OP_ShopPlayerSell=0x0000
|
||||
OP_ShopPlayerSell=0x791b
|
||||
OP_ShopRequest=0x4fed
|
||||
OP_ShopEnd=0x30a8
|
||||
OP_ShopEndConfirm=0x3196
|
||||
@ -601,7 +601,7 @@ OP_MoveLogDisregard=0x0000 # gone I think
|
||||
|
||||
# named unknowns, to make looking for real unknown easier
|
||||
OP_AnnoyingZoneUnknown=0x0000
|
||||
OP_Some6ByteHPUpdate=0x0000 seems to happen when you target group members
|
||||
OP_Some6ByteHPUpdate=0x0000 #seems to happen when you target group members
|
||||
OP_QueryResponseThing=0x0000
|
||||
|
||||
|
||||
@ -610,9 +610,9 @@ OP_QueryResponseThing=0x0000
|
||||
#OP_LoginUnknown2=0x040b # OP_SendSkillCapsChecksum
|
||||
|
||||
# Petition Opcodes
|
||||
OP_PetitionSearch=0x0000 search term for petition
|
||||
OP_PetitionSearchResults=0x0000 (list of?) matches from search
|
||||
OP_PetitionSearchText=0x0000 text results of search
|
||||
OP_PetitionSearch=0x0000 #search term for petition
|
||||
OP_PetitionSearchResults=0x0000 #(list of?) matches from search
|
||||
OP_PetitionSearchText=0x0000 #text results of search
|
||||
|
||||
OP_PetitionUpdate=0x0000
|
||||
OP_PetitionCheckout=0x0000
|
||||
|
||||
@ -155,6 +155,7 @@ sub ShowMenuPrompt {
|
||||
2 => \&database_dump_compress,
|
||||
3 => \&Run_Database_Check,
|
||||
4 => \&AA_Fetch,
|
||||
5 => \&OpCodes_Fetch,
|
||||
0 => \&Exit,
|
||||
);
|
||||
|
||||
@ -204,6 +205,7 @@ Database Management Menu (Please Select):
|
||||
Ideal to perform before performing updates
|
||||
3) $option[3]
|
||||
4) AAs - Get Latest AA's from PEQ (This deletes AA's already in the database)
|
||||
5) OPCodes - Download latest opcodes from repository
|
||||
0) Exit
|
||||
|
||||
EO_MENU
|
||||
@ -305,6 +307,36 @@ sub AA_Fetch{
|
||||
print "\nDone...\n\n";
|
||||
}
|
||||
|
||||
#::: Fetch Latest Opcodes
|
||||
sub OpCodes_Fetch{
|
||||
print "Pulling down latest opcodes...\n";
|
||||
%opcodes = (
|
||||
1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"],
|
||||
2 => ["mail_opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/mail_opcodes.conf"],
|
||||
3 => ["Titanium", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Titanium.conf"],
|
||||
4 => ["Secrets of Faydwer", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoF.conf"],
|
||||
5 => ["Seeds of Destruction", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoD.conf"],
|
||||
6 => ["Underfoot", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Underfoot.conf"],
|
||||
7 => ["Rain of Fear", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF.conf"],
|
||||
8 => ["Rain of Fear 2", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF2.conf"],
|
||||
);
|
||||
$loop = 1;
|
||||
while($opcodes{$loop}[0]){
|
||||
#::: Split the URL by the patches folder to get the file name from URL
|
||||
@real_file = split("patches/", $opcodes{$loop}[1]);
|
||||
$find = 0;
|
||||
while($real_file[$find]){
|
||||
$file_name = $real_file[$find];
|
||||
$find++;
|
||||
}
|
||||
|
||||
print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n";
|
||||
GetRemoteFile($opcodes{$loop}[1], $file_name);
|
||||
$loop++;
|
||||
}
|
||||
print "\nDone...\n\n";
|
||||
}
|
||||
|
||||
#::: Responsible for Database Upgrade Routines
|
||||
sub Run_Database_Check{
|
||||
#::: Run 2 - Running pending updates...
|
||||
|
||||
39
utils/scripts/parse_crashes.pl
Normal file
39
utils/scripts/parse_crashes.pl
Normal file
@ -0,0 +1,39 @@
|
||||
opendir my $dir, "logs" or die "Cannot open directory: $!";
|
||||
my @files = readdir $dir;
|
||||
closedir $dir;
|
||||
$inc = 0;
|
||||
foreach my $val (@files){
|
||||
if($val=~/crash_zone/i){
|
||||
$stl = 0;
|
||||
$crash[$inc] = "";
|
||||
my $file = "logs/" . $val;
|
||||
open my $info, $file or die "Could not open $file: $!";
|
||||
while( my $line = <$info>) {
|
||||
if($line=~/CRTStartup/i){ $stl = 0; }
|
||||
@data = split(']', $line);
|
||||
if($stl == 1){ $crash[$inc] .= $data[1]; }
|
||||
if($line=~/dbghelp.dll/i){ $stl = 1; }
|
||||
}
|
||||
close $info;
|
||||
$inc++;
|
||||
}
|
||||
}
|
||||
|
||||
#::: Count Crash Occurrence first
|
||||
$i = 0;
|
||||
while($crash[$i]){
|
||||
$crash_count[length($crash[$i])]++;
|
||||
$unique_crash[length($crash[$i])] = $crash[$i];
|
||||
$i++;
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
while($crash[$i]){
|
||||
if($unique_crash_tracker[length($crash[$i])] != 1){
|
||||
print "Crash Occurrence " . $crash_count[length($crash[$i])] . " Time(s) Length (" . length($crash[$i]) . ") \n\n";
|
||||
print $crash[$i] . "\n";
|
||||
print "=========================================\n";
|
||||
}
|
||||
$unique_crash_tracker[length($crash[$i])] = 1;
|
||||
$i++;
|
||||
}
|
||||
@ -316,6 +316,10 @@
|
||||
9060|2014_12_09_items_table_update.sql|SHOW COLUMNS FROM `items` LIKE 'herosforgemodel'|empty|
|
||||
9061|2014_12_13_inventory_table_update.sql|SHOW COLUMNS FROM `inventory` LIKE 'ornament_hero_model'|empty|
|
||||
9062|2014_12_15_multiple_table_updates.sql|SHOW COLUMNS FROM `items` LIKE 'augslot6type'|empty|
|
||||
9063|2014_12_24_npc_types_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'd_melee_texture1'|empty|
|
||||
9064|2014_12_24_npc_types_table_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'herosforgemodel'|empty|
|
||||
9065|2014_12_26_merc_weaponinfo_table_update.sql|SHOW COLUMNS FROM `vwMercNpcTypes` LIKE 'd_melee_texture1'|empty|
|
||||
9066|2014_12_31_npc_types_default_values_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'bodytype'|contains|YES
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE `npc_types` ADD `herosforgemodel` int( 11 ) NOT NULL DEFAULT '0' AFTER `helmtexture`;
|
||||
2
utils/sql/git/required/2014_12_24_npc_types_update.sql
Normal file
2
utils/sql/git/required/2014_12_24_npc_types_update.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE `npc_types` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) DEFAULT NULL;
|
||||
ALTER TABLE `npc_types` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) DEFAULT NULL;
|
||||
@ -0,0 +1,69 @@
|
||||
/* Drop the current Merc View */
|
||||
DROP VIEW vwMercNpcTypes;
|
||||
|
||||
/* Rename fields to match the source changes */
|
||||
ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture1` `d_melee_texture1` INT(11) NOT NULL DEFAULT 0;
|
||||
ALTER TABLE `merc_weaponinfo` CHANGE `d_meele_texture2` `d_melee_texture2` INT(11) NOT NULL DEFAULT 0;
|
||||
|
||||
/* Re-Create the Merc View with new field names */
|
||||
CREATE VIEW vwMercNpcTypes AS
|
||||
SELECT
|
||||
ms.merc_npc_type_id,
|
||||
'' AS name,
|
||||
ms.clientlevel,
|
||||
ms.level,
|
||||
mtyp.race_id,
|
||||
mstyp.class_id,
|
||||
ms.hp,
|
||||
ms.mana,
|
||||
0 AS gender,
|
||||
mai.texture,
|
||||
mai.helmtexture,
|
||||
ms.attack_speed,
|
||||
ms.STR,
|
||||
ms.STA,
|
||||
ms.DEX,
|
||||
ms.AGI,
|
||||
ms._INT,
|
||||
ms.WIS,
|
||||
ms.CHA,
|
||||
ms.MR,
|
||||
ms.CR,
|
||||
ms.DR,
|
||||
ms.FR,
|
||||
ms.PR,
|
||||
ms.Corrup,
|
||||
ms.mindmg,
|
||||
ms.maxdmg,
|
||||
ms.attack_count,
|
||||
ms.special_abilities AS special_abilities,
|
||||
mwi.d_melee_texture1,
|
||||
mwi.d_melee_texture2,
|
||||
mwi.prim_melee_type,
|
||||
mwi.sec_melee_type,
|
||||
ms.runspeed,
|
||||
ms.hp_regen_rate,
|
||||
ms.mana_regen_rate,
|
||||
1 AS bodytype,
|
||||
mai.armortint_id,
|
||||
mai.armortint_red,
|
||||
mai.armortint_green,
|
||||
mai.armortint_blue,
|
||||
ms.AC,
|
||||
ms.ATK,
|
||||
ms.Accuracy,
|
||||
ms.spellscale,
|
||||
ms.healscale
|
||||
FROM merc_stats ms
|
||||
INNER JOIN merc_armorinfo mai
|
||||
ON ms.merc_npc_type_id = mai.merc_npc_type_id
|
||||
AND mai.minlevel <= ms.level AND mai.maxlevel >= ms.level
|
||||
INNER JOIN merc_weaponinfo mwi
|
||||
ON ms.merc_npc_type_id = mwi.merc_npc_type_id
|
||||
AND mwi.minlevel <= ms.level AND mwi.maxlevel >= ms.level
|
||||
INNER JOIN merc_templates mtem
|
||||
ON mtem.merc_npc_type_id = ms.merc_npc_type_id
|
||||
INNER JOIN merc_types mtyp
|
||||
ON mtem.merc_type_id = mtyp.merc_type_id
|
||||
INNER JOIN merc_subtypes mstyp
|
||||
ON mtem.merc_subtype_id = mstyp.merc_subtype_id;
|
||||
@ -0,0 +1,3 @@
|
||||
ALTER TABLE `npc_types` MODIFY `bodytype` INT(11) NOT NULL DEFAULT '1';
|
||||
ALTER TABLE `npc_types` MODIFY `d_melee_texture1` INT(11) NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `npc_types` MODIFY `d_melee_texture2` INT(11) NOT NULL DEFAULT '0';
|
||||
10
zone/aa.cpp
10
zone/aa.cpp
@ -606,6 +606,9 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
||||
//the target of these swarm pets will take offense to being cast on...
|
||||
if(targ != nullptr)
|
||||
targ->AddToHateList(this, 1, 0);
|
||||
|
||||
// The other pointers we make are handled elsewhere.
|
||||
delete made_npc;
|
||||
}
|
||||
|
||||
void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {
|
||||
@ -698,6 +701,9 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
||||
entity_list.AddNPC(npca, true, true);
|
||||
summon_count--;
|
||||
}
|
||||
|
||||
// The other pointers we make are handled elsewhere.
|
||||
delete made_npc;
|
||||
}
|
||||
|
||||
void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
@ -844,8 +850,8 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
|
||||
make_npc->loottable_id = 0;
|
||||
make_npc->merchanttype = 0;
|
||||
make_npc->d_meele_texture1 = 0;
|
||||
make_npc->d_meele_texture2 = 0;
|
||||
make_npc->d_melee_texture1 = 0;
|
||||
make_npc->d_melee_texture2 = 0;
|
||||
|
||||
NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3);
|
||||
|
||||
|
||||
@ -1298,7 +1298,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
|
||||
void Mob::RogueEvade(Mob *other)
|
||||
{
|
||||
int amount = other->GetHateAmount(this) - (GetLevel() * 13);
|
||||
other->SetHate(this, std::max(1, amount));
|
||||
other->SetHateAmountOnEnt(this, std::max(1, amount));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1519,7 +1519,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
|
||||
}
|
||||
|
||||
entity_list.RemoveFromTargets(this);
|
||||
hate_list.RemoveEnt(this);
|
||||
hate_list.RemoveEntFromHateList(this);
|
||||
RemoveAutoXTargets();
|
||||
|
||||
//remove ourself from all proximities
|
||||
@ -2080,12 +2080,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
|
||||
if (killerMob) {
|
||||
if(GetClass() != LDON_TREASURE)
|
||||
hate_list.Add(killerMob, damage);
|
||||
hate_list.AddEntToHateList(killerMob, damage);
|
||||
}
|
||||
|
||||
safe_delete(app);
|
||||
|
||||
Mob *give_exp = hate_list.GetDamageTop(this);
|
||||
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
|
||||
if(give_exp == nullptr)
|
||||
give_exp = killer;
|
||||
@ -2415,7 +2415,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
|
||||
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
|
||||
{
|
||||
|
||||
assert(other != nullptr);
|
||||
|
||||
@ -2428,7 +2429,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
|
||||
bool wasengaged = IsEngaged();
|
||||
Mob* owner = other->GetOwner();
|
||||
Mob* mypet = this->GetPet();
|
||||
Mob* mypet = this->GetPet();
|
||||
Mob* myowner = this->GetOwner();
|
||||
Mob* targetmob = this->GetTarget();
|
||||
|
||||
@ -2503,7 +2504,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
|
||||
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
|
||||
|
||||
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
|
||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||
|
||||
if(other->IsClient())
|
||||
other->CastToClient()->AddAutoXTarget(this);
|
||||
@ -2515,8 +2516,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
|
||||
}
|
||||
else {
|
||||
if(!hate_list.IsOnHateList(other->CastToBot()->GetBotOwner()))
|
||||
hate_list.Add(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
|
||||
if(!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner()))
|
||||
hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
|
||||
}
|
||||
}
|
||||
#endif //BOTS
|
||||
@ -2527,8 +2528,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient());
|
||||
}
|
||||
else {
|
||||
if(!hate_list.IsOnHateList(other->CastToMerc()->GetMercOwner()))
|
||||
hate_list.Add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
|
||||
if(!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner()))
|
||||
hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
|
||||
}
|
||||
} //MERC
|
||||
|
||||
@ -2543,7 +2544,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
// owner must get on list, but he's not actually gained any hate yet
|
||||
if(!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
{
|
||||
hate_list.Add(owner, 0, 0, false, !iBuffTic);
|
||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||
if(owner->IsClient())
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
}
|
||||
@ -2552,10 +2553,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
|
||||
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
|
||||
if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
mypet->hate_list.Add(other, 0, 0, bFrenzy);
|
||||
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
} else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
|
||||
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
myowner->hate_list.Add(other, 0, 0, bFrenzy);
|
||||
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
|
||||
if (other->GetTempPetCount())
|
||||
@ -3905,6 +3906,7 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
// argument 'weapon' not used
|
||||
void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) {
|
||||
|
||||
if (!on) {
|
||||
@ -4947,7 +4949,7 @@ void Client::SetAttackTimer()
|
||||
// this is probably wrong
|
||||
if (quiver_haste > 0)
|
||||
speed *= quiver_haste;
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
|
||||
|
||||
if (i == MainPrimary)
|
||||
PrimaryWeapon = ItemToUse;
|
||||
@ -4995,6 +4997,6 @@ void NPC::SetAttackTimer()
|
||||
}
|
||||
}
|
||||
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
892
zone/bonuses.cpp
892
zone/bonuses.cpp
File diff suppressed because it is too large
Load Diff
183
zone/bot.cpp
183
zone/bot.cpp
@ -234,45 +234,28 @@ void Bot::SetBotSpellID(uint32 newSpellID) {
|
||||
this->npc_spells_id = newSpellID;
|
||||
}
|
||||
|
||||
uint32 Bot::GetBotArcheryRange() {
|
||||
uint32 result = 0;
|
||||
uint32 Bot::GetBotArcheryRange()
|
||||
{
|
||||
const ItemInst *range_inst = GetBotItem(MainRange);
|
||||
const ItemInst *ammo_inst = GetBotItem(MainAmmo);
|
||||
|
||||
ItemInst* rangeItem = GetBotItem(MainRange);
|
||||
|
||||
if(!rangeItem)
|
||||
// empty slots
|
||||
if (!range_inst || !ammo_inst)
|
||||
return 0;
|
||||
|
||||
const Item_Struct* botweapon = rangeItem->GetItem();
|
||||
const Item_Struct *range_item = range_inst->GetItem();
|
||||
const Item_Struct *ammo_item = ammo_inst->GetItem();
|
||||
|
||||
uint32 archeryMaterial;
|
||||
uint32 archeryColor;
|
||||
uint32 archeryBowID;
|
||||
uint32 archeryAmmoID;
|
||||
// no item struct for whatever reason
|
||||
if (!range_item || !ammo_item)
|
||||
return 0;
|
||||
|
||||
if(botweapon && botweapon->ItemType == ItemTypeBow) {
|
||||
uint32 range = 0;
|
||||
// bad item types
|
||||
if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow)
|
||||
return 0;
|
||||
|
||||
archeryMaterial = atoi(botweapon->IDFile + 2);
|
||||
archeryBowID = botweapon->ID;
|
||||
archeryColor = botweapon->Color;
|
||||
range =+ botweapon->Range;
|
||||
|
||||
rangeItem = GetBotItem(MainAmmo);
|
||||
if(rangeItem)
|
||||
botweapon = rangeItem->GetItem();
|
||||
|
||||
if(!botweapon || (botweapon->ItemType != ItemTypeArrow)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
range += botweapon->Range;
|
||||
|
||||
archeryAmmoID = botweapon->ID;
|
||||
|
||||
result = range;
|
||||
}
|
||||
|
||||
return result;
|
||||
// everything is good!
|
||||
return range_item->Range + ammo_item->Range;
|
||||
}
|
||||
|
||||
void Bot::ChangeBotArcherWeapons(bool isArcher) {
|
||||
@ -386,8 +369,8 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str
|
||||
|
||||
BotNPCType.npc_id = 0;
|
||||
BotNPCType.texture = 0;
|
||||
BotNPCType.d_meele_texture1 = 0;
|
||||
BotNPCType.d_meele_texture2 = 0;
|
||||
BotNPCType.d_melee_texture1 = 0;
|
||||
BotNPCType.d_melee_texture2 = 0;
|
||||
BotNPCType.qglobal = false;
|
||||
BotNPCType.attack_speed = 0;
|
||||
BotNPCType.runspeed = 1.25;
|
||||
@ -431,8 +414,8 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b
|
||||
Result.hp_regen = 1;
|
||||
Result.mana_regen = 1;
|
||||
Result.texture = 0;
|
||||
Result.d_meele_texture1 = 0;
|
||||
Result.d_meele_texture2 = 0;
|
||||
Result.d_melee_texture1 = 0;
|
||||
Result.d_melee_texture2 = 0;
|
||||
Result.qglobal = false;
|
||||
Result.npc_spells_id = 0;
|
||||
Result.attack_speed = 0;
|
||||
@ -3439,9 +3422,9 @@ void Bot::AI_Process() {
|
||||
rest_timer.Disable();
|
||||
|
||||
if(IsRooted())
|
||||
SetTarget(hate_list.GetClosest(this));
|
||||
SetTarget(hate_list.GetClosestEntOnHateList(this));
|
||||
else
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
|
||||
if(!GetTarget())
|
||||
return;
|
||||
@ -3808,9 +3791,9 @@ void Bot::PetAIProcess() {
|
||||
if (IsEngaged()) {
|
||||
|
||||
if (botPet->IsRooted())
|
||||
botPet->SetTarget(hate_list.GetClosest(botPet));
|
||||
botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet));
|
||||
else
|
||||
botPet->SetTarget(hate_list.GetTop(botPet));
|
||||
botPet->SetTarget(hate_list.GetEntWithMostHateOnList(botPet));
|
||||
|
||||
// Let's check if we have a los with our target.
|
||||
// If we don't, our hate_list is wiped.
|
||||
@ -5871,7 +5854,7 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes att
|
||||
|
||||
Save();
|
||||
|
||||
Mob *give_exp = hate_list.GetDamageTop(this);
|
||||
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
Client *give_exp_client = nullptr;
|
||||
|
||||
if(give_exp && give_exp->IsClient())
|
||||
@ -6025,7 +6008,7 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic)
|
||||
void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
|
||||
{
|
||||
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic);
|
||||
}
|
||||
@ -11716,106 +11699,47 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back",
|
||||
"Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand",
|
||||
"Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" };
|
||||
const ItemInst* item1 = nullptr;
|
||||
const Item_Struct* item2 = nullptr;
|
||||
|
||||
const ItemInst* inst = nullptr;
|
||||
const Item_Struct* item = nullptr;
|
||||
bool is2Hweapon = false;
|
||||
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i)
|
||||
{
|
||||
|
||||
std::string item_link;
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
|
||||
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
|
||||
if((i == MainSecondary) && is2Hweapon) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item1 = b->CastToBot()->GetBotItem(i);
|
||||
if(item1)
|
||||
item2 = item1->GetItem();
|
||||
inst = b->CastToBot()->GetBotItem(i);
|
||||
if (inst)
|
||||
item = inst->GetItem();
|
||||
else
|
||||
item2 = nullptr;
|
||||
item = nullptr;
|
||||
|
||||
if(!TempErrorMessage.empty()) {
|
||||
c->Message(13, "Database Error: %s", TempErrorMessage.c_str());
|
||||
return;
|
||||
}
|
||||
if(item2 == 0) {
|
||||
if(item == nullptr) {
|
||||
c->Message(15, "I need something for my %s (Item %i)", equipped[i], i);
|
||||
continue;
|
||||
}
|
||||
if((i == MainPrimary) && ((item2->ItemType == ItemType2HSlash) || (item2->ItemType == ItemType2HBlunt) || (item2->ItemType == ItemType2HPiercing))) {
|
||||
if((i == MainPrimary) && ((item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HPiercing))) {
|
||||
is2Hweapon = true;
|
||||
}
|
||||
|
||||
char* itemLink = 0;
|
||||
if((i == MainCharm) || (i == MainRange) || (i == MainPrimary) || (i == MainSecondary) || (i == MainAmmo)) {
|
||||
if (c->GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item2->ID,
|
||||
item1->GetAugmentItemID(0),
|
||||
item1->GetAugmentItemID(1),
|
||||
item1->GetAugmentItemID(2),
|
||||
item1->GetAugmentItemID(3),
|
||||
item1->GetAugmentItemID(4),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
|
||||
}
|
||||
else
|
||||
{
|
||||
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
|
||||
0,
|
||||
item2->ID,
|
||||
item1->GetAugmentItemID(0),
|
||||
item1->GetAugmentItemID(1),
|
||||
item1->GetAugmentItemID(2),
|
||||
item1->GetAugmentItemID(3),
|
||||
item1->GetAugmentItemID(4),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c->GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item2->ID,
|
||||
item1->GetAugmentItemID(0),
|
||||
item1->GetAugmentItemID(1),
|
||||
item1->GetAugmentItemID(2),
|
||||
item1->GetAugmentItemID(3),
|
||||
item1->GetAugmentItemID(4),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
|
||||
}
|
||||
else
|
||||
{
|
||||
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
|
||||
0,
|
||||
item2->ID,
|
||||
item1->GetAugmentItemID(0),
|
||||
item1->GetAugmentItemID(1),
|
||||
item1->GetAugmentItemID(2),
|
||||
item1->GetAugmentItemID(3),
|
||||
item1->GetAugmentItemID(4),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
|
||||
}
|
||||
}
|
||||
// I could not find a difference between the criteria positive code and the criteria negative code..
|
||||
// ..so, I deleted the check (old criteria: i = { MainCharm, MainRange, MainPrimary, MainSecondary, MainAmmo })
|
||||
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(15, "Using %s in my %s (Item %i)", item_link.c_str(), equipped[i], i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -14364,8 +14288,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<BotGroup>::iterator botGroupItr = botGroup.begin();
|
||||
for(botGroupItr; botGroupItr != botGroup.end(); ++botGroupItr) {
|
||||
for(auto botGroupItr = botGroup.begin(); botGroupItr != botGroup.end(); ++botGroupItr) {
|
||||
// Don't try to re-spawn the botgroup's leader.
|
||||
if(botGroupItr->BotID == botGroupLeader->GetBotID()) { continue; }
|
||||
|
||||
@ -15474,7 +15397,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
else {
|
||||
Mob *target = c->GetTarget();
|
||||
|
||||
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
|
||||
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
|
||||
const InspectMessage_Struct& playermessage = c->GetInspectMessage();
|
||||
InspectMessage_Struct& botmessage = target->CastToBot()->GetInspectMessage();
|
||||
|
||||
@ -15504,7 +15427,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
|
||||
Mob *target = c->GetTarget();
|
||||
|
||||
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
|
||||
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
|
||||
Bot* bardBot = target->CastToBot();
|
||||
|
||||
if(bardBot) {
|
||||
|
||||
@ -208,7 +208,7 @@ public:
|
||||
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
|
||||
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
|
||||
void Camp(bool databaseSave = true);
|
||||
virtual void AddToHateList(Mob* other, int32 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);
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual void Zone();
|
||||
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }
|
||||
|
||||
276
zone/client.cpp
276
zone/client.cpp
@ -1817,45 +1817,8 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
}
|
||||
ns->spawn.size = 0; // Changing size works, but then movement stops! (wth?)
|
||||
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
|
||||
if (!m_pp.showhelm) ns->spawn.showhelm = 0;
|
||||
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
|
||||
|
||||
/*
|
||||
// Equipment/Weapons already set from Mob::FillSpawnStruct
|
||||
// Commenting this out for now
|
||||
const Item_Struct* item = nullptr;
|
||||
const ItemInst* inst = nullptr;
|
||||
int16 invslot;
|
||||
|
||||
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
|
||||
{
|
||||
// Only Player Races Wear Armor
|
||||
if (IsPlayerRace(race) || matslot > 6)
|
||||
{
|
||||
invslot = Inventory::CalcSlotFromMaterial(matslot);
|
||||
if (invslot == INVALID_INDEX)
|
||||
continue;
|
||||
|
||||
if ((inst = m_inv[invslot]) && inst->IsType(ItemClassCommon))
|
||||
{
|
||||
item = inst->GetItem();
|
||||
|
||||
if (matslot > 6)
|
||||
{
|
||||
// Weapon Models
|
||||
ns->spawn.equipment[matslot].material = GetEquipmentMaterial(matslot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Armor Materials/Models
|
||||
ns->spawn.equipment[matslot].material = item->Material;
|
||||
ns->spawn.equipment[matslot].elitematerial = item->EliteMaterial;
|
||||
ns->spawn.equipment[matslot].heroforgemodel = GetHerosForgeModel(matslot);
|
||||
ns->spawn.colors[matslot].color = m_pp.item_tint[matslot].rgb.use_tint ? m_pp.item_tint[matslot].color : item->Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool Client::GMHideMe(Client* client) {
|
||||
@ -6305,8 +6268,8 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
|
||||
made_npc->drakkin_heritage = GetDrakkinHeritage();
|
||||
made_npc->drakkin_tattoo = GetDrakkinTattoo();
|
||||
made_npc->drakkin_details = GetDrakkinDetails();
|
||||
made_npc->d_meele_texture1 = GetEquipmentMaterial(MaterialPrimary);
|
||||
made_npc->d_meele_texture2 = GetEquipmentMaterial(MaterialSecondary);
|
||||
made_npc->d_melee_texture1 = GetEquipmentMaterial(MaterialPrimary);
|
||||
made_npc->d_melee_texture2 = GetEquipmentMaterial(MaterialSecondary);
|
||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) {
|
||||
made_npc->armor_tint[i] = GetEquipmentColor(i);
|
||||
}
|
||||
@ -8295,3 +8258,236 @@ void Client::SendColoredText(uint32 color, std::string message)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// class Client::TextLink
|
||||
//
|
||||
std::string Client::TextLink::GenerateLink()
|
||||
{
|
||||
m_Link.clear();
|
||||
m_LinkBody.clear();
|
||||
m_LinkText.clear();
|
||||
|
||||
generate_body();
|
||||
generate_text();
|
||||
|
||||
if (m_LinkBody.length() && m_LinkText.length()) {
|
||||
m_Link.append(StringFormat("%c", 0x12));
|
||||
m_Link.append(m_LinkBody);
|
||||
m_Link.append(m_LinkText);
|
||||
m_Link.append(StringFormat("%c", 0x12));
|
||||
}
|
||||
|
||||
if ((m_Link.length() == 0) || (m_Link.length() > 250)) {
|
||||
m_Error = true;
|
||||
m_Link = "<LINKER ERROR>";
|
||||
_log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {l: %u, b: %u, t: %u})",
|
||||
m_LinkType, m_Link.length(), m_LinkBody.length(), m_LinkText.length());
|
||||
}
|
||||
|
||||
return m_Link;
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLink()
|
||||
{
|
||||
if (m_Link.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_Link.c_str();
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLinkBody()
|
||||
{
|
||||
if (m_LinkBody.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_LinkBody.c_str();
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLinkText()
|
||||
{
|
||||
if (m_LinkText.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_LinkText.c_str();
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkString()
|
||||
{
|
||||
if (m_Link.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_Link;
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkBodyString()
|
||||
{
|
||||
if (m_LinkBody.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_LinkBody;
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkTextString()
|
||||
{
|
||||
if (m_LinkText.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_LinkText;
|
||||
}
|
||||
|
||||
void Client::TextLink::Reset()
|
||||
{
|
||||
m_LinkType = linkBlank;
|
||||
m_ItemData = nullptr;
|
||||
m_LootData = nullptr;
|
||||
m_ItemInst = nullptr;
|
||||
m_ProxyItemID = NOT_USED;
|
||||
m_ProxyText = nullptr;
|
||||
m_TaskUse = false;
|
||||
m_Link.clear();
|
||||
m_LinkBody.clear();
|
||||
m_LinkText.clear();
|
||||
m_ClientVersion = EQClientUnknown;
|
||||
m_Error = false;
|
||||
}
|
||||
|
||||
void Client::TextLink::generate_body()
|
||||
{
|
||||
enum { field_0 = 0, field_1, field_2, field_3, field_4, field_5, field_6, field_7, field_8, field_9, field_10, field_11, field_12, field_13 };
|
||||
static const int field_count = 14;
|
||||
static const bool field_use[_EQClientCount][field_count] = {
|
||||
// 6.2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X"
|
||||
// SoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
// RoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
// RoF2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
|
||||
//(RoF2) %01x %05x %05x %05x %05x %05x %05x %05x %01x %01x %04x %01x %05x %08x
|
||||
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true }, // EQClientUnknown
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClient6.2
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClientTitanium
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoF
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoD
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientUnderfoot
|
||||
{ true, true, true, true, true, true, true, true, false, true, true, true, true, true }, // EQClientRoF
|
||||
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true } // EQClientRoF2
|
||||
};
|
||||
|
||||
/*%01X*/ uint8 unknown_0 = NOT_USED;
|
||||
/*%05X*/ uint32 item_id = NOT_USED;
|
||||
/*%05X*/ uint32 augment_0 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_1 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_2 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_3 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_4 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_5 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_8 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_9 = NOT_USED;
|
||||
/*%04X*/ uint32 unknown_10 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_11 = NOT_USED;
|
||||
/*%05X*/ uint32 unknown_12 = NOT_USED;
|
||||
/*%08X*/ int hash = NOT_USED;
|
||||
|
||||
switch (m_LinkType) {
|
||||
case linkBlank:
|
||||
break;
|
||||
case linkItemData:
|
||||
if (m_ItemData != nullptr) {
|
||||
item_id = m_ItemData->ID;
|
||||
// TODO: add hash call
|
||||
}
|
||||
break;
|
||||
case linkLootItem:
|
||||
if (m_LootData != nullptr) {
|
||||
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data == nullptr) { break; }
|
||||
item_id = item_data->ID;
|
||||
augment_0 = m_LootData->aug_1;
|
||||
augment_1 = m_LootData->aug_2;
|
||||
augment_2 = m_LootData->aug_3;
|
||||
augment_3 = m_LootData->aug_4;
|
||||
augment_4 = m_LootData->aug_5;
|
||||
augment_5 = m_LootData->aug_6;
|
||||
// TODO: add hash call
|
||||
}
|
||||
break;
|
||||
case linkItemInst:
|
||||
if (m_ItemInst != nullptr) {
|
||||
if (m_ItemInst->GetItem() == nullptr) { break; }
|
||||
item_id = m_ItemInst->GetItem()->ID;
|
||||
augment_0 = m_ItemInst->GetAugmentItemID(0);
|
||||
augment_1 = m_ItemInst->GetAugmentItemID(1);
|
||||
augment_2 = m_ItemInst->GetAugmentItemID(2);
|
||||
augment_3 = m_ItemInst->GetAugmentItemID(3);
|
||||
augment_4 = m_ItemInst->GetAugmentItemID(4);
|
||||
augment_5 = m_ItemInst->GetAugmentItemID(5);
|
||||
// TODO: add hash call
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_ProxyItemID != NOT_USED) {
|
||||
item_id = m_ProxyItemID;
|
||||
}
|
||||
|
||||
if (m_TaskUse) {
|
||||
hash = 0x0000000014505DC2;
|
||||
}
|
||||
|
||||
if (field_use[m_ClientVersion][field_0]) { m_LinkBody.append(StringFormat("%01x", unknown_0)); }
|
||||
if (field_use[m_ClientVersion][field_1]) { m_LinkBody.append(StringFormat("%05x", item_id)); }
|
||||
if (field_use[m_ClientVersion][field_2]) { m_LinkBody.append(StringFormat("%05x", augment_0)); }
|
||||
if (field_use[m_ClientVersion][field_3]) { m_LinkBody.append(StringFormat("%05x", augment_1)); }
|
||||
if (field_use[m_ClientVersion][field_4]) { m_LinkBody.append(StringFormat("%05x", augment_2)); }
|
||||
if (field_use[m_ClientVersion][field_5]) { m_LinkBody.append(StringFormat("%05x", augment_3)); }
|
||||
if (field_use[m_ClientVersion][field_6]) { m_LinkBody.append(StringFormat("%05x", augment_4)); }
|
||||
if (field_use[m_ClientVersion][field_7]) { m_LinkBody.append(StringFormat("%05x", augment_5)); }
|
||||
if (field_use[m_ClientVersion][field_8]) { m_LinkBody.append(StringFormat("%01x", unknown_8)); }
|
||||
if (field_use[m_ClientVersion][field_9]) { m_LinkBody.append(StringFormat("%01x", unknown_9)); }
|
||||
if (field_use[m_ClientVersion][field_10]) { m_LinkBody.append(StringFormat("%04x", unknown_10)); }
|
||||
if (field_use[m_ClientVersion][field_11]) { m_LinkBody.append(StringFormat("%01x", unknown_11)); }
|
||||
if (field_use[m_ClientVersion][field_12]) { m_LinkBody.append(StringFormat("%05x", unknown_12)); }
|
||||
if (field_use[m_ClientVersion][field_13]) { m_LinkBody.append(StringFormat("%08x", hash)); }
|
||||
}
|
||||
|
||||
void Client::TextLink::generate_text()
|
||||
{
|
||||
if (m_ProxyText != nullptr) {
|
||||
m_LinkText = m_ProxyText;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_LinkType) {
|
||||
case linkBlank:
|
||||
break;
|
||||
case linkItemData:
|
||||
if (m_ItemData != nullptr) {
|
||||
m_LinkText = m_ItemData->Name;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case linkLootItem:
|
||||
if (m_LootData != nullptr) {
|
||||
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data != nullptr) {
|
||||
m_LinkText = item_data->Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case linkItemInst:
|
||||
if (m_ItemInst != nullptr) {
|
||||
if (m_ItemInst->GetItem() != nullptr) {
|
||||
m_LinkText = m_ItemInst->GetItem()->Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_LinkText = "null";
|
||||
}
|
||||
|
||||
@ -804,6 +804,7 @@ public:
|
||||
int32 GetAugmentIDAt(int16 slot_id, uint8 augslot);
|
||||
bool PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update = false);
|
||||
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
|
||||
void SendCursorBuffer();
|
||||
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
|
||||
bool SwapItem(MoveItem_Struct* move_in);
|
||||
void SwapItemResync(MoveItem_Struct* move_slots);
|
||||
@ -814,8 +815,57 @@ public:
|
||||
void SetStats(uint8 type,int16 set_val);
|
||||
void IncStats(uint8 type,int16 increase_val);
|
||||
void DropItem(int16 slot_id);
|
||||
bool MakeItemLink(char* &ret_link, const ItemInst* inst);
|
||||
int GetItemLinkHash(const ItemInst* inst);
|
||||
|
||||
//
|
||||
// class Client::TextLink
|
||||
//
|
||||
class TextLink {
|
||||
public:
|
||||
enum LinkType { linkBlank = 0, linkItemData, linkLootItem, linkItemInst };
|
||||
|
||||
TextLink() { Reset(); }
|
||||
|
||||
void SetLinkType(LinkType linkType) { m_LinkType = linkType; }
|
||||
void SetItemData(const Item_Struct* itemData) { m_ItemData = itemData; }
|
||||
void SetLootData(const ServerLootItem_Struct* lootData) { m_LootData = lootData; }
|
||||
void SetItemInst(const ItemInst* itemInst) { m_ItemInst = itemInst; }
|
||||
void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to
|
||||
void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use
|
||||
void SetTaskUse() { m_TaskUse = true; }
|
||||
void SetClientVersion(EQClientVersion clientVersion) { m_ClientVersion = EQLimits::ValidateClientVersion(clientVersion); }
|
||||
|
||||
std::string GenerateLink();
|
||||
bool LinkError() { return m_Error; }
|
||||
|
||||
const char* GetLink(); // contains full format: '/12x' '<LinkBody>' '<LinkText>' '/12x'
|
||||
const char* GetLinkBody(); // contains format: '<LinkBody>'
|
||||
const char* GetLinkText(); // contains format: '<LinkText>'
|
||||
std::string GetLinkString();
|
||||
std::string GetLinkBodyString();
|
||||
std::string GetLinkTextString();
|
||||
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
void generate_body();
|
||||
void generate_text();
|
||||
|
||||
int m_LinkType;
|
||||
const Item_Struct* m_ItemData;
|
||||
const ServerLootItem_Struct* m_LootData;
|
||||
const ItemInst* m_ItemInst;
|
||||
uint32 m_ProxyItemID;
|
||||
const char* m_ProxyText;
|
||||
bool m_TaskUse;
|
||||
std::string m_Link;
|
||||
std::string m_LinkBody;
|
||||
std::string m_LinkText;
|
||||
EQClientVersion m_ClientVersion;
|
||||
bool m_Error;
|
||||
};
|
||||
|
||||
int GetItemLinkHash(const ItemInst* inst); // move to Item_Struct..or make use of the pre-calculated database field
|
||||
|
||||
void SendItemLink(const ItemInst* inst, bool sendtoall=false);
|
||||
void SendLootItemInPacket(const ItemInst* inst, int16 slot_id);
|
||||
void SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type);
|
||||
@ -832,11 +882,11 @@ public:
|
||||
|
||||
bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;}
|
||||
bool Thirsty() const {if (GetGM()) return false; return m_pp.thirst_level <= 3000;}
|
||||
int32 GetHunger() const { return m_pp.hunger_level; }
|
||||
int32 GetThirst() const { return m_pp.thirst_level; }
|
||||
void SetHunger(int32 in_hunger);
|
||||
void SetThirst(int32 in_thirst);
|
||||
void SetConsumption(int32 in_hunger, int32 in_thirst);
|
||||
int32 GetHunger() const { return m_pp.hunger_level; }
|
||||
int32 GetThirst() const { return m_pp.thirst_level; }
|
||||
void SetHunger(int32 in_hunger);
|
||||
void SetThirst(int32 in_thirst);
|
||||
void SetConsumption(int32 in_hunger, int32 in_thirst);
|
||||
|
||||
bool CheckTradeLoreConflict(Client* other);
|
||||
void LinkDead();
|
||||
@ -937,7 +987,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst);
|
||||
inline bool IsTaskActive(int TaskID) { return (taskstate ? taskstate->IsTaskActive(TaskID) : false); }
|
||||
inline bool IsTaskActivityActive(int TaskID, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityActive(TaskID, ActivityID) : false); }
|
||||
inline ActivityState GetTaskActivityState(int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(index, ActivityID) : ActivityHidden); }
|
||||
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count) { if(taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count); }
|
||||
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count, bool ignore_quest_update = false) { if (taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count, ignore_quest_update); }
|
||||
inline void ResetTaskActivity(int TaskID, int ActivityID) { if(taskstate) taskstate->ResetTaskActivity(this, TaskID, ActivityID); }
|
||||
inline void UpdateTasksOnKill(int NPCTypeID) { if(taskstate) taskstate->UpdateTasksOnKill(this, NPCTypeID); }
|
||||
inline void UpdateTasksForItem(ActivityType Type, int ItemID, int Count=1) { if(taskstate) taskstate->UpdateTasksForItem(this, Type, ItemID, Count); }
|
||||
|
||||
@ -1364,7 +1364,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
database.LoadCharacterFactionValues(cid, factionvalues);
|
||||
|
||||
/* Load Character Account Data: Temp until I move */
|
||||
query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme` FROM `account` WHERE `id` = %u", this->AccountID());
|
||||
query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme`, `time_creation` FROM `account` WHERE `id` = %u", this->AccountID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
admin = atoi(row[0]);
|
||||
@ -1373,7 +1373,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
gmspeed = atoi(row[3]);
|
||||
revoked = atoi(row[4]);
|
||||
gmhideme = atoi(row[5]);
|
||||
if (account_creation){ account_creation = atoul(row[6]); }
|
||||
account_creation = atoul(row[6]);
|
||||
}
|
||||
|
||||
/* Load Character Data */
|
||||
@ -1388,7 +1388,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
|
||||
if (LFP){ LFP = atoi(row[0]); }
|
||||
if (LFG){ LFG = atoi(row[1]); }
|
||||
if (firstlogon){ firstlogon = atoi(row[3]); }
|
||||
if (row[3])
|
||||
firstlogon = atoi(row[3]);
|
||||
}
|
||||
|
||||
if (RuleB(Character, SharedBankPlat))
|
||||
@ -3090,7 +3091,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
// Adding augment
|
||||
if (in_augment->augment_action == 0)
|
||||
{
|
||||
ItemInst *tobe_auged, *auged_with = nullptr;
|
||||
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
|
||||
int8 slot = -1;
|
||||
Inventory& user_inv = GetInv();
|
||||
|
||||
@ -3160,7 +3161,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (in_augment->augment_action == 1)
|
||||
{
|
||||
ItemInst *tobe_auged, *auged_with = nullptr;
|
||||
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
|
||||
int8 slot = -1;
|
||||
Inventory& user_inv = GetInv();
|
||||
|
||||
@ -5258,7 +5259,7 @@ void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app)
|
||||
entity_list.QueueClients(this, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
hate_list.RemoveEnt(this->CastToMob());
|
||||
hate_list.RemoveEntFromHateList(this->CastToMob());
|
||||
|
||||
Disconnect();
|
||||
return;
|
||||
@ -7009,37 +7010,28 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
|
||||
|
||||
if (!CursorItem->NoDrop || CursorItemInst->IsAttuned())
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
|
||||
Allowed = false;
|
||||
}
|
||||
else if (CursorItemInst->IsNoneEmptyContainer())
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
|
||||
Allowed = false;
|
||||
}
|
||||
else if (CursorItemInst->IsAugmented())
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
|
||||
Allowed = false;
|
||||
}
|
||||
else if (CursorItem->NoRent == 0)
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
|
||||
Allowed = false;
|
||||
}
|
||||
else if (CursorItem->LoreFlag && GuildBanks->HasItem(GuildID(), CursorItem->ID))
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
|
||||
Allowed = false;
|
||||
}
|
||||
|
||||
if (!Allowed)
|
||||
{
|
||||
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
|
||||
GuildBankDepositAck(true);
|
||||
|
||||
return;
|
||||
@ -9210,12 +9202,6 @@ void Client::Handle_OP_LootItem(const EQApplicationPacket *app)
|
||||
LogFile->write(EQEMuLog::Error, "Wrong size: OP_LootItem, size=%i, expected %i", app->size, sizeof(LootingItem_Struct));
|
||||
return;
|
||||
}
|
||||
/*
|
||||
** fixed the looting code so that it sends the correct opcodes
|
||||
** and now correctly removes the looted item the player selected
|
||||
** as well as gives the player the proper item.
|
||||
** Also fixed a few UI lock ups that would occur.
|
||||
*/
|
||||
|
||||
EQApplicationPacket* outapp = 0;
|
||||
Entity* entity = entity_list.GetID(*((uint16*)app->pBuffer));
|
||||
@ -9802,7 +9788,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
// Illegal bagslot useage checks. Currently, user only receives a message if this check is triggered.
|
||||
// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
|
||||
bool mi_hack = false;
|
||||
|
||||
if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
|
||||
@ -9825,7 +9811,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessable bag slots!"); }
|
||||
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
|
||||
|
||||
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
|
||||
SwapItemResync(mi);
|
||||
@ -12361,22 +12347,30 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
int freeslot = 0;
|
||||
if (charges > 0 && (freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0){
|
||||
ItemInst* inst2 = inst->Clone();
|
||||
if (RuleB(Merchant, UsePriceMod)){
|
||||
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false));
|
||||
|
||||
while (true) {
|
||||
if (inst2 == nullptr)
|
||||
break;
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)){
|
||||
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false));
|
||||
}
|
||||
else
|
||||
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate);
|
||||
inst2->SetMerchantSlot(freeslot);
|
||||
|
||||
uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot);
|
||||
|
||||
if (inst2->IsStackable()) {
|
||||
inst2->SetCharges(MerchantQuantity);
|
||||
}
|
||||
inst2->SetMerchantCount(MerchantQuantity);
|
||||
|
||||
SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant);
|
||||
safe_delete(inst2);
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate);
|
||||
inst2->SetMerchantSlot(freeslot);
|
||||
|
||||
uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot);
|
||||
|
||||
if (inst2->IsStackable()) {
|
||||
inst2->SetCharges(MerchantQuantity);
|
||||
}
|
||||
inst2->SetMerchantCount(MerchantQuantity);
|
||||
|
||||
SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant);
|
||||
safe_delete(inst2);
|
||||
}
|
||||
|
||||
// start QS code
|
||||
|
||||
1003
zone/command.cpp
1003
zone/command.cpp
File diff suppressed because it is too large
Load Diff
@ -135,7 +135,8 @@ enum {
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
MAX_SPECIAL_ATTACK = 43
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
MAX_SPECIAL_ATTACK = 44
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
|
||||
@ -1214,7 +1214,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
||||
parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);
|
||||
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
|
||||
|
||||
if ((RuleB(Character, EnableDiscoveredItems))) {
|
||||
if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) {
|
||||
if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
|
||||
client->DiscoverItem(inst->GetItem()->ID);
|
||||
}
|
||||
@ -1261,33 +1261,38 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
||||
}
|
||||
}
|
||||
|
||||
if (GetPlayerKillItem() != -1){
|
||||
if (GetPlayerKillItem() != -1) {
|
||||
SetPlayerKillItemID(0);
|
||||
}
|
||||
|
||||
/* Send message with item link to groups and such */
|
||||
char *link = 0, *link2 = 0; //just like a db query :-)
|
||||
client->MakeItemLink(link2, inst);
|
||||
MakeAnyLenString(&link, "%c" "%s" "%s" "%c",
|
||||
0x12,
|
||||
link2,
|
||||
item->Name,
|
||||
0x12);
|
||||
safe_delete_array(link2);
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
linker.SetClientVersion(client->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link);
|
||||
if(!IsPlayerCorpse()) {
|
||||
// When sending to multiple/unknown client types, we set for the highest client..
|
||||
// ..which is processed when 'EQClientUnknown,' or default value, is selected.
|
||||
// This should help with any current issues..or it may create more! O.o
|
||||
linker.SetClientVersion(EQClientUnknown);
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
Group *g = client->GetGroup();
|
||||
if(g != nullptr) {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
|
||||
} else {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
|
||||
}
|
||||
else {
|
||||
Raid *r = client->GetRaid();
|
||||
if(r != nullptr) {
|
||||
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
|
||||
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_delete_array(link);
|
||||
}
|
||||
else {
|
||||
SendEndLootErrorPacket(client);
|
||||
|
||||
@ -232,6 +232,7 @@ int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::stri
|
||||
|
||||
int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
// needs pointer validation on 'item' argument
|
||||
return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers);
|
||||
}
|
||||
|
||||
@ -335,6 +336,9 @@ bool PerlembParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
|
||||
if(!perl)
|
||||
return false;
|
||||
|
||||
if (itm == nullptr)
|
||||
return false;
|
||||
|
||||
if(evt >= _LargestEventID)
|
||||
return false;
|
||||
|
||||
@ -449,6 +453,9 @@ void PerlembParser::LoadGlobalPlayerScript(std::string filename) {
|
||||
}
|
||||
|
||||
void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) {
|
||||
if (item == nullptr)
|
||||
return;
|
||||
|
||||
std::stringstream package_name;
|
||||
package_name << "qst_item_" << item->GetID();
|
||||
|
||||
@ -855,6 +862,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye
|
||||
}
|
||||
}
|
||||
else if(isItemQuest) {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
const Item_Struct* item = iteminst->GetItem();
|
||||
package_name = "qst_item_";
|
||||
package_name += itoa(item->ID);
|
||||
@ -1292,6 +1300,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_SCALE_CALC:
|
||||
case EVENT_ITEM_ENTER_ZONE: {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
break;
|
||||
@ -1299,6 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_ITEM_CLICK_CAST:
|
||||
case EVENT_ITEM_CLICK: {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
|
||||
@ -2277,18 +2277,20 @@ XS(XS__updatetaskactivity);
|
||||
XS(XS__updatetaskactivity)
|
||||
{
|
||||
dXSARGS;
|
||||
unsigned int task, activity;
|
||||
unsigned int task, activity, ignore_quest_update;
|
||||
int count = 1;
|
||||
ignore_quest_update = 0;
|
||||
if(items == 2) {
|
||||
task = (int)SvIV(ST(0));
|
||||
activity = (int)SvIV(ST(1));
|
||||
quest_manager.updatetaskactivity(task, activity, count);
|
||||
quest_manager.updatetaskactivity(task, activity, count, false);
|
||||
}
|
||||
else if(items == 3) {
|
||||
task = (int)SvIV(ST(0));
|
||||
activity = (int)SvIV(ST(1));
|
||||
count = (int)SvIV(ST(2));
|
||||
quest_manager.updatetaskactivity(task, activity, count);
|
||||
bool ignore_quest_update = (bool)SvTRUE(ST(3));
|
||||
quest_manager.updatetaskactivity(task, activity, count, ignore_quest_update);
|
||||
} else {
|
||||
Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity [,count])");
|
||||
}
|
||||
|
||||
@ -210,6 +210,8 @@ Embperl::~Embperl()
|
||||
" if(tied *STDERR) { untie(*STDERR); }"
|
||||
,FALSE);
|
||||
#endif
|
||||
PL_perl_destruct_level = 1;
|
||||
perl_destruct(my_perl);
|
||||
perl_free(my_perl);
|
||||
PERL_SYS_TERM();
|
||||
my_perl = NULL;
|
||||
|
||||
@ -2043,13 +2043,16 @@ void EntityList::RemoveAllNPCs()
|
||||
|
||||
void EntityList::RemoveAllMercs()
|
||||
{
|
||||
// doesn't clear the data
|
||||
merc_list.clear();
|
||||
}
|
||||
|
||||
void EntityList::RemoveAllGroups()
|
||||
{
|
||||
while (group_list.size())
|
||||
while (group_list.size()) {
|
||||
safe_delete(group_list.front());
|
||||
group_list.pop_front();
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
@ -2057,8 +2060,10 @@ void EntityList::RemoveAllGroups()
|
||||
|
||||
void EntityList::RemoveAllRaids()
|
||||
{
|
||||
while (raid_list.size())
|
||||
while (raid_list.size()) {
|
||||
safe_delete(raid_list.front());
|
||||
raid_list.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::RemoveAllDoors()
|
||||
@ -2268,7 +2273,8 @@ bool EntityList::RemoveGroup(uint32 delete_id)
|
||||
while(iterator != group_list.end())
|
||||
{
|
||||
if((*iterator)->GetID() == delete_id) {
|
||||
group_list.remove (*iterator);
|
||||
safe_delete(*iterator);
|
||||
group_list.remove(*iterator);
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
@ -2291,7 +2297,8 @@ bool EntityList::RemoveRaid(uint32 delete_id)
|
||||
while(iterator != raid_list.end())
|
||||
{
|
||||
if((*iterator)->GetID() == delete_id) {
|
||||
raid_list.remove (*iterator);
|
||||
safe_delete(*iterator);
|
||||
raid_list.remove(*iterator);
|
||||
return true;
|
||||
}
|
||||
++iterator;
|
||||
@ -2462,7 +2469,7 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
|
||||
if (!settoone)
|
||||
it->second->RemoveFromHateList(mob);
|
||||
else
|
||||
it->second->SetHate(mob, 1);
|
||||
it->second->SetHateAmountOnEnt(mob, 1);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
@ -2846,7 +2853,7 @@ void EntityList::DoubleAggro(Mob *who)
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
if (it->second->CheckAggro(who))
|
||||
it->second->SetHate(who, it->second->CastToNPC()->GetHateAmount(who),
|
||||
it->second->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who),
|
||||
it->second->CastToNPC()->GetHateAmount(who) * 2);
|
||||
++it;
|
||||
}
|
||||
@ -2857,7 +2864,7 @@ void EntityList::HalveAggro(Mob *who)
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
if (it->second->CastToNPC()->CheckAggro(who))
|
||||
it->second->CastToNPC()->SetHate(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
|
||||
it->second->CastToNPC()->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@ -2872,9 +2879,9 @@ void EntityList::Evade(Mob *who)
|
||||
amt = it->second->CastToNPC()->GetHateAmount(who);
|
||||
amt -= flatval;
|
||||
if (amt > 0)
|
||||
it->second->CastToNPC()->SetHate(who, amt);
|
||||
it->second->CastToNPC()->SetHateAmountOnEnt(who, amt);
|
||||
else
|
||||
it->second->CastToNPC()->SetHate(who, 0);
|
||||
it->second->CastToNPC()->SetHateAmountOnEnt(who, 0);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
@ -2942,7 +2949,7 @@ void EntityList::ClearZoneFeignAggro(Client *targ)
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::AggroZone(Mob *who, int hate)
|
||||
void EntityList::AggroZone(Mob *who, uint32 hate)
|
||||
{
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
@ -2963,11 +2970,6 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id)
|
||||
}
|
||||
}
|
||||
|
||||
bool tracking_compare(const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b)
|
||||
{
|
||||
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
|
||||
}
|
||||
|
||||
bool EntityList::MakeTrackPacket(Client *client)
|
||||
{
|
||||
std::list<std::pair<Mob *, float> > tracking_list;
|
||||
@ -2985,8 +2987,6 @@ bool EntityList::MakeTrackPacket(Client *client)
|
||||
if (distance < 300)
|
||||
distance = 300;
|
||||
|
||||
Group *g = client->GetGroup();
|
||||
|
||||
for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) {
|
||||
if (!it->second || it->second == client || !it->second->IsTrackable() ||
|
||||
it->second->IsInvisible(client))
|
||||
@ -2999,7 +2999,10 @@ bool EntityList::MakeTrackPacket(Client *client)
|
||||
tracking_list.push_back(std::make_pair(it->second, MobDistance));
|
||||
}
|
||||
|
||||
tracking_list.sort(tracking_compare);
|
||||
tracking_list.sort(
|
||||
[](const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b) {
|
||||
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
|
||||
});
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size());
|
||||
Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer;
|
||||
outapp->priority = 6;
|
||||
@ -3007,15 +3010,13 @@ bool EntityList::MakeTrackPacket(Client *client)
|
||||
int index = 0;
|
||||
for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) {
|
||||
Mob *cur_entity = it->first;
|
||||
outtrack->Entrys[index].entityid = cur_entity->GetID();
|
||||
outtrack->Entrys[index].entityid = (uint32)cur_entity->GetID();
|
||||
outtrack->Entrys[index].distance = it->second;
|
||||
outtrack->Entrys[index].level = cur_entity->GetLevel();
|
||||
outtrack->Entrys[index].NPC = !cur_entity->IsClient();
|
||||
if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob()))
|
||||
outtrack->Entrys[index].GroupMember = 1;
|
||||
else
|
||||
outtrack->Entrys[index].GroupMember = 0;
|
||||
outtrack->Entrys[index].is_npc = !cur_entity->IsClient();
|
||||
strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name));
|
||||
outtrack->Entrys[index].is_pet = cur_entity->IsPet();
|
||||
outtrack->Entrys[index].is_merc = cur_entity->IsMerc();
|
||||
}
|
||||
|
||||
client->QueuePacket(outapp);
|
||||
@ -3681,7 +3682,7 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
|
||||
if (n->GetSwarmInfo()) {
|
||||
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
||||
if (!n->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
n->hate_list.Add(other, 0, 0, bFrenzy);
|
||||
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
|
||||
@ -355,7 +355,7 @@ public:
|
||||
void ClearAggro(Mob* targ);
|
||||
void ClearFeignAggro(Mob* targ);
|
||||
void ClearZoneFeignAggro(Client* targ);
|
||||
void AggroZone(Mob* who, int hate = 0);
|
||||
void AggroZone(Mob* who, uint32 hate = 0);
|
||||
|
||||
bool Fighting(Mob* targ);
|
||||
void RemoveFromHateLists(Mob* mob, bool settoone = false);
|
||||
|
||||
@ -249,7 +249,7 @@ void Client::GoFish()
|
||||
Bait = m_inv.GetItem(bslot);
|
||||
|
||||
//if the bait isnt equipped, need to add its skill bonus
|
||||
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) {
|
||||
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == SkillFishing) {
|
||||
fishing_skill += Bait->GetItem()->SkillModValue;
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +122,8 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
|
||||
uint32 i;
|
||||
uint8 membercount = 0;
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (members[i] != nullptr) {
|
||||
// Don't split with Mercs or Bots
|
||||
if (members[i] != nullptr && members[i]->IsClient()) {
|
||||
membercount++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
@ -36,7 +36,7 @@ extern Zone *zone;
|
||||
|
||||
HateList::HateList()
|
||||
{
|
||||
owner = nullptr;
|
||||
hate_owner = nullptr;
|
||||
}
|
||||
|
||||
HateList::~HateList()
|
||||
@ -45,29 +45,29 @@ HateList::~HateList()
|
||||
|
||||
// added for frenzy support
|
||||
// checks if target still is in frenzy mode
|
||||
void HateList::CheckFrenzyHate()
|
||||
void HateList::IsEntityInFrenzyMode()
|
||||
{
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
if ((*iterator)->ent->GetHPRatio() >= 20)
|
||||
(*iterator)->bFrenzy = false;
|
||||
if ((*iterator)->entity_on_hatelist->GetHPRatio() >= 20)
|
||||
(*iterator)->is_entity_frenzy = false;
|
||||
++iterator;
|
||||
}
|
||||
}
|
||||
|
||||
void HateList::Wipe()
|
||||
void HateList::WipeHateList()
|
||||
{
|
||||
auto iterator = list.begin();
|
||||
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
Mob* m = (*iterator)->ent;
|
||||
if(m)
|
||||
Mob* m = (*iterator)->entity_on_hatelist;
|
||||
if (m)
|
||||
{
|
||||
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), m, "0", 0);
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
|
||||
|
||||
if(m->IsClient())
|
||||
if (m->IsClient())
|
||||
m->CastToClient()->DecrementAggroCount();
|
||||
}
|
||||
delete (*iterator);
|
||||
@ -76,38 +76,38 @@ void HateList::Wipe()
|
||||
}
|
||||
}
|
||||
|
||||
bool HateList::IsOnHateList(Mob *mob)
|
||||
bool HateList::IsEntOnHateList(Mob *mob)
|
||||
{
|
||||
if(Find(mob))
|
||||
if (Find(mob))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
tHateEntry *HateList::Find(Mob *ent)
|
||||
struct_HateList *HateList::Find(Mob *in_entity)
|
||||
{
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
if((*iterator)->ent == ent)
|
||||
if ((*iterator)->entity_on_hatelist == in_entity)
|
||||
return (*iterator);
|
||||
++iterator;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HateList::Set(Mob* other, uint32 in_hate, uint32 in_dam)
|
||||
void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage)
|
||||
{
|
||||
tHateEntry *p = Find(other);
|
||||
if(p)
|
||||
struct_HateList *entity = Find(other);
|
||||
if (entity)
|
||||
{
|
||||
if(in_dam > 0)
|
||||
p->damage = in_dam;
|
||||
if(in_hate > 0)
|
||||
p->hate = in_hate;
|
||||
if (in_damage > 0)
|
||||
entity->hatelist_damage = in_damage;
|
||||
if (in_hate > 0)
|
||||
entity->stored_hate_amount = in_hate;
|
||||
}
|
||||
}
|
||||
|
||||
Mob* HateList::GetDamageTop(Mob* hater)
|
||||
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
|
||||
{
|
||||
Mob* current = nullptr;
|
||||
Group* grp = nullptr;
|
||||
@ -115,119 +115,117 @@ Mob* HateList::GetDamageTop(Mob* hater)
|
||||
uint32 dmg_amt = 0;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
grp = nullptr;
|
||||
r = nullptr;
|
||||
|
||||
if((*iterator)->ent && (*iterator)->ent->IsClient()){
|
||||
r = entity_list.GetRaidByClient((*iterator)->ent->CastToClient());
|
||||
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){
|
||||
r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient());
|
||||
}
|
||||
|
||||
grp = entity_list.GetGroupByMob((*iterator)->ent);
|
||||
grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist);
|
||||
|
||||
if((*iterator)->ent && r){
|
||||
if(r->GetTotalRaidDamage(hater) >= dmg_amt)
|
||||
if ((*iterator)->entity_on_hatelist && r){
|
||||
if (r->GetTotalRaidDamage(hater) >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->ent;
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = r->GetTotalRaidDamage(hater);
|
||||
}
|
||||
}
|
||||
else if ((*iterator)->ent != nullptr && grp != nullptr)
|
||||
else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr)
|
||||
{
|
||||
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->ent;
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = grp->GetTotalGroupDamage(hater);
|
||||
}
|
||||
}
|
||||
else if ((*iterator)->ent != nullptr && (uint32)(*iterator)->damage >= dmg_amt)
|
||||
else if ((*iterator)->entity_on_hatelist != nullptr && (uint32)(*iterator)->hatelist_damage >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->ent;
|
||||
dmg_amt = (*iterator)->damage;
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = (*iterator)->hatelist_damage;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
Mob* HateList::GetClosest(Mob *hater) {
|
||||
Mob* close = nullptr;
|
||||
float closedist = 99999.9f;
|
||||
float thisdist;
|
||||
Mob* HateList::GetClosestEntOnHateList(Mob *hater) {
|
||||
Mob* close_entity = nullptr;
|
||||
float close_distance = 99999.9f;
|
||||
float this_distance;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end()) {
|
||||
thisdist = (*iterator)->ent->DistNoRootNoZ(*hater);
|
||||
if((*iterator)->ent != nullptr && thisdist <= closedist) {
|
||||
closedist = thisdist;
|
||||
close = (*iterator)->ent;
|
||||
while (iterator != list.end()) {
|
||||
this_distance = (*iterator)->entity_on_hatelist->DistNoRootNoZ(*hater);
|
||||
if ((*iterator)->entity_on_hatelist != nullptr && this_distance <= close_distance) {
|
||||
close_distance = this_distance;
|
||||
close_entity = (*iterator)->entity_on_hatelist;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
|
||||
if ((!close && hater->IsNPC()) || (close && close->DivineAura()))
|
||||
close = hater->CastToNPC()->GetHateTop();
|
||||
if ((!close_entity && hater->IsNPC()) || (close_entity && close_entity->DivineAura()))
|
||||
close_entity = hater->CastToNPC()->GetHateTop();
|
||||
|
||||
return close;
|
||||
return close_entity;
|
||||
}
|
||||
|
||||
|
||||
// a few comments added, rearranged code for readability
|
||||
void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAddIfNotExist)
|
||||
void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, bool in_is_entity_frenzied, bool iAddIfNotExist)
|
||||
{
|
||||
if(!ent)
|
||||
if (!in_entity)
|
||||
return;
|
||||
|
||||
if(ent->IsCorpse())
|
||||
if (in_entity->IsCorpse())
|
||||
return;
|
||||
|
||||
if(ent->IsClient() && ent->CastToClient()->IsDead())
|
||||
if (in_entity->IsClient() && in_entity->CastToClient()->IsDead())
|
||||
return;
|
||||
|
||||
tHateEntry *p = Find(ent);
|
||||
if (p)
|
||||
struct_HateList *entity = Find(in_entity);
|
||||
if (entity)
|
||||
{
|
||||
p->damage+=(in_dam>=0)?in_dam:0;
|
||||
p->hate+=in_hate;
|
||||
p->bFrenzy = bFrenzy;
|
||||
entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0;
|
||||
entity->stored_hate_amount += in_hate;
|
||||
entity->is_entity_frenzy = in_is_entity_frenzied;
|
||||
}
|
||||
else if (iAddIfNotExist) {
|
||||
p = new tHateEntry;
|
||||
p->ent = ent;
|
||||
p->damage = (in_dam>=0)?in_dam:0;
|
||||
p->hate = in_hate;
|
||||
p->bFrenzy = bFrenzy;
|
||||
list.push_back(p);
|
||||
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0);
|
||||
entity = new struct_HateList;
|
||||
entity->entity_on_hatelist = in_entity;
|
||||
entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0;
|
||||
entity->stored_hate_amount = in_hate;
|
||||
entity->is_entity_frenzy = in_is_entity_frenzied;
|
||||
list.push_back(entity);
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0);
|
||||
|
||||
if (ent->IsClient()) {
|
||||
if (owner->CastToNPC()->IsRaidTarget())
|
||||
ent->CastToClient()->SetEngagedRaidTarget(true);
|
||||
ent->CastToClient()->IncrementAggroCount();
|
||||
if (in_entity->IsClient()) {
|
||||
if (hate_owner->CastToNPC()->IsRaidTarget())
|
||||
in_entity->CastToClient()->SetEngagedRaidTarget(true);
|
||||
in_entity->CastToClient()->IncrementAggroCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HateList::RemoveEnt(Mob *ent)
|
||||
bool HateList::RemoveEntFromHateList(Mob *in_entity)
|
||||
{
|
||||
if (!ent)
|
||||
if (!in_entity)
|
||||
return false;
|
||||
|
||||
bool found = false;
|
||||
bool is_found = false;
|
||||
auto iterator = list.begin();
|
||||
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
if((*iterator)->ent == ent)
|
||||
if ((*iterator)->entity_on_hatelist == in_entity)
|
||||
{
|
||||
if(ent)
|
||||
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "0", 0);
|
||||
found = true;
|
||||
if (in_entity)
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
|
||||
is_found = true;
|
||||
|
||||
|
||||
if(ent && ent->IsClient())
|
||||
ent->CastToClient()->DecrementAggroCount();
|
||||
|
||||
if (in_entity && in_entity->IsClient())
|
||||
in_entity->CastToClient()->DecrementAggroCount();
|
||||
|
||||
delete (*iterator);
|
||||
iterator = list.erase(iterator);
|
||||
@ -236,123 +234,127 @@ bool HateList::RemoveEnt(Mob *ent)
|
||||
else
|
||||
++iterator;
|
||||
}
|
||||
return found;
|
||||
return is_found;
|
||||
}
|
||||
|
||||
void HateList::DoFactionHits(int32 nfl_id) {
|
||||
if (nfl_id <= 0)
|
||||
void HateList::DoFactionHits(int32 npc_faction_level_id) {
|
||||
if (npc_faction_level_id <= 0)
|
||||
return;
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
Client *p;
|
||||
Client *client;
|
||||
|
||||
if ((*iterator)->ent && (*iterator)->ent->IsClient())
|
||||
p = (*iterator)->ent->CastToClient();
|
||||
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient())
|
||||
client = (*iterator)->entity_on_hatelist->CastToClient();
|
||||
else
|
||||
p = nullptr;
|
||||
client = nullptr;
|
||||
|
||||
if (p)
|
||||
p->SetFactionLevel(p->CharacterID(), nfl_id, p->GetBaseClass(), p->GetBaseRace(), p->GetDeity());
|
||||
if (client)
|
||||
client->SetFactionLevel(client->CharacterID(), npc_faction_level_id, client->GetBaseClass(), client->GetBaseRace(), client->GetDeity());
|
||||
++iterator;
|
||||
}
|
||||
}
|
||||
|
||||
int HateList::SummonedPetCount(Mob *hater) {
|
||||
int HateList::GetSummonedPetCountOnHateList(Mob *hater) {
|
||||
|
||||
//Function to get number of 'Summoned' pets on a targets hate list to allow calculations for certian spell effects.
|
||||
//Unclear from description that pets are required to be 'summoned body type'. Will not require at this time.
|
||||
int petcount = 0;
|
||||
int pet_count = 0;
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end()) {
|
||||
while (iterator != list.end()) {
|
||||
|
||||
if((*iterator)->ent != nullptr && (*iterator)->ent->IsNPC() && ((*iterator)->ent->CastToNPC()->IsPet() || ((*iterator)->ent->CastToNPC()->GetSwarmOwner() > 0)))
|
||||
if ((*iterator)->entity_on_hatelist != nullptr && (*iterator)->entity_on_hatelist->IsNPC() && ((*iterator)->entity_on_hatelist->CastToNPC()->IsPet() || ((*iterator)->entity_on_hatelist->CastToNPC()->GetSwarmOwner() > 0)))
|
||||
{
|
||||
++petcount;
|
||||
++pet_count;
|
||||
}
|
||||
|
||||
|
||||
++iterator;
|
||||
}
|
||||
|
||||
return petcount;
|
||||
return pet_count;
|
||||
}
|
||||
|
||||
Mob *HateList::GetTop(Mob *center)
|
||||
Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
||||
{
|
||||
Mob* top = nullptr;
|
||||
int32 hate = -1;
|
||||
|
||||
if(center == nullptr)
|
||||
// hack fix for zone shutdown crashes on some servers
|
||||
if (!zone->IsLoaded())
|
||||
return nullptr;
|
||||
|
||||
if (RuleB(Aggro,SmartAggroList)){
|
||||
Mob* topClientTypeInRange = nullptr;
|
||||
int32 hateClientTypeInRange = -1;
|
||||
Mob* top_hate = nullptr;
|
||||
int32 hate = -1;
|
||||
|
||||
if (center == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (RuleB(Aggro, SmartAggroList)){
|
||||
Mob* top_client_type_in_range = nullptr;
|
||||
int32 hate_client_type_in_range = -1;
|
||||
int skipped_count = 0;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *cur = (*iterator);
|
||||
int16 aggroMod = 0;
|
||||
struct_HateList *cur = (*iterator);
|
||||
int16 aggro_mod = 0;
|
||||
|
||||
if(!cur){
|
||||
if (!cur){
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!cur->ent){
|
||||
if (!cur->entity_on_hatelist){
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
|
||||
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) {
|
||||
skipped_count++;
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur->ent->Sanctuary()) {
|
||||
if(hate == -1)
|
||||
if (cur->entity_on_hatelist->Sanctuary()) {
|
||||
if (hate == -1)
|
||||
{
|
||||
top = cur->ent;
|
||||
top_hate = cur->entity_on_hatelist;
|
||||
hate = 1;
|
||||
}
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){
|
||||
if(hate == -1)
|
||||
if (cur->entity_on_hatelist->DivineAura() || cur->entity_on_hatelist->IsMezzed() || cur->entity_on_hatelist->IsFeared()){
|
||||
if (hate == -1)
|
||||
{
|
||||
top = cur->ent;
|
||||
top_hate = cur->entity_on_hatelist;
|
||||
hate = 0;
|
||||
}
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 currentHate = cur->hate;
|
||||
int32 current_hate = cur->stored_hate_amount;
|
||||
|
||||
if(cur->ent->IsClient()){
|
||||
if (cur->entity_on_hatelist->IsClient()){
|
||||
|
||||
if(cur->ent->CastToClient()->IsSitting()){
|
||||
aggroMod += RuleI(Aggro, SittingAggroMod);
|
||||
if (cur->entity_on_hatelist->CastToClient()->IsSitting()){
|
||||
aggro_mod += RuleI(Aggro, SittingAggroMod);
|
||||
}
|
||||
|
||||
if(center){
|
||||
if(center->GetTarget() == cur->ent)
|
||||
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
|
||||
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
|
||||
if (center){
|
||||
if (center->GetTarget() == cur->entity_on_hatelist)
|
||||
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
|
||||
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
|
||||
{
|
||||
if(center->CombatRange(cur->ent)){
|
||||
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
|
||||
if (center->CombatRange(cur->entity_on_hatelist)){
|
||||
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
|
||||
|
||||
if(currentHate > hateClientTypeInRange || cur->bFrenzy){
|
||||
hateClientTypeInRange = currentHate;
|
||||
topClientTypeInRange = cur->ent;
|
||||
if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy){
|
||||
hate_client_type_in_range = current_hate;
|
||||
top_client_type_in_range = cur->entity_on_hatelist;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,112 +362,112 @@ Mob *HateList::GetTop(Mob *center)
|
||||
|
||||
}
|
||||
else{
|
||||
if(center){
|
||||
if(center->GetTarget() == cur->ent)
|
||||
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
|
||||
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
|
||||
if (center){
|
||||
if (center->GetTarget() == cur->entity_on_hatelist)
|
||||
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
|
||||
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
|
||||
{
|
||||
if(center->CombatRange(cur->ent)){
|
||||
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
|
||||
if (center->CombatRange(cur->entity_on_hatelist)){
|
||||
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cur->ent->GetMaxHP() != 0 && ((cur->ent->GetHP()*100/cur->ent->GetMaxHP()) < 20)){
|
||||
aggroMod += RuleI(Aggro, CriticallyWoundedAggroMod);
|
||||
if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){
|
||||
aggro_mod += RuleI(Aggro, CriticallyWoundedAggroMod);
|
||||
}
|
||||
|
||||
if(aggroMod){
|
||||
currentHate += (currentHate * aggroMod / 100);
|
||||
if (aggro_mod){
|
||||
current_hate += (current_hate * aggro_mod / 100);
|
||||
}
|
||||
|
||||
if(currentHate > hate || cur->bFrenzy){
|
||||
hate = currentHate;
|
||||
top = cur->ent;
|
||||
if (current_hate > hate || cur->is_entity_frenzy){
|
||||
hate = current_hate;
|
||||
top_hate = cur->entity_on_hatelist;
|
||||
}
|
||||
|
||||
++iterator;
|
||||
}
|
||||
|
||||
if(topClientTypeInRange != nullptr && top != nullptr) {
|
||||
bool isTopClientType = top->IsClient();
|
||||
if (top_client_type_in_range != nullptr && top_hate != nullptr) {
|
||||
bool isTopClientType = top_hate->IsClient();
|
||||
#ifdef BOTS
|
||||
if(!isTopClientType) {
|
||||
if(top->IsBot()) {
|
||||
if (!isTopClientType) {
|
||||
if (top_hate->IsBot()) {
|
||||
isTopClientType = true;
|
||||
topClientTypeInRange = top;
|
||||
top_client_type_in_range = top_hate;
|
||||
}
|
||||
}
|
||||
#endif //BOTS
|
||||
|
||||
if(!isTopClientType) {
|
||||
if(top->IsMerc()) {
|
||||
if (!isTopClientType) {
|
||||
if (top_hate->IsMerc()) {
|
||||
isTopClientType = true;
|
||||
topClientTypeInRange = top;
|
||||
top_client_type_in_range = top_hate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTopClientType) {
|
||||
if (top->GetSpecialAbility(ALLOW_TO_TANK)){
|
||||
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){
|
||||
isTopClientType = true;
|
||||
topClientTypeInRange = top;
|
||||
top_client_type_in_range = top_hate;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isTopClientType)
|
||||
return topClientTypeInRange ? topClientTypeInRange : nullptr;
|
||||
if (!isTopClientType)
|
||||
return top_client_type_in_range ? top_client_type_in_range : nullptr;
|
||||
|
||||
return top ? top : nullptr;
|
||||
return top_hate ? top_hate : nullptr;
|
||||
}
|
||||
else {
|
||||
if(top == nullptr && skipped_count > 0) {
|
||||
if (top_hate == nullptr && skipped_count > 0) {
|
||||
return center->GetTarget() ? center->GetTarget() : nullptr;
|
||||
}
|
||||
return top ? top : nullptr;
|
||||
return top_hate ? top_hate : nullptr;
|
||||
}
|
||||
}
|
||||
else{
|
||||
auto iterator = list.begin();
|
||||
int skipped_count = 0;
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *cur = (*iterator);
|
||||
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
|
||||
struct_HateList *cur = (*iterator);
|
||||
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) {
|
||||
skipped_count++;
|
||||
++iterator;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(cur->ent != nullptr && ((cur->hate > hate) || cur->bFrenzy ))
|
||||
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
|
||||
{
|
||||
top = cur->ent;
|
||||
hate = cur->hate;
|
||||
top_hate = cur->entity_on_hatelist;
|
||||
hate = cur->stored_hate_amount;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
if(top == nullptr && skipped_count > 0) {
|
||||
if (top_hate == nullptr && skipped_count > 0) {
|
||||
return center->GetTarget() ? center->GetTarget() : nullptr;
|
||||
}
|
||||
return top ? top : nullptr;
|
||||
return top_hate ? top_hate : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mob *HateList::GetMostHate(){
|
||||
Mob *HateList::GetEntWithMostHateOnList(){
|
||||
Mob* top = nullptr;
|
||||
int32 hate = -1;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while(iterator != list.end())
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *cur = (*iterator);
|
||||
if(cur->ent != nullptr && (cur->hate > hate))
|
||||
struct_HateList *cur = (*iterator);
|
||||
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
|
||||
{
|
||||
top = cur->ent;
|
||||
hate = cur->hate;
|
||||
top = cur->entity_on_hatelist;
|
||||
hate = cur->stored_hate_amount;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
@ -473,16 +475,16 @@ Mob *HateList::GetMostHate(){
|
||||
}
|
||||
|
||||
|
||||
Mob *HateList::GetRandom()
|
||||
Mob *HateList::GetRandomEntOnHateList()
|
||||
{
|
||||
int count = list.size();
|
||||
if(count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
|
||||
if (count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
|
||||
return NULL;
|
||||
|
||||
if(count == 1) //No need to do all that extra work if we only have one hate entry
|
||||
if (count == 1) //No need to do all that extra work if we only have one hate entry
|
||||
{
|
||||
if(*list.begin()) // Just in case tHateEntry is invalidated somehow...
|
||||
return (*list.begin())->ent;
|
||||
if (*list.begin()) // Just in case tHateEntry is invalidated somehow...
|
||||
return (*list.begin())->entity_on_hatelist;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -492,38 +494,36 @@ Mob *HateList::GetRandom()
|
||||
for (int i = 0; i < random; i++)
|
||||
++iterator;
|
||||
|
||||
return (*iterator)->ent;
|
||||
return (*iterator)->entity_on_hatelist;
|
||||
}
|
||||
|
||||
int32 HateList::GetEntHate(Mob *ent, bool damage)
|
||||
int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage)
|
||||
{
|
||||
tHateEntry *p;
|
||||
struct_HateList *entity;
|
||||
|
||||
p = Find(ent);
|
||||
entity = Find(in_entity);
|
||||
|
||||
if ( p && damage)
|
||||
return p->damage;
|
||||
else if (p)
|
||||
return p->hate;
|
||||
if (entity && damage)
|
||||
return entity->hatelist_damage;
|
||||
else if (entity)
|
||||
return entity->stored_hate_amount;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//looking for any mob with hate > -1
|
||||
bool HateList::IsEmpty() {
|
||||
bool HateList::IsHateListEmpty() {
|
||||
return(list.size() == 0);
|
||||
}
|
||||
|
||||
// Prints hate list to a client
|
||||
void HateList::PrintToClient(Client *c)
|
||||
void HateList::PrintHateListToClient(Client *c)
|
||||
{
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *e = (*iterator);
|
||||
struct_HateList *e = (*iterator);
|
||||
c->Message(0, "- name: %s, damage: %d, hate: %d",
|
||||
(e->ent && e->ent->GetName()) ? e->ent->GetName() : "(null)",
|
||||
e->damage, e->hate);
|
||||
(e->entity_on_hatelist && e->entity_on_hatelist->GetName()) ? e->entity_on_hatelist->GetName() : "(null)",
|
||||
e->hatelist_damage, e->stored_hate_amount);
|
||||
|
||||
++iterator;
|
||||
}
|
||||
@ -531,7 +531,7 @@ void HateList::PrintToClient(Client *c)
|
||||
|
||||
int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts)
|
||||
{
|
||||
if(!target || !caster)
|
||||
if (!target || !caster)
|
||||
return 0;
|
||||
|
||||
int ret = 0;
|
||||
@ -539,25 +539,25 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *h = (*iterator);
|
||||
struct_HateList *h = (*iterator);
|
||||
++iterator;
|
||||
if(h && h->ent && h->ent != caster)
|
||||
if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster)
|
||||
{
|
||||
if(caster->CombatRange(h->ent))
|
||||
if (caster->CombatRange(h->entity_on_hatelist))
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
id_list.push_back(h->entity_on_hatelist->GetID());
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list<uint32>::iterator iter = id_list.begin();
|
||||
while(iter != id_list.end())
|
||||
while (iter != id_list.end())
|
||||
{
|
||||
Mob *cur = entity_list.GetMobID((*iter));
|
||||
if(cur)
|
||||
if (cur)
|
||||
{
|
||||
for(int i = 0; i < count; ++i) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
caster->Attack(cur, MainPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
@ -569,7 +569,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
|
||||
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center)
|
||||
{
|
||||
if(!caster)
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
Mob* center = caster;
|
||||
@ -588,33 +588,32 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *h = (*iterator);
|
||||
if(range > 0)
|
||||
struct_HateList *h = (*iterator);
|
||||
if (range > 0)
|
||||
{
|
||||
dist_targ = center->DistNoRoot(*h->ent);
|
||||
if(dist_targ <= range && dist_targ >= min_range2)
|
||||
dist_targ = center->DistNoRoot(*h->entity_on_hatelist);
|
||||
if (dist_targ <= range && dist_targ >= min_range2)
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||
id_list.push_back(h->entity_on_hatelist->GetID());
|
||||
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster);
|
||||
id_list.push_back(h->entity_on_hatelist->GetID());
|
||||
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, 0, caster);
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
|
||||
std::list<uint32>::iterator iter = id_list.begin();
|
||||
while(iter != id_list.end())
|
||||
while (iter != id_list.end())
|
||||
{
|
||||
Mob *cur = entity_list.GetMobID((*iter));
|
||||
if(cur)
|
||||
if (cur)
|
||||
{
|
||||
caster->SpellOnTarget(spell_id, cur);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef HATELIST_H
|
||||
@ -25,11 +25,12 @@ class Mob;
|
||||
class Raid;
|
||||
struct ExtraAttackOptions;
|
||||
|
||||
struct tHateEntry
|
||||
struct struct_HateList
|
||||
{
|
||||
Mob *ent;
|
||||
int32 damage, hate;
|
||||
bool bFrenzy;
|
||||
Mob *entity_on_hatelist;
|
||||
int32 hatelist_damage;
|
||||
uint32 stored_hate_amount;
|
||||
bool is_entity_frenzy;
|
||||
};
|
||||
|
||||
class HateList
|
||||
@ -38,53 +39,38 @@ public:
|
||||
HateList();
|
||||
~HateList();
|
||||
|
||||
// adds a mob to the hatelist
|
||||
void Add(Mob *ent, int32 in_hate=0, int32 in_dam=0, bool bFrenzy = false, bool iAddIfNotExist = true);
|
||||
// sets existing hate
|
||||
void Set(Mob *other, uint32 in_hate, uint32 in_dam);
|
||||
// removes mobs from hatelist
|
||||
bool RemoveEnt(Mob *ent);
|
||||
// Remove all
|
||||
void Wipe();
|
||||
// ???
|
||||
void DoFactionHits(int32 nfl_id);
|
||||
// Gets Hate amount for mob
|
||||
int32 GetEntHate(Mob *ent, bool damage = false);
|
||||
// gets top hated mob
|
||||
Mob *GetTop(Mob *center);
|
||||
// gets any on the list
|
||||
Mob *GetRandom();
|
||||
// get closest mob or nullptr if list empty
|
||||
Mob *GetClosest(Mob *hater);
|
||||
// gets top mob or nullptr if hate list empty
|
||||
Mob *GetDamageTop(Mob *hater);
|
||||
// used to check if mob is on hatelist
|
||||
bool IsOnHateList(Mob *);
|
||||
// used to remove or add frenzy hate
|
||||
void CheckFrenzyHate();
|
||||
//Gets the target with the most hate regardless of things like frenzy etc.
|
||||
Mob* GetMostHate();
|
||||
// Count 'Summoned' pets on hatelist
|
||||
int SummonedPetCount(Mob *hater);
|
||||
Mob *GetClosestEntOnHateList(Mob *hater);
|
||||
Mob *GetDamageTopOnHateList(Mob *hater);
|
||||
Mob *GetEntWithMostHateOnList(Mob *center);
|
||||
Mob *GetRandomEntOnHateList();
|
||||
Mob* GetEntWithMostHateOnList();
|
||||
|
||||
bool IsEntOnHateList(Mob *mob);
|
||||
bool IsHateListEmpty();
|
||||
bool RemoveEntFromHateList(Mob *ent);
|
||||
|
||||
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
|
||||
int GetSummonedPetCountOnHateList(Mob *hater);
|
||||
|
||||
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
|
||||
int32 GetEntHateAmount(Mob *ent, bool in_damage = false);
|
||||
|
||||
bool IsEmpty();
|
||||
void PrintToClient(Client *c);
|
||||
std::list<struct_HateList*>& GetHateList() { return list; }
|
||||
|
||||
//For accessing the hate list via perl; don't use for anything else
|
||||
std::list<tHateEntry*>& GetHateList() { return list; }
|
||||
void AddEntToHateList(Mob *ent, int32 in_hate = 0, int32 in_damage = 0, bool in_is_frenzied = false, bool add_to_hate_list_if_not_exist = true);
|
||||
void DoFactionHits(int32 npc_faction_level_id);
|
||||
void IsEntityInFrenzyMode();
|
||||
void PrintHateListToClient(Client *c);
|
||||
void SetHateAmountOnEnt(Mob *other, uint32 in_hate, uint32 in_damage);
|
||||
void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; }
|
||||
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
|
||||
void WipeHateList();
|
||||
|
||||
//setting owner
|
||||
void SetOwner(Mob *newOwner) { owner = newOwner; }
|
||||
|
||||
protected:
|
||||
tHateEntry* Find(Mob *ent);
|
||||
struct_HateList* Find(Mob *ent);
|
||||
private:
|
||||
std::list<tHateEntry*> list;
|
||||
Mob *owner;
|
||||
std::list<struct_HateList*> list;
|
||||
Mob *hate_owner;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -617,6 +617,7 @@ void Client::DropItem(int16 slot_id)
|
||||
|
||||
// Save client inventory change to database
|
||||
if (slot_id == MainCursor) {
|
||||
SendCursorBuffer();
|
||||
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
|
||||
database.SaveCursor(CharacterID(), s, e);
|
||||
} else {
|
||||
@ -678,6 +679,23 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
void Client::SendCursorBuffer() {
|
||||
// Temporary work-around for the RoF+ Client Buffer
|
||||
// Instead of dealing with client moving items in cursor buffer,
|
||||
// we can just send the next item in the cursor buffer to the cursor.
|
||||
if (GetClientVersion() >= EQClientRoF)
|
||||
{
|
||||
if (!GetInv().CursorEmpty())
|
||||
{
|
||||
const ItemInst* inst = GetInv().GetCursorItem();
|
||||
if (inst)
|
||||
{
|
||||
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove item from inventory
|
||||
void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) {
|
||||
#if (EQDEBUG >= 5)
|
||||
@ -794,10 +812,6 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
|
||||
}
|
||||
}
|
||||
|
||||
// Puts an item into the person's inventory
|
||||
// Any items already there will be removed from user's inventory
|
||||
// (Also saves changes back to the database: this may be optimized in the future)
|
||||
// client_update: Sends packet to client
|
||||
bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
||||
{
|
||||
mlog(INVENTORY__SLOTS, "Putting item %s (%d) on the cursor", inst.GetItem()->Name, inst.GetItem()->ID);
|
||||
@ -811,6 +825,10 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
||||
return database.SaveCursor(CharacterID(), s, e);
|
||||
}
|
||||
|
||||
// Puts an item into the person's inventory
|
||||
// Any items already there will be removed from user's inventory
|
||||
// (Also saves changes back to the database: this may be optimized in the future)
|
||||
// client_update: Sends packet to client
|
||||
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
|
||||
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||
|
||||
@ -908,7 +926,7 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur
|
||||
bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_cursor, ServerLootItem_Struct** bag_item_data)
|
||||
{
|
||||
// #1: Try to auto equip
|
||||
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && !inst.GetItem()->Attuneable && inst.GetItem()->ItemType != ItemTypeAugmentation)
|
||||
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != ItemTypeAugmentation)
|
||||
{
|
||||
// too messy as-is... <watch>
|
||||
for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) // originally (i < 22)
|
||||
@ -1009,105 +1027,113 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) {
|
||||
// TODO: needs clean-up to save references
|
||||
bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) {
|
||||
//we're sending back the entire "link", minus the null characters & item name
|
||||
//that way, we can use it for regular links & Task links
|
||||
//note: initiator needs to pass us ret_link
|
||||
|
||||
/*
|
||||
/*
|
||||
--- Usage ---
|
||||
Chat: "%c" "%s" "%s" "%c", 0x12, ret_link, inst->GetItem()->name, 0x12
|
||||
Task: "<a WndNotify=\"27," "%s" "\">" "%s" "</a>", ret_link, inst->GetItem()->name
|
||||
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
|
||||
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
|
||||
*/
|
||||
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
|
||||
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
|
||||
*/
|
||||
|
||||
if (!inst) //have to have an item to make the link
|
||||
if (!item) //have to have an item to make the link
|
||||
return false;
|
||||
|
||||
const Item_Struct* item = inst->GetItem();
|
||||
//format:
|
||||
//0 itemid aug1 aug2 aug3 aug4 aug5 evolving? loregroup evolved level hash
|
||||
//0 00000 00000 00000 00000 00000 00000 0 0000 0 00000000
|
||||
//length:
|
||||
//1 5 5 5 5 5 5 1 4 1 8 = 45
|
||||
//evolving item info: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145#558
|
||||
uint8 evolving = 0;
|
||||
uint16 loregroup = 0;
|
||||
uint8 evolvedlevel = 0;
|
||||
int hash = 0;
|
||||
|
||||
//int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead
|
||||
if (GetClientVersion() >= EQClientRoF2)
|
||||
{
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%01X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
int hash = NOT_USED;
|
||||
|
||||
// Tested with UF and RoF..there appears to be a problem with using non-augment arguments below...
|
||||
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
|
||||
// into it further to determine the cause..but, the function is setup to accept the parameters.
|
||||
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
|
||||
// some additional information when certain parameters are true -U
|
||||
//switch (GetClientVersion()) {
|
||||
switch (0) {
|
||||
case EQClientRoF2:
|
||||
// This operator contains 14 parameter masks..but, only 13 parameter values.
|
||||
// Even so, the client link appears ok... Need to figure out the discrepancy -U
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item->ID,
|
||||
inst->GetAugmentItemID(0),
|
||||
inst->GetAugmentItemID(1),
|
||||
inst->GetAugmentItemID(2),
|
||||
inst->GetAugmentItemID(3),
|
||||
inst->GetAugmentItemID(4),
|
||||
inst->GetAugmentItemID(5),
|
||||
evolving,
|
||||
loregroup,
|
||||
evolvedlevel,
|
||||
aug0,
|
||||
aug1,
|
||||
aug2,
|
||||
aug3,
|
||||
aug4,
|
||||
aug5,
|
||||
0,//evolving,
|
||||
0,//item->LoreGroup,
|
||||
0,//evolvedlevel,
|
||||
0,
|
||||
hash
|
||||
);
|
||||
}
|
||||
else if (GetClientVersion() >= EQClientRoF)
|
||||
{
|
||||
return true;
|
||||
case EQClientRoF:
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item->ID,
|
||||
inst->GetAugmentItemID(0),
|
||||
inst->GetAugmentItemID(1),
|
||||
inst->GetAugmentItemID(2),
|
||||
inst->GetAugmentItemID(3),
|
||||
inst->GetAugmentItemID(4),
|
||||
inst->GetAugmentItemID(5),
|
||||
evolving,
|
||||
loregroup,
|
||||
evolvedlevel,
|
||||
aug0,
|
||||
aug1,
|
||||
aug2,
|
||||
aug3,
|
||||
aug4,
|
||||
aug5,
|
||||
0,//evolving,
|
||||
0,//item->LoreGroup,
|
||||
0,//evolvedlevel,
|
||||
0,
|
||||
hash
|
||||
);
|
||||
}
|
||||
else if (GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
);
|
||||
return true;
|
||||
case EQClientUnderfoot:
|
||||
case EQClientSoD:
|
||||
case EQClientSoF:
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item->ID,
|
||||
inst->GetAugmentItemID(0),
|
||||
inst->GetAugmentItemID(1),
|
||||
inst->GetAugmentItemID(2),
|
||||
inst->GetAugmentItemID(3),
|
||||
inst->GetAugmentItemID(4),
|
||||
evolving,
|
||||
loregroup,
|
||||
evolvedlevel,
|
||||
aug0,
|
||||
aug1,
|
||||
aug2,
|
||||
aug3,
|
||||
aug4,
|
||||
0,//evolving,
|
||||
0,//item->LoreGroup,
|
||||
0,//evolvedlevel,
|
||||
0,
|
||||
hash
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
);
|
||||
return true;
|
||||
case EQClientTitanium:
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
|
||||
0,
|
||||
item->ID,
|
||||
inst->GetAugmentItemID(0),
|
||||
inst->GetAugmentItemID(1),
|
||||
inst->GetAugmentItemID(2),
|
||||
inst->GetAugmentItemID(3),
|
||||
inst->GetAugmentItemID(4),
|
||||
evolving,
|
||||
loregroup,
|
||||
evolvedlevel,
|
||||
aug0,
|
||||
aug1,
|
||||
aug2,
|
||||
aug3,
|
||||
aug4,
|
||||
0,//evolving,
|
||||
0,//item->LoreGroup,
|
||||
0,//evolvedlevel,
|
||||
hash
|
||||
);
|
||||
);
|
||||
return true;
|
||||
case EQClient62:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Client::GetItemLinkHash(const ItemInst* inst) {
|
||||
@ -1198,6 +1224,7 @@ int Client::GetItemLinkHash(const ItemInst* inst) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
// This appears to still be in use... The core of this should be incorporated into class Client::TextLink
|
||||
void Client::SendItemLink(const ItemInst* inst, bool send_to_all)
|
||||
{
|
||||
/*
|
||||
@ -1299,7 +1326,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
|
||||
// This could be expounded upon at some point to let the server know that
|
||||
// the client has moved a buffered cursor item onto the active cursor -U
|
||||
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed
|
||||
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
return true;
|
||||
}
|
||||
@ -1315,13 +1342,15 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
|
||||
DeleteItemInInventory(move_in->from_slot);
|
||||
SendCursorBuffer();
|
||||
|
||||
return true; // Item destroyed by client
|
||||
}
|
||||
else {
|
||||
mlog(INVENTORY__SLOTS, "Deleted item from slot %d as a result of an inventory container tradeskill combine.", move_in->from_slot);
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
DeleteItemInInventory(move_in->from_slot);
|
||||
return true; // Item deletetion
|
||||
return true; // Item deletion
|
||||
}
|
||||
}
|
||||
if(auto_attack && (move_in->from_slot == MainPrimary || move_in->from_slot == MainSecondary || move_in->from_slot == MainRange))
|
||||
@ -1363,7 +1392,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
//SetTint(dst_slot_id,src_inst->GetColor());
|
||||
if (src_inst->GetCharges() > 0 && (src_inst->GetCharges() < (int16)move_in->number_in_stack || move_in->number_in_stack > src_inst->GetItem()->StackSize))
|
||||
{
|
||||
Message(13,"Error: Insufficent number in stack.");
|
||||
Message(13,"Error: Insufficient number in stack.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1520,11 +1549,19 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
|
||||
safe_delete(world_inst);
|
||||
if (src_slot_id == MainCursor) {
|
||||
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
|
||||
if (src_slot_id == MainCursor)
|
||||
{
|
||||
if (dstitemid == 0)
|
||||
{
|
||||
SendCursorBuffer();
|
||||
}
|
||||
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
database.SaveCursor(character_id, s, e);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
database.SaveInventory(character_id, m_inv[src_slot_id], src_slot_id);
|
||||
}
|
||||
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit
|
||||
|
||||
@ -1551,6 +1588,10 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
|
||||
trade->AddEntity(dst_slot_id, move_in->number_in_stack);
|
||||
if (dstitemid == 0)
|
||||
{
|
||||
SendCursorBuffer();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
@ -1563,6 +1604,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
}
|
||||
|
||||
bool all_to_stack = false;
|
||||
// Step 5: Swap (or stack) items
|
||||
if (move_in->number_in_stack > 0) {
|
||||
// Determine if charged items can stack
|
||||
@ -1593,6 +1635,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) was entirely consumed. (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, usedcharges);
|
||||
database.SaveInventory(CharacterID(),nullptr,src_slot_id);
|
||||
m_inv.DeleteItem(src_slot_id);
|
||||
all_to_stack = true;
|
||||
} else {
|
||||
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges);
|
||||
}
|
||||
@ -1666,6 +1709,11 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
|
||||
// Step 7: Save change to the database
|
||||
if (src_slot_id == MainCursor){
|
||||
// If not swapping another item to cursor and stacking items were depleted
|
||||
if (dstitemid == 0 || all_to_stack == true)
|
||||
{
|
||||
SendCursorBuffer();
|
||||
}
|
||||
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
|
||||
database.SaveCursor(character_id, s, e);
|
||||
} else
|
||||
@ -1968,7 +2016,7 @@ void Client::DyeArmor(DyeStruct* dye){
|
||||
|
||||
bool Client::DecreaseByID(uint32 type, uint8 amt) {
|
||||
const Item_Struct* TempItem = 0;
|
||||
ItemInst* ins;
|
||||
ItemInst* ins = nullptr;
|
||||
int x;
|
||||
int num = 0;
|
||||
for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++)
|
||||
@ -2104,6 +2152,7 @@ void Client::RemoveNoRent(bool client_update) {
|
||||
std::list<ItemInst*>::iterator iter = local.begin();
|
||||
while (iter != local.end()) {
|
||||
inst = *iter;
|
||||
// should probably put a check here for valid pointer..but, that was checked when the item was put into inventory -U
|
||||
if (!inst->GetItem()->NoRent)
|
||||
mlog(INVENTORY__SLOTS, "NoRent Timer Lapse: Deleting %s from `Limbo`", inst->GetItem()->Name);
|
||||
else
|
||||
@ -2229,6 +2278,7 @@ void Client::RemoveDuplicateLore(bool client_update) {
|
||||
std::list<ItemInst*>::iterator iter = local.begin();
|
||||
while (iter != local.end()) {
|
||||
inst = *iter;
|
||||
// probably needs a valid pointer check -U
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
mlog(INVENTORY__ERROR, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name);
|
||||
safe_delete(*iter);
|
||||
@ -2431,8 +2481,8 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
|
||||
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
|
||||
|
||||
const ItemInst* InvItem;
|
||||
const Item_Struct *BaseItem;
|
||||
const ItemInst* InvItem = nullptr;
|
||||
const Item_Struct *BaseItem = nullptr;
|
||||
int16 WeaponSlot;
|
||||
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
|
||||
@ -324,7 +324,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
||||
what was this about???
|
||||
|
||||
if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){
|
||||
npc->d_meele_texture2=atoi(newid);
|
||||
npc->d_melee_texture2=atoi(newid);
|
||||
wc->wear_slot_id=8;
|
||||
if (item2->Material >0)
|
||||
wc->material=item2->Material;
|
||||
|
||||
@ -1354,8 +1354,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
||||
LuaCreateNPCParse(max_dmg, uint32, 4);
|
||||
LuaCreateNPCParse(attack_count, int16, 0);
|
||||
LuaCreateNPCParseString(special_abilities, 512, "");
|
||||
LuaCreateNPCParse(d_meele_texture1, uint16, 0);
|
||||
LuaCreateNPCParse(d_meele_texture2, uint16, 0);
|
||||
LuaCreateNPCParse(d_melee_texture1, uint16, 0);
|
||||
LuaCreateNPCParse(d_melee_texture2, uint16, 0);
|
||||
LuaCreateNPCParseString(ammo_idfile, 32, "");
|
||||
LuaCreateNPCParse(prim_melee_type, uint8, 0);
|
||||
LuaCreateNPCParse(sec_melee_type, uint8, 0);
|
||||
|
||||
@ -12,42 +12,42 @@
|
||||
|
||||
Lua_Mob Lua_HateEntry::GetEnt() {
|
||||
Lua_Safe_Call_Class(Lua_Mob);
|
||||
return Lua_Mob(self->ent);
|
||||
return Lua_Mob(self->entity_on_hatelist);
|
||||
}
|
||||
|
||||
void Lua_HateEntry::SetEnt(Lua_Mob e) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ent = e;
|
||||
self->entity_on_hatelist = e;
|
||||
}
|
||||
|
||||
int Lua_HateEntry::GetDamage() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->damage;
|
||||
return self->hatelist_damage;
|
||||
}
|
||||
|
||||
void Lua_HateEntry::SetDamage(int value) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->damage = value;
|
||||
self->hatelist_damage = value;
|
||||
}
|
||||
|
||||
int Lua_HateEntry::GetHate() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->hate;
|
||||
return self->stored_hate_amount;
|
||||
}
|
||||
|
||||
void Lua_HateEntry::SetHate(int value) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->hate = value;
|
||||
self->stored_hate_amount = value;
|
||||
}
|
||||
|
||||
int Lua_HateEntry::GetFrenzy() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->bFrenzy;
|
||||
return self->is_entity_frenzy;
|
||||
}
|
||||
|
||||
void Lua_HateEntry::SetFrenzy(bool value) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->bFrenzy = value;
|
||||
self->is_entity_frenzy = value;
|
||||
}
|
||||
|
||||
luabind::scope lua_register_hate_entry() {
|
||||
|
||||
@ -5,17 +5,17 @@
|
||||
#include "lua_ptr.h"
|
||||
|
||||
class Lua_Mob;
|
||||
struct tHateEntry;
|
||||
struct struct_HateList;
|
||||
|
||||
luabind::scope lua_register_hate_entry();
|
||||
luabind::scope lua_register_hate_list();
|
||||
|
||||
class Lua_HateEntry : public Lua_Ptr<tHateEntry>
|
||||
class Lua_HateEntry : public Lua_Ptr<struct_HateList>
|
||||
{
|
||||
typedef tHateEntry NativeType;
|
||||
typedef struct_HateList NativeType;
|
||||
public:
|
||||
Lua_HateEntry() : Lua_Ptr(nullptr) { }
|
||||
Lua_HateEntry(tHateEntry *d) : Lua_Ptr(d) { }
|
||||
Lua_HateEntry(struct_HateList *d) : Lua_Ptr(d) { }
|
||||
virtual ~Lua_HateEntry() { }
|
||||
|
||||
Lua_Mob GetEnt();
|
||||
|
||||
@ -895,17 +895,17 @@ void Lua_Mob::AddToHateList(Lua_Mob other, int hate, int damage, bool yell_for_h
|
||||
|
||||
void Lua_Mob::SetHate(Lua_Mob other) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetHate(other);
|
||||
self->SetHateAmountOnEnt(other);
|
||||
}
|
||||
|
||||
void Lua_Mob::SetHate(Lua_Mob other, int hate) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetHate(other, hate);
|
||||
self->SetHateAmountOnEnt(other, hate);
|
||||
}
|
||||
|
||||
void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetHate(other, hate, damage);
|
||||
self->SetHateAmountOnEnt(other, hate, damage);
|
||||
}
|
||||
|
||||
void Lua_Mob::HalveAggro(Lua_Mob other) {
|
||||
|
||||
@ -695,6 +695,9 @@ bool LuaParser::SpellHasQuestSub(uint32 spell_id, QuestEventID evt) {
|
||||
}
|
||||
|
||||
bool LuaParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
|
||||
if (itm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
evt = ConvertLuaEvent(evt);
|
||||
if(evt >= _LargestEventID) {
|
||||
return false;
|
||||
@ -738,6 +741,8 @@ void LuaParser::LoadGlobalPlayerScript(std::string filename) {
|
||||
}
|
||||
|
||||
void LuaParser::LoadItemScript(std::string filename, ItemInst *item) {
|
||||
if (item == nullptr)
|
||||
return;
|
||||
std::string package_name = "item_";
|
||||
package_name += std::to_string(static_cast<long long>(item->GetID()));
|
||||
|
||||
|
||||
@ -58,6 +58,7 @@ Map::Map() {
|
||||
Map::~Map() {
|
||||
if(imp) {
|
||||
imp->rm->release();
|
||||
safe_delete(imp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,4 +888,4 @@ void Map::TranslateVertex(Vertex &v, float tx, float ty, float tz) {
|
||||
v.x = v.x + tx;
|
||||
v.y = v.y + ty;
|
||||
v.z = v.z + tz;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1385,7 +1385,7 @@ void Merc::AI_Process() {
|
||||
rest_timer.Disable();
|
||||
|
||||
if(IsRooted())
|
||||
SetTarget(hate_list.GetClosest(this));
|
||||
SetTarget(hate_list.GetClosestEntOnHateList(this));
|
||||
else
|
||||
FindTarget();
|
||||
|
||||
@ -2454,11 +2454,11 @@ void Merc::CheckHateList() {
|
||||
Mob* groupMember = g->members[counter];
|
||||
if(groupMember) {
|
||||
if(npc->IsOnHatelist(groupMember)) {
|
||||
if(!hate_list.IsOnHateList(npc)) {
|
||||
if(!hate_list.IsEntOnHateList(npc)) {
|
||||
float range = g->HasRole(groupMember, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius);
|
||||
range *= range;
|
||||
if(npc->DistNoRootNoZ(*this) < range) {
|
||||
hate_list.Add(npc, 1);
|
||||
hate_list.AddEntToHateList(npc, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4644,13 +4644,6 @@ const char* Merc::GetRandomName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Compare_Merc_Spells(MercSpell i, MercSpell j);
|
||||
|
||||
bool Compare_Merc_Spells(MercSpell i, MercSpell j)
|
||||
{
|
||||
return(i.slot > j.slot);
|
||||
}
|
||||
|
||||
bool Merc::LoadMercSpells() {
|
||||
// loads mercs spells into list
|
||||
merc_spells.clear();
|
||||
@ -4683,7 +4676,9 @@ bool Merc::LoadMercSpells() {
|
||||
AddProcToWeapon(mercSpellEntryItr->spellid, true, mercSpellEntryItr->proc_chance);
|
||||
}
|
||||
}
|
||||
std::sort(merc_spells.begin(), merc_spells.end(), Compare_Merc_Spells);
|
||||
std::sort(merc_spells.begin(), merc_spells.end(), [](const MercSpell& a, const MercSpell& b) {
|
||||
return a.slot > b.slot;
|
||||
});
|
||||
|
||||
if (merc_spells.size() == 0)
|
||||
AIautocastspell_timer->Disable();
|
||||
|
||||
@ -287,8 +287,8 @@ protected:
|
||||
|
||||
uint16 skills[HIGHEST_SKILL+1];
|
||||
uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs
|
||||
uint16 d_meele_texture1; //this is an item Material value
|
||||
uint16 d_meele_texture2; //this is an item Material value (offhand)
|
||||
uint16 d_melee_texture1; //this is an item Material value
|
||||
uint16 d_melee_texture2; //this is an item Material value (offhand)
|
||||
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
|
||||
uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation
|
||||
|
||||
|
||||
41
zone/mob.cpp
41
zone/mob.cpp
@ -401,7 +401,7 @@ Mob::Mob(const char* in_name,
|
||||
PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong));
|
||||
DistractedFromGrid = false;
|
||||
PathingTraversedNodes = 0;
|
||||
hate_list.SetOwner(this);
|
||||
hate_list.SetHateOwner(this);
|
||||
|
||||
m_AllowBeneficial = false;
|
||||
m_DisableMelee = false;
|
||||
@ -925,7 +925,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.animation = 0;
|
||||
ns->spawn.findable = findable?1:0;
|
||||
ns->spawn.light = light;
|
||||
ns->spawn.showhelm = 1;
|
||||
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
|
||||
|
||||
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
|
||||
ns->spawn.NPC = IsClient() ? 0 : 1;
|
||||
@ -945,11 +945,11 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.drakkin_heritage = drakkin_heritage;
|
||||
ns->spawn.drakkin_tattoo = drakkin_tattoo;
|
||||
ns->spawn.drakkin_details = drakkin_details;
|
||||
ns->spawn.equip_chest2 = texture;
|
||||
ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 ? 0xff : texture;
|
||||
|
||||
// ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn mob invis
|
||||
|
||||
if(helmtexture && helmtexture != 0xFF)
|
||||
if (helmtexture && helmtexture != 0xFF && GetHerosForgeModel(0) == 0)
|
||||
{
|
||||
ns->spawn.helm=helmtexture;
|
||||
} else {
|
||||
@ -978,7 +978,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
|
||||
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
|
||||
|
||||
for (i = 0; i < _MaterialCount; i++)
|
||||
//for (i = 0; i < _MaterialCount; i++)
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
// Only Player Races Wear Armor
|
||||
if (Mob::IsPlayerRace(race) || i > 6)
|
||||
@ -2571,8 +2572,8 @@ bool Mob::RemoveFromHateList(Mob* mob)
|
||||
bool bFound = false;
|
||||
if(IsEngaged())
|
||||
{
|
||||
bFound = hate_list.RemoveEnt(mob);
|
||||
if(hate_list.IsEmpty())
|
||||
bFound = hate_list.RemoveEntFromHateList(mob);
|
||||
if(hate_list.IsHateListEmpty())
|
||||
{
|
||||
AI_Event_NoLongerEngaged();
|
||||
zone->DelAggroMob();
|
||||
@ -2580,7 +2581,7 @@ bool Mob::RemoveFromHateList(Mob* mob)
|
||||
}
|
||||
if(GetTarget() == mob)
|
||||
{
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
|
||||
return bFound;
|
||||
@ -2590,12 +2591,12 @@ void Mob::WipeHateList()
|
||||
{
|
||||
if(IsEngaged())
|
||||
{
|
||||
hate_list.Wipe();
|
||||
hate_list.WipeHateList();
|
||||
AI_Event_NoLongerEngaged();
|
||||
}
|
||||
else
|
||||
{
|
||||
hate_list.Wipe();
|
||||
hate_list.WipeHateList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2749,7 +2750,6 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
|
||||
|
||||
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
{
|
||||
|
||||
uint32 HeroModel = 0;
|
||||
if (material_slot >= 0 && material_slot < MaterialPrimary)
|
||||
{
|
||||
@ -2760,7 +2760,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
|
||||
if (item != 0 && invslot != INVALID_INDEX)
|
||||
{
|
||||
if (this->IsClient())
|
||||
if (IsClient())
|
||||
{
|
||||
const ItemInst* inst = CastToClient()->m_inv[invslot];
|
||||
if (inst)
|
||||
@ -2782,9 +2782,22 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
HeroModel = item->HerosForgeModel;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC())
|
||||
{
|
||||
HeroModel = CastToNPC()->GetHeroForgeModel();
|
||||
// Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
|
||||
if (HeroModel > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 && material_slot != 5)
|
||||
{
|
||||
HeroModel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HeroModel > 0)
|
||||
// Auto-Convert Hero Model to match the slot
|
||||
// Otherwise, use the exact Model if model is > 999
|
||||
// Robes for example are 11607 to 12107 in RoF
|
||||
if (HeroModel > 0 && HeroModel < 1000)
|
||||
{
|
||||
HeroModel *= 100;
|
||||
HeroModel += material_slot;
|
||||
@ -3504,7 +3517,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
}
|
||||
|
||||
else if (IsPet){
|
||||
int count = hate_list.SummonedPetCount(this);
|
||||
int count = hate_list.GetSummonedPetCountOnHateList(this);
|
||||
if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){
|
||||
use_spell = true;
|
||||
}
|
||||
|
||||
28
zone/mob.h
28
zone/mob.h
@ -452,19 +452,19 @@ public:
|
||||
static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel);
|
||||
inline uint32 GetLevelCon(uint8 iOtherLevel) const {
|
||||
return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GREEN; }
|
||||
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
|
||||
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
|
||||
bool bFrenzy = false, bool iBuffTic = false);
|
||||
bool RemoveFromHateList(Mob* mob);
|
||||
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);}
|
||||
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); }
|
||||
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); }
|
||||
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);}
|
||||
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);}
|
||||
Mob* GetHateTop() { return hate_list.GetTop(this);}
|
||||
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTop(other);}
|
||||
Mob* GetHateRandom() { return hate_list.GetRandom();}
|
||||
Mob* GetHateMost() { return hate_list.GetMostHate();}
|
||||
bool IsEngaged() { return(!hate_list.IsEmpty()); }
|
||||
void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);}
|
||||
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); }
|
||||
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate ? in_hate * 2 : 1)); }
|
||||
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHateAmount(tmob,is_dam);}
|
||||
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHateAmount(tmob, true);}
|
||||
Mob* GetHateTop() { return hate_list.GetEntWithMostHateOnList(this);}
|
||||
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTopOnHateList(other);}
|
||||
Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();}
|
||||
Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();}
|
||||
bool IsEngaged() { return(!hate_list.IsHateListEmpty()); }
|
||||
bool HateSummon();
|
||||
void FaceTarget(Mob* MobToFace = 0);
|
||||
void SetHeading(float iHeading) { if(heading != iHeading) { pLastChange = Timer::GetCurrentTime();
|
||||
@ -473,8 +473,8 @@ public:
|
||||
void AddFeignMemory(Client* attacker);
|
||||
void RemoveFromFeignMemory(Client* attacker);
|
||||
void ClearFeignMemory();
|
||||
void PrintHateListToClient(Client *who) { hate_list.PrintToClient(who); }
|
||||
std::list<tHateEntry*>& GetHateList() { return hate_list.GetHateList(); }
|
||||
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
|
||||
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
||||
bool CheckLosFN(Mob* other);
|
||||
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
|
||||
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
|
||||
@ -798,7 +798,7 @@ public:
|
||||
void CheckFlee();
|
||||
inline bool IsBlind() { return spellbonuses.IsBlind; }
|
||||
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
||||
float CalculateHeadingToTarget(float in_x, float in_y);
|
||||
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
|
||||
|
||||
@ -493,7 +493,7 @@ void Mob::AI_Start(uint32 iMoveDelay) {
|
||||
pAggroRange = 70;
|
||||
if (GetAssistRange() == 0)
|
||||
pAssistRange = 70;
|
||||
hate_list.Wipe();
|
||||
hate_list.WipeHateList();
|
||||
|
||||
delta_heading = 0;
|
||||
delta_x = 0;
|
||||
@ -553,7 +553,7 @@ void Mob::AI_Stop() {
|
||||
safe_delete(AIscanarea_timer);
|
||||
safe_delete(AIfeignremember_timer);
|
||||
|
||||
hate_list.Wipe();
|
||||
hate_list.WipeHateList();
|
||||
}
|
||||
|
||||
void NPC::AI_Stop() {
|
||||
@ -816,12 +816,12 @@ void Client::AI_Process()
|
||||
if (engaged)
|
||||
{
|
||||
if (IsRooted())
|
||||
SetTarget(hate_list.GetClosest(this));
|
||||
SetTarget(hate_list.GetClosestEntOnHateList(this));
|
||||
else
|
||||
{
|
||||
if(AItarget_check_timer->Check())
|
||||
{
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1041,7 +1041,7 @@ void Mob::AI_Process() {
|
||||
//
|
||||
if(RuleB(Combat, EnableFearPathing)){
|
||||
if(curfp) {
|
||||
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosest(this)))) {
|
||||
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) {
|
||||
//make sure everybody knows were not moving, for appearance sake
|
||||
if(IsMoving())
|
||||
{
|
||||
@ -1091,18 +1091,18 @@ void Mob::AI_Process() {
|
||||
// we are prevented from getting here if we are blind and don't have a target in range
|
||||
// from above, so no extra blind checks needed
|
||||
if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())
|
||||
SetTarget(hate_list.GetClosest(this));
|
||||
SetTarget(hate_list.GetClosestEntOnHateList(this));
|
||||
else
|
||||
{
|
||||
if(AItarget_check_timer->Check())
|
||||
{
|
||||
if (IsFocused()) {
|
||||
if (!target) {
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
} else {
|
||||
if (!ImprovedTaunt())
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1376,7 +1376,7 @@ void Mob::AI_Process() {
|
||||
//underwater stuff only works with water maps in the zone!
|
||||
if(IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
|
||||
if(!zone->watermap->InLiquid(target->GetX(), target->GetY(), target->GetZ())) {
|
||||
Mob *tar = hate_list.GetTop(this);
|
||||
Mob *tar = hate_list.GetEntWithMostHateOnList(this);
|
||||
if(tar == target) {
|
||||
WipeHateList();
|
||||
Heal();
|
||||
@ -2354,7 +2354,6 @@ create table npc_spells_entries (
|
||||
|
||||
bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID);
|
||||
bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSpellEffectID, int32 base, int32 limit, int32 max);
|
||||
bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j);
|
||||
|
||||
bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
|
||||
// ok, this function should load the list, and the parent list then shove them into the struct and sort
|
||||
@ -2479,7 +2478,9 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
|
||||
spell_list->entries[i].resist_adjust);
|
||||
}
|
||||
}
|
||||
std::sort(AIspells.begin(), AIspells.end(), Compare_AI_Spells);
|
||||
std::sort(AIspells.begin(), AIspells.end(), [](const AISpells_Struct& a, const AISpells_Struct& b) {
|
||||
return a.priority > b.priority;
|
||||
});
|
||||
|
||||
if (IsValidSpell(attack_proc_spell))
|
||||
AddProcToWeapon(attack_proc_spell, true, proc_chance);
|
||||
@ -2619,11 +2620,6 @@ bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j)
|
||||
{
|
||||
return(i.priority > j.priority);
|
||||
}
|
||||
|
||||
// adds a spell to the list, taking into account priority and resorting list as needed.
|
||||
void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint16 iType,
|
||||
int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust)
|
||||
|
||||
62
zone/npc.cpp
62
zone/npc.cpp
@ -261,8 +261,10 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
|
||||
if(!IsMerc())
|
||||
AI_Start();
|
||||
|
||||
d_meele_texture1 = d->d_meele_texture1;
|
||||
d_meele_texture2 = d->d_meele_texture2;
|
||||
d_melee_texture1 = d->d_melee_texture1;
|
||||
d_melee_texture2 = d->d_melee_texture2;
|
||||
herosforgemodel = d->herosforgemodel;
|
||||
|
||||
ammo_idfile = d->ammo_idfile;
|
||||
memset(equipment, 0, sizeof(equipment));
|
||||
prim_melee_type = d->prim_melee_type;
|
||||
@ -270,9 +272,9 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
|
||||
ranged_type = d->ranged_type;
|
||||
|
||||
// If Melee Textures are not set, set attack type to Hand to Hand as default
|
||||
if(!d_meele_texture1)
|
||||
if(!d_melee_texture1)
|
||||
prim_melee_type = 28;
|
||||
if(!d_meele_texture2)
|
||||
if(!d_melee_texture2)
|
||||
sec_melee_type = 28;
|
||||
|
||||
//give NPCs skill values...
|
||||
@ -498,32 +500,28 @@ void NPC::ClearItemList() {
|
||||
itemlist.clear();
|
||||
}
|
||||
|
||||
void NPC::QueryLoot(Client* to) {
|
||||
int x = 0;
|
||||
void NPC::QueryLoot(Client* to)
|
||||
{
|
||||
to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper);
|
||||
|
||||
ItemList::iterator cur,end;
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
for(; cur != end; ++cur) {
|
||||
int x = 0;
|
||||
for(ItemList::iterator cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) {
|
||||
const Item_Struct* item = database.GetItem((*cur)->item_id);
|
||||
if (item)
|
||||
if (to->GetClientVersion() >= EQClientRoF)
|
||||
{
|
||||
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
|
||||
}
|
||||
else if (to->GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X00000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
|
||||
}
|
||||
else
|
||||
{
|
||||
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
|
||||
}
|
||||
else
|
||||
if (item == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "Database error, invalid item");
|
||||
x++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
linker.SetClientVersion(to->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level);
|
||||
}
|
||||
|
||||
to->Message(0, "%i items on %s.", x, GetName());
|
||||
}
|
||||
|
||||
@ -924,8 +922,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
|
||||
npc_type->texture = atoi(sep.arg[3]);
|
||||
npc_type->light = 0;
|
||||
npc_type->runspeed = 1.25;
|
||||
npc_type->d_meele_texture1 = atoi(sep.arg[7]);
|
||||
npc_type->d_meele_texture2 = atoi(sep.arg[8]);
|
||||
npc_type->d_melee_texture1 = atoi(sep.arg[7]);
|
||||
npc_type->d_melee_texture2 = atoi(sep.arg[8]);
|
||||
npc_type->merchanttype = atoi(sep.arg[9]);
|
||||
npc_type->bodytype = atoi(sep.arg[10]);
|
||||
|
||||
@ -957,7 +955,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
|
||||
client->Message(0, "Current/Max HP: %i", npc->max_hp);
|
||||
client->Message(0, "Gender: %u", npc->gender);
|
||||
client->Message(0, "Class: %u", npc->class_);
|
||||
client->Message(0, "Weapon Item Number: %u/%u", npc->d_meele_texture1, npc->d_meele_texture2);
|
||||
client->Message(0, "Weapon Item Number: %u/%u", npc->d_melee_texture1, npc->d_melee_texture2);
|
||||
client->Message(0, "MerchantID: %u", npc->MerchantType);
|
||||
client->Message(0, "Bodytype: %u", npc->bodytype);
|
||||
}
|
||||
@ -1335,9 +1333,9 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const
|
||||
case MaterialChest:
|
||||
return texture;
|
||||
case MaterialPrimary:
|
||||
return d_meele_texture1;
|
||||
return d_melee_texture1;
|
||||
case MaterialSecondary:
|
||||
return d_meele_texture2;
|
||||
return d_melee_texture2;
|
||||
default:
|
||||
//they have nothing in the slot, and its not a special slot... they get nothing.
|
||||
return(0);
|
||||
@ -2136,10 +2134,10 @@ uint32 NPC::GetSpawnPointID() const
|
||||
void NPC::NPCSlotTexture(uint8 slot, uint16 texture)
|
||||
{
|
||||
if (slot == 7) {
|
||||
d_meele_texture1 = texture;
|
||||
d_melee_texture1 = texture;
|
||||
}
|
||||
else if (slot == 8) {
|
||||
d_meele_texture2 = texture;
|
||||
d_melee_texture2 = texture;
|
||||
}
|
||||
else if (slot < 6) {
|
||||
// Reserved for texturing individual armor slots
|
||||
|
||||
13
zone/npc.h
13
zone/npc.h
@ -249,8 +249,8 @@ public:
|
||||
|
||||
inline int32 GetNPCFactionID() const { return npc_faction_id; }
|
||||
inline int32 GetPrimaryFaction() const { return primary_faction; }
|
||||
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHate(in_ent);}
|
||||
bool IsOnHatelist(Mob*p) { return hate_list.IsOnHateList(p);}
|
||||
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHateAmount(in_ent);}
|
||||
bool IsOnHatelist(Mob*p) { return hate_list.IsEntOnHateList(p);}
|
||||
|
||||
void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }
|
||||
|
||||
@ -403,6 +403,9 @@ public:
|
||||
void mod_npc_killed(Mob* oos);
|
||||
void AISpellsList(Client *c);
|
||||
|
||||
uint32 GetHeroForgeModel() const { return herosforgemodel; }
|
||||
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
|
||||
|
||||
bool IsRaidTarget() const { return raid_target; };
|
||||
|
||||
protected:
|
||||
@ -492,8 +495,10 @@ protected:
|
||||
uint16 skills[HIGHEST_SKILL+1];
|
||||
|
||||
uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs
|
||||
uint16 d_meele_texture1; //this is an item Material value
|
||||
uint16 d_meele_texture2; //this is an item Material value (offhand)
|
||||
|
||||
uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203)
|
||||
uint16 d_melee_texture1; //this is an item Material value
|
||||
uint16 d_melee_texture2; //this is an item Material value (offhand)
|
||||
const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile')
|
||||
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
|
||||
uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation
|
||||
|
||||
@ -118,7 +118,15 @@ Object::Object(Client* client, const ItemInst* inst)
|
||||
m_data.heading = client->GetHeading();
|
||||
m_data.x = client->GetX();
|
||||
m_data.y = client->GetY();
|
||||
m_data.z = client->GetZ();
|
||||
if (client->GetClientVersion() >= EQClientRoF2)
|
||||
{
|
||||
// RoF2 places items at player's Z, which is 0.625 of their height.
|
||||
m_data.z = client->GetZ() - (client->GetSize() * 0.625f);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data.z = client->GetZ();
|
||||
}
|
||||
m_data.zone_id = zone->GetZoneID();
|
||||
|
||||
decay_timer.Start();
|
||||
|
||||
@ -345,10 +345,10 @@ bool CheckLOSBetweenPoints(Map::Vertex start, Map::Vertex end) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SortPathNodesByDistance(PathNodeSortStruct n1, PathNodeSortStruct n2)
|
||||
auto path_compare = [](const PathNodeSortStruct& a, const PathNodeSortStruct& b)
|
||||
{
|
||||
return n1.Distance < n2.Distance;
|
||||
}
|
||||
return a.Distance < b.Distance;
|
||||
};
|
||||
|
||||
std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
|
||||
{
|
||||
@ -382,7 +382,7 @@ std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
|
||||
|
||||
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
|
||||
{
|
||||
@ -420,7 +420,7 @@ std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
|
||||
|
||||
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
|
||||
{
|
||||
@ -573,8 +573,8 @@ void PathManager::SpawnPathNodes()
|
||||
npc_type->texture = 1;
|
||||
npc_type->light = 0;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_meele_texture1 = 1;
|
||||
npc_type->d_meele_texture2 = 1;
|
||||
npc_type->d_melee_texture1 = 1;
|
||||
npc_type->d_melee_texture2 = 1;
|
||||
npc_type->merchanttype = 1;
|
||||
npc_type->bodytype = 1;
|
||||
|
||||
@ -1120,7 +1120,7 @@ int PathManager::FindNearestPathNode(Map::Vertex Position)
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
|
||||
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
|
||||
|
||||
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
|
||||
{
|
||||
@ -1561,8 +1561,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
|
||||
npc_type->texture = 1;
|
||||
npc_type->light = 0;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_meele_texture1 = 1;
|
||||
npc_type->d_meele_texture2 = 1;
|
||||
npc_type->d_melee_texture1 = 1;
|
||||
npc_type->d_melee_texture2 = 1;
|
||||
npc_type->merchanttype = 1;
|
||||
npc_type->bodytype = 1;
|
||||
npc_type->STR = 150;
|
||||
@ -1621,8 +1621,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
|
||||
npc_type->texture = 1;
|
||||
npc_type->light = 0;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_meele_texture1 = 1;
|
||||
npc_type->d_meele_texture2 = 1;
|
||||
npc_type->d_melee_texture1 = 1;
|
||||
npc_type->d_melee_texture2 = 1;
|
||||
npc_type->merchanttype = 1;
|
||||
npc_type->bodytype = 1;
|
||||
npc_type->STR = 150;
|
||||
|
||||
@ -5057,14 +5057,21 @@ XS(XS_Client_UpdateTaskActivity); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_UpdateTaskActivity)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 4)
|
||||
Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count)");
|
||||
if (items < 4)
|
||||
Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update])");
|
||||
{
|
||||
bool ignore_quest_update = false;
|
||||
|
||||
Client * THIS;
|
||||
|
||||
int TaskID = (int)SvIV(ST(1));
|
||||
int ActivityID = (int)SvIV(ST(2));
|
||||
int Count = (int)SvUV(ST(3));
|
||||
|
||||
if (items == 5){
|
||||
ignore_quest_update = (bool)SvTRUE(ST(4));
|
||||
}
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *,tmp);
|
||||
@ -5074,7 +5081,7 @@ XS(XS_Client_UpdateTaskActivity)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->UpdateTaskActivity(TaskID, ActivityID, Count);
|
||||
THIS->UpdateTaskActivity(TaskID, ActivityID, Count, ignore_quest_update);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -6305,7 +6312,7 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$");
|
||||
newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$");
|
||||
newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$");
|
||||
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$");
|
||||
newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$");
|
||||
newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");
|
||||
|
||||
@ -40,19 +40,19 @@ XS(XS_HateEntry_GetEnt)
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetData(THIS)");
|
||||
{
|
||||
tHateEntry * THIS;
|
||||
struct_HateList * THIS;
|
||||
Mob * RETVAL;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(tHateEntry *,tmp);
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->ent;
|
||||
RETVAL = THIS->entity_on_hatelist;
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Mob", (void*)RETVAL);
|
||||
}
|
||||
@ -66,20 +66,20 @@ XS(XS_HateEntry_GetHate)
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetHate(THIS)");
|
||||
{
|
||||
tHateEntry * THIS;
|
||||
struct_HateList * THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(tHateEntry *,tmp);
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->hate;
|
||||
RETVAL = THIS->stored_hate_amount;
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
@ -92,20 +92,20 @@ XS(XS_HateEntry_GetDamage)
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: HateEntry::GetDamage(THIS)");
|
||||
{
|
||||
tHateEntry * THIS;
|
||||
struct_HateList * THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "HateEntry")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(tHateEntry *,tmp);
|
||||
THIS = INT2PTR(struct_HateList *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->damage;
|
||||
RETVAL = THIS->hatelist_damage;
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
|
||||
@ -5354,7 +5354,7 @@ XS(XS_Mob_SetHate)
|
||||
damage = (int32)SvIV(ST(3));
|
||||
}
|
||||
|
||||
THIS->SetHate(other, hate, damage);
|
||||
THIS->SetHateAmountOnEnt(other, hate, damage);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -6599,7 +6599,7 @@ XS(XS_Mob_GetHateList)
|
||||
|
||||
while(iter != hate_list.end())
|
||||
{
|
||||
tHateEntry *entry = (*iter);
|
||||
struct_HateList *entry = (*iter);
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "HateEntry", (void*)entry);
|
||||
XPUSHs(ST(0));
|
||||
|
||||
@ -393,6 +393,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
npc_type->gender = monster->gender;
|
||||
npc_type->luclinface = monster->luclinface;
|
||||
npc_type->helmtexture = monster->helmtexture;
|
||||
npc_type->herosforgemodel = monster->herosforgemodel;
|
||||
} else
|
||||
LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid);
|
||||
|
||||
|
||||
@ -200,6 +200,9 @@ bool QuestParserCollection::SpellHasQuestSub(uint32 spell_id, QuestEventID evt)
|
||||
}
|
||||
|
||||
bool QuestParserCollection::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
|
||||
if (itm == nullptr)
|
||||
return false;
|
||||
|
||||
std::string item_script;
|
||||
if(itm->GetItem()->ScriptFileID != 0) {
|
||||
item_script = "script_";
|
||||
@ -350,6 +353,8 @@ int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, s
|
||||
|
||||
int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
// needs pointer validation check on 'item' argument
|
||||
|
||||
std::string item_script;
|
||||
if(item->GetItem()->ScriptFileID != 0) {
|
||||
item_script = "script_";
|
||||
|
||||
@ -1227,13 +1227,18 @@ void QuestManager::settime(uint8 new_hour, uint8 new_min) {
|
||||
void QuestManager::itemlink(int item_id) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (initiator) {
|
||||
const ItemInst* inst = database.CreateItem(item_id);
|
||||
char* link = 0;
|
||||
if (initiator->MakeItemLink(link, inst))
|
||||
initiator->Message(0, "%s tells you, %c%s%s%c", owner->GetCleanName(),
|
||||
0x12, link, inst->GetItem()->Name, 0x12);
|
||||
safe_delete_array(link);
|
||||
safe_delete(inst);
|
||||
const Item_Struct* item = database.GetItem(item_id);
|
||||
if (item == nullptr)
|
||||
return;
|
||||
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), item_link.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2103,11 +2108,12 @@ int QuestManager::gettaskactivitydonecount(int task, int activity) {
|
||||
|
||||
}
|
||||
|
||||
void QuestManager::updatetaskactivity(int task, int activity, int count) {
|
||||
void QuestManager::updatetaskactivity(int task, int activity, int count, bool ignore_quest_update /*= false*/)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
|
||||
if(RuleB(TaskSystem, EnableTaskSystem) && initiator)
|
||||
initiator->UpdateTaskActivity(task, activity, count);
|
||||
initiator->UpdateTaskActivity(task, activity, count, ignore_quest_update);
|
||||
}
|
||||
|
||||
void QuestManager::resettaskactivity(int task, int activity) {
|
||||
@ -2336,7 +2342,7 @@ int QuestManager::collectitems_processSlot(int16 slot_id, uint32 item_id,
|
||||
bool remove)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
ItemInst *item;
|
||||
ItemInst *item = nullptr;
|
||||
int quantity = 0;
|
||||
|
||||
item = initiator->GetInv().GetItem(slot_id);
|
||||
@ -2461,16 +2467,19 @@ uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) {
|
||||
// Item Link for use in Variables - "my $example_link = quest::varlink(item_id);"
|
||||
const char* QuestManager::varlink(char* perltext, int item_id) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
const ItemInst* inst = database.CreateItem(item_id);
|
||||
if (!inst)
|
||||
const Item_Struct* item = database.GetItem(item_id);
|
||||
if (!item)
|
||||
return "INVALID ITEM ID IN VARLINK";
|
||||
char* link = 0;
|
||||
char* tempstr = 0;
|
||||
if (initiator->MakeItemLink(link, inst)) { // make a link to the item
|
||||
snprintf(perltext, 250, "%c%s%s%c", 0x12, link, inst->GetItem()->Name, 0x12);
|
||||
}
|
||||
safe_delete_array(link); // MakeItemLink() uses new also
|
||||
safe_delete(inst);
|
||||
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
if (initiator)
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
|
||||
return perltext;
|
||||
}
|
||||
|
||||
@ -2656,24 +2665,16 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
|
||||
sayid = sayid + 500000;
|
||||
|
||||
//Create the say link as an item link hash
|
||||
char linktext[250];
|
||||
Client::TextLink linker;
|
||||
linker.SetProxyItemID(sayid);
|
||||
linker.SetProxyText(LinkName);
|
||||
if (initiator)
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
if (initiator) {
|
||||
if (initiator->GetClientVersion() >= EQClientRoF2)
|
||||
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12);
|
||||
else if (initiator->GetClientVersion() >= EQClientRoF)
|
||||
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "0000000000000000000000000000000000000000000000000", LinkName, 0x12);
|
||||
else if (initiator->GetClientVersion() >= EQClientSoF)
|
||||
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000", LinkName, 0x12);
|
||||
else
|
||||
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "000000000000000000000000000000000000000", LinkName, 0x12);
|
||||
} else { // If no initiator, create an RoF2 saylink, since older clients handle RoF2 ones better than RoF2 handles older ones.
|
||||
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12);
|
||||
}
|
||||
auto say_link = linker.GenerateLink();
|
||||
strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
|
||||
strcpy(Phrase,linktext);
|
||||
return Phrase;
|
||||
|
||||
}
|
||||
|
||||
const char* QuestManager::getguildnamebyid(int guild_id) {
|
||||
|
||||
@ -183,7 +183,7 @@ public:
|
||||
bool istaskactive(int task);
|
||||
bool istaskactivityactive(int task, int activity);
|
||||
int gettaskactivitydonecount(int task, int activity);
|
||||
void updatetaskactivity(int task, int activity, int count);
|
||||
void updatetaskactivity(int task, int activity, int count, bool ignore_quest_update = false);
|
||||
void resettaskactivity(int task, int activity);
|
||||
void taskexploredarea(int exploreid);
|
||||
void assigntask(int taskid);
|
||||
|
||||
@ -106,7 +106,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE) || who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE))
|
||||
return; //-5?
|
||||
|
||||
int32 hate = max_damage;
|
||||
uint32 hate = max_damage;
|
||||
if(hate_override > -1)
|
||||
hate = hate_override;
|
||||
|
||||
@ -583,7 +583,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
int32 ndamage = 0;
|
||||
int32 max_hit = 0;
|
||||
int32 min_hit = 0;
|
||||
int32 hate = 0;
|
||||
uint32 hate = 0;
|
||||
int32 primaryweapondamage = 0;
|
||||
int32 backstab_dmg = 0;
|
||||
|
||||
@ -889,7 +889,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
if (HeadShot_Dmg)
|
||||
HeadShot = true;
|
||||
|
||||
int32 hate = 0;
|
||||
uint32 hate = 0;
|
||||
int32 TotalDmg = 0;
|
||||
int16 WDmg = 0;
|
||||
int16 ADmg = 0;
|
||||
@ -2354,7 +2354,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
skillinuse = SkillOffense;
|
||||
|
||||
int damage = 0;
|
||||
int32 hate = 0;
|
||||
uint32 hate = 0;
|
||||
int Hand = MainPrimary;
|
||||
if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
|
||||
|
||||
|
||||
@ -1897,10 +1897,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if (CalculatePoisonCounters(buffs[j].spellid) == 0)
|
||||
continue;
|
||||
if (effect_value >= static_cast<int>(buffs[j].counters)) {
|
||||
if (caster)
|
||||
if (caster) {
|
||||
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
|
||||
caster->CastOnCurer(buffs[j].spellid);
|
||||
CastOnCure(buffs[j].spellid);
|
||||
}
|
||||
effect_value -= buffs[j].counters;
|
||||
buffs[j].counters = 0;
|
||||
BuffFadeBySlot(j);
|
||||
@ -1930,10 +1931,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
continue;
|
||||
if (effect_value >= static_cast<int>(buffs[j].counters))
|
||||
{
|
||||
if (caster)
|
||||
if (caster) {
|
||||
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
|
||||
caster->CastOnCurer(buffs[j].spellid);
|
||||
CastOnCure(buffs[j].spellid);
|
||||
}
|
||||
effect_value -= buffs[j].counters;
|
||||
buffs[j].counters = 0;
|
||||
BuffFadeBySlot(j);
|
||||
@ -1965,10 +1967,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
continue;
|
||||
if (effect_value >= static_cast<int>(buffs[j].counters))
|
||||
{
|
||||
if (caster)
|
||||
if (caster) {
|
||||
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
|
||||
caster->CastOnCurer(buffs[j].spellid);
|
||||
CastOnCure(buffs[j].spellid);
|
||||
}
|
||||
effect_value -= buffs[j].counters;
|
||||
buffs[j].counters = 0;
|
||||
BuffFadeBySlot(j);
|
||||
@ -1999,10 +2002,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if (CalculateCorruptionCounters(buffs[j].spellid) == 0)
|
||||
continue;
|
||||
if (effect_value >= static_cast<int>(buffs[j].counters)) {
|
||||
if (caster)
|
||||
if (caster) {
|
||||
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
|
||||
caster->CastOnCurer(buffs[j].spellid);
|
||||
CastOnCure(buffs[j].spellid);
|
||||
}
|
||||
effect_value -= buffs[j].counters;
|
||||
buffs[j].counters = 0;
|
||||
BuffFadeBySlot(j);
|
||||
@ -2658,7 +2662,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
caster->Taunt(this->CastToNPC(), false, static_cast<float>(spell.base[i]));
|
||||
|
||||
if (spell.base2[i] > 0)
|
||||
CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i]));
|
||||
CastToNPC()->SetHateAmountOnEnt(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2689,7 +2693,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
|
||||
CastToNPC()->SetHate(caster, new_hate);
|
||||
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2710,9 +2714,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
}else{
|
||||
int32 newhate = GetHateAmount(caster) + effect_value;
|
||||
if (newhate < 1)
|
||||
SetHate(caster,1);
|
||||
SetHateAmountOnEnt(caster,1);
|
||||
else
|
||||
SetHate(caster,newhate);
|
||||
SetHateAmountOnEnt(caster,newhate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3542,9 +3546,9 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
}else{
|
||||
int32 newhate = GetHateAmount(caster) + effect_value;
|
||||
if (newhate < 1) {
|
||||
SetHate(caster,1);
|
||||
SetHateAmountOnEnt(caster,1);
|
||||
} else {
|
||||
SetHate(caster,newhate);
|
||||
SetHateAmountOnEnt(caster,newhate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3724,11 +3728,11 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
case SE_AddHateOverTimePct:
|
||||
{
|
||||
if (IsNPC()){
|
||||
int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
|
||||
CastToNPC()->SetHate(caster, new_hate);
|
||||
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -6420,7 +6424,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
|
||||
|
||||
//Limit to amount of pets
|
||||
if (value >= 221 && value <= 249){
|
||||
int count = hate_list.SummonedPetCount(this);
|
||||
int count = hate_list.GetSummonedPetCountOnHateList(this);
|
||||
|
||||
for (int base2_value = 221; base2_value <= 249; ++base2_value){
|
||||
if (value == base2_value){
|
||||
|
||||
@ -1195,22 +1195,29 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
uint32 recastdelay = 0;
|
||||
uint32 recasttype = 0;
|
||||
|
||||
for (int r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) {
|
||||
const ItemInst* aug_i = inst->GetAugment(r);
|
||||
|
||||
if(!aug_i)
|
||||
continue;
|
||||
const Item_Struct* aug = aug_i->GetItem();
|
||||
if(!aug)
|
||||
continue;
|
||||
|
||||
if ( aug->Click.Effect == spell_id )
|
||||
{
|
||||
recastdelay = aug_i->GetItem()->RecastDelay;
|
||||
recasttype = aug_i->GetItem()->RecastType;
|
||||
fromaug = true;
|
||||
while (true) {
|
||||
if (inst == nullptr)
|
||||
break;
|
||||
|
||||
for (int r = AUG_BEGIN; r < EmuConstants::ITEM_COMMON_SIZE; r++) {
|
||||
const ItemInst* aug_i = inst->GetAugment(r);
|
||||
|
||||
if (!aug_i)
|
||||
continue;
|
||||
const Item_Struct* aug = aug_i->GetItem();
|
||||
if (!aug)
|
||||
continue;
|
||||
|
||||
if (aug->Click.Effect == spell_id)
|
||||
{
|
||||
recastdelay = aug_i->GetItem()->RecastDelay;
|
||||
recasttype = aug_i->GetItem()->RecastType;
|
||||
fromaug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Test the aug recast delay
|
||||
@ -3649,11 +3656,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
spelltar->AddToHateList(this, aggro);
|
||||
}
|
||||
else{
|
||||
int32 newhate = spelltar->GetHateAmount(this) + aggro;
|
||||
uint32 newhate = spelltar->GetHateAmount(this) + aggro;
|
||||
if (newhate < 1) {
|
||||
spelltar->SetHate(this,1);
|
||||
spelltar->SetHateAmountOnEnt(this,1);
|
||||
} else {
|
||||
spelltar->SetHate(this,newhate);
|
||||
spelltar->SetHateAmountOnEnt(this,newhate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3681,9 +3688,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
spelltar->AddToHateList(this, aggro_amount); else{
|
||||
int32 newhate = spelltar->GetHateAmount(this) + aggro_amount;
|
||||
if (newhate < 1) {
|
||||
spelltar->SetHate(this,1);
|
||||
spelltar->SetHateAmountOnEnt(this,1);
|
||||
} else {
|
||||
spelltar->SetHate(this,newhate);
|
||||
spelltar->SetHateAmountOnEnt(this,newhate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3896,6 +3903,8 @@ void Mob::BuffFadeDetrimental() {
|
||||
BuffFadeBySlot(j, false);
|
||||
}
|
||||
}
|
||||
//we tell BuffFadeBySlot not to recalc, so we can do it only once when were done
|
||||
CalcBonuses();
|
||||
}
|
||||
|
||||
void Mob::BuffFadeDetrimentalByCaster(Mob *caster)
|
||||
@ -3916,6 +3925,8 @@ void Mob::BuffFadeDetrimentalByCaster(Mob *caster)
|
||||
}
|
||||
}
|
||||
}
|
||||
//we tell BuffFadeBySlot not to recalc, so we can do it only once when were done
|
||||
CalcBonuses();
|
||||
}
|
||||
|
||||
void Mob::BuffFadeBySitModifier()
|
||||
@ -4195,6 +4206,10 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
//Get resist modifier and adjust it based on focus 2 resist about eq to 1% resist chance
|
||||
int resist_modifier = (use_resist_override) ? resist_override : spells[spell_id].ResistDiff;
|
||||
|
||||
if(caster->GetSpecialAbility(CASTING_RESIST_DIFF))
|
||||
resist_modifier += caster->GetSpecialAbilityParam(CASTING_RESIST_DIFF, 0);
|
||||
|
||||
int focus_resist = caster->GetFocusEffect(focusResistRate, spell_id);
|
||||
resist_modifier -= 2 * focus_resist;
|
||||
|
||||
|
||||
106
zone/tasks.cpp
106
zone/tasks.cpp
@ -1786,7 +1786,7 @@ void ClientTaskState::UpdateTasksOnTouch(Client *c, int ZoneID) {
|
||||
|
||||
return;
|
||||
}
|
||||
void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count) {
|
||||
void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count, bool ignore_quest_update) {
|
||||
|
||||
_log(TASKS__UPDATE, "IncrementDoneCount");
|
||||
|
||||
@ -1795,10 +1795,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
|
||||
if(ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount > Task->Activity[ActivityID].GoalCount)
|
||||
ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount = Task->Activity[ActivityID].GoalCount;
|
||||
|
||||
char buf[24];
|
||||
snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID);
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0);
|
||||
if (!ignore_quest_update){
|
||||
char buf[24];
|
||||
snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID);
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0);
|
||||
}
|
||||
|
||||
ActiveTasks[TaskIndex].Activity[ActivityID].Updated=true;
|
||||
// Have we reached the goal count for this activity ?
|
||||
@ -1821,11 +1823,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
|
||||
c->Message(0, "Your task '%s' has been updated.", Task->Title);
|
||||
|
||||
if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) {
|
||||
char buf[24];
|
||||
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
|
||||
|
||||
if (!ignore_quest_update){
|
||||
char buf[24];
|
||||
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
|
||||
buf[23] = '\0';
|
||||
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
|
||||
}
|
||||
/* QS: PlayerLogTaskUpdates :: Update */
|
||||
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
|
||||
std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
|
||||
@ -2039,7 +2042,8 @@ bool ClientTaskState::IsTaskActivityActive(int TaskID, int ActivityID) {
|
||||
|
||||
}
|
||||
|
||||
void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count) {
|
||||
void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update /*= false*/)
|
||||
{
|
||||
|
||||
_log(TASKS__UPDATE, "ClientTaskState UpdateTaskActivity(%i, %i, %i).", TaskID, ActivityID, Count);
|
||||
|
||||
@ -2048,8 +2052,8 @@ void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID,
|
||||
|
||||
int ActiveTaskIndex = -1;
|
||||
|
||||
for(int i=0; i<MAXACTIVETASKS; i++) {
|
||||
if(ActiveTasks[i].TaskID==TaskID) {
|
||||
for (int i = 0; i < MAXACTIVETASKS; i++) {
|
||||
if (ActiveTasks[i].TaskID == TaskID) {
|
||||
ActiveTaskIndex = i;
|
||||
break;
|
||||
}
|
||||
@ -2069,7 +2073,7 @@ void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID,
|
||||
// The Activity is not currently active
|
||||
if(ActiveTasks[ActiveTaskIndex].Activity[ActivityID].State != ActivityActive) return;
|
||||
_log(TASKS__UPDATE, "Increment done count on UpdateTaskActivity");
|
||||
IncrementDoneCount(c, Task, ActiveTaskIndex, ActivityID, Count);
|
||||
IncrementDoneCount(c, Task, ActiveTaskIndex, ActivityID, Count, ignore_quest_update);
|
||||
|
||||
}
|
||||
|
||||
@ -2743,17 +2747,17 @@ void TaskManager::SendSingleActiveTaskToClient(Client *c, int TaskIndex, bool Ta
|
||||
}
|
||||
}
|
||||
|
||||
void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceNumber, int StartTime, int Duration, bool BringUpTaskJournal) {
|
||||
|
||||
|
||||
if((TaskID<1) || (TaskID>=MAXTASKS) || !Tasks[TaskID]) return;
|
||||
void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceNumber, int StartTime, int Duration, bool BringUpTaskJournal)
|
||||
{
|
||||
if ((TaskID < 1) || (TaskID >= MAXTASKS) || !Tasks[TaskID])
|
||||
return;
|
||||
|
||||
int PacketLength = sizeof(TaskDescriptionHeader_Struct) + strlen(Tasks[TaskID]->Title) + 1
|
||||
+ sizeof(TaskDescriptionData1_Struct) + strlen(Tasks[TaskID]->Description) + 1
|
||||
+ sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct);
|
||||
|
||||
std::string RewardText;
|
||||
int ItemID = 0;
|
||||
int ItemID = NOT_USED;
|
||||
|
||||
// If there is an item make the Reward text into a link to the item (only the first item if a list
|
||||
// is specified). I have been unable to get multiple item links to work.
|
||||
@ -2768,62 +2772,20 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN
|
||||
if(ItemID < 0)
|
||||
ItemID = 0;
|
||||
}
|
||||
|
||||
if(ItemID) {
|
||||
char *RewardTmp = 0;
|
||||
if(strlen(Tasks[TaskID]->Reward) != 0) {
|
||||
const Item_Struct* reward_item = database.GetItem(ItemID);
|
||||
|
||||
switch(c->GetClientVersion()) {
|
||||
case EQClientTitanium:
|
||||
{
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
|
||||
break;
|
||||
}
|
||||
case EQClientRoF:
|
||||
{
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// All clients after Titanium
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
|
||||
}
|
||||
}
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(reward_item);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
linker.SetTaskUse();
|
||||
if (strlen(Tasks[TaskID]->Reward) != 0)
|
||||
linker.SetProxyText(Tasks[TaskID]->Reward);
|
||||
|
||||
}
|
||||
else {
|
||||
const Item_Struct *Item = database.GetItem(ItemID);
|
||||
|
||||
if(Item) {
|
||||
|
||||
switch(c->GetClientVersion()) {
|
||||
case EQClientTitanium:
|
||||
{
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Item->Name ,0x12);
|
||||
break;
|
||||
}
|
||||
case EQClientRoF:
|
||||
{
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Item->Name ,0x12);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// All clients after Titanium
|
||||
MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c",
|
||||
0x12, ItemID, Item->Name ,0x12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(RewardTmp) RewardText += RewardTmp;
|
||||
safe_delete_array(RewardTmp);
|
||||
auto reward_link = linker.GenerateLink();
|
||||
RewardText += reward_link.c_str();
|
||||
}
|
||||
else {
|
||||
RewardText += Tasks[TaskID]->Reward;
|
||||
|
||||
@ -175,7 +175,7 @@ public:
|
||||
bool IsTaskActive(int TaskID);
|
||||
bool IsTaskActivityActive(int TaskID, int ActivityID);
|
||||
ActivityState GetTaskActivityState(int index, int ActivityID);
|
||||
void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count);
|
||||
void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update = false);
|
||||
void ResetTaskActivity(Client *c, int TaskID, int ActivityID);
|
||||
void CancelTask(Client *c, int SequenceNumber, bool RemoveFromDB = true);
|
||||
void CancelAllTasks(Client *c);
|
||||
@ -204,7 +204,7 @@ public:
|
||||
|
||||
private:
|
||||
bool UnlockActivities(int CharID, int TaskIndex);
|
||||
void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count=1);
|
||||
void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count = 1, bool ignore_quest_update = false);
|
||||
int ActiveTaskCount;
|
||||
ClientTaskInformation ActiveTasks[MAXACTIVETASKS];
|
||||
std::vector<int>EnabledTasks;
|
||||
|
||||
@ -94,7 +94,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
|
||||
return;
|
||||
}
|
||||
|
||||
ItemInst *tobe_auged, *auged_with = nullptr;
|
||||
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
|
||||
int8 slot=-1;
|
||||
|
||||
// Verify 2 items in the augmentation device
|
||||
@ -1185,6 +1185,8 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float
|
||||
bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id,
|
||||
uint32 char_id, DBTradeskillRecipe_Struct *spec)
|
||||
{
|
||||
if (container == nullptr)
|
||||
return false;
|
||||
|
||||
std::string containers;// make where clause segment for container(s)
|
||||
if (some_id == 0)
|
||||
|
||||
@ -159,6 +159,9 @@ Mob* Trade::With()
|
||||
// Private Method: Send item data for trade item to other person involved in trade
|
||||
void Trade::SendItemData(const ItemInst* inst, int16 dest_slot_id)
|
||||
{
|
||||
if (inst == nullptr)
|
||||
return;
|
||||
|
||||
// @merth: This needs to be redone with new item classes
|
||||
Mob* mob = With();
|
||||
if (!mob->IsClient())
|
||||
|
||||
@ -315,8 +315,8 @@ void Trap::CreateHiddenTrigger()
|
||||
make_npc->gender = 0;
|
||||
make_npc->loottable_id = 0;
|
||||
make_npc->npc_spells_id = 0;
|
||||
make_npc->d_meele_texture1 = 0;
|
||||
make_npc->d_meele_texture2 = 0;
|
||||
make_npc->d_melee_texture1 = 0;
|
||||
make_npc->d_melee_texture2 = 0;
|
||||
make_npc->trackable = 0;
|
||||
make_npc->level = level;
|
||||
strcpy(make_npc->special_abilities, "19,1^20,1^24,1^25,1");
|
||||
|
||||
@ -21,15 +21,15 @@ class WaterMap
|
||||
{
|
||||
public:
|
||||
WaterMap() { }
|
||||
~WaterMap() { }
|
||||
|
||||
virtual ~WaterMap() { }
|
||||
|
||||
static WaterMap* LoadWaterMapfile(std::string zone_name);
|
||||
virtual WaterRegionType ReturnRegionType(float y, float x, float z) const { return RegionTypeNormal; }
|
||||
virtual bool InWater(float y, float x, float z) const { return false; }
|
||||
virtual bool InVWater(float y, float x, float z) const { return false; }
|
||||
virtual bool InLava(float y, float x, float z) const { return false; }
|
||||
virtual bool InLiquid(float y, float x, float z) const { return false; }
|
||||
|
||||
|
||||
protected:
|
||||
virtual bool Load(FILE *fp) { return false; }
|
||||
};
|
||||
|
||||
@ -391,7 +391,9 @@ void NPC::GetClosestWaypoint(std::list<wplist> &wp_list, int count, float m_x, f
|
||||
w_dist.index = i;
|
||||
distances.push_back(w_dist);
|
||||
}
|
||||
distances.sort(wp_distance_pred);
|
||||
distances.sort([](const wp_distance& a, const wp_distance& b) {
|
||||
return a.dist < b.dist;
|
||||
});
|
||||
|
||||
std::list<wp_distance>::iterator iter = distances.begin();
|
||||
for(int i = 0; i < count; ++i)
|
||||
@ -694,7 +696,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
{
|
||||
Map::Vertex dest(x_pos, y_pos, z_pos);
|
||||
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr); + 2.0f;
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
|
||||
mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);
|
||||
|
||||
|
||||
@ -2234,7 +2234,10 @@ void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
|
||||
}
|
||||
|
||||
void Zone::ReloadWorld(uint32 Option){
|
||||
if(Option == 1){
|
||||
if (Option == 0) {
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
} else if(Option == 1) {
|
||||
zone->Repop(0);
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
|
||||
207
zone/zonedb.cpp
207
zone/zonedb.cpp
@ -1740,15 +1740,15 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
// according to spawn2.
|
||||
std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, "
|
||||
"npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, "
|
||||
"npc_types.texture, npc_types.helmtexture, npc_types.size, "
|
||||
"npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, "
|
||||
"npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, "
|
||||
"npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, "
|
||||
"npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, "
|
||||
"npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, "
|
||||
"npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR,"
|
||||
"npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities,"
|
||||
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_meele_texture1,"
|
||||
"npc_types.d_meele_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type,"
|
||||
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1,"
|
||||
"npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type,"
|
||||
"npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable,"
|
||||
"npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, "
|
||||
"npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, "
|
||||
@ -1790,88 +1790,86 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
tmpNPCType->gender = atoi(row[7]);
|
||||
tmpNPCType->texture = atoi(row[8]);
|
||||
tmpNPCType->helmtexture = atoi(row[9]);
|
||||
tmpNPCType->size = atof(row[10]);
|
||||
tmpNPCType->loottable_id = atoi(row[11]);
|
||||
tmpNPCType->merchanttype = atoi(row[12]);
|
||||
tmpNPCType->alt_currency_type = atoi(row[13]);
|
||||
tmpNPCType->adventure_template = atoi(row[14]);
|
||||
tmpNPCType->trap_template = atoi(row[15]);
|
||||
tmpNPCType->attack_speed = atof(row[16]);
|
||||
tmpNPCType->STR = atoi(row[17]);
|
||||
tmpNPCType->STA = atoi(row[18]);
|
||||
tmpNPCType->DEX = atoi(row[19]);
|
||||
tmpNPCType->AGI = atoi(row[20]);
|
||||
tmpNPCType->INT = atoi(row[21]);
|
||||
tmpNPCType->WIS = atoi(row[22]);
|
||||
tmpNPCType->CHA = atoi(row[23]);
|
||||
tmpNPCType->MR = atoi(row[24]);
|
||||
tmpNPCType->CR = atoi(row[25]);
|
||||
tmpNPCType->DR = atoi(row[26]);
|
||||
tmpNPCType->FR = atoi(row[27]);
|
||||
tmpNPCType->PR = atoi(row[28]);
|
||||
tmpNPCType->Corrup = atoi(row[29]);
|
||||
tmpNPCType->PhR = atoi(row[30]);
|
||||
tmpNPCType->min_dmg = atoi(row[31]);
|
||||
tmpNPCType->max_dmg = atoi(row[32]);
|
||||
tmpNPCType->attack_count = atoi(row[33]);
|
||||
tmpNPCType->herosforgemodel = atoul(row[10]);
|
||||
tmpNPCType->size = atof(row[11]);
|
||||
tmpNPCType->loottable_id = atoi(row[12]);
|
||||
tmpNPCType->merchanttype = atoi(row[13]);
|
||||
tmpNPCType->alt_currency_type = atoi(row[14]);
|
||||
tmpNPCType->adventure_template = atoi(row[15]);
|
||||
tmpNPCType->trap_template = atoi(row[16]);
|
||||
tmpNPCType->attack_speed = atof(row[17]);
|
||||
tmpNPCType->STR = atoi(row[18]);
|
||||
tmpNPCType->STA = atoi(row[19]);
|
||||
tmpNPCType->DEX = atoi(row[20]);
|
||||
tmpNPCType->AGI = atoi(row[21]);
|
||||
tmpNPCType->INT = atoi(row[22]);
|
||||
tmpNPCType->WIS = atoi(row[23]);
|
||||
tmpNPCType->CHA = atoi(row[24]);
|
||||
tmpNPCType->MR = atoi(row[25]);
|
||||
tmpNPCType->CR = atoi(row[26]);
|
||||
tmpNPCType->DR = atoi(row[27]);
|
||||
tmpNPCType->FR = atoi(row[28]);
|
||||
tmpNPCType->PR = atoi(row[29]);
|
||||
tmpNPCType->Corrup = atoi(row[30]);
|
||||
tmpNPCType->PhR = atoi(row[31]);
|
||||
tmpNPCType->min_dmg = atoi(row[32]);
|
||||
tmpNPCType->max_dmg = atoi(row[33]);
|
||||
tmpNPCType->attack_count = atoi(row[34]);
|
||||
|
||||
if (row[34] != nullptr)
|
||||
strn0cpy(tmpNPCType->special_abilities, row[34], 512);
|
||||
if (row[35] != nullptr)
|
||||
strn0cpy(tmpNPCType->special_abilities, row[35], 512);
|
||||
else
|
||||
tmpNPCType->special_abilities[0] = '\0';
|
||||
|
||||
tmpNPCType->npc_spells_id = atoi(row[35]);
|
||||
tmpNPCType->npc_spells_effects_id = atoi(row[36]);
|
||||
tmpNPCType->d_meele_texture1 = atoi(row[37]);
|
||||
tmpNPCType->d_meele_texture2 = atoi(row[38]);
|
||||
strn0cpy(tmpNPCType->ammo_idfile, row[39], 30);
|
||||
tmpNPCType->prim_melee_type = atoi(row[40]);
|
||||
tmpNPCType->sec_melee_type = atoi(row[41]);
|
||||
tmpNPCType->ranged_type = atoi(row[42]);
|
||||
tmpNPCType->runspeed= atof(row[43]);
|
||||
tmpNPCType->findable = atoi(row[44]) == 0? false : true;
|
||||
tmpNPCType->trackable = atoi(row[45]) == 0? false : true;
|
||||
tmpNPCType->hp_regen = atoi(row[46]);
|
||||
tmpNPCType->mana_regen = atoi(row[47]);
|
||||
tmpNPCType->npc_spells_id = atoi(row[36]);
|
||||
tmpNPCType->npc_spells_effects_id = atoi(row[37]);
|
||||
tmpNPCType->d_melee_texture1 = atoi(row[38]);
|
||||
tmpNPCType->d_melee_texture2 = atoi(row[39]);
|
||||
strn0cpy(tmpNPCType->ammo_idfile, row[40], 30);
|
||||
tmpNPCType->prim_melee_type = atoi(row[41]);
|
||||
tmpNPCType->sec_melee_type = atoi(row[42]);
|
||||
tmpNPCType->ranged_type = atoi(row[43]);
|
||||
tmpNPCType->runspeed= atof(row[44]);
|
||||
tmpNPCType->findable = atoi(row[45]) == 0? false : true;
|
||||
tmpNPCType->trackable = atoi(row[46]) == 0? false : true;
|
||||
tmpNPCType->hp_regen = atoi(row[47]);
|
||||
tmpNPCType->mana_regen = atoi(row[48]);
|
||||
|
||||
// set defaultvalue for aggroradius
|
||||
tmpNPCType->aggroradius = (int32)atoi(row[48]);
|
||||
// set default value for aggroradius
|
||||
tmpNPCType->aggroradius = (int32)atoi(row[49]);
|
||||
if (tmpNPCType->aggroradius <= 0)
|
||||
tmpNPCType->aggroradius = 70;
|
||||
|
||||
tmpNPCType->assistradius = (int32)atoi(row[49]);
|
||||
tmpNPCType->assistradius = (int32)atoi(row[50]);
|
||||
if (tmpNPCType->assistradius <= 0)
|
||||
tmpNPCType->assistradius = tmpNPCType->aggroradius;
|
||||
|
||||
if (row[50] && strlen(row[50]))
|
||||
tmpNPCType->bodytype = (uint8)atoi(row[50]);
|
||||
if (row[51] && strlen(row[51]))
|
||||
tmpNPCType->bodytype = (uint8)atoi(row[51]);
|
||||
else
|
||||
tmpNPCType->bodytype = 0;
|
||||
|
||||
tmpNPCType->npc_faction_id = atoi(row[51]);
|
||||
tmpNPCType->npc_faction_id = atoi(row[52]);
|
||||
|
||||
tmpNPCType->luclinface = atoi(row[52]);
|
||||
tmpNPCType->hairstyle = atoi(row[53]);
|
||||
tmpNPCType->haircolor = atoi(row[54]);
|
||||
tmpNPCType->eyecolor1 = atoi(row[55]);
|
||||
tmpNPCType->eyecolor2 = atoi(row[56]);
|
||||
tmpNPCType->beardcolor = atoi(row[57]);
|
||||
tmpNPCType->beard = atoi(row[58]);
|
||||
tmpNPCType->drakkin_heritage = atoi(row[59]);
|
||||
tmpNPCType->drakkin_tattoo = atoi(row[60]);
|
||||
tmpNPCType->drakkin_details = atoi(row[61]);
|
||||
tmpNPCType->luclinface = atoi(row[53]);
|
||||
tmpNPCType->hairstyle = atoi(row[54]);
|
||||
tmpNPCType->haircolor = atoi(row[55]);
|
||||
tmpNPCType->eyecolor1 = atoi(row[56]);
|
||||
tmpNPCType->eyecolor2 = atoi(row[57]);
|
||||
tmpNPCType->beardcolor = atoi(row[58]);
|
||||
tmpNPCType->beard = atoi(row[59]);
|
||||
tmpNPCType->drakkin_heritage = atoi(row[60]);
|
||||
tmpNPCType->drakkin_tattoo = atoi(row[61]);
|
||||
tmpNPCType->drakkin_details = atoi(row[62]);
|
||||
|
||||
uint32 armor_tint_id = atoi(row[62]);
|
||||
uint32 armor_tint_id = atoi(row[63]);
|
||||
|
||||
tmpNPCType->armor_tint[0] = (atoi(row[63]) & 0xFF) << 16;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[64]) & 0xFF) << 8;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF);
|
||||
tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF);
|
||||
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
|
||||
|
||||
if (armor_tint_id == 0)
|
||||
for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++)
|
||||
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
|
||||
else if (tmpNPCType->armor_tint[0] == 0)
|
||||
if (armor_tint_id != 0)
|
||||
{
|
||||
std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
|
||||
"red2c, grn2c, blu2c, "
|
||||
@ -1886,46 +1884,57 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
armor_tint_id);
|
||||
auto armortint_results = QueryDatabase(armortint_query);
|
||||
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
|
||||
armor_tint_id = 0;
|
||||
else {
|
||||
{
|
||||
armor_tint_id = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto armorTint_row = armortint_results.begin();
|
||||
|
||||
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
|
||||
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++)
|
||||
{
|
||||
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
|
||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
|
||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
|
||||
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
armor_tint_id = 0;
|
||||
}
|
||||
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
|
||||
if (armor_tint_id == 0)
|
||||
{
|
||||
for (int index = MaterialChest; index < _MaterialCount; index++)
|
||||
{
|
||||
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
|
||||
}
|
||||
}
|
||||
|
||||
tmpNPCType->see_invis = atoi(row[66]);
|
||||
tmpNPCType->see_invis_undead = atoi(row[67]) == 0? false: true; // Set see_invis_undead flag
|
||||
if (row[68] != nullptr)
|
||||
strn0cpy(tmpNPCType->lastname, row[68], 32);
|
||||
tmpNPCType->see_invis = atoi(row[67]);
|
||||
tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
|
||||
if (row[69] != nullptr)
|
||||
strn0cpy(tmpNPCType->lastname, row[69], 32);
|
||||
|
||||
tmpNPCType->qglobal = atoi(row[69]) == 0? false: true; // qglobal
|
||||
tmpNPCType->AC = atoi(row[70]);
|
||||
tmpNPCType->npc_aggro = atoi(row[71]) == 0? false: true;
|
||||
tmpNPCType->spawn_limit = atoi(row[72]);
|
||||
tmpNPCType->see_hide = atoi(row[73]) == 0? false: true;
|
||||
tmpNPCType->see_improved_hide = atoi(row[74]) == 0? false: true;
|
||||
tmpNPCType->ATK = atoi(row[75]);
|
||||
tmpNPCType->accuracy_rating = atoi(row[76]);
|
||||
tmpNPCType->avoidance_rating = atoi(row[77]);
|
||||
tmpNPCType->slow_mitigation = atoi(row[78]);
|
||||
tmpNPCType->maxlevel = atoi(row[79]);
|
||||
tmpNPCType->scalerate = atoi(row[80]);
|
||||
tmpNPCType->private_corpse = atoi(row[81]) == 1 ? true: false;
|
||||
tmpNPCType->unique_spawn_by_name = atoi(row[82]) == 1 ? true: false;
|
||||
tmpNPCType->underwater = atoi(row[83]) == 1 ? true: false;
|
||||
tmpNPCType->emoteid = atoi(row[84]);
|
||||
tmpNPCType->spellscale = atoi(row[85]);
|
||||
tmpNPCType->healscale = atoi(row[86]);
|
||||
tmpNPCType->no_target_hotkey = atoi(row[87]) == 1 ? true: false;
|
||||
tmpNPCType->raid_target = atoi(row[88]) == 0 ? false: true;
|
||||
tmpNPCType->attack_delay = atoi(row[89]);
|
||||
tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal
|
||||
tmpNPCType->AC = atoi(row[71]);
|
||||
tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true;
|
||||
tmpNPCType->spawn_limit = atoi(row[73]);
|
||||
tmpNPCType->see_hide = atoi(row[74]) == 0? false: true;
|
||||
tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true;
|
||||
tmpNPCType->ATK = atoi(row[76]);
|
||||
tmpNPCType->accuracy_rating = atoi(row[77]);
|
||||
tmpNPCType->avoidance_rating = atoi(row[78]);
|
||||
tmpNPCType->slow_mitigation = atoi(row[79]);
|
||||
tmpNPCType->maxlevel = atoi(row[80]);
|
||||
tmpNPCType->scalerate = atoi(row[81]);
|
||||
tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false;
|
||||
tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
|
||||
tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false;
|
||||
tmpNPCType->emoteid = atoi(row[85]);
|
||||
tmpNPCType->spellscale = atoi(row[86]);
|
||||
tmpNPCType->healscale = atoi(row[87]);
|
||||
tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
||||
tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true;
|
||||
tmpNPCType->attack_delay = atoi(row[90]);
|
||||
|
||||
// If NPC with duplicate NPC id already in table,
|
||||
// free item we attempted to add.
|
||||
@ -1968,7 +1977,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
|
||||
"vwMercNpcTypes.CR, vwMercNpcTypes.DR, vwMercNpcTypes.FR, vwMercNpcTypes.PR, "
|
||||
"vwMercNpcTypes.Corrup, vwMercNpcTypes.mindmg, vwMercNpcTypes.maxdmg, "
|
||||
"vwMercNpcTypes.attack_count, vwMercNpcTypes.special_abilities, "
|
||||
"vwMercNpcTypes.d_meele_texture1, vwMercNpcTypes.d_meele_texture2, "
|
||||
"vwMercNpcTypes.d_melee_texture1, vwMercNpcTypes.d_melee_texture2, "
|
||||
"vwMercNpcTypes.prim_melee_type, vwMercNpcTypes.sec_melee_type, "
|
||||
"vwMercNpcTypes.runspeed, vwMercNpcTypes.hp_regen_rate, vwMercNpcTypes.mana_regen_rate, "
|
||||
"vwMercNpcTypes.bodytype, vwMercNpcTypes.armortint_id, "
|
||||
@ -2027,8 +2036,8 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
|
||||
else
|
||||
tmpNPCType->special_abilities[0] = '\0';
|
||||
|
||||
tmpNPCType->d_meele_texture1 = atoi(row[28]);
|
||||
tmpNPCType->d_meele_texture2 = atoi(row[29]);
|
||||
tmpNPCType->d_melee_texture1 = atoi(row[28]);
|
||||
tmpNPCType->d_melee_texture2 = atoi(row[29]);
|
||||
tmpNPCType->prim_melee_type = atoi(row[30]);
|
||||
tmpNPCType->sec_melee_type = atoi(row[31]);
|
||||
tmpNPCType->runspeed= atof(row[32]);
|
||||
|
||||
@ -49,6 +49,7 @@ struct NPCType
|
||||
uint32 npc_id;
|
||||
uint8 texture;
|
||||
uint8 helmtexture;
|
||||
uint32 herosforgemodel;
|
||||
uint32 loottable_id;
|
||||
uint32 npc_spells_id;
|
||||
uint32 npc_spells_effects_id;
|
||||
@ -90,8 +91,8 @@ struct NPCType
|
||||
uint32 max_dmg;
|
||||
int16 attack_count;
|
||||
char special_abilities[512];
|
||||
uint16 d_meele_texture1;
|
||||
uint16 d_meele_texture2;
|
||||
uint16 d_melee_texture1;
|
||||
uint16 d_melee_texture2;
|
||||
char ammo_idfile[30];
|
||||
uint8 prim_melee_type;
|
||||
uint8 sec_melee_type;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user