From f854137ca029fa6e90cab5133bd8ee6194f8e1cb Mon Sep 17 00:00:00 2001 From: Trust Date: Fri, 4 Dec 2020 19:26:16 -0500 Subject: [PATCH 1/9] [BUG] Fix for Group Leader Disband Issue Added public/private class for oldleadername so we can save the previous leader name when the entity is destroyed then allow us to transfer leadership. Adjusted DelmemberOOZ and in zone functions to include removal of the old leader when disbanding. --- common/eqemu_logsys.h | 2 + common/servertalk.h | 12 ++++ world/zoneserver.cpp | 8 +++ zone/entity.cpp | 38 +++++++++++-- zone/entity.h | 3 +- zone/groups.cpp | 126 +++++++++++++++++++++++++----------------- zone/groups.h | 4 ++ zone/worldserver.cpp | 13 ++++- 8 files changed, 147 insertions(+), 59 deletions(-) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index d28478a97..c8f724a17 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -120,6 +120,7 @@ namespace Logs { Loot, Expeditions, DynamicZones, + Group, MaxCategoryID /* Don't Remove this */ }; @@ -199,6 +200,7 @@ namespace Logs { "Loot", "Expeditions", "DynamicZones", + "Group", }; } diff --git a/common/servertalk.h b/common/servertalk.h index 40be635ad..816807b56 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -80,6 +80,7 @@ #define ServerOP_UpdateSpawn 0x003f #define ServerOP_SpawnStatusChange 0x0040 #define ServerOP_DropClient 0x0041 // DropClient +#define ServerOP_ChangeGroupLeader 0x0042 #define ServerOP_ReloadTasks 0x0060 #define ServerOP_DepopAllPlayersCorpses 0x0061 #define ServerOP_ReloadTitles 0x0062 @@ -861,6 +862,7 @@ struct ServerGroupLeave_Struct { uint16 instance_id; uint32 gid; char member_name[64]; //kick this member from the group + bool checkleader; }; struct ServerGroupJoin_Struct { @@ -870,10 +872,20 @@ struct ServerGroupJoin_Struct { char member_name[64]; //this person is joining the group }; +struct ServerGroupLeader_Struct { + uint32 zoneid; + uint16 instance_id; + uint32 gid; + char leader_name[64]; + char oldleader_name[64]; +}; + struct ServerForceGroupUpdate_Struct { uint32 origZoneID; uint16 instance_id; uint32 gid; + char leader_name[64]; + char oldleader_name[64]; }; struct ServerGroupChannelMessage_Struct { diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index f09d08db1..58bd9f177 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -277,6 +277,14 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { break; } + case ServerOP_ChangeGroupLeader: { + if (pack->size != sizeof(ServerGroupLeader_Struct)) { + break; + } + zoneserver_list.SendPacket(pack); //bounce it to all zones + break; + } + case ServerOP_RaidAdd: { if (pack->size != sizeof(ServerRaidGeneralAction_Struct)) break; diff --git a/zone/entity.cpp b/zone/entity.cpp index 1ad03eea0..51d6043a4 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4209,7 +4209,7 @@ void EntityList::ForceGroupUpdate(uint32 gid) } } -void EntityList::SendGroupLeave(uint32 gid, const char *name) +void EntityList::SendGroupLeave(uint32 gid, const char *name, bool checkleader) { auto it = client_list.begin(); while (it != client_list.end()) { @@ -4225,13 +4225,39 @@ void EntityList::SendGroupLeave(uint32 gid, const char *name) gj->action = groupActLeave; strcpy(gj->yourname, c->GetName()); Mob *Leader = g->GetLeader(); - if (Leader) + if (Leader) { Leader->CastToClient()->GetGroupAAs(&gj->leader_aas); + } c->QueuePacket(outapp); safe_delete(outapp); - g->DelMemberOOZ(name); - if (g->IsLeader(c) && c->IsLFP()) + g->DelMemberOOZ(name, checkleader); + if (g->IsLeader(c) && c->IsLFP()) { c->UpdateLFP(); + } + } + } + } + ++it; + } +} + +void EntityList::SendGroupLeader(uint32 gid, const char *lname, const char *oldlname) +{ + auto it = client_list.begin(); + while (it != client_list.end()) { + if (it->second){ + Group *g = nullptr; + g = it->second->GetGroup(); + if (g) { + if (g->GetID() == gid) { + EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; + gj->action = groupActMakeLeader; + strcpy(gj->membername, lname); + strcpy(gj->yourname, oldlname); + it->second->QueuePacket(outapp); + Log(Logs::Detail, Logs::Group, "SendGroupLeader(): Entity loop leader update packet sent to: %s .", it->second->GetName()); + safe_delete(outapp); } } } @@ -4254,9 +4280,9 @@ void EntityList::SendGroupJoin(uint32 gid, const char *name) gj->action = groupActJoin; strcpy(gj->yourname, it->second->GetName()); Mob *Leader = g->GetLeader(); - if (Leader) + if (Leader) { Leader->CastToClient()->GetGroupAAs(&gj->leader_aas); - + } it->second->QueuePacket(outapp); safe_delete(outapp); } diff --git a/zone/entity.h b/zone/entity.h index b7f90b6f9..ec617acf7 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -478,8 +478,9 @@ public: void CameraEffect(uint32 duration, uint32 intensity); Mob* GetClosestMobByBodyType(Mob* sender, bodyType BodyType); void ForceGroupUpdate(uint32 gid); - void SendGroupLeave(uint32 gid, const char *name); + void SendGroupLeave(uint32 gid, const char *name, bool checkleader); void SendGroupJoin(uint32 gid, const char *name); + void SendGroupLeader(uint32 gid, const char *lname, const char *oldlname); void SaveAllClientsTaskState(); void ReloadAllClientsTaskState(int TaskID=0); diff --git a/zone/groups.cpp b/zone/groups.cpp index 4b8e25d09..abc868460 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -59,8 +59,12 @@ Group::Group(uint32 gid) } if(gid != 0) { - if(!LearnMembers()) + if(!LearnMembers()) { SetID(0); + } + if(GetLeader() != nullptr) { + SetOldLeaderName(GetLeaderName()); + } } for(int i = 0; i < MAX_MARKED_NPCS; ++i) MarkedNPCs[i] = 0; @@ -78,6 +82,8 @@ Group::Group(Mob* leader) members[0] = leader; leader->SetGrouped(true); SetLeader(leader); + SetOldLeaderName(leader->GetName()); + Log(Logs::Detail, Logs::Group, "Group:Group() Setting OldLeader to: %s and Leader to: %s", GetOldLeaderName(), leader->GetName()); AssistTargetID = 0; TankTargetID = 0; PullerTargetID = 0; @@ -604,39 +610,61 @@ void Group::SendGroupJoinOOZ(Mob* NewMember) { } -bool Group::DelMemberOOZ(const char *Name) { +bool Group::DelMemberOOZ(const char *Name, bool checkleader) { - if(!Name) return false; + if (!Name) return false; + bool removed = false; // If a member out of zone has disbanded, clear out their name. - // - for(unsigned int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(!strcasecmp(Name, membername[i])) + for (unsigned int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (!strcasecmp(Name, membername[i])) { // This shouldn't be called if the member is in this zone. - if(!members[i]) { - if(!strncmp(GetLeaderName(), Name, 64)) - { + if (!members[i]) { + if (!strncmp(GetLeaderName(), Name, 64)) { //TODO: Transfer leadership if leader disbands OOZ. UpdateGroupAAs(); } - memset(membername[i], 0, 64); - MemberRoles[i] = 0; - if(GroupCount() < 3) - { + if (GroupCount() < 3) { UnDelegateMarkNPC(NPCMarkerName.c_str()); - if (GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->ClientVersion() < EQ::versions::ClientVersion::SoD) { - UnDelegateMainAssist(MainAssistName.c_str()); + if (GetLeader() && GetLeader()->IsClient() && + GetLeader()->CastToClient()->ClientVersion() < EQ::versions::ClientVersion::SoD) { + UnDelegateMainAssist(MainAssistName.c_str()); } ClearAllNPCMarks(); } - if (Name == mentoree_name) + if (Name == mentoree_name) { ClearGroupMentor(); - return true; + } + + memset(membername[i], 0, 64); + MemberRoles[i] = 0; + removed = true; + Log(Logs::Detail, Logs::Group, "DelMemberOOZ: Removed Member: %s", Name); + break; } + } } - return false; + if (GroupCount() < 2) { + DisbandGroup(); + return true; + } + + if (checkleader) { + Log(Logs::Detail, Logs::Group, "DelMemberOOZ: Checking leader..."); + if (strcmp(GetOldLeaderName(), Name) == 0 && GroupCount() >= 2) { + for (uint32 nl = 0; nl < MAX_GROUP_MEMBERS; nl++) { + if (members[nl]) { + if (members[nl]->IsClient()) { + ChangeLeader(members[nl]); + break; + } + } + } + } + } + return removed; } bool Group::DelMember(Mob* oldmember, bool ignoresender) @@ -646,16 +674,6 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) return false; } - // TODO: fix this shit - // okay, so there is code below that tries to handle this. It does not. - // So instead of figuring it out now, lets just disband the group so the client doesn't - // sit there with a broken group and there isn't any group leader shuffling going on - // since the code below doesn't work. - if (oldmember == GetLeader()) { - DisbandGroup(); - return true; - } - for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) { if (members[i] == oldmember) @@ -664,44 +682,36 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) membername[i][0] = '\0'; memset(membername[i],0,64); MemberRoles[i] = 0; + Log(Logs::Detail, Logs::Group, "DelMember: Removed Member: %s", oldmember->GetCleanName()); break; } } - /* This may seem pointless but the case above does not cover the following situation: - * Group has Leader a, member b, member c - * b and c are out of zone - * a disconnects/quits - * b or c zone back in and disconnects/quits - * a is still "leader" from GetLeader()'s perspective and will crash the zone when we DelMember(b) - * Ultimately we should think up a better solution to this. - */ - if(oldmember == GetLeader()) + if(GroupCount() < 2) { - SetLeader(nullptr); + DisbandGroup(); + return true; } - //handle leader quitting group gracefully - if (oldmember == GetLeader() && GroupCount() >= 2) + // If the leader has quit and we have 2 or more players left in group, we want to first check the zone the old leader was in for a new leader. + // If a suitable replacement cannot be found, we need to go out of zone. If checkleader remains true after this method completes, another + // loop will be run in DelMemberOOZ. + bool checkleader = true; + if (strcmp(GetOldLeaderName(),oldmember->GetCleanName()) == 0 && GroupCount() >= 2) { for(uint32 nl = 0; nl < MAX_GROUP_MEMBERS; nl++) { - if(members[nl]) + if(members[nl]) { if (members[nl]->IsClient()) { ChangeLeader(members[nl]); + checkleader = false; break; } } } } - - if (!GetLeaderName()) - { - DisbandGroup(); - return true; - } auto pack = new ServerPacket(ServerOP_GroupLeave, sizeof(ServerGroupLeave_Struct)); ServerGroupLeave_Struct* gl = (ServerGroupLeave_Struct*)pack->pBuffer; @@ -709,6 +719,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) gl->zoneid = zone->GetZoneID(); gl->instance_id = zone->GetInstanceID(); strcpy(gl->member_name, oldmember->GetCleanName()); + gl->checkleader = checkleader; worldserver.SendPacket(pack); safe_delete(pack); @@ -800,6 +811,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) Bot::UpdateGroupCastingRoles(this); #endif + safe_delete(outapp); return true; } @@ -2330,17 +2342,16 @@ void Group::ChangeLeader(Mob* newleader) // this changes the current group leader, notifies other members, and updates leadship AA // if the new leader is invalid, do nothing - if (!newleader || !newleader->IsClient()) + if (!newleader) { return; - - Mob* oldleader = GetLeader(); + } auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gu = (GroupJoin_Struct*) outapp->pBuffer; gu->action = groupActMakeLeader; strcpy(gu->membername, newleader->GetName()); - strcpy(gu->yourname, oldleader->GetName()); + strcpy(gu->yourname, GetOldLeaderName()); SetLeader(newleader); database.SetGroupLeaderName(GetID(), newleader->GetName()); UpdateGroupAAs(); @@ -2352,9 +2363,22 @@ void Group::ChangeLeader(Mob* newleader) members[i]->CastToClient()->SendGroupLeaderChangePacket(newleader->GetName()); members[i]->CastToClient()->QueuePacket(outapp); + Log(Logs::Detail, Logs::Group, "ChangeLeader(): Local leader update packet sent to: %s .", members[i]->GetName()); } } safe_delete(outapp); + + Log(Logs::Detail, Logs::Group, "ChangeLeader(): Old Leader is: %s New leader is: %s", GetOldLeaderName(), newleader->GetName()); + + ServerPacket* pack = new ServerPacket(ServerOP_ChangeGroupLeader, sizeof(ServerGroupLeader_Struct)); + ServerGroupLeader_Struct* fgu = (ServerGroupLeader_Struct*)pack->pBuffer; + fgu->zoneid = zone->GetZoneID(); + fgu->gid = GetID(); + strcpy(fgu->leader_name, newleader->GetName()); + strcpy(fgu->oldleader_name, GetOldLeaderName()); + worldserver.SendPacket(pack); + + SetOldLeaderName(newleader->GetName()); } const char *Group::GetClientNameByIndex(uint8 index) diff --git a/zone/groups.h b/zone/groups.h index 57dfdbfb6..c27f9d59a 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -37,6 +37,8 @@ public: GroupIDConsumer() { id = 0; } GroupIDConsumer(uint32 gid) { id = gid; } inline const uint32 GetID() const { return id; } + void SetOldLeaderName(const char* oldleader) { strcpy(oldleadername, oldleader); } + char* GetOldLeaderName() { return oldleadername; } protected: friend class EntityList; @@ -44,6 +46,7 @@ protected: inline void SetID(uint32 set_id) { id = set_id; } private: uint32 id; + char oldleadername[64]; // Keeps the previous leader name, so when the entity is destroyed we can still transfer leadership. }; class Group : public GroupIDConsumer { @@ -58,6 +61,7 @@ public: void SendLeadershipAAUpdate(); void SendWorldGroup(uint32 zone_id,Mob* zoningmember); bool DelMemberOOZ(const char *Name); + bool DelMemberOOZ(const char *Name, bool checkleader); bool DelMember(Mob* oldmember,bool ignoresender = false); void DisbandGroup(bool joinraid = false); void GetMemberList(std::list& member_list, bool clear_list = true); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 920a3d958..eea45d057 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -877,7 +877,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (gl->zoneid == zone->GetZoneID() && gl->instance_id == zone->GetInstanceID()) break; - entity_list.SendGroupLeave(gl->gid, gl->member_name); + entity_list.SendGroupLeave(gl->gid, gl->member_name, gl->checkleader); } break; } @@ -1114,6 +1114,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) break; } + case ServerOP_ChangeGroupLeader: { + ServerGroupLeader_Struct *fgu = (ServerGroupLeader_Struct *) pack->pBuffer; + if (zone) { + if (fgu->zoneid == zone->GetZoneID()) { + break; + } + entity_list.SendGroupLeader(fgu->gid, fgu->leader_name, fgu->oldleader_name); + } + break; + } + case ServerOP_OOZGroupMessage: { ServerGroupChannelMessage_Struct* gcm = (ServerGroupChannelMessage_Struct*)pack->pBuffer; if (zone) { From 83928fa4d09dec2407367ed40f6019380f03b446 Mon Sep 17 00:00:00 2001 From: Trust Date: Wed, 2 Dec 2020 17:21:22 -0500 Subject: [PATCH 2/9] [REBASE] Prevent Bards from auto equip loot when using instrument --- zone/inventory.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index b047197d2..71749be45 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1154,9 +1154,34 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool } } } + if( i == EQ::invslot::slotPrimary && m_inv[EQ::invslot::slotSecondary] ) { + uint8 instrument = m_inv[MainSecondary]->GetItem()->ItemType; + if( + instrument == EQ::item::ItemTypeWindInstrument || + instrument == EQ::item::ItemTypeStringedInstrument || + instrument == EQ::item::ItemTypeBrassInstrument || + instrument == EQ::item::ItemTypePercussionInstrument + ) { + LogInventory("Cannot equip a primary item with [{}] already in the secondary.", m_inv[MainSecondary]->GetItem()->Name); + continue; // Do not auto-equip Primary when instrument is in Secondary + } + } if (i == EQ::invslot::slotSecondary && m_inv[EQ::invslot::slotPrimary]) { // check to see if primary slot is a two hander - if (m_inv[EQ::invslot::slotPrimary]->GetItem()->IsType2HWeapon()) + uint8 instrument = inst.GetItem()->ItemType; + if( + instrument == EQ::item::ItemTypeWindInstrument || + instrument == EQ::item::ItemTypeStringedInstrument || + instrument == EQ::item::ItemTypeBrassInstrument || + instrument == EQ::item::ItemTypePercussionInstrument + ) { + LogInventory("Cannot equip a secondary instrument with [{}] already in the primary.", m_inv[MainPrimary]->GetItem()->Name); + continue; // Do not auto-equip instrument in Secondary when Primary is equipped. + } + + uint8 use = m_inv[MainPrimary]->GetItem()->ItemType; + if(use == EQ::item::ItemType2HSlash || use == EQ::item::ItemType2HBlunt || use == EQ::item::ItemType2HPiercing) { continue; + } } if (i == EQ::invslot::slotSecondary && inst.IsWeapon() && !CanThisClassDualWield()) { continue; @@ -1169,7 +1194,6 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool if (worn_slot_material != EQ::textures::materialInvalid) { SendWearChange(worn_slot_material); } - parse->EventItem(EVENT_EQUIP_ITEM, this, &inst, nullptr, "", i); return true; } From 789cfb24909a879a5b7b7b5ad1f043b09bd30d68 Mon Sep 17 00:00:00 2001 From: Trust Date: Fri, 4 Dec 2020 17:12:15 -0500 Subject: [PATCH 3/9] [REBASE] Barter was allowing the purchase of bags. Bags could contain anything and it would be traded. --- zone/trading.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/zone/trading.cpp b/zone/trading.cpp index 632fd4fb7..1d75bd941 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -2648,6 +2648,11 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { return; } + if(item->IsClassBag()) { + Message(Chat::Red, "That item is a Bag."); + return; + } + if(!item->Stackable) { for(uint32 i = 0; i < Quantity; i++) { @@ -3001,29 +3006,27 @@ void Client::UpdateBuyLine(const EQApplicationPacket *app) { LogTrading("UpdateBuyLine: Char: [{}] BuySlot: [{}] ItemID [{}] [{}] Quantity [{}] Toggle: [{}] Price [{}] ItemCount [{}] LoreConflict [{}]", GetName(), BuySlot, ItemID, item->Name, Quantity, ToggleOnOff, Price, ItemCount, LoreConflict); - if((item->NoDrop != 0) && !LoreConflict && (Quantity > 0) && HasMoney(Quantity * Price) && ToggleOnOff && (ItemCount == 0)) { + if((item->NoDrop != 0) && (!item->IsClassBag())&& !LoreConflict && (Quantity > 0) && HasMoney(Quantity * Price) && ToggleOnOff && (ItemCount == 0)) { LogTrading("Adding to database"); database.AddBuyLine(CharacterID(), BuySlot, ItemID, ItemName, Quantity, Price); QueuePacket(app); } else { - if(ItemCount > 0) + if(ItemCount > 0) { Message(Chat::Red, "Buy line %s disabled as Item Compensation is not currently supported.", ItemName); - - else if(Quantity <= 0) + } else if(Quantity <= 0) { Message(Chat::Red, "Buy line %s disabled as the quantity is invalid.", ItemName); - - else if(LoreConflict) + } else if(LoreConflict) { Message(Chat::Red, "Buy line %s disabled as the item is LORE and you have one already.", ItemName); - - else if(item->NoDrop == 0) + } else if(item->NoDrop == 0) { Message(Chat::Red, "Buy line %s disabled as the item is NODROP.", ItemName); - - else if(ToggleOnOff) + } else if(item->IsClassBag()) { + Message(Chat::Red, "Buy line %s disabled as the item is a Bag.", ItemName); + } else if(ToggleOnOff) { Message(Chat::Red, "Buy line %s disabled due to insufficient funds.", ItemName); - - else + } else { database.RemoveBuyLine(CharacterID(), BuySlot); + } auto outapp = new EQApplicationPacket(OP_Barter, 936); From 538092d59ecb1bc87eb1ddffda57eddc07096068 Mon Sep 17 00:00:00 2001 From: Trust Date: Thu, 31 Dec 2020 11:33:04 -0500 Subject: [PATCH 4/9] Fix for incorrect slot definition. --- zone/inventory.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 71749be45..0a052824a 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1155,14 +1155,14 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool } } if( i == EQ::invslot::slotPrimary && m_inv[EQ::invslot::slotSecondary] ) { - uint8 instrument = m_inv[MainSecondary]->GetItem()->ItemType; + uint8 instrument = m_inv[EQ::invslot::slotSecondary]->GetItem()->ItemType; if( instrument == EQ::item::ItemTypeWindInstrument || instrument == EQ::item::ItemTypeStringedInstrument || instrument == EQ::item::ItemTypeBrassInstrument || instrument == EQ::item::ItemTypePercussionInstrument ) { - LogInventory("Cannot equip a primary item with [{}] already in the secondary.", m_inv[MainSecondary]->GetItem()->Name); + LogInventory("Cannot equip a primary item with [{}] already in the secondary.", m_inv[EQ::invslot::slotSecondary]->GetItem()->Name); continue; // Do not auto-equip Primary when instrument is in Secondary } } @@ -1174,11 +1174,11 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool instrument == EQ::item::ItemTypeBrassInstrument || instrument == EQ::item::ItemTypePercussionInstrument ) { - LogInventory("Cannot equip a secondary instrument with [{}] already in the primary.", m_inv[MainPrimary]->GetItem()->Name); + LogInventory("Cannot equip a secondary instrument with [{}] already in the primary.", m_inv[EQ::invslot::slotPrimary]->GetItem()->Name); continue; // Do not auto-equip instrument in Secondary when Primary is equipped. } - uint8 use = m_inv[MainPrimary]->GetItem()->ItemType; + uint8 use = m_inv[EQ::invslot::slotPrimary]->GetItem()->ItemType; if(use == EQ::item::ItemType2HSlash || use == EQ::item::ItemType2HBlunt || use == EQ::item::ItemType2HPiercing) { continue; } From 7fbf522aa3d7553bee3a673f00b34148c3abfd7d Mon Sep 17 00:00:00 2001 From: Trust Date: Sat, 2 Jan 2021 22:54:26 -0500 Subject: [PATCH 5/9] Added LogGroup to logging aliases. --- common/eqemu_logsys_log_aliases.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index efe25dabe..307cc9fc5 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -161,6 +161,11 @@ OutF(LogSys, Logs::Detail, Logs::Doors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ } while (0) +#define LogGroup(message, ...) do {\ + if (LogSys.log_settings[Logs::Group].is_category_enabled == 1)\ + OutF(LogSys, Logs::General, Logs::Group, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + #define LogGuilds(message, ...) do {\ if (LogSys.log_settings[Logs::Guilds].is_category_enabled == 1)\ OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ @@ -719,6 +724,9 @@ #define LogDoorsDetail(message, ...) do {\ } while (0) +#define LogGroup(message, ...) do {\ +} while (0) + #define LogGuilds(message, ...) do {\ } while (0) From 29e693d443030325073b90e598ed41b4ce85083a Mon Sep 17 00:00:00 2001 From: Trust Date: Sat, 2 Jan 2021 22:57:57 -0500 Subject: [PATCH 6/9] Also added LogGroupDetail --- common/eqemu_logsys_log_aliases.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index 307cc9fc5..e32b43b4f 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -166,6 +166,11 @@ OutF(LogSys, Logs::General, Logs::Group, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ } while (0) +#define LogGroupDetail(message, ...) do {\ + if (LogSys.log_settings[Logs::Group].is_category_enabled == 1)\ + OutF(LogSys, Logs::Detail, Logs::Group, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + #define LogGuilds(message, ...) do {\ if (LogSys.log_settings[Logs::Guilds].is_category_enabled == 1)\ OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ @@ -727,6 +732,9 @@ #define LogGroup(message, ...) do {\ } while (0) +#define LogGroupDetail(message, ...) do {\ +} while (0) + #define LogGuilds(message, ...) do {\ } while (0) From d6e29810f196133093b1bf0395fd1b55ea743174 Mon Sep 17 00:00:00 2001 From: Matthew Silvia Date: Sat, 2 Jan 2021 23:17:47 -0500 Subject: [PATCH 7/9] #endurance --- zone/command.cpp | 14 ++++++++++++++ zone/command.h | 1 + 2 files changed, 15 insertions(+) diff --git a/zone/command.cpp b/zone/command.cpp index 123d3889b..c9dc2cf7d 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -206,6 +206,7 @@ int command_init(void) command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) || command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) || command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) || + command_add("endurance", "Restores you or your target's endurance.", 50, command_endurance) || command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) || command_add("face", "- Change the face of your target", 80, command_face) || command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", 80, command_faction) || @@ -737,6 +738,19 @@ void command_logcommand(Client *c, const char *message) /* * commands go below here */ +void command_endurance(Client *c, const Seperator *sep) +{ + Mob *t; + + t = c->GetTarget() ? c->GetTarget() : c; + + if (t->IsClient()) + t->CastToClient()->SetEndurance(t->CastToClient()->GetMaxEndurance()); + else + t->SetEndurance(t->GetMaxEndurance()); + + t->Message(Chat::White, "Your endurance has been refilled."); +} void command_setstat(Client* c, const Seperator* sep){ if(sep->arg[1][0] && sep->arg[2][0] && c->GetTarget()!=0 && c->GetTarget()->IsClient()){ c->GetTarget()->CastToClient()->SetStats(atoi(sep->arg[1]),atoi(sep->arg[2])); diff --git a/zone/command.h b/zone/command.h index a6f967d78..bae126019 100644 --- a/zone/command.h +++ b/zone/command.h @@ -99,6 +99,7 @@ void command_emote(Client *c, const Seperator *sep); void command_emotesearch(Client* c, const Seperator *sep); void command_emoteview(Client* c, const Seperator *sep); void command_enablerecipe(Client *c, const Seperator *sep); +void command_endurance(Client *c, const Seperator *sep); void command_equipitem(Client *c, const Seperator *sep); void command_face(Client *c, const Seperator *sep); void command_faction(Client *c, const Seperator *sep); From 3fa236c2bb66ccb98bb2a94c31eff739dccb02bc Mon Sep 17 00:00:00 2001 From: Evan Alexander King Date: Sun, 3 Jan 2021 03:09:27 -0500 Subject: [PATCH 8/9] Add client->Fling() to Perl/Lua. - $client->Fling(value, target_x, target_y, target_z, ignore_los, clipping) in Perl. - client:Fling(value, target_x, target_y, target_z, ignore_los, clipping) in Lua. --- zone/client.cpp | 22 ++++++++++++++++++++++ zone/client.h | 2 ++ zone/lua_client.cpp | 20 +++++++++++++++++++- zone/lua_client.h | 3 +++ zone/perl_client.cpp | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index 06f04ec1b..726d736e2 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9988,3 +9988,25 @@ void Client::MovePCDynamicZone(const std::string& zone_name, int zone_version, b auto zone_id = ZoneID(zone_name.c_str()); MovePCDynamicZone(zone_id, zone_version, msg_if_invalid); } + +void Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping) { + BuffFadeByEffect(SE_Levitate); + if (CheckLosFN(target_x, target_y, target_z, 6.0f) || ignore_los) { + auto outapp_fling = new EQApplicationPacket(OP_Fling, sizeof(fling_struct)); + fling_struct* flingTo = (fling_struct*)outapp_fling->pBuffer; + if(clipping) + flingTo->collision = 0; + else + flingTo->collision = -1; + + flingTo->travel_time = -1; + flingTo->unk3 = 1; + flingTo->disable_fall_damage = 1; + flingTo->speed_z = value; + flingTo->new_y = target_y; + flingTo->new_x = target_x; + flingTo->new_z = target_z; + outapp_fling->priority = 6; + FastQueuePacket(&outapp_fling); + } +} \ No newline at end of file diff --git a/zone/client.h b/zone/client.h index f2b1892c9..6829ce303 100644 --- a/zone/client.h +++ b/zone/client.h @@ -794,6 +794,8 @@ public: uint32 GetCharMaxLevelFromQGlobal(); uint32 GetCharMaxLevelFromBucket(); + void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los = false, bool clipping = false); + inline bool IsStanding() const {return (playeraction == 0);} inline bool IsSitting() const {return (playeraction == 1);} inline bool IsCrouching() const {return (playeraction == 2);} diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 30518e520..7a843331b 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1877,6 +1877,21 @@ void Lua_Client::MovePCDynamicZone(std::string zone_name, int zone_version, bool return self->MovePCDynamicZone(zone_name, zone_version, msg_if_invalid); } +void Lua_Client::Fling(float value, float target_x, float target_y, float target_z) { + Lua_Safe_Call_Void(); + self->Fling(value, target_x, target_y, target_z); +} + +void Lua_Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los) { + Lua_Safe_Call_Void(); + self->Fling(value, target_x, target_y, target_z, ignore_los); +} + +void Lua_Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping) { + Lua_Safe_Call_Void(); + self->Fling(value, target_x, target_y, target_z, ignore_los, clipping); +} + luabind::scope lua_register_client() { return luabind::class_("Client") .def(luabind::constructor<>()) @@ -2204,7 +2219,10 @@ luabind::scope lua_register_client() { .def("MovePCDynamicZone", (void(Lua_Client::*)(uint32, int, bool))&Lua_Client::MovePCDynamicZone) .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string))&Lua_Client::MovePCDynamicZone) .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int))&Lua_Client::MovePCDynamicZone) - .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int, bool))&Lua_Client::MovePCDynamicZone); + .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int, bool))&Lua_Client::MovePCDynamicZone) + .def("Fling", (void(Lua_Client::*)(float,float,float,float))&Lua_Client::Fling) + .def("Fling", (void(Lua_Client::*)(float,float,float,float,bool))&Lua_Client::Fling) + .def("Fling", (void(Lua_Client::*)(float,float,float,float,bool,bool))&Lua_Client::Fling); } luabind::scope lua_register_inventory_where() { diff --git a/zone/lua_client.h b/zone/lua_client.h index 8bfa5bda0..e30a94fd2 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -360,6 +360,9 @@ public: void MovePCDynamicZone(std::string zone_name); void MovePCDynamicZone(std::string zone_name, int zone_version); void MovePCDynamicZone(std::string zone_name, int zone_version, bool msg_if_invalid); + void Fling(float value, float target_x, float target_y, float target_z); + void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los); + void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping); }; #endif diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 5b8ed1a05..1dc9f2128 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -7051,6 +7051,41 @@ XS(XS_Client_MovePCDynamicZone) { XSRETURN_EMPTY; } +XS(XS_Client_Fling); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_Fling) { + dXSARGS; + if (items < 5 || items > 7) + Perl_croak(aTHX_ "Usage: Client::Fling(THIS, value, target_x, target_y, target_z, ignore_los, clipping)"); + { + Client* THIS; + float value = (float) SvNV(ST(1)); + float target_x = (float) SvNV(ST(2)); + float target_y = (float) SvNV(ST(3)); + float target_z = (float) SvNV(ST(4)); + bool ignore_los = false; + bool clipping = false; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (items > 5) + ignore_los = (bool) SvTRUE(ST(5)); + + if (items > 6) + clipping = (bool) SvTRUE(ST(6)); + + THIS->Fling(value, target_x, target_y, target_z, ignore_los, clipping); + } + XSRETURN_EMPTY; +} + #ifdef __cplusplus extern "C" #endif @@ -7108,6 +7143,7 @@ XS(boot_Client) { newXSproto(strcpy(buf, "Escape"), XS_Client_Escape, file, "$"); newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$"); newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$"); + newXSproto(strcpy(buf, "Fling"), XS_Client_Fling, file, "$$$$$;$$"); newXSproto(strcpy(buf, "ForageItem"), XS_Client_ForageItem, file, "$"); newXSproto(strcpy(buf, "Freeze"), XS_Client_Freeze, file, "$"); newXSproto(strcpy(buf, "GetAAExp"), XS_Client_GetAAExp, file, "$"); From c58ba2e6a55e78b4cf9ae1250b3428cd98e52f8a Mon Sep 17 00:00:00 2001 From: Evan Alexander King Date: Sun, 3 Jan 2021 03:20:57 -0500 Subject: [PATCH 9/9] Add GetTargetRingX(), GetTargetRingY(), and GetTargetRingZ() to Lua. --- zone/lua_client.cpp | 18 ++++++++++++++++++ zone/lua_client.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 30518e520..dfb315aac 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -329,6 +329,21 @@ uint32 Lua_Client::GetBindZoneID(int index) { return self->GetBindZoneID(index); } +float Lua_Client::GetTargetRingX() { + Lua_Safe_Call_Real(); + return self->GetTargetRingX(); +} + +float Lua_Client::GetTargetRingY() { + Lua_Safe_Call_Real(); + return self->GetTargetRingY(); +} + +float Lua_Client::GetTargetRingZ() { + Lua_Safe_Call_Real(); + return self->GetTargetRingZ(); +} + void Lua_Client::MovePC(int zone, float x, float y, float z, float heading) { Lua_Safe_Call_Void(); self->MovePC(zone, x, y, z, heading); @@ -1942,6 +1957,9 @@ luabind::scope lua_register_client() { .def("GetBindHeading", (float(Lua_Client::*)(int))&Lua_Client::GetBindHeading) .def("GetBindZoneID", (uint32(Lua_Client::*)(void))&Lua_Client::GetBindZoneID) .def("GetBindZoneID", (uint32(Lua_Client::*)(int))&Lua_Client::GetBindZoneID) + .def("GetTargetRingX", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingX) + .def("GetTargetRingY", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingY) + .def("GetTargetRingZ", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingZ) .def("SetPrimaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetPrimaryWeaponOrnamentation) .def("SetSecondaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetSecondaryWeaponOrnamentation) .def("MovePC", (void(Lua_Client::*)(int,float,float,float,float))&Lua_Client::MovePC) diff --git a/zone/lua_client.h b/zone/lua_client.h index 8bfa5bda0..cb53b30cc 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -92,6 +92,9 @@ public: float GetBindHeading(int index); uint32 GetBindZoneID(); uint32 GetBindZoneID(int index); + float GetTargetRingX(); + float GetTargetRingY(); + float GetTargetRingZ(); void MovePC(int zone, float x, float y, float z, float heading); void MovePCInstance(int zone, int instance, float x, float y, float z, float heading); void MoveZone(const char *zone_short_name);