Merge remote-tracking branch 'remotes/origin/master' into web_interface

Conflicts:
	common/shareddb.cpp
This commit is contained in:
Akkadius
2015-01-04 06:45:50 -06:00
85 changed files with 2703 additions and 2329 deletions
+50
View File
@@ -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
+6 -5
View File
@@ -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 {
+26 -8
View File
@@ -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;
+4
View File
@@ -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);
+8 -31
View File
@@ -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);
}
}
+136 -80
View File
@@ -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,27 +4924,8 @@ 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())
{
@@ -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
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
+2
View File
@@ -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
+56 -96
View File
@@ -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;
+12 -21
View File
@@ -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
+4 -4
View File
@@ -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;
+3 -3
View File
@@ -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);
}
+2 -2
View File
@@ -2624,8 +2624,8 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 padding002;
uint32 entityid;
//uint16 padding002;
float distance;
};
+1 -1
View File
@@ -1094,7 +1094,7 @@ namespace Titanium
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
{
OUT(entityid);
OUT(padding002);
//OUT(padding002);
OUT(distance);
}
+2 -2
View File
@@ -2319,8 +2319,8 @@ struct MobHealth
};
struct Track_Struct {
uint16 entityid;
uint16 padding002;
uint32 entityid;
//uint16 padding002;
float distance;
};
+4 -4
View File
@@ -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;
+30 -4
View File
@@ -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);
}
+3 -1
View File
@@ -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()
+1 -1
View File
@@ -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); }
+1 -1
View File
@@ -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
+14 -14
View File
@@ -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
+32
View File
@@ -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
View 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++;
}
+4
View File
@@ -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`;
@@ -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';
+8 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
}
+16 -14
View File
@@ -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);
@@ -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);
}
}
+446 -446
View File
File diff suppressed because it is too large Load Diff
+52 -129
View File
@@ -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;
if(botweapon && botweapon->ItemType == ItemTypeBow) {
uint32 range = 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)) {
// no item struct for whatever reason
if (!range_item || !ammo_item)
return 0;
}
range += botweapon->Range;
// bad item types
if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow)
return 0;
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) {
+1 -1
View File
@@ -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; }
+236 -40
View File
@@ -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";
}
+53 -3
View File
@@ -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);
@@ -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); }
+18 -24
View File
@@ -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,6 +12347,11 @@ 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();
while (true) {
if (inst2 == nullptr)
break;
if (RuleB(Merchant, UsePriceMod)){
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false));
}
@@ -12377,6 +12368,9 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant);
safe_delete(inst2);
break;
}
}
// start QS code
+336 -463
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -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
+19 -14
View File
@@ -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);
}
@@ -1266,28 +1266,33 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
}
/* 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);
+10
View File
@@ -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);
+5 -3
View File
@@ -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])");
}
+2
View File
@@ -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;
+24 -23
View File
@@ -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,9 +2060,11 @@ 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,6 +2273,7 @@ bool EntityList::RemoveGroup(uint32 delete_id)
while(iterator != group_list.end())
{
if((*iterator)->GetID() == delete_id) {
safe_delete(*iterator);
group_list.remove(*iterator);
#if EQDEBUG >= 5
CheckGroupList (__FILE__, __LINE__);
@@ -2291,6 +2297,7 @@ bool EntityList::RemoveRaid(uint32 delete_id)
while(iterator != raid_list.end())
{
if((*iterator)->GetID() == delete_id) {
safe_delete(*iterator);
raid_list.remove(*iterator);
return true;
}
@@ -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;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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;
}
+2 -1
View File
@@ -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++;
}
}
+168 -169
View File
@@ -36,7 +36,7 @@ extern Zone *zone;
HateList::HateList()
{
owner = nullptr;
hate_owner = nullptr;
}
HateList::~HateList()
@@ -45,27 +45,27 @@ 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())
{
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())
{
Mob* m = (*iterator)->ent;
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())
m->CastToClient()->DecrementAggroCount();
@@ -76,38 +76,38 @@ void HateList::Wipe()
}
}
bool HateList::IsOnHateList(Mob *mob)
bool HateList::IsEntOnHateList(Mob *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())
{
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_damage > 0)
entity->hatelist_damage = in_damage;
if (in_hate > 0)
p->hate = in_hate;
entity->stored_hate_amount = in_hate;
}
}
Mob* HateList::GetDamageTop(Mob* hater)
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
{
Mob* current = nullptr;
Group* grp = nullptr;
@@ -120,114 +120,112 @@ Mob* HateList::GetDamageTop(Mob* hater)
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 ((*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;
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())
{
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())
{
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()) {
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;
// hack fix for zone shutdown crashes on some servers
if (!zone->IsLoaded())
return nullptr;
Mob* top_hate = nullptr;
int32 hate = -1;
if (center == nullptr)
return nullptr;
if (RuleB(Aggro, SmartAggroList)){
Mob* topClientTypeInRange = nullptr;
int32 hateClientTypeInRange = -1;
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())
{
tHateEntry *cur = (*iterator);
int16 aggroMod = 0;
struct_HateList *cur = (*iterator);
int16 aggro_mod = 0;
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 (!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 (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 (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 (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;
}
}
}
@@ -361,68 +363,68 @@ Mob *HateList::GetTop(Mob *center)
}
else{
if (center){
if(center->GetTarget() == cur->ent)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
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 (top_hate->IsBot()) {
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
#endif //BOTS
if (!isTopClientType) {
if(top->IsMerc()) {
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;
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{
@@ -430,42 +432,42 @@ Mob *HateList::GetTop(Mob *center)
int skipped_count = 0;
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
struct_HateList *cur = (*iterator);
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
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())
{
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,7 +475,7 @@ 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.
@@ -482,7 +484,7 @@ Mob *HateList::GetRandom()
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;
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;
}
@@ -539,13 +539,13 @@ 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;
}
}
@@ -588,20 +588,20 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *h = (*iterator);
struct_HateList *h = (*iterator);
if (range > 0)
{
dist_targ = center->DistNoRoot(*h->ent);
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;
}
@@ -617,4 +617,3 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
iter++;
}
}
+29 -43
View File
@@ -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);
int32 GetEntHateAmount(Mob *ent, bool in_damage = false);
std::list<struct_HateList*>& 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();
bool IsEmpty();
void PrintToClient(Client *c);
//For accessing the hate list via perl; don't use for anything else
std::list<tHateEntry*>& GetHateList() { return list; }
//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
+118 -68
View File
@@ -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,7 +1027,8 @@ 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
@@ -1022,92 +1041,99 @@ bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) {
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;
}
}
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) {
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++) {
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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);
+8 -8
View File
@@ -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() {
+4 -4
View File
@@ -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();
+3 -3
View File
@@ -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) {
+5
View File
@@ -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()));
+1
View File
@@ -58,6 +58,7 @@ Map::Map() {
Map::~Map() {
if(imp) {
imp->rm->release();
safe_delete(imp);
}
}
+6 -11
View File
@@ -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();
+2 -2
View File
@@ -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
+27 -14
View File
@@ -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;
}
+14 -14
View File
@@ -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);
+12 -16
View File
@@ -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)
+30 -32
View File
@@ -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
+9 -4
View File
@@ -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
+8
View File
@@ -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();
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();
+12 -12
View File
@@ -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;
+11 -4
View File
@@ -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, "$$");
+9 -9
View 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);
+2 -2
View File
@@ -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));
+1
View File
@@ -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);
+5
View File
@@ -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_";
+35 -34
View File
@@ -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) {
+1 -1
View File
@@ -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);
+4 -4
View File
@@ -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;
+17 -13
View File
@@ -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){
+21 -6
View File
@@ -1195,7 +1195,11 @@ 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++) {
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)
@@ -1213,6 +1217,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
}
}
break;
}
//Test the aug recast delay
if(IsClient() && fromaug && recastdelay > 0)
{
@@ -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;
+24 -62
View File
@@ -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;
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) {
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);
@@ -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;
+2 -2
View File
@@ -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;
+3 -1
View File
@@ -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)
+3
View File
@@ -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())
+2 -2
View File
@@ -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");
+1 -1
View File
@@ -21,7 +21,7 @@ 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; }
+4 -2
View File
@@ -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);
+4 -1
View File
@@ -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();
+106 -97
View File
@@ -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 default value for aggroradius
tmpNPCType->aggroradius = (int32)atoi(row[48]);
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 {
}
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]);
+3 -2
View File
@@ -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;