mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
fix: a trade offer takes no undeletable item and no unapproved model
The client's trade window also refuses an item that can not be deleted and a brick built model whose moderation status is not approved. An offer with such an item is now refused like the other offers the window can not make. Whether an item can be deleted is what the inventory already works out for a delete: not the item of the mount the player rides, and not an item its row of the DeletionRestrictions table restricts. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -43,7 +43,7 @@ std::optional<std::vector<TradeItem>> Trade::ResolveOffer(
|
||||
if (tradeItem.itemCount == 0 || !seen.insert(tradeItem.itemId).second) return std::nullopt;
|
||||
|
||||
const auto held = findHeld(tradeItem.itemId);
|
||||
if (!held || held->count == 0 || held->bound || held->equipped) return std::nullopt;
|
||||
if (!held || held->count == 0 || held->bound || held->equipped || !held->deletable || !held->approved) return std::nullopt;
|
||||
|
||||
resolved.push_back({ tradeItem.itemId, held->lot, std::min(tradeItem.itemCount, held->count) });
|
||||
}
|
||||
@@ -55,10 +55,22 @@ std::function<std::optional<HeldTradeItem>(LWOOBJID)> Trade::HeldIn(const Invent
|
||||
return [&inventory](const LWOOBJID itemId) -> std::optional<HeldTradeItem> {
|
||||
const auto* const item = inventory.FindItemById(itemId);
|
||||
if (!item) return std::nullopt;
|
||||
return HeldTradeItem{ item->GetLot(), item->GetCount(), item->GetBound(), item->IsEquipped() };
|
||||
return HeldTradeItem{
|
||||
item->GetLot(), item->GetCount(), item->GetBound(), item->IsEquipped(),
|
||||
inventory.CanDelete(*item), IsApproved(item->GetLot(), item->GetConfig())
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
bool Trade::IsApproved(const LOT lot, const LwoNameValue& config) {
|
||||
if (lot != BrickBuiltModelLot) return true;
|
||||
|
||||
const auto status = config.find(u"userModelMod");
|
||||
if (status == config.end() || status->second->GetValueType() != eLDFType::LDF_TYPE_S32) return false;
|
||||
|
||||
return static_cast<const LDFData<int32_t>*>(status->second.get())->GetValue() == ApprovedModerationStatus;
|
||||
}
|
||||
|
||||
Trade::~Trade() {
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,13 @@ struct HeldTradeItem {
|
||||
// The trade window takes neither a bound item nor an equipped one
|
||||
bool bound = false;
|
||||
bool equipped = false;
|
||||
// Nor an item the player may not delete, nor a brick built model that is not approved
|
||||
bool deletable = true;
|
||||
bool approved = true;
|
||||
};
|
||||
|
||||
struct LwoNameValue;
|
||||
|
||||
class InventoryComponent;
|
||||
|
||||
class Trade {
|
||||
@@ -35,7 +40,8 @@ public:
|
||||
* @param findHeld gives the held item with an ID, or nothing if the player has no such item
|
||||
* @return the offer with every LOT taken from the held item and every count limited to the held count,
|
||||
* or nothing if the offer names an item the player does not hold, the same item twice, a count of 0,
|
||||
* a bound or equipped item, or more items than the trade window has slots
|
||||
* a bound or equipped item, an item the player may not delete, a brick built model that is not approved,
|
||||
* or more items than the trade window has slots
|
||||
*/
|
||||
static std::optional<std::vector<TradeItem>> ResolveOffer(
|
||||
const std::vector<TradeItem>& offered,
|
||||
@@ -46,6 +52,18 @@ public:
|
||||
*/
|
||||
static std::function<std::optional<HeldTradeItem>(LWOOBJID)> HeldIn(const InventoryComponent& inventory);
|
||||
|
||||
/**
|
||||
* Whether the trade window takes an item for its moderation status. Only a brick built model has one,
|
||||
* the userModelMod of its config, and only an approved one is taken.
|
||||
*/
|
||||
static bool IsApproved(LOT lot, const LwoNameValue& config);
|
||||
|
||||
// The item a brick built model is
|
||||
static constexpr LOT BrickBuiltModelLot = 6662;
|
||||
|
||||
// The userModelMod of an approved model
|
||||
static constexpr int32_t ApprovedModerationStatus = 1;
|
||||
|
||||
// The slots one side of the trade window has
|
||||
static constexpr uint32_t MaxOfferedItems = 8;
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace {
|
||||
{ 200, { 3040, 1 } },
|
||||
{ 300, { 1727, 2, true, false } },
|
||||
{ 400, { 1727, 2, false, true } },
|
||||
{ 500, { 1727, 2, false, false, false, true } },
|
||||
{ 600, { 6662, 1, false, false, true, false } },
|
||||
};
|
||||
|
||||
class TradeAcceptTest : public GameDependenciesTest {
|
||||
@@ -80,6 +82,43 @@ TEST(TradeOfferTest, AnEquippedItemIsRefused) {
|
||||
EXPECT_FALSE(Trade::ResolveOffer({ { 400, 1727, 1 } }, FindHeld).has_value());
|
||||
}
|
||||
|
||||
TEST(TradeOfferTest, AnItemThatMayNotBeDeletedIsRefused) {
|
||||
EXPECT_FALSE(Trade::ResolveOffer({ { 500, 1727, 1 } }, FindHeld).has_value());
|
||||
EXPECT_FALSE(Trade::ResolveOffer({ { 100, 1727, 1 }, { 500, 1727, 1 } }, FindHeld).has_value());
|
||||
}
|
||||
|
||||
TEST(TradeOfferTest, AModelThatIsNotApprovedIsRefused) {
|
||||
EXPECT_FALSE(Trade::ResolveOffer({ { 600, 6662, 1 } }, FindHeld).has_value());
|
||||
EXPECT_FALSE(Trade::ResolveOffer({ { 100, 1727, 1 }, { 600, 6662, 1 } }, FindHeld).has_value());
|
||||
}
|
||||
|
||||
TEST(TradeOfferTest, OnlyAnApprovedBrickBuiltModelIsApproved) {
|
||||
LwoNameValue config;
|
||||
// No moderation status
|
||||
EXPECT_FALSE(Trade::IsApproved(Trade::BrickBuiltModelLot, config));
|
||||
|
||||
config.Insert<int32_t>(u"userModelMod", 0);
|
||||
EXPECT_FALSE(Trade::IsApproved(Trade::BrickBuiltModelLot, config));
|
||||
|
||||
config.Insert<int32_t>(u"userModelMod", 2);
|
||||
EXPECT_FALSE(Trade::IsApproved(Trade::BrickBuiltModelLot, config));
|
||||
|
||||
// Not a number
|
||||
config.Insert<bool>(u"userModelMod", true);
|
||||
EXPECT_FALSE(Trade::IsApproved(Trade::BrickBuiltModelLot, config));
|
||||
|
||||
config.Insert<int32_t>(u"userModelMod", Trade::ApprovedModerationStatus);
|
||||
EXPECT_TRUE(Trade::IsApproved(Trade::BrickBuiltModelLot, config));
|
||||
}
|
||||
|
||||
TEST(TradeOfferTest, AnItemThatIsNotAModelHasNoModerationStatus) {
|
||||
LwoNameValue config;
|
||||
EXPECT_TRUE(Trade::IsApproved(1727, config));
|
||||
|
||||
config.Insert<int32_t>(u"userModelMod", 0);
|
||||
EXPECT_TRUE(Trade::IsApproved(1727, config));
|
||||
}
|
||||
|
||||
TEST(TradeOfferTest, AnOfferFillsTheSlotsOfTheTradeWindowAtMost) {
|
||||
const auto findAny = [](const LWOOBJID) -> std::optional<HeldTradeItem> {
|
||||
return HeldTradeItem{ 1727, 1 };
|
||||
|
||||
Reference in New Issue
Block a user