Skip to content

Commit

Permalink
Complete rework on npcs shop add item functions (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
dudantas committed Feb 25, 2022
1 parent 4c7a35a commit caf0a97
Show file tree
Hide file tree
Showing 19 changed files with 467 additions and 147 deletions.
25 changes: 13 additions & 12 deletions data/items/items.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
<item id="5" name="lemonade" />
<item id="6" name="milk" />
<item id="7" name="manafluid" />
<item id="8" name="lifefluid" />
<item id="9" name="oil" />
<item id="10" name="urine" />
<item id="11" name="coconut milk" />
<item id="12" name="wine" />
<item id="13" name="mud" />
<item id="14" name="fruit juice" />
<item id="15" name="lava" />
<item id="16" name="rum" />
<item id="17" name="swamp" />
<item id="18" name="tea" />
<item id="19" name="mead" />
<item id="10" name="lifefluid" />
<item id="11" name="oil" />
<item id="13" name="urine" />
<item id="14" name="coconut milk" />
<item id="15" name="wine" />
<item id="19" name="mud" />
<item id="21" name="fruit juice" />
<item id="26" name="lava" />
<item id="27" name="rum" />
<item id="28" name="swamp" />
<item id="35" name="tea" />
<item id="43" name="mead" />

<item id="100" name="void"/>
<item id="101" name="earth"/>
Expand Down Expand Up @@ -32171,6 +32171,7 @@
<attribute key="weight" value="6200"/>
</item>
<item id="19250" article="a" name="reward chest">
<attribute key="type" value="rewardchest" />
<attribute key="description" value="This chest contains your rewards earned in battles."/>
<attribute key="moveable" value="0"/>
<attribute key="allowpickUpAble" value="0"/>
Expand Down
53 changes: 51 additions & 2 deletions data/scripts/lib/register_npc_type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,57 @@ end

registerNpcType.shop = function(npcType, mask)
if type(mask.shop) == "table" then
for _, shopItem in pairs(mask.shop) do
npcType:addShopItem(shopItem)
for _, shopItems in pairs(mask.shop) do
local parent = Shop()
if shopItems.itemName or shopItems.itemname then
parent:setNameItem(shopItems.itemName or shopItems.itemname)
end
if shopItems.clientId or shopItems.clientid then
parent:setId(shopItems.clientId or shopItems.clientid)
end
if shopItems.subType or shopItems.subtype or shopItems.count then
parent:setCount(shopItems.subType or shopItems.subtype or shopItems.count)
end
if shopItems.buy then
parent:setBuyPrice(shopItems.buy)
end
if shopItems.sell then
parent:setSellPrice(shopItems.sell)
end
if shopItems.storageKey or shopItems.storagekey then
parent:setStorageKey(shopItems.storageKey or shopItems.storagekey)
end
if shopItems.storageValue or shopItems.storagevalue then
parent:setStorageValue(shopItems.storageValue or shopItems.storagevalue)
end
if shopItems.child then
for _, children in pairs(shopItems.child) do
local child = Shop()
if shopItems.itemName or shopItems.itemname then
child:setNameItem(shopItems.itemName or shopItems.itemname)
end
if shopItems.clientId or shopItems.clientid then
child:setId(shopItems.clientId or shopItems.clientid)
end
if shopItems.subType or shopItems.subtype or shopItems.count then
child:setCount(shopItems.subType or shopItems.subtype or shopItems.count)
end
if shopItems.buy then
child:setBuyPrice(shopItems.buy)
end
if shopItems.sell then
child:setSellPrice(shopItems.sell)
end
if shopItems.storageKey or shopItems.storagekey then
child:setStorageKey(shopItems.storageKey or shopItems.storagekey)
end
if shopItems.storageValue or shopItems.storagevalue then
child:setStorageValue(shopItems.storageValue or shopItems.storagevalue)
end
parent:addChildShop(child)
end
end
npcType:addShopItem(parent)
end
end
end
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ target_sources(${PROJECT_NAME}
lua/functions/creatures/monster/monster_type_functions.cpp
lua/functions/creatures/npc/npc_functions.cpp
lua/functions/creatures/npc/npc_type_functions.cpp
lua/functions/creatures/npc/shop_functions.cpp
lua/functions/creatures/player/group_functions.cpp
lua/functions/creatures/player/guild_functions.cpp
lua/functions/creatures/player/mount_functions.cpp
Expand Down
46 changes: 24 additions & 22 deletions src/creatures/creatures_definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,30 +706,8 @@ struct HistoryMarketOffer {
MarketOfferState_t state;
};

struct ShopInfo {
uint16_t itemClientId;
std::string name;
int32_t subType;
uint32_t buyPrice;
uint32_t sellPrice;
int32_t storageKey, storageValue;

ShopInfo() {
itemClientId = 0;
subType = 1;
buyPrice = 0;
sellPrice = 0;
storageKey = 0;
storageValue = 0;
}

explicit ShopInfo(uint16_t newItemId, int32_t newSubType = 0, uint32_t newBuyPrice = 0, uint32_t newSellPrice = 0, int32_t newStorageKey = 0, int32_t newStorageValue = 0, std::string newName = "")
: itemClientId(newItemId), subType(newSubType), buyPrice(newBuyPrice), sellPrice(newSellPrice), storageKey(newStorageKey), storageValue(newStorageValue), name(std::move(newName)) {}
};

using MarketOfferList = std::list<MarketOffer>;
using HistoryMarketOfferList = std::list<HistoryMarketOffer>;
using ShopInfoMap = std::unordered_map<std::string, ShopInfo>;
using StashItemList = std::map<uint16_t, uint32_t>;

struct Familiar {
Expand Down Expand Up @@ -830,6 +808,30 @@ struct LootBlock {
}
};

struct ShopBlock {
uint16_t itemId;
std::string itemName;
int32_t itemSubType;
uint32_t itemBuyPrice;
uint32_t itemSellPrice;
int32_t itemStorageKey;
int32_t itemStorageValue;

std::vector<ShopBlock> childShop;
ShopBlock() {
itemId = 0;
itemName = "";
itemSubType = 0;
itemBuyPrice = 0;
itemSellPrice = 0;
itemStorageKey = 0;
itemStorageValue = 0;
}

explicit ShopBlock(uint16_t newItemId, int32_t newSubType = 0, uint32_t newBuyPrice = 0, uint32_t newSellPrice = 0, int32_t newStorageKey = 0, int32_t newStorageValue = 0, std::string newName = "")
: itemId(newItemId), itemSubType(newSubType), itemBuyPrice(newBuyPrice), itemSellPrice(newSellPrice), itemStorageKey(newStorageKey), itemStorageValue(newStorageValue), itemName(std::move(newName)) {}
};

struct summonBlock_t {
std::string name;
uint32_t chance;
Expand Down
38 changes: 24 additions & 14 deletions src/creatures/npcs/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,28 +220,34 @@ void Npc::onPlayerBuyItem(Player* player, uint16_t serverId,
return;
}

uint32_t buyPrice = 0;
const ItemType& itemType = Item::items[serverId];

if (getShopItems().find(itemType.name) == getShopItems().end()) {
return;
const std::vector<ShopBlock> &shopVector = getShopItemVector();
for (ShopBlock shopBlock : shopVector)
{
if (itemType.id == shopBlock.itemId && shopBlock.itemBuyPrice != 0)
{
buyPrice = shopBlock.itemBuyPrice;
}
}

ShopInfo shopInfo = getShopItems()[itemType.name];
int64_t totalCost = shopInfo.buyPrice * amount;
int64_t totalCost = buyPrice * amount;
if (getCurrency() == ITEM_GOLD_COIN) {
if (!g_game.removeMoney(player, totalCost, 0, true)) {
SPDLOG_ERROR("[Npc::onPlayerBuyItem (removeMoney)] - Player {} have a problem for buy item {} on shop for npc {}", player->getName(), serverId, getName());
return;
}
} else if(!player->removeItemOfType(getCurrency(), shopInfo.buyPrice, -1, false)) {
} else if(!player->removeItemOfType(getCurrency(), buyPrice, -1, false)) {
SPDLOG_ERROR("[Npc::onPlayerBuyItem (removeItemOfType)] - Player {} have a problem for buy item {} on shop for npc {}", player->getName(), serverId, getName());
return;
}

// onPlayerBuyItem(self, player, itemId, subType, amount, ignore, inBackpacks)
// onPlayerBuyItem(self, player, itemId, subType, amount, ignore inBackpacks)
CreatureCallback callback = CreatureCallback(npcType->info.scriptInterface, this);
if (callback.startScriptInterface(npcType->info.playerBuyEvent)) {
callback.pushSpecificCreature(this);
callback.pushCreature(player);
callback.pushNumber(serverId);
callback.pushNumber(itemType.clientId);
callback.pushNumber(subType);
callback.pushNumber(amount);
callback.pushBoolean(inBackpacks);
Expand All @@ -261,19 +267,23 @@ void Npc::onPlayerSellItem(Player* player, uint16_t serverId,
return;
}

uint32_t sellPrice = 0;
const ItemType& itemType = Item::items[serverId];

if (getShopItems().find(itemType.name) == getShopItems().end()) {
return;
const std::vector<ShopBlock> &shopVector = getShopItemVector();
for (ShopBlock shopBlock : shopVector)
{
if (itemType.id == shopBlock.itemId && shopBlock.itemSellPrice != 0)
{
sellPrice = shopBlock.itemSellPrice;
}
}

ShopInfo shopInfo = getShopItems()[itemType.name];

if(!player->removeItemOfType(serverId, amount, -1, false, false)) {
SPDLOG_ERROR("[Npc::onPlayerSellItem] - Player {} have a problem for sell item {} on shop for npc {}", player->getName(), serverId, getName());
return;
}

int64_t totalCost = shopInfo.sellPrice * amount;
int64_t totalCost = sellPrice * amount;
g_game.addMoney(player, totalCost, 0);

// onPlayerSellItem(self, player, itemId, subType, amount, ignore)
Expand Down
4 changes: 2 additions & 2 deletions src/creatures/npcs/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ class Npc final : public Creature
npcType->info.currencyId = currency;
}

ShopInfoMap getShopItems() {
return npcType->info.shopItems;
std::vector<ShopBlock> getShopItemVector() {
return npcType->info.shopItemVector;
}

bool isPushable() const override {
Expand Down
15 changes: 15 additions & 0 deletions src/creatures/npcs/npcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ bool NpcType::loadCallback(LuaScriptInterface* scriptInterface)
return true;
}

void NpcType::loadShop(NpcType* npcType, ShopBlock shopBlock)
{
if (shopBlock.childShop.empty()) {
bool isContainer = Item::items[shopBlock.itemId].isContainer();
if (isContainer) {
for (ShopBlock child : shopBlock.childShop) {
shopBlock.childShop.push_back(child);
}
}
npcType->info.shopItemVector.push_back(shopBlock);
} else {
npcType->info.shopItemVector.push_back(shopBlock);
}
}

NpcType* Npcs::getNpcType(const std::string& name, bool create /* = false*/)
{
std::string key = asLowerCaseString(name);
Expand Down
17 changes: 13 additions & 4 deletions src/creatures/npcs/npcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@

#include "creatures/creature.h"

class Shop {
public:
Shop() = default;

// non-copyable
Shop(const Shop&) = delete;
Shop& operator=(const Shop&) = delete;

ShopBlock shopBlock;
};

class NpcType
{
struct NpcInfo {
Expand Down Expand Up @@ -63,7 +74,7 @@ class NpcType

std::vector<voiceBlock_t> voiceVector;
std::vector<std::string> scripts;
ShopInfoMap shopItems;
std::vector<ShopBlock> shopItemVector;

NpcsEvent_t eventType = NPCS_EVENT_NONE;
};
Expand All @@ -80,9 +91,7 @@ class NpcType
std::string nameDescription;
NpcInfo info;

void addShopItem(const std::string &itemName, const ShopInfo &shopInfo) {
info.shopItems[itemName] = shopInfo;
}
void loadShop(NpcType* npcType, ShopBlock shopBlock);

bool loadCallback(LuaScriptInterface* scriptInterface);
bool canSpawn(const Position& pos);
Expand Down
21 changes: 5 additions & 16 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3793,22 +3793,11 @@ bool Player::hasShopItemForSale(uint16_t itemId, uint8_t subType) const
return false;
}

const ItemType& it = Item::items.getItemIdByClientId(itemId);
ShopInfoMap shopItemMap = shopOwner->getShopItems();
if (shopItemMap.find(it.name) == shopItemMap.end()) {
return false;
}

const ShopInfo& shopInfo = shopItemMap[it.name];
if (shopInfo.buyPrice == 0) {
return false;
}

if (!it.isFluidContainer()) {
return true;
}

return shopInfo.subType == subType;
const ItemType& itemType = Item::items[itemId];
std::vector<ShopBlock> shoplist = shopOwner->getShopItemVector();
return std::any_of(shoplist.begin(), shoplist.end(), [&](const ShopBlock& shopBlock) {
return shopBlock.itemId == itemId && shopBlock.itemBuyPrice != 0 && (!itemType.isFluidContainer() || shopBlock.itemSubType == subType);
});
}

void Player::internalAddThing(Thing* thing)
Expand Down
8 changes: 4 additions & 4 deletions src/creatures/players/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1299,10 +1299,10 @@ class Player final : public Creature, public Cylinder
}
}
void sendSaleItemList(const std::map<uint32_t, uint32_t>& inventoryMap) const {
if (client && shopOwner) {
client->sendSaleItemList(shopOwner->getShopItems(), inventoryMap);
}
}
if (client && shopOwner) {
client->sendSaleItemList(shopOwner->getShopItemVector(), inventoryMap);
}
}
void sendCloseShop() const {
if (client) {
client->sendCloseShop();
Expand Down
26 changes: 11 additions & 15 deletions src/lua/functions/creatures/npc/npc_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ int NpcFunctions::luaNpcIsMerchant(lua_State* L) {
return 1;
}

ShopInfoMap shopItems = npc->getShopItems();
const std::vector<ShopBlock> shopItems = npc->getShopItemVector();

if (shopItems.empty()) {
pushBoolean(L, false);
Expand All @@ -426,22 +426,18 @@ int NpcFunctions::luaNpcGetShopItem(lua_State* L) {
return 1;
}

ShopInfoMap shopItems = npc->getShopItems();
const ItemType &itemType = Item::items.getItemIdByClientId(getNumber<uint16_t>(L, 2));

if (shopItems.find(itemType.name) == shopItems.end()) {
reportErrorFunc("No shop item found for clientId");
pushBoolean(L, false);
return 1;
const std::vector<ShopBlock> &shopVector = npc->getShopItemVector();
for (ShopBlock shopBlock : shopVector)
{
setField(L, "id", shopBlock.itemId);
setField(L, "name", shopBlock.itemName);
setField(L, "subType", shopBlock.itemSubType);
setField(L, "buyPrice", shopBlock.itemBuyPrice);
setField(L, "sellPrice", shopBlock.itemSellPrice);
setField(L, "storageKey", shopBlock.itemStorageKey);
setField(L, "storageValue", shopBlock.itemStorageValue);
}

ShopInfo shopInfo = shopItems[itemType.name];
setField(L, "clientId", shopInfo.itemClientId);
setField(L, "name", shopInfo.name);
setField(L, "subType", shopInfo.subType);
setField(L, "buyPrice", shopInfo.buyPrice);
setField(L, "sellPrice", shopInfo.sellPrice);

pushBoolean(L, true);
return 1;
}
Expand Down

0 comments on commit caf0a97

Please sign in to comment.