mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-22 13:37:22 +00:00
Updated vendor component
Fixed a few issues in VendorComponent. - Corrected serialization to only happen on construction. - Added functionality to refresh the vendor based on info from the vendor component table - some whitespaceing inconsistencies. - Sorted includes. Tested the vendor in Nimbus Station and when the player re-enters the world, the vendor inventory refreshes, as opposed to previously where the world would need to reset in order to refresh the inventory.
This commit is contained in:
parent
aca2bb1090
commit
5afeb265cd
@ -1,116 +1,135 @@
|
|||||||
#include "VendorComponent.h"
|
#include "VendorComponent.h"
|
||||||
#include "Game.h"
|
|
||||||
#include "dServer.h"
|
|
||||||
|
|
||||||
#include <BitStream.h>
|
#include <BitStream.h>
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "dServer.h"
|
||||||
|
|
||||||
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
||||||
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
SetupConstants();
|
||||||
auto* vendorComponentTable = CDClientManager::Instance()->GetTable<CDVendorComponentTable>("VendorComponent");
|
RefreshInventory(true);
|
||||||
auto* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
|
|
||||||
auto* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
|
|
||||||
|
|
||||||
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR);
|
|
||||||
std::vector<CDVendorComponent> vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); });
|
|
||||||
if (vendorComps.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_BuyScalar = vendorComps[0].buyScalar;
|
|
||||||
m_SellScalar = vendorComps[0].sellScalar;
|
|
||||||
int lootMatrixID = vendorComps[0].LootMatrixIndex;
|
|
||||||
std::vector<CDLootMatrix> lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == lootMatrixID); });
|
|
||||||
if (lootMatrices.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const auto& lootMatrix : lootMatrices) {
|
|
||||||
int lootTableID = lootMatrix.LootTableIndex;
|
|
||||||
std::vector<CDLootTable> vendorItems = lootTableTable->Query([=](CDLootTable entry) { return (entry.LootTableIndex == lootTableID); });
|
|
||||||
if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) {
|
|
||||||
for (CDLootTable item : vendorItems) {
|
|
||||||
m_Inventory.insert({item.itemid, item.sortPriority});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto randomCount = GeneralUtils::GenerateRandomNumber<int32_t>(lootMatrix.minToDrop, lootMatrix.maxToDrop);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < randomCount; i++) {
|
|
||||||
if (vendorItems.empty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
|
||||||
|
|
||||||
const auto& randomItem = vendorItems[randomItemIndex];
|
|
||||||
|
|
||||||
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
|
||||||
|
|
||||||
m_Inventory.insert({randomItem.itemid, randomItem.sortPriority});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Because I want a vendor to sell these cameras
|
|
||||||
if (parent->GetLOT() == 13569) {
|
|
||||||
auto randomCamera = GeneralUtils::GenerateRandomNumber<int32_t>(0, 2);
|
|
||||||
|
|
||||||
switch (randomCamera) {
|
|
||||||
case 0:
|
|
||||||
m_Inventory.insert({16253, 0}); //Grungagroid
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
m_Inventory.insert({16254, 0}); //Hipstabrick
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
m_Inventory.insert({16204, 0}); //Megabrixel snapshot
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Custom code for Max vanity NPC
|
|
||||||
if (parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) {
|
|
||||||
m_Inventory.clear();
|
|
||||||
m_Inventory.insert({11909, 0}); //Top hat w frog
|
|
||||||
m_Inventory.insert({7785, 0}); //Flash bulb
|
|
||||||
m_Inventory.insert({12764, 0}); //Big fountain soda
|
|
||||||
m_Inventory.insert({12241, 0}); //Hot cocoa (from fb)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VendorComponent::~VendorComponent() = default;
|
VendorComponent::~VendorComponent() = default;
|
||||||
|
|
||||||
void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||||
outBitStream->Write1();
|
// Only serialize this entity on construction.
|
||||||
outBitStream->Write1(); // this bit is REQUIRED for vendor + mission multiinteract
|
// [bool] hasVendorInfo
|
||||||
outBitStream->Write(HasCraftingStation());
|
// [bool] hasStandardItems (always true?)
|
||||||
|
// [bool] hasMulticostItems (only true for umami with their cooking for now.)
|
||||||
|
if (!bIsInitialUpdate) return;
|
||||||
|
outBitStream->Write1();
|
||||||
|
outBitStream->Write1();
|
||||||
|
outBitStream->Write(HasCraftingStation());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VendorComponent::OnUse(Entity* originator) {
|
void VendorComponent::OnUse(Entity* originator) {
|
||||||
GameMessages::SendVendorOpenWindow(m_Parent, originator->GetSystemAddress());
|
GameMessages::SendVendorOpenWindow(m_Parent, originator->GetSystemAddress());
|
||||||
GameMessages::SendVendorStatusUpdate(m_Parent, originator->GetSystemAddress());
|
GameMessages::SendVendorStatusUpdate(m_Parent, originator->GetSystemAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
float VendorComponent::GetBuyScalar() const {
|
float VendorComponent::GetBuyScalar() const {
|
||||||
return m_BuyScalar;
|
return m_BuyScalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
float VendorComponent::GetSellScalar() const {
|
float VendorComponent::GetSellScalar() const {
|
||||||
return m_SellScalar;
|
return m_SellScalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VendorComponent::SetBuyScalar(float value) {
|
void VendorComponent::SetBuyScalar(float value) {
|
||||||
m_BuyScalar = value;
|
m_BuyScalar = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VendorComponent::SetSellScalar(float value) {
|
void VendorComponent::SetSellScalar(float value) {
|
||||||
m_SellScalar = value;
|
m_SellScalar = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<LOT, int>& VendorComponent::GetInventory() {
|
std::map<LOT, int>& VendorComponent::GetInventory() {
|
||||||
return m_Inventory;
|
return m_Inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VendorComponent::HasCraftingStation() {
|
bool VendorComponent::HasCraftingStation() {
|
||||||
// As far as we know, only Umami has a crafting station
|
// As far as we know, only Umami has a crafting station
|
||||||
return m_Parent->GetLOT() == 13800;
|
return m_Parent->GetLOT() == 13800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VendorComponent::RefreshInventory(bool isCreation) {
|
||||||
|
//Custom code for Max vanity NPC
|
||||||
|
if (m_Parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) {
|
||||||
|
if (!isCreation) return;
|
||||||
|
m_Inventory.insert({11909, 0}); //Top hat w frog
|
||||||
|
m_Inventory.insert({7785, 0}); //Flash bulb
|
||||||
|
m_Inventory.insert({12764, 0}); //Big fountain soda
|
||||||
|
m_Inventory.insert({12241, 0}); //Hot cocoa (from fb)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_Inventory.clear();
|
||||||
|
auto* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
|
||||||
|
std::vector<CDLootMatrix> lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == m_LootMatrixID); });
|
||||||
|
|
||||||
|
if (lootMatrices.empty()) return;
|
||||||
|
// Done with lootMatrix table
|
||||||
|
|
||||||
|
auto* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
|
||||||
|
|
||||||
|
for (const auto& lootMatrix : lootMatrices) {
|
||||||
|
int lootTableID = lootMatrix.LootTableIndex;
|
||||||
|
std::vector<CDLootTable> vendorItems = lootTableTable->Query([=](CDLootTable entry) { return (entry.LootTableIndex == lootTableID); });
|
||||||
|
if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) {
|
||||||
|
for (CDLootTable item : vendorItems) {
|
||||||
|
m_Inventory.insert({item.itemid, item.sortPriority});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto randomCount = GeneralUtils::GenerateRandomNumber<int32_t>(lootMatrix.minToDrop, lootMatrix.maxToDrop);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < randomCount; i++) {
|
||||||
|
if (vendorItems.empty()) break;
|
||||||
|
|
||||||
|
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
||||||
|
|
||||||
|
const auto& randomItem = vendorItems[randomItemIndex];
|
||||||
|
|
||||||
|
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
||||||
|
|
||||||
|
m_Inventory.insert({randomItem.itemid, randomItem.sortPriority});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Because I want a vendor to sell these cameras
|
||||||
|
if (m_Parent->GetLOT() == 13569) {
|
||||||
|
auto randomCamera = GeneralUtils::GenerateRandomNumber<int32_t>(0, 2);
|
||||||
|
|
||||||
|
switch (randomCamera) {
|
||||||
|
case 0:
|
||||||
|
m_Inventory.insert({16253, 0}); //Grungagroid
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
m_Inventory.insert({16254, 0}); //Hipstabrick
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_Inventory.insert({16204, 0}); //Megabrixel snapshot
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback timer to refresh this inventory.
|
||||||
|
m_Parent->AddCallbackTimer(m_RefreshTimeSeconds, [this]() {
|
||||||
|
RefreshInventory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void VendorComponent::SetupConstants() {
|
||||||
|
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
||||||
|
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR);
|
||||||
|
|
||||||
|
auto* vendorComponentTable = CDClientManager::Instance()->GetTable<CDVendorComponentTable>("VendorComponent");
|
||||||
|
std::vector<CDVendorComponent> vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); });
|
||||||
|
if (vendorComps.empty()) return;
|
||||||
|
m_BuyScalar = vendorComps[0].buyScalar;
|
||||||
|
m_SellScalar = vendorComps[0].sellScalar;
|
||||||
|
m_RefreshTimeSeconds = vendorComps[0].refreshTimeSeconds;
|
||||||
|
m_LootMatrixID = vendorComps[0].LootMatrixIndex;
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
#ifndef VENDORCOMPONENT_H
|
#ifndef VENDORCOMPONENT_H
|
||||||
#define VENDORCOMPONENT_H
|
#define VENDORCOMPONENT_H
|
||||||
|
|
||||||
#include "RakNetTypes.h"
|
|
||||||
#include "Entity.h"
|
|
||||||
#include "GameMessages.h"
|
|
||||||
#include "CDClientManager.h"
|
#include "CDClientManager.h"
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "GameMessages.h"
|
||||||
|
#include "RakNetTypes.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component for vendor NPCs. A vendor sells items to the player.
|
* A component for vendor NPCs. A vendor sells items to the player.
|
||||||
@ -56,17 +57,36 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::map<LOT, int>& GetInventory();
|
std::map<LOT, int>& GetInventory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the inventory of this vendor.
|
||||||
|
*/
|
||||||
|
void RefreshInventory(bool isCreation = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on startup of vendor to setup the variables for the component.
|
||||||
|
*/
|
||||||
|
void SetupConstants();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The buy scaler.
|
* The buy scalar.
|
||||||
*/
|
*/
|
||||||
float m_BuyScalar;
|
float m_BuyScalar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sell scaler.
|
* The sell scalar.
|
||||||
*/
|
*/
|
||||||
float m_SellScalar;
|
float m_SellScalar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The refresh time of this vendors' inventory.
|
||||||
|
*/
|
||||||
|
float m_RefreshTimeSeconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loot matrix id of this vendor.
|
||||||
|
*/
|
||||||
|
uint32_t m_LootMatrixID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of items the vendor sells.
|
* The list of items the vendor sells.
|
||||||
*/
|
*/
|
||||||
|
@ -1252,8 +1252,7 @@ void GameMessages::SendVendorOpenWindow(Entity* entity, const SystemAddress& sys
|
|||||||
SEND_PACKET
|
SEND_PACKET
|
||||||
}
|
}
|
||||||
|
|
||||||
// ah yes, impl code in a send function, beautiful!
|
void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly) {
|
||||||
void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr) {
|
|
||||||
CBITSTREAM
|
CBITSTREAM
|
||||||
CMSGHEADER
|
CMSGHEADER
|
||||||
|
|
||||||
@ -1265,7 +1264,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s
|
|||||||
bitStream.Write(entity->GetObjectID());
|
bitStream.Write(entity->GetObjectID());
|
||||||
bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE);
|
bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE);
|
||||||
|
|
||||||
bitStream.Write(false);
|
bitStream.Write(bUpdateOnly);
|
||||||
bitStream.Write(static_cast<uint32_t>(vendorItems.size()));
|
bitStream.Write(static_cast<uint32_t>(vendorItems.size()));
|
||||||
|
|
||||||
for (std::pair<LOT, int> item : vendorItems) {
|
for (std::pair<LOT, int> item : vendorItems) {
|
||||||
@ -1273,6 +1272,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s
|
|||||||
bitStream.Write(static_cast<int>(item.second));
|
bitStream.Write(static_cast<int>(item.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST
|
||||||
SEND_PACKET
|
SEND_PACKET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace GameMessages {
|
|||||||
void SendModularBuildEnd(Entity* entity);
|
void SendModularBuildEnd(Entity* entity);
|
||||||
|
|
||||||
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
||||||
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly = false);
|
||||||
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
||||||
|
@ -324,6 +324,7 @@ enum GAME_MSG : unsigned short {
|
|||||||
GAME_MSG_ACTIVITY_STOP = 408,
|
GAME_MSG_ACTIVITY_STOP = 408,
|
||||||
GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409,
|
GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409,
|
||||||
GAME_MSG_SHOOTING_GALLERY_FIRE = 411,
|
GAME_MSG_SHOOTING_GALLERY_FIRE = 411,
|
||||||
|
GAME_MSG_REQUEST_VENDOR_STATUS_UPDATE = 416,
|
||||||
GAME_MSG_VENDOR_STATUS_UPDATE = 417,
|
GAME_MSG_VENDOR_STATUS_UPDATE = 417,
|
||||||
GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425,
|
GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425,
|
||||||
GAME_MSG_CONSUME_CLIENT_ITEM = 427,
|
GAME_MSG_CONSUME_CLIENT_ITEM = 427,
|
||||||
|
Loading…
Reference in New Issue
Block a user