mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-31 04:32:06 +00:00 
			
		
		
		
	feat: achievement vendor and vendor feedback (#1461)
* Groundwork * movie buying logic out of gm handler make transaction result more useful * Full implementation Cleanup and fix some calls in gamemessages * Load the component in the entity Patch Auth * new line at eof * cache lookups * remove sort * fix includes
This commit is contained in:
		| @@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t { | ||||
| 	INTERACTION_MANAGER, | ||||
| 	DONATION_VENDOR, | ||||
| 	COMBAT_MEDIATOR, | ||||
| 	COMMENDATION_VENDOR, | ||||
| 	ACHIEVEMENT_VENDOR, | ||||
| 	GATE_RUSH_CONTROL, | ||||
| 	RAIL_ACTIVATOR, | ||||
| 	ROLLER, | ||||
|   | ||||
							
								
								
									
										15
									
								
								dCommon/dEnums/eVendorTransactionResult.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								dCommon/dEnums/eVendorTransactionResult.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #ifndef __EVENDORTRANSACTIONRESULT__ | ||||
| #define __EVENDORTRANSACTIONRESULT__ | ||||
|  | ||||
| #include <cstdint> | ||||
|  | ||||
| enum class eVendorTransactionResult : uint32_t { | ||||
| 	SELL_SUCCESS = 0, | ||||
| 	SELL_FAIL, | ||||
| 	PURCHASE_SUCCESS, | ||||
| 	PURCHASE_FAIL, | ||||
| 	DONATION_FAIL, | ||||
| 	DONATION_FULL | ||||
| }; | ||||
|  | ||||
| #endif // !__EVENDORTRANSACTIONRESULT__ | ||||
| @@ -79,7 +79,6 @@ void CDMissionsTable::LoadValuesFromDatabase() { | ||||
| 		entries.push_back(entry); | ||||
| 		tableData.nextRow(); | ||||
| 	} | ||||
|  | ||||
| 	tableData.finalize(); | ||||
|  | ||||
| 	Default.id = -1; | ||||
| @@ -118,3 +117,12 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun | ||||
| 	return Default; | ||||
| } | ||||
|  | ||||
| const std::set<int32_t> CDMissionsTable::GetMissionsForReward(LOT lot) { | ||||
| 	std::set<int32_t> toReturn {}; | ||||
| 	for (const auto& entry : GetEntries()) { | ||||
| 		if (lot == entry.reward_item1 || lot == entry.reward_item2 || lot == entry.reward_item3 || lot == entry.reward_item4) { | ||||
| 			toReturn.insert(entry.id); | ||||
| 		} | ||||
| 	} | ||||
| 	return toReturn; | ||||
| } | ||||
|   | ||||
| @@ -70,6 +70,9 @@ public: | ||||
|  | ||||
| 	const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const; | ||||
|  | ||||
| 	const std::set<int32_t> GetMissionsForReward(LOT lot); | ||||
|  | ||||
|  | ||||
| 	static CDMissions Default; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -82,6 +82,7 @@ | ||||
| #include "CollectibleComponent.h" | ||||
| #include "ItemComponent.h" | ||||
| #include "GhostComponent.h" | ||||
| #include "AchievementVendorComponent.h" | ||||
|  | ||||
| // Table includes | ||||
| #include "CDComponentsRegistryTable.h" | ||||
| @@ -615,6 +616,8 @@ void Entity::Initialize() { | ||||
| 		AddComponent<VendorComponent>(); | ||||
| 	} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) { | ||||
| 		AddComponent<DonationVendorComponent>(); | ||||
| 	} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ACHIEVEMENT_VENDOR, -1) != -1)) { | ||||
| 		AddComponent<AchievementVendorComponent>(); | ||||
| 	} | ||||
|  | ||||
| 	if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) { | ||||
| @@ -1191,6 +1194,11 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType | ||||
| 		donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate); | ||||
| 	} | ||||
|  | ||||
| 	AchievementVendorComponent* achievementVendorComponent; | ||||
| 	if (TryGetComponent(eReplicaComponentType::ACHIEVEMENT_VENDOR, achievementVendorComponent)) { | ||||
| 		achievementVendorComponent->Serialize(outBitStream, bIsInitialUpdate); | ||||
| 	} | ||||
|  | ||||
| 	BouncerComponent* bouncerComponent; | ||||
| 	if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) { | ||||
| 		bouncerComponent->Serialize(outBitStream, bIsInitialUpdate); | ||||
|   | ||||
							
								
								
									
										72
									
								
								dGame/dComponents/AchievementVendorComponent.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								dGame/dComponents/AchievementVendorComponent.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #include "AchievementVendorComponent.h" | ||||
| #include "MissionComponent.h" | ||||
| #include "InventoryComponent.h" | ||||
| #include "eMissionState.h" | ||||
| #include "CDComponentsRegistryTable.h" | ||||
| #include "CDItemComponentTable.h" | ||||
| #include "eVendorTransactionResult.h" | ||||
| #include "CheatDetection.h" | ||||
| #include "UserManager.h" | ||||
| #include "CDMissionsTable.h" | ||||
|  | ||||
| bool AchievementVendorComponent::SellsItem(Entity* buyer, const LOT lot) { | ||||
| 	auto* missionComponent = buyer->GetComponent<MissionComponent>(); | ||||
| 	if (!missionComponent) return false; | ||||
|  | ||||
| 	if (m_PlayerPurchasableItems[buyer->GetObjectID()].contains(lot)){ | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	CDMissionsTable* missionsTable = CDClientManager::GetTable<CDMissionsTable>(); | ||||
| 	const auto missions = missionsTable->GetMissionsForReward(lot); | ||||
| 	for (const auto mission : missions) { | ||||
| 		if (missionComponent->GetMissionState(mission) == eMissionState::COMPLETE) { | ||||
| 			m_PlayerPurchasableItems[buyer->GetObjectID()].insert(lot); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { | ||||
| 	// get the item Comp from the item LOT | ||||
| 	CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>(); | ||||
| 	CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>(); | ||||
| 	int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM); | ||||
| 	CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); | ||||
| 	uint32_t costLOT = itemComp.commendationLOT; | ||||
| 	 | ||||
| 	if (costLOT == -1 || !SellsItem(buyer, lot)) { | ||||
| 		auto* user = UserManager::Instance()->GetUser(buyer->GetSystemAddress()); | ||||
| 		CheatDetection::ReportCheat(user, buyer->GetSystemAddress(), "Attempted to buy item %i from achievement vendor %i that is not purchasable", lot, m_Parent->GetLOT()); | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto* inventoryComponent = buyer->GetComponent<InventoryComponent>(); | ||||
| 	if (!inventoryComponent)  { | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (costLOT == 13763) { // Faction Token Proxy | ||||
| 		auto* missionComponent = buyer->GetComponent<MissionComponent>(); | ||||
| 		if (!missionComponent) return; | ||||
|  | ||||
| 		if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) costLOT = 8318; // "Assembly Token" | ||||
| 		if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) costLOT = 8321; // "Venture League Token" | ||||
| 		if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) costLOT = 8319; // "Sentinels Token" | ||||
| 		if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) costLOT = 8320; // "Paradox Token" | ||||
| 	} | ||||
|  | ||||
| 	const uint32_t altCurrencyCost = itemComp.commendationCost * count; | ||||
| 	if (inventoryComponent->GetLotCount(costLOT) < altCurrencyCost) { | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	inventoryComponent->RemoveItem(costLOT, altCurrencyCost); | ||||
| 	inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR); | ||||
| 	GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS); | ||||
|  | ||||
| } | ||||
							
								
								
									
										23
									
								
								dGame/dComponents/AchievementVendorComponent.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								dGame/dComponents/AchievementVendorComponent.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #ifndef __ACHIEVEMENTVENDORCOMPONENT__H__ | ||||
| #define __ACHIEVEMENTVENDORCOMPONENT__H__ | ||||
|  | ||||
| #include "VendorComponent.h" | ||||
| #include "eReplicaComponentType.h" | ||||
| #include <set> | ||||
| #include <map> | ||||
|  | ||||
| class Entity; | ||||
|  | ||||
| class AchievementVendorComponent final : public VendorComponent { | ||||
| public: | ||||
| 	static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::ACHIEVEMENT_VENDOR; | ||||
| 	AchievementVendorComponent(Entity* parent) : VendorComponent(parent) {}; | ||||
| 	bool SellsItem(Entity* buyer, const LOT lot); | ||||
| 	void Buy(Entity* buyer, LOT lot, uint32_t count); | ||||
|  | ||||
| private: | ||||
| 	std::map<LWOOBJID,std::set<LOT>> m_PlayerPurchasableItems; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif  //!__ACHIEVEMENTVENDORCOMPONENT__H__ | ||||
| @@ -1,4 +1,5 @@ | ||||
| set(DGAME_DCOMPONENTS_SOURCES | ||||
| 	"AchievementVendorComponent.cpp" | ||||
| 	"ActivityComponent.cpp" | ||||
| 	"BaseCombatAIComponent.cpp" | ||||
| 	"BouncerComponent.cpp" | ||||
|   | ||||
| @@ -8,6 +8,11 @@ | ||||
| #include "CDLootMatrixTable.h" | ||||
| #include "CDLootTableTable.h" | ||||
| #include "CDItemComponentTable.h" | ||||
| #include "InventoryComponent.h" | ||||
| #include "Character.h" | ||||
| #include "eVendorTransactionResult.h" | ||||
| #include "UserManager.h" | ||||
| #include "CheatDetection.h" | ||||
|  | ||||
| VendorComponent::VendorComponent(Entity* parent) : Component(parent) { | ||||
| 	m_HasStandardCostItems = false; | ||||
| @@ -151,3 +156,60 @@ void VendorComponent::HandleMrReeCameras(){ | ||||
| 		m_Inventory.push_back(SoldItem(camera, 0)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void VendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { | ||||
|  | ||||
| 	if (!SellsItem(lot)) { | ||||
| 		auto* user = UserManager::Instance()->GetUser(buyer->GetSystemAddress()); | ||||
| 		CheatDetection::ReportCheat(user, buyer->GetSystemAddress(), "Attempted to buy item %i from achievement vendor %i that is not purchasable", lot, m_Parent->GetLOT()); | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto* inventoryComponent = buyer->GetComponent<InventoryComponent>(); | ||||
| 	if (!inventoryComponent) { | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
| 	CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>(); | ||||
| 	CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>(); | ||||
| 	int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM); | ||||
| 	CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); | ||||
|  | ||||
| 	// Extra currency that needs to be deducted in case of crafting | ||||
| 	auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); | ||||
| 	for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) { | ||||
| 		if (inventoryComponent->GetLotCount(crafintCurrencyLOT) < (crafintCurrencyCount * count)) { | ||||
| 			GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) { | ||||
| 		inventoryComponent->RemoveItem(crafintCurrencyLOT, crafintCurrencyCount * count); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	float buyScalar = GetBuyScalar(); | ||||
| 	const auto coinCost = static_cast<uint32_t>(std::floor((itemComp.baseValue * buyScalar) * count)); | ||||
|  | ||||
| 	Character* character = buyer->GetCharacter(); | ||||
| 	if (!character || character->GetCoins() < coinCost) { | ||||
| 		GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (Inventory::IsValidItem(itemComp.currencyLOT)) { | ||||
| 		const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count; | ||||
| 		if (inventoryComponent->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { | ||||
| 			GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 			return; | ||||
| 		} | ||||
| 		inventoryComponent->RemoveItem(itemComp.currencyLOT, altCurrencyCost); | ||||
| 	} | ||||
|  | ||||
| 	character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR); | ||||
| 	inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR); | ||||
| 	GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS); | ||||
|  | ||||
| } | ||||
| @@ -47,6 +47,7 @@ public: | ||||
| 		m_DirtyVendor = true; | ||||
| 	} | ||||
|  | ||||
| 	void Buy(Entity* buyer, LOT lot, uint32_t count); | ||||
|  | ||||
| private: | ||||
| 	void SetupMaxCustomVendor(); | ||||
|   | ||||
| @@ -78,6 +78,7 @@ | ||||
| #include "LevelProgressionComponent.h" | ||||
| #include "DonationVendorComponent.h" | ||||
| #include "GhostComponent.h" | ||||
| #include "AchievementVendorComponent.h" | ||||
|  | ||||
| // Message includes: | ||||
| #include "dZoneManager.h" | ||||
| @@ -97,6 +98,7 @@ | ||||
| #include "ePetAbilityType.h" | ||||
| #include "ActivityManager.h" | ||||
| #include "PlayerManager.h" | ||||
| #include "eVendorTransactionResult.h" | ||||
|  | ||||
| #include "CDComponentsRegistryTable.h" | ||||
| #include "CDObjectsTable.h" | ||||
| @@ -1323,15 +1325,14 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s | ||||
| 	SEND_PACKET; | ||||
| } | ||||
|  | ||||
| void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr) { | ||||
| void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result) { | ||||
| 	CBITSTREAM; | ||||
| 	CMSGHEADER; | ||||
|  | ||||
| 	int iResult = 0x02; // success, seems to be the only relevant one | ||||
|  | ||||
| 	bitStream.Write(entity->GetObjectID()); | ||||
| 	bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT); | ||||
| 	bitStream.Write(iResult); | ||||
| 	bitStream.Write(result); | ||||
|  | ||||
| 	SEND_PACKET; | ||||
| } | ||||
| @@ -4664,94 +4665,27 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti | ||||
| 	if (!user) return; | ||||
| 	Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar()); | ||||
| 	if (!player) return; | ||||
| 	 | ||||
| 	// handle buying normal items | ||||
| 	auto* vendorComponent = entity->GetComponent<VendorComponent>(); | ||||
| 	if (vendorComponent) { | ||||
| 		vendorComponent->Buy(player, item, count); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto* propertyVendorComponent = static_cast<PropertyVendorComponent*>(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); | ||||
| 	// handle buying achievement items | ||||
| 	auto* achievementVendorComponent = entity->GetComponent<AchievementVendorComponent>(); | ||||
| 	if (achievementVendorComponent) { | ||||
| 		achievementVendorComponent->Buy(player, item, count); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (propertyVendorComponent != nullptr) { | ||||
| 	// Handle buying properties | ||||
| 	auto* propertyVendorComponent = entity->GetComponent<PropertyVendorComponent>(); | ||||
| 	if (propertyVendorComponent) { | ||||
| 		propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count); | ||||
|  | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	const auto isCommendationVendor = entity->GetLOT() == 13806; | ||||
|  | ||||
| 	auto* vend = entity->GetComponent<VendorComponent>(); | ||||
| 	if (!vend && !isCommendationVendor) return; | ||||
|  | ||||
| 	auto* inv = player->GetComponent<InventoryComponent>(); | ||||
| 	if (!inv) return; | ||||
|  | ||||
| 	if (!isCommendationVendor && !vend->SellsItem(item)) { | ||||
| 		LOG("User %llu %s tried to buy an item %i from a vendor when they do not sell said item", player->GetObjectID(), user->GetUsername().c_str(), item); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>(); | ||||
| 	CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>(); | ||||
|  | ||||
| 	int itemCompID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM); | ||||
| 	CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); | ||||
|  | ||||
| 	Character* character = player->GetCharacter(); | ||||
| 	if (!character) return; | ||||
|  | ||||
| 	// Extra currency that needs to be deducted in case of crafting | ||||
| 	auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); | ||||
| 	for (const auto& craftingCurrency : craftingCurrencies) { | ||||
| 		inv->RemoveItem(craftingCurrency.first, craftingCurrency.second * count); | ||||
| 	} | ||||
|  | ||||
| 	if (isCommendationVendor) { | ||||
| 		if (itemComp.commendationLOT != 13763) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		auto* missionComponent = player->GetComponent<MissionComponent>(); | ||||
|  | ||||
| 		if (missionComponent == nullptr) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		LOT tokenId = -1; | ||||
|  | ||||
| 		if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) tokenId = 8318; // "Assembly Token" | ||||
| 		if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) tokenId = 8321; // "Venture League Token" | ||||
| 		if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) tokenId = 8319; // "Sentinels Token" | ||||
| 		if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) tokenId = 8320; // "Paradox Token" | ||||
|  | ||||
| 		const uint32_t altCurrencyCost = itemComp.commendationCost * count; | ||||
|  | ||||
| 		if (inv->GetLotCount(tokenId) < altCurrencyCost) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		inv->RemoveItem(tokenId, altCurrencyCost); | ||||
|  | ||||
| 		inv->AddItem(item, count, eLootSourceType::VENDOR); | ||||
| 	} else { | ||||
| 		float buyScalar = vend->GetBuyScalar(); | ||||
|  | ||||
| 		const auto coinCost = static_cast<uint32_t>(std::floor((itemComp.baseValue * buyScalar) * count)); | ||||
|  | ||||
| 		if (character->GetCoins() < coinCost) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (Inventory::IsValidItem(itemComp.currencyLOT)) { | ||||
| 			const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count; | ||||
|  | ||||
| 			if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost); | ||||
| 		} | ||||
|  | ||||
| 		character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR); | ||||
| 		inv->AddItem(item, count, eLootSourceType::VENDOR); | ||||
| 	} | ||||
|  | ||||
| 	GameMessages::SendVendorTransactionResult(entity, sysAddr); | ||||
| } | ||||
|  | ||||
| void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { | ||||
| @@ -4785,7 +4719,10 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit | ||||
| 	CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); | ||||
|  | ||||
| 	// Items with a base value of 0 or max int are special items that should not be sold if they're not sub items | ||||
| 	if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) return; | ||||
| 	if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) { | ||||
| 		GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	float sellScalar = vend->GetSellScalar(); | ||||
| 	if (Inventory::IsValidItem(itemComp.currencyLOT)) { | ||||
| @@ -4793,11 +4730,9 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit | ||||
| 		inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens. | ||||
| 	} | ||||
|  | ||||
| 	//inv->RemoveItem(count, -1, iObjID); | ||||
| 	inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true); | ||||
| 	character->SetCoins(std::floor(character->GetCoins() + (static_cast<uint32_t>(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR); | ||||
| 	//Game::entityManager->SerializeEntity(player); // so inventory updates | ||||
| 	GameMessages::SendVendorTransactionResult(entity, sysAddr); | ||||
| 	GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_SUCCESS); | ||||
| } | ||||
|  | ||||
| void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { | ||||
| @@ -4839,16 +4774,16 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* | ||||
| 	const auto cost = static_cast<uint32_t>(std::floor(((itemComp.baseValue * sellScalar) * count))); | ||||
|  | ||||
| 	if (character->GetCoins() < cost) { | ||||
| 		GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (Inventory::IsValidItem(itemComp.currencyLOT)) { | ||||
| 		const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count; | ||||
|  | ||||
| 		if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { | ||||
| 			GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost); | ||||
| 	} | ||||
|  | ||||
| @@ -4856,7 +4791,7 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* | ||||
| 	inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false); | ||||
| 	character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR); | ||||
| 	//Game::entityManager->SerializeEntity(player); // so inventory updates | ||||
| 	GameMessages::SendVendorTransactionResult(entity, sysAddr); | ||||
| 	GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_SUCCESS); | ||||
| } | ||||
|  | ||||
| void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { | ||||
|   | ||||
| @@ -38,6 +38,7 @@ enum class eUseItemResponse : uint32_t; | ||||
| enum class eQuickBuildFailReason : uint32_t; | ||||
| enum class eQuickBuildState : uint32_t; | ||||
| enum class BehaviorSlot : int32_t; | ||||
| enum class eVendorTransactionResult : uint32_t; | ||||
|  | ||||
| namespace GameMessages { | ||||
| 	class PropertyDataMessage; | ||||
| @@ -135,7 +136,7 @@ namespace GameMessages { | ||||
|  | ||||
| 	void SendVendorOpenWindow(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, eVendorTransactionResult result); | ||||
|  | ||||
| 	void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining); | ||||
| 	void SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID item); | ||||
|   | ||||
| @@ -82,7 +82,7 @@ void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, c | ||||
| 	if (serverType == ServerType::Auth) bitStream.Write(ServiceId::Auth); | ||||
| 	else if (serverType == ServerType::World) bitStream.Write(ServiceId::World); | ||||
| 	else bitStream.Write(ServiceId::General); | ||||
| 	bitStream.Write<uint32_t>(774909490); | ||||
| 	bitStream.Write<uint64_t>(215523405360); | ||||
|  | ||||
| 	server->Send(&bitStream, sysAddr, false); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Aaron Kimbrell
					Aaron Kimbrell