Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: achievement vendor and vendor feedback #1461

Merged
merged 8 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dCommon/dEnums/eReplicaComponentType.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions dCommon/dEnums/eVendorTransactionResult.h
Original file line number Diff line number Diff line change
@@ -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__
24 changes: 23 additions & 1 deletion dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void CDMissionsTable::LoadValuesFromDatabase() {
entries.push_back(entry);
tableData.nextRow();
}

std::ranges::sort(entries, [](const CDMissions& lhs, const CDMissions& rhs) { return lhs.id < rhs.id; });
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
tableData.finalize();

Default.id = -1;
Expand Down Expand Up @@ -118,3 +118,25 @@ 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()) {
aronwk-aaron marked this conversation as resolved.
Show resolved Hide resolved
if (lot == entry.reward_item1) {
toReturn.insert(entry.id);
continue;
}
if (lot == entry.reward_item2) {
toReturn.insert(entry.id);
continue;
}
if (lot == entry.reward_item3) {
toReturn.insert(entry.id);
continue;
}
if (lot == entry.reward_item4) {
toReturn.insert(entry.id);
continue;
}
}
return toReturn;
}
3 changes: 3 additions & 0 deletions dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class CDMissionsTable : public CDTable<CDMissionsTable, std::vector<CDMissions>>

const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const;

const std::set<int32_t> GetMissionsForReward(LOT lot);


static CDMissions Default;
};

8 changes: 8 additions & 0 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include "CollectibleComponent.h"
#include "ItemComponent.h"
#include "GhostComponent.h"
#include "AchievementVendorComponent.h"

// Table includes
#include "CDComponentsRegistryTable.h"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
63 changes: 63 additions & 0 deletions dGame/dComponents/AchievementVendorComponent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#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) const {
auto* missionComponent = buyer->GetComponent<MissionComponent>();
CDMissionsTable* missionsTable = CDClientManager::GetTable<CDMissionsTable>();
const auto missions = missionsTable->GetMissionsForReward(lot);
for (const auto mission : missions) {
if (missionComponent->GetMissionState(mission) == eMissionState::COMPLETE) 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);

}
21 changes: 21 additions & 0 deletions dGame/dComponents/AchievementVendorComponent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef __ACHIEVEMENTVENDORCOMPONENT__H__
#define __ACHIEVEMENTVENDORCOMPONENT__H__

#include "VendorComponent.h"
#include "eReplicaComponentType.h"

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) const;
void Buy(Entity* buyer, LOT lot, uint32_t count);

private:

};


#endif //!__ACHIEVEMENTVENDORCOMPONENT__H__
1 change: 1 addition & 0 deletions dGame/dComponents/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(DGAME_DCOMPONENTS_SOURCES
"AchievementVendorComponent.cpp"
"ActivityComponent.cpp"
"BaseCombatAIComponent.cpp"
"BouncerComponent.cpp"
Expand Down
62 changes: 62 additions & 0 deletions dGame/dComponents/VendorComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

}
1 change: 1 addition & 0 deletions dGame/dComponents/VendorComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class VendorComponent : public Component {
m_DirtyVendor = true;
}

void Buy(Entity* buyer, LOT lot, uint32_t count);

private:
void SetupMaxCustomVendor();
Expand Down
Loading
Loading