From 54d494da36269eb071141010ab558dc0f480ad18 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Tue, 21 Apr 2020 00:40:18 -0400 Subject: [PATCH 01/15] Fix errant merchant full messages and add logging for later use (#1035) * Fix errant merchant full issues, add logging for later use * Rename merchant list dump more clearly * spaces around '=' * Added line spacing, Co-authored-by: Noudess --- zone/inventory.cpp | 44 ++++++----- zone/zone.cpp | 185 ++++++++++++++++++++++++++++++++------------- zone/zone.h | 1 + 3 files changed, 159 insertions(+), 71 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 3ee86df47..f9438b32c 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2913,23 +2913,33 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item if (!inst) return; - if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { - if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) - return; - } - else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { - auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT); - if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) - return; - } - else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { - if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) - return; - } - else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { - auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT; - if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) - return; + if (packet_type != ItemPacketMerchant) { + if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { + if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) { + LogError("Item not sent to merchant : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { + auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT); + if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) { + LogError("Item not sent to merchant2 : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { + if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) { + LogError("Item not sent to merchant3 : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { + auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT; + if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) { + LogError("Item not sent to merchant4 : slot [{}]", slot_id); + return; + } + } } // Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization) diff --git a/zone/zone.cpp b/zone/zone.cpp index 398c985c6..d64c198d3 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -330,81 +330,156 @@ bool Zone::LoadGroundSpawns() { return(true); } -int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) { - int freeslot = 0; - std::list merlist = merchanttable[merchantid]; - std::list::const_iterator itr; - uint32 i = 1; - for (itr = merlist.begin(); itr != merlist.end(); ++itr) { - MerchantList ml = *itr; - if (ml.item == item) - return 0; - - // Account for merchant lists with gaps in them. - if (ml.slot >= i) - i = ml.slot + 1; - } +void Zone::DumpMerchantList(uint32 npcid) { std::list tmp_merlist = tmpmerchanttable[npcid]; std::list::const_iterator tmp_itr; - bool update_charges = false; TempMerchantList ml; - while (freeslot == 0 && !update_charges) { - freeslot = i; - for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { - ml = *tmp_itr; - if (ml.item == item) { - update_charges = true; - freeslot = 0; - break; - } - if ((ml.slot == i) || (ml.origslot == i)) { - freeslot = 0; - } - } - i++; + + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml = *tmp_itr; + + LogInventory("slot[{}] Orig[{}] Item[{}] Charges[{}]", ml.slot, ml.origslot, ml.item, ml.charges); } - if (update_charges) { +} + +int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) { + + LogInventory("Transaction of [{}] [{}]", charges, item); + //DumpMerchantList(npcid); + // Iterate past main items. + // If the item being transacted is in this list, return 0; + std::list merlist = merchanttable[merchantid]; + std::list::const_iterator itr; + uint32 temp_slot_index = 1; + for (itr = merlist.begin(); itr != merlist.end(); ++itr) { + MerchantList ml = *itr; + if (ml.item == item) { + return 0; + } + + // Account for merchant lists with gaps in them. + if (ml.slot >= temp_slot_index) { + temp_slot_index = ml.slot + 1; + } + } + + LogInventory("Searching Temporary List. Main list ended at [{}]", temp_slot_index-1); + + // Now search the temporary list. + std::list tmp_merlist = tmpmerchanttable[npcid]; + std::list::const_iterator tmp_itr; + TempMerchantList ml; + uint32 first_empty_slot = 0; // Save 1st vacant slot while searching.. + bool found = false; + + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml = *tmp_itr; + + if (ml.item == item) { + found = true; + LogInventory("Item found in temp list at [{}] with [{}] charges", ml.origslot, ml.charges); + break; + } + } + + if (found) { tmp_merlist.clear(); std::list oldtmp_merlist = tmpmerchanttable[npcid]; for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) { TempMerchantList ml2 = *tmp_itr; if(ml2.item != item) tmp_merlist.push_back(ml2); + else { + if (sold) { + LogInventory("Total charges is [{}] + [{}] charges", ml.charges, charges); + ml.charges = ml.charges + charges; + } + else { + ml.charges = charges; + LogInventory("new charges is [{}] charges", ml.charges); + } + + if (!ml.origslot) { + ml.origslot = ml.slot; + } + + if (charges > 0) { + database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges); + tmp_merlist.push_back(ml); + } + else { + database.DeleteMerchantTemp(npcid, ml.origslot); + } + } } - if (sold) - ml.charges = ml.charges + charges; - else - ml.charges = charges; - if (!ml.origslot) - ml.origslot = ml.slot; - if (charges > 0) { - database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges); - tmp_merlist.push_back(ml); - } - else { - database.DeleteMerchantTemp(npcid, ml.origslot); - } + tmpmerchanttable[npcid] = tmp_merlist; - - if (sold) - return ml.slot; - + //DumpMerchantList(npcid); + return ml.slot; } - if (freeslot) { - if (charges < 0) //sanity check only, shouldnt happen + else { + if (charges < 0) { //sanity check only, shouldnt happen charges = 0x7FFF; - database.SaveMerchantTemp(npcid, freeslot, item, charges); + } + + // Find an ununsed db slot # + std::list slots; + TempMerchantList ml3; + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml3 = *tmp_itr; + slots.push_back(ml3.origslot); + } + slots.sort(); + std::list::const_iterator slots_itr; + uint32 first_empty_slot = 0; + uint32 idx = temp_slot_index; + for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) { + if (!first_empty_slot && *slots_itr > idx) { + LogInventory("Popped [{}]", *slots_itr); + LogInventory("First Gap Found at [{}]", idx); + break; + } + + ++idx; + } + + first_empty_slot = idx; + + // Find an ununsed mslot + slots.clear(); + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml3 = *tmp_itr; + slots.push_back(ml3.slot); + } + slots.sort(); + uint32 first_empty_mslot=0; + idx = temp_slot_index; + for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) { + if (!first_empty_mslot && *slots_itr > idx) { + LogInventory("Popped [{}]", *slots_itr); + LogInventory("First Gap Found at [{}]", idx); + break; + } + + ++idx; + } + + first_empty_mslot = idx; + + database.SaveMerchantTemp(npcid, first_empty_slot, item, charges); tmp_merlist = tmpmerchanttable[npcid]; TempMerchantList ml2; ml2.charges = charges; + LogInventory("Adding slot [{}] with [{}] charges.", first_empty_mslot, charges); ml2.item = item; ml2.npcid = npcid; - ml2.slot = freeslot; - ml2.origslot = ml2.slot; + ml2.slot = first_empty_mslot; + ml2.origslot = first_empty_slot; tmp_merlist.push_back(ml2); tmpmerchanttable[npcid] = tmp_merlist; + //DumpMerchantList(npcid); + return ml2.slot; } - return freeslot; } uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { @@ -413,8 +488,10 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { std::list::const_iterator Iterator; for (Iterator = TmpMerchantList.begin(); Iterator != TmpMerchantList.end(); ++Iterator) - if ((*Iterator).slot == Slot) + if ((*Iterator).slot == Slot) { + LogInventory("Slot [{}] has [{}] charges.", Slot, (*Iterator).charges); return (*Iterator).charges; + } return 0; } diff --git a/zone/zone.h b/zone/zone.h index fc7fa8bf7..6d8fc54e6 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -163,6 +163,7 @@ public: inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); } inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); } int GetZoneTotalBlockedSpells() { return zone_total_blocked_spells; } + void DumpMerchantList(uint32 npcid); int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false); int32 MobsAggroCount() { return aggroedmobs; } From 387e1668a5bc3b27e1460dbff74d5337fdfb6383 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Apr 2020 01:25:09 -0500 Subject: [PATCH 02/15] Remove hard delete from `DeleteInstance` so that the purge timer can pick it up later --- common/database_instances.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 10a2ce032..0e6e8b380 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -515,8 +515,8 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) { void Database::DeleteInstance(uint16 instance_id) { - std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); - QueryDatabase(query); +// std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); +// QueryDatabase(query); query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id); QueryDatabase(query); From 954247956e6e2c8e3351b6760b0d003d90c842ad Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Apr 2020 02:11:06 -0500 Subject: [PATCH 03/15] Adjust syntax --- common/database_instances.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 0e6e8b380..617a2baf6 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -515,8 +515,7 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) { void Database::DeleteInstance(uint16 instance_id) { -// std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); -// QueryDatabase(query); + std::string query; query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id); QueryDatabase(query); From 2bcaf2a476913bb6407e6c887b169f4214d53f5a Mon Sep 17 00:00:00 2001 From: Noudess Date: Thu, 30 Apr 2020 11:35:09 -0400 Subject: [PATCH 04/15] Extended Movement Manager to have a FlyTo --- zone/mob_movement_manager.cpp | 164 ++++++++++++++++++++++++++++++++++ zone/mob_movement_manager.h | 1 + 2 files changed, 165 insertions(+) diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 4ac0c7f23..904bc5246 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -263,6 +263,146 @@ protected: double m_total_v_dist; }; +class FlyToCommand : public IMovementCommand { +public: + FlyToCommand(float x, float y, float z, MobMovementMode mob_movement_mode) + { + m_distance_moved_since_correction = 0.0; + m_move_to_x = x; + m_move_to_y = y; + m_move_to_z = z; + m_move_to_mode = mob_movement_mode; + m_last_sent_time = 0.0; + m_last_sent_speed = 0; + m_started = false; + m_total_h_dist = 0.0; + m_total_v_dist = 0.0; + } + + virtual ~FlyToCommand() + { + + } + + /** + * @param mob_movement_manager + * @param mob + * @return + */ + virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob) + { + if (!mob->IsAIControlled()) { + return true; + } + + //Send a movement packet when you start moving + double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0; + int current_speed = 0; + + if (m_move_to_mode == MovementRunning) { + if (mob->IsFeared()) { + current_speed = mob->GetFearSpeed(); + } + else { + current_speed = mob->GetRunspeed(); + } + } + else { + current_speed = mob->GetWalkspeed(); + } + + if (!m_started) { + m_started = true; + //rotate to the point + mob->SetMoving(true); + mob->SetHeading(mob->CalculateHeadingToTarget(m_move_to_x, m_move_to_y)); + + m_last_sent_speed = current_speed; + m_last_sent_time = current_time; + m_total_h_dist = DistanceNoZ(mob->GetPosition(), glm::vec4(m_move_to_x, m_move_to_y, 0.0f, 0.0f)); + m_total_v_dist = m_move_to_z - mob->GetZ(); + mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium); + } + + //When speed changes + if (current_speed != m_last_sent_speed) { + m_distance_moved_since_correction = 0.0; + m_last_sent_speed = current_speed; + m_last_sent_time = current_time; + mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium); + } + + //If x seconds have passed without sending an update. + if (current_time - m_last_sent_time >= 0.5) { + m_distance_moved_since_correction = 0.0; + m_last_sent_speed = current_speed; + m_last_sent_time = current_time; + mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium); + } + + auto &p = mob->GetPosition(); + glm::vec2 tar(m_move_to_x, m_move_to_y); + glm::vec2 pos(p.x, p.y); + double len = glm::distance(pos, tar); + if (len == 0) { + return true; + } + + mob->SetMoved(true); + + glm::vec2 dir = tar - pos; + glm::vec2 ndir = glm::normalize(dir); + double distance_moved = frame_time * current_speed * 0.4f * 1.45f; + + if (distance_moved > len) { + if (mob->IsNPC()) { + entity_list.ProcessMove(mob->CastToNPC(), m_move_to_x, m_move_to_y, m_move_to_z); + } + + mob->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z); + + if (RuleB(Map, FixZWhenPathing)) { + mob->FixZ(); + } + return true; + } + else { + glm::vec2 npos = pos + (ndir * static_cast(distance_moved)); + + len -= distance_moved; + double total_distance_traveled = m_total_h_dist - len; + double start_z = m_move_to_z - m_total_v_dist; + double z_at_pos = start_z + (m_total_v_dist * (total_distance_traveled / m_total_h_dist)); + + if (mob->IsNPC()) { + entity_list.ProcessMove(mob->CastToNPC(), npos.x, npos.y, z_at_pos); + } + + mob->SetPosition(npos.x, npos.y, z_at_pos); + } + + return false; + } + + virtual bool Started() const + { + return m_started; + } + +protected: + double m_distance_moved_since_correction; + double m_move_to_x; + double m_move_to_y; + double m_move_to_z; + MobMovementMode m_move_to_mode; + bool m_started; + + double m_last_sent_time; + int m_last_sent_speed; + double m_total_h_dist; + double m_total_v_dist; +}; + class SwimToCommand : public MoveToCommand { public: SwimToCommand(float x, float y, float z, MobMovementMode mob_movement_mode) : MoveToCommand(x, y, z, mob_movement_mode) @@ -921,6 +1061,8 @@ void MobMovementManager::FillCommandStruct( */ void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) { + Mob *target=who->GetTarget(); + if (!zone->HasMap() || !zone->HasWaterMap()) { auto iter = _impl->Entries.find(who); auto &ent = (*iter); @@ -936,6 +1078,16 @@ void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMove else if (who->IsUnderwaterOnly()) { UpdatePathUnderwater(who, x, y, z, mob_movement_mode); } + // If we can fly, and we have a target and we have LoS, simply fly to them. + // if we ever lose LoS we go back to mesh run mode. + else if (target && who->GetFlyMode() == GravityBehavior::Flying && + who->CheckLosFN(x,y,z,target->GetSize())) { + auto iter = _impl->Entries.find(who); + auto &ent = (*iter); + + PushFlyTo(ent.second, x, y, z, mob_movement_mode); + PushStopMoving(ent.second); + } else { UpdatePathGround(who, x, y, z, mob_movement_mode); } @@ -1275,6 +1427,18 @@ void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, ent.Commands.push_back(std::unique_ptr(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode))); } +/** + * @param ent + * @param x + * @param y + * @param z + * @param mob_movement_mode + */ +void MobMovementManager::PushFlyTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode) +{ + ent.Commands.push_back(std::unique_ptr(new FlyToCommand(x, y, z, mob_movement_mode))); +} + /** * @param mob_movement_entry */ diff --git a/zone/mob_movement_manager.h b/zone/mob_movement_manager.h index ff7e08436..85d062804 100644 --- a/zone/mob_movement_manager.h +++ b/zone/mob_movement_manager.h @@ -85,6 +85,7 @@ private: void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading); void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode); void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode); + void PushFlyTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode); void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode); void PushStopMoving(MobMovementEntry &mob_movement_entry); void PushEvadeCombat(MobMovementEntry &mob_movement_entry); From 263ed3913b94aebfc9ac6ce959e43c469bf3b959 Mon Sep 17 00:00:00 2001 From: = <=isaacseniorx@gmail.com> Date: Wed, 6 May 2020 02:44:17 +0000 Subject: [PATCH 05/15] Don't scale 0 values --- zone/npc.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 39b1b046b..edc9f88c3 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -2443,18 +2443,27 @@ void NPC::LevelScale() { if (RuleB(NPC, NewLevelScaling)) { if (scalerate == 0 || maxlevel <= 25) { - // pre-pop seems to scale by 20 HP increments while newer by 100 - // We also don't want 100 increments on newer noobie zones, check level - if (zone->GetZoneID() < 200 || level < 48) { - max_hp += (random_level - level) * 20; - base_hp += (random_level - level) * 20; - } else { - max_hp += (random_level - level) * 100; - base_hp += (random_level - level) * 100; + // Don't add HP to dynamically scaled NPCs since this will be calculated later + if (max_hp > 0 || skip_auto_scale) + { + // pre-pop seems to scale by 20 HP increments while newer by 100 + // We also don't want 100 increments on newer noobie zones, check level + if (zone->GetZoneID() < 200 || level < 48) { + max_hp += (random_level - level) * 20; + base_hp += (random_level - level) * 20; + } else { + max_hp += (random_level - level) * 100; + base_hp += (random_level - level) * 100; + } + + current_hp = max_hp; + } + + // Don't add max_dmg to dynamically scaled NPCs since this will be calculated later + if (max_dmg > 0 || skip_auto_scale) + { + max_dmg += (random_level - level) * 2; } - - current_hp = max_hp; - max_dmg += (random_level - level) * 2; } else { uint8 scale_adjust = 1; From 0b03f276609e75be64891d68e9f081292657b766 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 May 2020 23:05:07 -0400 Subject: [PATCH 06/15] Add GetNPCBySpawnID() to Perl/Lua. --- zone/entity.cpp | 16 ++++++++++++++++ zone/entity.h | 1 + zone/lua_entity_list.cpp | 6 ++++++ zone/lua_entity_list.h | 1 + zone/perl_entity.cpp | 29 +++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+) diff --git a/zone/entity.cpp b/zone/entity.cpp index 23ff268fc..c80f83ec5 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1097,6 +1097,22 @@ NPC *EntityList::GetNPCByNPCTypeID(uint32 npc_id) return nullptr; } +NPC *EntityList::GetNPCBySpawnID(uint32 spawn_id) +{ + if (spawn_id == 0 || npc_list.empty()) { + return nullptr; + } + + auto it = npc_list.begin(); + while (it != npc_list.end()) { + if (it->second->GetSpawnGroupId() == spawn_id) { + return it->second; + } + ++it; + } + return nullptr; +} + Mob *EntityList::GetMob(uint16 get_id) { Entity *ent = nullptr; diff --git a/zone/entity.h b/zone/entity.h index 3c182be29..8c705897a 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -166,6 +166,7 @@ public: return nullptr; } NPC *GetNPCByNPCTypeID(uint32 npc_id); + NPC *GetNPCBySpawnID(uint32 spawn_id); inline Merc *GetMercByID(uint16 id) { auto it = merc_list.find(id); diff --git a/zone/lua_entity_list.cpp b/zone/lua_entity_list.cpp index abfc020d6..e4f2b207d 100644 --- a/zone/lua_entity_list.cpp +++ b/zone/lua_entity_list.cpp @@ -80,6 +80,11 @@ Lua_NPC Lua_EntityList::GetNPCByNPCTypeID(int npc_type) { return Lua_NPC(self->GetNPCByNPCTypeID(npc_type)); } +Lua_NPC Lua_EntityList::GetNPCBySpawnID(uint32 spawn_id) { + Lua_Safe_Call_Class(Lua_NPC); + return Lua_NPC(self->GetNPCBySpawnID(spawn_id)); +} + Lua_Client Lua_EntityList::GetClientByName(const char *name) { Lua_Safe_Call_Class(Lua_Client); return Lua_Client(self->GetClientByName(name)); @@ -449,6 +454,7 @@ luabind::scope lua_register_entity_list() { .def("IsMobSpawnedByNpcTypeID", (bool(Lua_EntityList::*)(int))&Lua_EntityList::IsMobSpawnedByNpcTypeID) .def("GetNPCByID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByID) .def("GetNPCByNPCTypeID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByNPCTypeID) + .def("GetNPCBySpawnID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCBySpawnID) .def("GetClientByName", (Lua_Client(Lua_EntityList::*)(const char*))&Lua_EntityList::GetClientByName) .def("GetClientByAccID", (Lua_Client(Lua_EntityList::*)(uint32))&Lua_EntityList::GetClientByAccID) .def("GetClientByID", (Lua_Client(Lua_EntityList::*)(int))&Lua_EntityList::GetClientByID) diff --git a/zone/lua_entity_list.h b/zone/lua_entity_list.h index 6b0074674..04030e58e 100644 --- a/zone/lua_entity_list.h +++ b/zone/lua_entity_list.h @@ -54,6 +54,7 @@ public: bool IsMobSpawnedByNpcTypeID(int npc_type); Lua_NPC GetNPCByID(int id); Lua_NPC GetNPCByNPCTypeID(int npc_type); + Lua_NPC GetNPCBySpawnID(uint32 spawn_id); Lua_Client GetClientByName(const char *name); Lua_Client GetClientByAccID(uint32 acct_id); Lua_Client GetClientByID(int id); diff --git a/zone/perl_entity.cpp b/zone/perl_entity.cpp index 0f7fe21c7..3280d0a56 100644 --- a/zone/perl_entity.cpp +++ b/zone/perl_entity.cpp @@ -219,6 +219,34 @@ XS(XS_EntityList_GetNPCByNPCTypeID) { XSRETURN(1); } +XS(XS_EntityList_GetNPCBySpawnID); /* prototype to pass -Wmissing-prototypes */ +XS(XS_EntityList_GetNPCBySpawnID) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: EntityList::GetNPCBySpawnID(THIS, spawn_id)"); + { + EntityList *THIS; + NPC *RETVAL; + uint32 spawn_id = (uint32) SvUV(ST(1)); + + if (sv_derived_from(ST(0), "EntityList")) { + IV tmp = SvIV((SV *) SvRV(ST(0))); + THIS = INT2PTR(EntityList *, tmp); + } else { + Perl_croak(aTHX_ "THIS is not of type EntityList"); + } + + if (THIS == nullptr) { + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + } + + RETVAL = THIS->GetNPCBySpawnID(spawn_id); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "NPC", (void *) RETVAL); + } + XSRETURN(1); +} + XS(XS_EntityList_GetClientByName); /* prototype to pass -Wmissing-prototypes */ XS(XS_EntityList_GetClientByName) { dXSARGS; @@ -1998,6 +2026,7 @@ XS(boot_EntityList) { newXSproto(strcpy(buf, "IsMobSpawnedByNpcTypeID"), XS_EntityList_IsMobSpawnedByNpcTypeID, file, "$$"); newXSproto(strcpy(buf, "GetNPCByID"), XS_EntityList_GetNPCByID, file, "$$"); newXSproto(strcpy(buf, "GetNPCByNPCTypeID"), XS_EntityList_GetNPCByNPCTypeID, file, "$$"); + newXSproto(strcpy(buf, "GetNPCBySpawnID"), XS_EntityList_GetNPCBySpawnID, file, "$$"); newXSproto(strcpy(buf, "GetClientByName"), XS_EntityList_GetClientByName, file, "$$"); newXSproto(strcpy(buf, "GetClientByAccID"), XS_EntityList_GetClientByAccID, file, "$$"); newXSproto(strcpy(buf, "GetClientByID"), XS_EntityList_GetClientByID, file, "$$"); From 0a42ded33f51bef4126fdeefe9be8a7810535ef7 Mon Sep 17 00:00:00 2001 From: Noudess Date: Fri, 8 May 2020 09:58:53 -0400 Subject: [PATCH 07/15] Expose client method NotifyNewTitlesAvailable for perl and lua --- zone/lua_client.cpp | 6 ++++++ zone/lua_client.h | 1 + zone/perl_client.cpp | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 955130922..e161c5e20 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1210,6 +1210,11 @@ void Lua_Client::OpenLFGuildWindow() { self->OpenLFGuildWindow(); } +void Lua_Client::NotifyNewTitlesAvailable() { + Lua_Safe_Call_Void(); + self->NotifyNewTitlesAvailable(); +} + void Lua_Client::Signal(uint32 id) { Lua_Safe_Call_Void(); self->Signal(id); @@ -1820,6 +1825,7 @@ luabind::scope lua_register_client() { .def("GetAllMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetAllMoney) .def("GetMoney", (uint32(Lua_Client::*)(uint8, uint8))&Lua_Client::GetMoney) .def("OpenLFGuildWindow", (void(Lua_Client::*)(void))&Lua_Client::OpenLFGuildWindow) + .def("NotifyNewTitlesAvailable", (void(Lua_Client::*)(void))&Lua_Client::NotifyNewTitlesAvailable) .def("Signal", (void(Lua_Client::*)(uint32))&Lua_Client::Signal) .def("AddAlternateCurrencyValue", (void(Lua_Client::*)(uint32,int))&Lua_Client::AddAlternateCurrencyValue) .def("SetAlternateCurrencyValue", (void(Lua_Client::*)(uint32,int))&Lua_Client::SetAlternateCurrencyValue) diff --git a/zone/lua_client.h b/zone/lua_client.h index b0eb719e8..600b594f2 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -269,6 +269,7 @@ public: uint64 GetAllMoney(); uint32 GetMoney(uint8 type, uint8 subtype); void OpenLFGuildWindow(); + void NotifyNewTitlesAvailable(); void Signal(uint32 id); void AddAlternateCurrencyValue(uint32 currency, int amount); void SetAlternateCurrencyValue(uint32 currency, int amount); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index e46b5e8d4..66cf78084 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -5522,6 +5522,27 @@ XS(XS_Client_OpenLFGuildWindow) { XSRETURN_EMPTY; } +XS(XS_NotifyNewTitlesAvailable); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_NotifyNewTitlesAvailable) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::NotifyNewTitlesAvailable(THIS)"); + { + Client *THIS; + + 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."); + + THIS->NotifyNewTitlesAvailable(); + } + XSRETURN_EMPTY; +} + XS(XS_Client_SignalClient); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_SignalClient) { dXSARGS; @@ -6568,6 +6589,7 @@ XS(boot_Client) { newXSproto(strcpy(buf, "NPCSpawn"), XS_Client_NPCSpawn, file, "$$$;$"); newXSproto(strcpy(buf, "NukeItem"), XS_Client_NukeItem, file, "$$;$"); newXSproto(strcpy(buf, "OpenLFGuildWindow"), XS_Client_OpenLFGuildWindow, file, "$"); + newXSproto(strcpy(buf, "NotifyNewTitlesAvailable"), XS_Client_NotifyNewTitlesAvailable, file, "$"); newXSproto(strcpy(buf, "PlayMP3"), XS_Client_PlayMP3, file, "$;$"); newXSproto(strcpy(buf, "Popup2"), XS_Client_Popup2, file, "$$$;$$$$$$$"); newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$"); From 572ad1b6ab4ecca91cd04eea1f5e4396562e3463 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 8 May 2020 12:56:10 -0400 Subject: [PATCH 08/15] Identify SubType in Item structs in some clients This maybe in older clients as well, but I couldn't verify it and those clients never did anything with this field so it doesn't matter. MQ2 calls this SubClass, but we call the field it's a "sub" of Type so I figured we'd call it SubType. We still need to rename the DB field and handle it server side etc --- common/patches/rof2_structs.h | 4 ++-- common/patches/rof_structs.h | 4 ++-- common/patches/uf_structs.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 10ce35654..92021c283 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4804,8 +4804,8 @@ struct ItemQuaternaryBodyStruct int32 HealAmt; int32 SpellDmg; int32 Clairvoyance; - uint8 unknown18; //Power Source Capacity or evolve filename? - uint32 evolve_string; // Some String, but being evolution related is just a guess + int32 SubType; + uint8 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; uint16 unknown20; uint8 unknown21; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 03f1a951a..bdf416724 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4744,8 +4744,8 @@ struct ItemQuaternaryBodyStruct int32 HealAmt; int32 SpellDmg; int32 Clairvoyance; - uint8 unknown18; //Power Source Capacity or evolve filename? - uint32 evolve_string; // Some String, but being evolution related is just a guess + int32 SubType; + uint8 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; uint32 unknown20; // Bard Stuff? //uint32 unknown21; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index b6eb414e1..3a66e2a88 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4215,8 +4215,8 @@ struct ItemQuaternaryBodyStruct int32 HealAmt; int32 SpellDmg; int32 Clairvoyance; - uint8 unknown18; //Power Source Capacity or evolve filename? - uint32 evolve_string; // Some String, but being evolution related is just a guess + int32 SubType; + uint8 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; uint32 unknown20; // Bard Stuff? uint32 unknown21; From 5471774b4c677268ecd83aae6ad2ab8c6f134cc2 Mon Sep 17 00:00:00 2001 From: Noudess Date: Fri, 8 May 2020 18:24:25 -0400 Subject: [PATCH 09/15] Repair prototype --- zone/perl_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 66cf78084..1c0c42bf5 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -5522,7 +5522,7 @@ XS(XS_Client_OpenLFGuildWindow) { XSRETURN_EMPTY; } -XS(XS_NotifyNewTitlesAvailable); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_NotifyNewTitlesAvailable); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_NotifyNewTitlesAvailable) { dXSARGS; if (items != 1) From 914ea274066b4437dc3c2058e06284c6a9e13d42 Mon Sep 17 00:00:00 2001 From: Jose123456 Date: Sat, 9 May 2020 12:40:33 -0700 Subject: [PATCH 10/15] Compile on Freebsd (#1044) * Compile on Freebsd Small changes needed for compilation on Freebsd. Note that you'll have to pass -DEQEMU_BUILD_ZLIB=OFF on the cmake command line. The bundled zlib-ng does not build on Freebsd even though mainline zlib-ng does. * Fix build errors: typo --- CMakeLists.txt | 5 ++++- common/crash.cpp | 5 +++++ common/proc_launcher.h | 4 ++++ common/util/uuid.cpp | 13 +++++++++++++ zone/main.cpp | 8 +++++++- 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b12e2ee1..c164cfba4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,7 +328,10 @@ IF(UNIX) IF(NOT DARWIN) SET(SERVER_LIBS ${SERVER_LIBS} "rt") ENDIF() - SET(SERVER_LIBS ${SERVER_LIBS} "uuid") + # Freebsd provides uuids in the C library + IF(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + SET(SERVER_LIBS ${SERVER_LIBS} "uuid") + ENDIF() ENDIF() IF(EQEMU_BUILD_LOGIN AND NOT TLS_LIBRARY_ENABLED) diff --git a/common/crash.cpp b/common/crash.cpp index 155bfcf2a..cecb52f02 100644 --- a/common/crash.cpp +++ b/common/crash.cpp @@ -118,6 +118,11 @@ void set_exception_handler() { #include #include +#ifdef __FreeBSD__ +#include +#include +#endif + void print_trace() { auto uid = geteuid(); diff --git a/common/proc_launcher.h b/common/proc_launcher.h index 6289579cd..23b7e523c 100644 --- a/common/proc_launcher.h +++ b/common/proc_launcher.h @@ -24,6 +24,10 @@ #include #include +#ifdef __FreeBSD__ +#include +#endif + //I forced this object to become a singleton because it registers its //signal handler for UNIX class ProcLauncher { diff --git a/common/util/uuid.cpp b/common/util/uuid.cpp index c5b6b9a4d..633ffebaf 100644 --- a/common/util/uuid.cpp +++ b/common/util/uuid.cpp @@ -14,6 +14,10 @@ #include #endif +#ifdef __FreeBSD__ +#include +#endif + unsigned char hexDigitToChar(char ch) { if (ch > 47 && ch < 58) @@ -126,6 +130,15 @@ EQ::Util::UUID EQ::Util::UUID::Generate() return buffer; #endif + +#ifdef __FreeBSD__ + uuid_t l_id; + char l_uuid[37]; + uint32_t l_ignored; + uuid_create(&l_id, &l_ignored); + uuid_to_string(&l_id, (char**) &l_uuid, &l_ignored); + return FromString(l_uuid); +#endif } EQ::Util::UUID EQ::Util::UUID::FromString(const std::string &str) diff --git a/zone/main.cpp b/zone/main.cpp index 0445534d4..364df32b9 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -92,6 +92,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/unix.h" #endif +#ifdef __FreeBSD__ +#include +#endif + extern volatile bool is_zone_loaded; EntityList entity_list; @@ -431,8 +435,10 @@ int main(int argc, char** argv) { EQStreamIdentifier stream_identifier; RegisterAllPatches(stream_identifier); -#ifndef WIN32 +#ifdef __linux__ LogDebug("Main thread running with thread id [{}]", pthread_self()); +#elif defined(__FreeBSD__) + LogDebug("Main thread running with thread id [{}]", pthread_getthreadid_np()); #endif bool worldwasconnected = worldserver.Connected(); From 518bcb58d3e99e8834d3b5a7e69418c103ded77c Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 9 May 2020 18:12:24 -0400 Subject: [PATCH 11/15] Fix #findzone to allow you to search using part of a zone's short name. --- zone/command.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/command.cpp b/zone/command.cpp index 42453faab..7157434c9 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -4125,7 +4125,8 @@ void command_findzone(Client *c, const Seperator *sep) */ if (id == 0) { query = fmt::format( - "SELECT zoneidnumber, short_name, long_name, version FROM zone WHERE long_name LIKE '%{}%'", + "SELECT zoneidnumber, short_name, long_name, version FROM zone WHERE long_name LIKE '%{}%' OR `short_name` LIKE '%{}%'", + EscapeString(sep->arg[1]), EscapeString(sep->arg[1]) ); } From 12c4b201692f3b0b06874cd2bf9da4c3deb7a164 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 9 May 2020 21:15:34 -0400 Subject: [PATCH 12/15] Add CrossZoneSignalPlayerByGroupID() to Perl/Lua. --- common/servertalk.h | 6 ++++++ world/zoneserver.cpp | 1 + zone/embparser_api.cpp | 19 +++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 9 +++++++++ zone/questmgr.h | 1 + zone/worldserver.cpp | 11 +++++++++++ 7 files changed, 52 insertions(+) diff --git a/common/servertalk.h b/common/servertalk.h index 032df1ddc..5c5749fe3 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -198,6 +198,7 @@ #define ServerOP_UCSServerStatusRequest 0x4013 #define ServerOP_UCSServerStatusReply 0x4014 #define ServerOP_HotReloadQuests 0x4015 +#define ServerOP_CZSignalGroup 0x4016 /** * QueryServer @@ -1167,6 +1168,11 @@ struct CZClientSignal_Struct { uint32 data; }; +struct CZGroupSignal_Struct { + int group_id; + uint32 data; +}; + struct CZNPCSignal_Struct { uint32 npctype_id; uint32 data; diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 08ccbfaff..7731fd571 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1241,6 +1241,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_CZSignalNPC: case ServerOP_CZSetEntityVariableByNPCTypeID: case ServerOP_CZSignalClient: + case ServerOP_CZSignalGroup: case ServerOP_CZSetEntityVariableByClientName: case ServerOP_WWMarquee: case ServerOP_DepopAllPlayersCorpses: diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c65cd204c..8f2714d64 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3721,6 +3721,24 @@ XS(XS__crosszonesignalclientbycharid) { XSRETURN_EMPTY; } +XS(XS__crosszonesignalclientbygroupid); +XS(XS__crosszonesignalclientbygroupid) { + dXSARGS; + + if (items != 2) + Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbygroupid(int group_id, int value)"); + + if (items == 2) { + int group_id = (int) SvIV(ST(0)); + uint32 int_value = (uint32) SvIV(ST(1)); + quest_manager.CrossZoneSignalPlayerByGroupID(group_id, int_value); + } else { + Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbygroupid(int group_id, int value)"); + } + + XSRETURN_EMPTY; +} + XS(XS__crosszonesignalclientbyname); XS(XS__crosszonesignalclientbyname) { dXSARGS; @@ -4176,6 +4194,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file); newXS(strcpy(buf, "crosszonesetentityvariablebyclientname"), XS__crosszonesetentityvariablebyclientname, file); newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file); + newXS(strcpy(buf, "crosszonesignalclientbygroupid"), XS__crosszonesignalclientbygroupid, file); newXS(strcpy(buf, "crosszonesignalclientbyname"), XS__crosszonesignalclientbyname, file); newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file); newXS(strcpy(buf, "worldwidemarquee"), XS__worldwidemarquee, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index d047238de..df890660c 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1026,6 +1026,10 @@ void lua_cross_zone_signal_client_by_char_id(uint32 player_id, int signal) { quest_manager.CrossZoneSignalPlayerByCharID(player_id, signal); } +void lua_cross_zone_signal_client_by_group_id(uint32 group_id, int signal) { + quest_manager.CrossZoneSignalPlayerByGroupID(group_id, signal); +} + void lua_cross_zone_signal_client_by_name(const char *player, int signal) { quest_manager.CrossZoneSignalPlayerByName(player, signal); } @@ -1839,6 +1843,7 @@ luabind::scope lua_register_general() { luabind::def("voice_tell", &lua_voice_tell), luabind::def("send_mail", &lua_send_mail), luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id), + luabind::def("cross_zone_signal_client_by_group_id", &lua_cross_zone_signal_client_by_group_id), luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name), luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name), luabind::def("cross_zone_set_entity_variable_by_client_name", &lua_cross_zone_set_entity_variable_by_client_name), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index ba6a5340c..e1933323f 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -3211,6 +3211,15 @@ void QuestManager::CrossZoneSignalPlayerByCharID(int charid, uint32 data){ safe_delete(pack); } +void QuestManager::CrossZoneSignalPlayerByGroupID(int group_id, uint32 data){ + auto pack = new ServerPacket(ServerOP_CZSignalGroup, sizeof(CZGroupSignal_Struct)); + CZGroupSignal_Struct* CZGS = (CZGroupSignal_Struct*) pack->pBuffer; + CZGS->group_id = group_id; + CZGS->data = data; + worldserver.SendPacket(pack); + safe_delete(pack); +} + void QuestManager::CrossZoneSignalPlayerByName(const char *CharName, uint32 data){ uint32 message_len = strlen(CharName) + 1; auto pack = new ServerPacket(ServerOP_CZSignalClientByName, sizeof(CZClientSignalByName_Struct) + message_len); diff --git a/zone/questmgr.h b/zone/questmgr.h index 14ddea9c8..2a12fcd84 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -279,6 +279,7 @@ public: int32 GetZoneID(const char *zone); const char *GetZoneLongName(const char *zone); void CrossZoneSignalPlayerByCharID(int charid, uint32 data); + void CrossZoneSignalPlayerByGroupID(int group_id, uint32 data); void CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 data); void CrossZoneSignalPlayerByName(const char *CharName, uint32 data); void CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 4b2034067..a983b7cfa 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1915,6 +1915,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } break; } + case ServerOP_CZSignalGroup: + { + CZGroupSignal_Struct* CZGS = (CZGroupSignal_Struct*)pack->pBuffer; + auto client_list = entity_list.GetClientList(); + for (auto client : client_list) { + if (client.second->GetGroup() && client.second->GetGroup()->GetID() == CZGS->group_id) { + client.second->Signal(CZGS->data); + } + } + break; + } case ServerOP_CZSignalClientByName: { CZClientSignalByName_Struct* CZCS = (CZClientSignalByName_Struct*)pack->pBuffer; From 0e6a0b5a7000a0e98d8e7c9e8dfd0069cedbe7f3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 9 May 2020 22:37:35 -0400 Subject: [PATCH 13/15] Add Item SubType to data structures and DB --- common/item_data.h | 1 + common/item_fieldlist.h | 1 + common/patches/rof.cpp | 1 + common/patches/rof2.cpp | 1 + common/patches/uf.cpp | 3 ++- common/shareddb.cpp | 1 + common/spdat.h | 2 +- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + utils/sql/git/required/2020_05_09_items_subtype.sql | 1 + 10 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 utils/sql/git/required/2020_05_09_items_subtype.sql diff --git a/common/item_data.h b/common/item_data.h index 58bc4c889..d5570f856 100644 --- a/common/item_data.h +++ b/common/item_data.h @@ -434,6 +434,7 @@ namespace EQEmu //uint32 Unk054; int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item uint8 ItemType; // Item Type/Skill (itemClass* from above) + int32 SubType; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass) uint8 Material; // Item material type uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?) float SellRate; // Sell rate diff --git a/common/item_fieldlist.h b/common/item_fieldlist.h index 665783498..3c00f1e44 100644 --- a/common/item_fieldlist.h +++ b/common/item_fieldlist.h @@ -203,3 +203,4 @@ F(procname) F(wornname) F(focusname) F(scrollname) +F(subtype) diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index fd75cb3db..fed2802df 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -5504,6 +5504,7 @@ namespace RoF iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; iqbs.Clairvoyance = item->Clairvoyance; + iqbs.SubType = item->SubType; iqbs.unknown28 = 0; iqbs.unknown30 = 0; iqbs.unknown39 = 1; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 36257771b..209324740 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5759,6 +5759,7 @@ namespace RoF2 iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; iqbs.Clairvoyance = item->Clairvoyance; + iqbs.SubType = item->SubType; //unknown18; //Power Source Capacity or evolve filename? //evolve_string; // Some String, but being evolution related is just a guess diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index ef28e8e33..4b97658d2 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -4106,7 +4106,8 @@ namespace UF iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; iqbs.Clairvoyance = item->Clairvoyance; - + iqbs.SubType = item->SubType; + ob.write((const char*)&iqbs, sizeof(UF::structs::ItemQuaternaryBodyStruct)); EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 48cc1309d..6c327b188 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1029,6 +1029,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]); item.ItemType = (uint8)atoi(row[ItemField::itemtype]); + item.SubType = atoi(row[ItemField::subtype]); item.Material = (uint8)atoi(row[ItemField::material]); item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]); item.SellRate = (float)atof(row[ItemField::sellrate]); diff --git a/common/spdat.h b/common/spdat.h index c7c6027c6..9c9cf3f53 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -634,7 +634,7 @@ typedef enum { #define SE_LimitRace 412 // implemented - Limits to spells cast by a certain race (Note: not used in any known live spells) #define SE_FcBaseEffects 413 // implemented - Increases the power of bard songs, skill attacks, runes, bard allowed foci, damage/heal #define SE_LimitCastingSkill 414 // implemented - Limit a focus to include spells cast using a specific skill. -//#define SE_FFItemClass 415 // not used +//#define SE_FFItemClass 415 // not used - base1 matches ItemType, base2 matches SubType, -1 ignored, max is bitmask of valid slots #define SE_ACv2 416 // implemented - New AC spell effect #define SE_ManaRegen_v2 417 // implemented - New mana regen effect #define SE_SkillDamageAmount2 418 // implemented - adds skill damage directly to certain attacks diff --git a/common/version.h b/common/version.h index 7c378e763..c840ebdc5 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9152 +#define CURRENT_BINARY_DATABASE_VERSION 9153 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 28b22028e..c6af34a98 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -406,6 +406,7 @@ 9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty| 9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty| 9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9152|empty| +9153|2020_05_09_items_subtype.sql|SHOW COLUMNS from `items` LIKE 'UNK219'|not_empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2020_05_09_items_subtype.sql b/utils/sql/git/required/2020_05_09_items_subtype.sql new file mode 100644 index 000000000..43b38d14f --- /dev/null +++ b/utils/sql/git/required/2020_05_09_items_subtype.sql @@ -0,0 +1 @@ +ALTER TABLE `items` CHANGE `UNK219` `subtype` int(11) not null default '0'; From 4d934061765d85aa9d97b075d35da96c8f1d8253 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 10 May 2020 09:16:16 -0400 Subject: [PATCH 14/15] Fix typo in crosszonesignalclientbyname Perl_croak. --- zone/embparser_api.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c65cd204c..c1263980d 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3726,14 +3726,14 @@ XS(XS__crosszonesignalclientbyname) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbycharid(string name, int value)"); + Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbyname(string name, int value)"); if (items == 2) { char *name = (char *) SvPV_nolen(ST(0)); uint32 int_value = (uint32) SvIV(ST(1)); quest_manager.CrossZoneSignalPlayerByName(name, int_value); } else { - Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbycharid(string name, int value)"); + Perl_croak(aTHX_ "Usage: quest::crosszonesignalclientbyname(string name, int value)"); } XSRETURN_EMPTY; From 857b24727c96cbf15d4f66292f1f53674e827c57 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 10 May 2020 16:52:33 -0400 Subject: [PATCH 15/15] Add CrossZoneMessagePlayerByGuildID() to Perl/Lua. --- common/servertalk.h | 7 +++++++ world/zoneserver.cpp | 1 + zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 11 +++++++++++ zone/questmgr.h | 1 + zone/worldserver.cpp | 11 +++++++++++ 7 files changed, 54 insertions(+) diff --git a/common/servertalk.h b/common/servertalk.h index 032df1ddc..318e0cf06 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -198,6 +198,7 @@ #define ServerOP_UCSServerStatusRequest 0x4013 #define ServerOP_UCSServerStatusReply 0x4014 #define ServerOP_HotReloadQuests 0x4015 +#define ServerOP_CZMessageGuild 0x4021 /** * QueryServer @@ -1334,6 +1335,12 @@ struct CZMessagePlayer_Struct { char Message[512]; }; +struct CZMessageGuild_Struct { + uint32 Type; + int GuildID; + char Message[512]; +}; + struct WWMarquee_Struct { uint32 Type; uint32 Priority; diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 08ccbfaff..3f1c8eae0 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1238,6 +1238,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { } case ServerOP_CZSignalClientByName: case ServerOP_CZMessagePlayer: + case ServerOP_CZMessageGuild: case ServerOP_CZSignalNPC: case ServerOP_CZSetEntityVariableByNPCTypeID: case ServerOP_CZSignalClient: diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c65cd204c..55ca42c00 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3757,6 +3757,23 @@ XS(XS__crosszonemessageplayerbyname) { XSRETURN_EMPTY; } +XS(XS__crosszonemessageplayerbyguildid); +XS(XS__crosszonemessageplayerbyguildid) { + dXSARGS; + + if (items != 3) + Perl_croak(aTHX_ "Usage: quest::crosszonemessageplayerbyguildid(int typ, int guild_id, string message)"); + + if (items == 3) { + uint32 type = (uint32) SvIV(ST(0)); + int guild_id = (int) SvIV(ST(1)); + char *message = (char *) SvPV_nolen(ST(2)); + quest_manager.CrossZoneMessagePlayerByGuildID(type, guild_id, message); + } + + XSRETURN_EMPTY; +} + XS(XS__enablerecipe); XS(XS__enablerecipe) { dXSARGS; @@ -4173,6 +4190,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file); newXS(strcpy(buf, "createguild"), XS__createguild, file); newXS(strcpy(buf, "crosszonemessageplayerbyname"), XS__crosszonemessageplayerbyname, file); + newXS(strcpy(buf, "crosszonemessageplayerbyguildid"), XS__crosszonemessageplayerbyguildid, file); newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file); newXS(strcpy(buf, "crosszonesetentityvariablebyclientname"), XS__crosszonesetentityvariablebyclientname, file); newXS(strcpy(buf, "crosszonesignalclientbycharid"), XS__crosszonesignalclientbycharid, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index d047238de..ee3318f31 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1034,6 +1034,10 @@ void lua_cross_zone_message_player_by_name(uint32 type, const char *player, cons quest_manager.CrossZoneMessagePlayerByName(type, player, message); } +void lua_cross_zone_message_player_by_guild_id(uint32 type, int guild_id, const char *message) { + quest_manager.CrossZoneMessagePlayerByGuildID(type, guild_id, message); +} + void lua_cross_zone_set_entity_variable_by_client_name(const char *player, const char *id, const char *m_var) { quest_manager.CrossZoneSetEntityVariableByClientName(player, id, m_var); } @@ -1841,6 +1845,7 @@ luabind::scope lua_register_general() { luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id), luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name), luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name), + luabind::def("cross_zone_message_player_by_guild_id", &lua_cross_zone_message_player_by_guild_id), luabind::def("cross_zone_set_entity_variable_by_client_name", &lua_cross_zone_set_entity_variable_by_client_name), luabind::def("world_wide_marquee", &lua_world_wide_marquee), luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index ba6a5340c..38e6c808c 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -3234,6 +3234,17 @@ void QuestManager::CrossZoneMessagePlayerByName(uint32 Type, const char *CharNam safe_delete(pack); } +void QuestManager::CrossZoneMessagePlayerByGuildID(uint32 Type, int GuildID, const char *Message){ + uint32 message_len = strlen(Message) + 1; + auto pack = new ServerPacket(ServerOP_CZMessageGuild, sizeof(CZMessageGuild_Struct) + message_len); + CZMessageGuild_Struct* CZGM = (CZMessageGuild_Struct*) pack->pBuffer; + CZGM->Type = Type; + CZGM->GuildID = GuildID; + strn0cpy(CZGM->Message, Message, 512); + worldserver.SendPacket(pack); + safe_delete(pack); +} + void QuestManager::CrossZoneSetEntityVariableByClientName(const char *CharName, const char *id, const char *m_var){ uint32 message_len = strlen(id) + 1; uint32 message_len2 = strlen(m_var) + 1; diff --git a/zone/questmgr.h b/zone/questmgr.h index 14ddea9c8..15c46f694 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -284,6 +284,7 @@ public: void CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var); void CrossZoneSetEntityVariableByClientName(const char *CharName, const char *id, const char *m_var); void CrossZoneMessagePlayerByName(uint32 Type, const char *CharName, const char *Message); + void CrossZoneMessagePlayerByGuildID(uint32 Type, int GuildID, const char *Message); void WorldWideMarquee(uint32 Type, uint32 Priority, uint32 FadeIn, uint32 FadeOut, uint32 Duration, const char *Message); bool EnableRecipe(uint32 recipe_id); bool DisableRecipe(uint32 recipe_id); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 4b2034067..46bac74ed 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1933,6 +1933,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } break; } + case ServerOP_CZMessageGuild: + { + CZMessageGuild_Struct* CZGM = (CZMessageGuild_Struct*)pack->pBuffer; + auto client_list = entity_list.GetClientList(); + for (auto client : client_list) { + if (client.second->GuildID() > 0 && client.second->GuildID() == CZGM->GuildID) { + client.second->Message(CZGM->Type, CZGM->Message); + } + } + break; + } case ServerOP_CZSetEntityVariableByClientName: { CZSetEntVarByClientName_Struct* CZCS = (CZSetEntVarByClientName_Struct*)pack->pBuffer;