triinnt 8 Postado 7 horas atrás Compartilhar Postado 7 horas atrás Boa noite! Estava desenvolvendo um projeto de NDBO e precisava de um Stack-Item que suportasse mais de 100 itens. Dei uma procurada na net, mas não encontrei uma solução adequada. Os que encontrei eram bugados ou tinham um limite de 255 itens. No fim, acabei fazendo um, que permite configurar o limite diretamente no config.lua. Porém, como acabaram de fazer um e soltram FREE uma parte do codigo, irei disponibilizar aqui como foi feito. Em container.cpp: Procure por: __queryMaxCount e substitua ou modifique para isso: Spoiler ReturnValue Container::__queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount, uint32_t flags) const { const Item* item = thing->getItem(); if(!item) { maxQueryCount = 0; return RET_NOTPOSSIBLE; } if(((flags & FLAG_NOLIMIT) == FLAG_NOLIMIT)) { maxQueryCount = std::max((uint32_t)1, count); return RET_NOERROR; } int32_t freeSlots = std::max((int32_t)(capacity() - size()), (int32_t)0); if(item->isStackable()) { uint32_t n = 0; if(index == INDEX_WHEREEVER) { //Iterate through every item and check how much free stackable slots there is. uint32_t slotIndex = 0; for(ItemList::const_iterator cit = itemlist.begin(); cit != itemlist.end(); ++cit, ++slotIndex) { if((*cit) != item && (*cit)->getID() == item->getID() && (*cit)->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) //65kitem { uint32_t remainder = (g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - (*cit)->getItemCount()); //65kitem if(__queryAdd(slotIndex, item, remainder, flags) == RET_NOERROR) n += remainder; } } } else { const Thing* destThing = __getThing(index-1); const Item* destItem = NULL; if(destThing) destItem = destThing->getItem(); if(destItem && destItem->getID() == item->getID() && destItem->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX))//65kitem { uint32_t remainder = g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - destItem->getItemCount(); //65kitem if(__queryAdd(index, item, remainder, flags) == RET_NOERROR) n = remainder; } } maxQueryCount = freeSlots * g_config.getNumber(ConfigManager::STACK_ITEM_MAX) + n; //65kitem if(maxQueryCount < count) return RET_CONTAINERNOTENOUGHROOM; } else { maxQueryCount = freeSlots; if(!maxQueryCount) return RET_CONTAINERNOTENOUGHROOM; } return RET_NOERROR; } Ainda em container.cpp, procure por __queryDestination e modifique ou substitua por: Spoiler Cylinder* Container::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { if(index == 254 /*move up*/) { index = INDEX_WHEREEVER; *destItem = NULL; Container* parentContainer = dynamic_cast<Container*>(getParent()); if(parentContainer) return parentContainer; return this; } if(index == 255 /*add wherever*/) { index = INDEX_WHEREEVER; *destItem = NULL; } else if(index >= (int32_t)capacity()) { /* if you have a container, maximize it to show all 20 slots then you open a bag that is inside the container you will have a bag with 8 slots and a "grey" area where the other 12 slots where from the container if you drop the item on that grey area the client calculates the slot position as if the bag has 20 slots */ index = INDEX_WHEREEVER; *destItem = NULL; } const Item* item = thing->getItem(); if(!item) return this; bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags); if(autoStack && item->isStackable() && item->getParent() != this) { //try find a suitable item to stack with uint32_t n = itemlist.size(); for(ItemList::reverse_iterator cit = itemlist.rbegin(); cit != itemlist.rend(); ++cit, --n) { if((*cit) != item && (*cit)->getID() == item->getID() && (*cit)->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) //65k item { *destItem = (*cit); index = n; return this; } } } if(index != INDEX_WHEREEVER) { Thing* destThing = __getThing(index); if(destThing) *destItem = destThing->getItem(); if(Cylinder* subCylinder = dynamic_cast<Cylinder*>(*destItem)) { index = INDEX_WHEREEVER; *destItem = NULL; return subCylinder; } } return this; } Agora em game.cpp: Procure por: playerMoveThing e mude para: Spoiler bool Game::playerMoveThing(const uint32_t& playerId, const Position& fromPos, const uint16_t& spriteId, const int16_t& fromStackpos, const Position& toPos, const uint16_t& count) playerMoveItem e mude para: Spoiler bool Game::playerMoveItem(const uint32_t& playerId, const Position& fromPos, const uint16_t& spriteId, const int16_t& fromStackpos, const Position& toPos, const uint16_t& count) internalMoveItem em "Item* updateItem = NULL;" e mude para Spoiler Item* updateItem = NULL; if(item->isStackable()) { uint16_t n = 0; if(toItem && toItem->getID() == item->getID()) { n = std::min((uint32_t)g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - toItem->getItemCount(), m); toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n); updateItem = toItem; } if(m - n > 0) moveItem = Item::CreateItem(item->getID(), m - n); else moveItem = NULL; if(item->isRemoved()) freeThing(item); } internalMoveTradeItem em "Item* updateItem = NULL;" e mude para : Spoiler if(item->isStackable()) { uint16_t n = 0; if(toItem && toItem->getID() == item->getID()) { n = std::min((uint32_t)g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - toItem->getItemCount(), m); toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n); updateItem = toItem; } if(m - n > 0) moveItem = Item::CreateItem(item->getID(), m - n); else moveItem = NULL; if(item->isRemoved()) freeThing(item); } internalAddItem em "Item* toItem = *stackItem;" mude para Spoiler if(item->isStackable() && toItem) { uint32_t m = std::min((uint32_t)item->getItemCount(), maxQueryCount), n = 0; if(toItem->getID() == item->getID()) { n = std::min((uint32_t)g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - toItem->getItemCount(), m); toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n); } Agora em game.h: Procure por playerMoveThing e mude para: bool playerMoveThing(const uint32_t& playerId, const Position& fromPos, const uint16_t& spriteId, const int16_t& fromStackpos, const Position& toPos, const uint16_t& count); Procure por playerMoveItem e mude para: bool playerMoveItem(const uint32_t& playerId, const Position& fromPos, const uint16_t& spriteId, const int16_t& fromStackpos, const Position& toPos, const uint16_t& count); Agora em item.cpp: Procue por setSubType((uint16_t)_count); e comente ele. Agora em item.h: Procure por getWorth() e substitua por: int64_t getWorth() const {return getItemCount() * items[id].worth;} Procue por uint16_t id; e em "count" mude para esse: int16_t count; Agora em luascript.cpp: Procure por luaDoTransformItem e mude para: Spoiler int32_t LuaInterface::luaDoTransformItem(lua_State* L) { //doTransformItem(uid, newId[, count/subType]) int32_t count = -1; if(lua_gettop(L) > 2) count = popNumber(L); uint32_t newId = popNumber(L), uid = popNumber(L); ScriptEnviroment* env = getEnv(); Item* item = env->getItemByUID(uid); if(!item) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[newId]; if(it.stackable && count > g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) count = g_config.getNumber(ConfigManager::STACK_ITEM_MAX); Item* newItem = g_game.transformItem(item, newId, count); if(newItem && newItem != item) { env->removeThing(uid); env->insertThing(uid, newItem); if(newItem->getUniqueId() != 0) env->addUniqueThing(newItem); } lua_pushboolean(L, true); return 1; } Procure por luaDoPlayerAddItem e mude para: Spoiler int32_t LuaInterface::luaDoPlayerAddItem(lua_State* L) { //doPlayerAddItem(cid, itemid[, count/subtype = 1[, canDropOnMap = true[, slot = 0]]]) //doPlayerAddItem(cid, itemid[, count = 1[, canDropOnMap = true[, subtype = 1[, slot = 0]]]]) int32_t params = lua_gettop(L), subType = 1, slot = SLOT_WHEREEVER; if(params > 5) slot = popNumber(L); if(params > 4) { if(params > 5) subType = popNumber(L); else slot = popNumber(L); } bool canDropOnMap = true; if(params > 3) canDropOnMap = popBoolean(L); uint32_t count = 1; if(params > 2) count = popNumber(L); uint32_t itemId = popNumber(L); if(slot > SLOT_AMMO) { errorEx("Invalid slot"); lua_pushboolean(L, false); return 1; } ScriptEnviroment* env = getEnv(); Player* player = env->getPlayerByUID((uint32_t)popNumber(L)); if(!player) { errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND)); lua_pushboolean(L, false); return 1; } const ItemType& it = Item::items[itemId]; int32_t itemCount = 1; if(params > 4) itemCount = std::max((uint32_t)1, count); else if(it.hasSubType()) { if(it.stackable) itemCount = (int32_t)std::ceil((float)count / g_config.getNumber(ConfigManager::STACK_ITEM_MAX)); subType = count; } uint32_t ret = 0; Item* newItem = NULL; while(itemCount > 0) { int32_t stackCount = std::min<int32_t>(g_config.getNumber(ConfigManager::STACK_ITEM_MAX), subType); if(!(newItem = Item::CreateItem(itemId, stackCount))) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return ++ret; } if(it.stackable) subType -= stackCount; Item* stackItem = NULL; if(g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap, (slots_t)slot, &stackItem) != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return ++ret; } ++ret; if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else if(stackItem) lua_pushnumber(L, env->addThing(stackItem)); else lua_pushnil(L); --itemCount; } if (newItem) { if (newItem->isStackable()) { player->updateInventoryWeight(); player->sendStats(); } } if(ret) return ret; lua_pushnil(L); return 1; } Procure por luaDoCreateItem e mude para: Spoiler int32_t LuaInterface::luaDoCreateItem(lua_State* L) { //doCreateItem(itemid[, type/count = 1], pos) //Returns uid of the created item, only works on tiles. PositionEx pos; popPosition(L, pos); uint32_t count = 1; if(lua_gettop(L) > 1) count = popNumber(L); const ItemType& it = Item::items[popNumber(L)]; ScriptEnviroment* env = getEnv(); Tile* tile = g_game.getTile(pos); if(!tile) { if(it.group == ITEM_GROUP_GROUND) { Item* item = Item::CreateItem(it.id); tile = IOMap::createTile(item, NULL, pos.x, pos.y, pos.z); g_game.setTile(tile); lua_pushnumber(L, env->addThing(item)); } else { errorEx(getError(LUA_ERROR_TILE_NOT_FOUND)); lua_pushboolean(L, false); } return 1; } int32_t itemCount = 1, subType = 1; if(it.hasSubType()) { if(it.stackable) itemCount = (int32_t)std::ceil(count / g_config.getNumber(ConfigManager::STACK_ITEM_MAX)); subType = count; } else itemCount = std::max(1U, count); uint32_t ret = 0; Item* newItem = NULL; while(itemCount > 0) { int32_t stackCount = std::min<int32_t>(g_config.getNumber(ConfigManager::STACK_ITEM_MAX), subType); if(!(newItem = Item::CreateItem(it.id, stackCount))) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return ++ret; } if(it.stackable) subType -= stackCount; uint32_t dummy = 0; Item* stackItem = NULL; if(g_game.internalAddItem(NULL, tile, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT, false, dummy, &stackItem) != RET_NOERROR) { delete newItem; lua_pushboolean(L, false); return ++ret; } ++ret; if(newItem->getParent()) lua_pushnumber(L, env->addThing(newItem)); else if(stackItem) lua_pushnumber(L, env->addThing(stackItem)); else lua_pushnil(L); --itemCount; } if(ret) return ret; lua_pushnil(L); return 1; } Procure por luaDoCreateItemEx e mude para: Spoiler int32_t LuaInterface::luaDoCreateItemEx(lua_State* L) { //doCreateItemEx(itemid[, count/subType]) uint32_t count = 0; if(lua_gettop(L) > 1) count = popNumber(L); ScriptEnviroment* env = getEnv(); const ItemType& it = Item::items[(uint32_t)popNumber(L)]; if(it.stackable && count > g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) count = g_config.getNumber(ConfigManager::STACK_ITEM_MAX); Item* newItem = Item::CreateItem(it.id, count); if(!newItem) { errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND)); lua_pushboolean(L, false); return 1; } newItem->setParent(VirtualCylinder::virtualCylinder); env->addTempItem(env, newItem); lua_pushnumber(L, env->addThing(newItem)); return 1; } Agora em networkmessage.cpp: Procure por void NetworkMessage::addItem e mude para: Spoiler void NetworkMessage::addItem(uint16_t id, uint16_t count, Player* player, bool withDescription) { const ItemType& it = Item::items[id]; uint16_t spriteId = it.clientId; if(g_config.getBool(ConfigManager::MW_REPLACE_ENABLE)){ spriteId = getReplaceMW(spriteId, player); } add<uint16_t>(spriteId); if (it.stackable) { add<uint16_t>(count); } else if (it.isSplash() || it.isFluidContainer()) { addByte(fluidMap[count & 7]); } if (withDescription) { addString(""); } } Procure por void NetworkMessage::addItem e mude para: Spoiler void NetworkMessage::addItem(const Item* item, Player* player, bool withDescription) { const ItemType& it = Item::items[item->getID()]; uint16_t spriteId = it.clientId; if(g_config.getBool(ConfigManager::MW_REPLACE_ENABLE)){ spriteId = getReplaceMW(spriteId, player); } add<uint16_t>(spriteId); if (it.stackable) { add<uint16_t>(item->getSubType()); } else if (it.isSplash() || it.isFluidContainer()) { addByte(fluidMap[item->getFluidType() & 7]); } if (withDescription) { addString(item->getDescription(0)); } } Agora em networkmessage.h: Procure por void addItem e mude para: void addItem(uint16_t id, uint16_t count, Player* player, bool withDescription = false); Agora em player.cpp: Procure por __queryMaxCount e mude para: Spoiler ReturnValue Player::__queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount, uint32_t flags) const { const Item* item = thing->getItem(); if(!item) { maxQueryCount = 0; return RET_NOTPOSSIBLE; } if(index == INDEX_WHEREEVER) { uint32_t n = 0; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(Item* inventoryItem = inventory[i]) { if(Container* subContainer = inventoryItem->getContainer()) { uint32_t queryCount = 0; subContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags); //iterate through all items, including sub-containers (deep search) n += queryCount; for(ContainerIterator cit = subContainer->begin(); cit != subContainer->end(); ++cit) { if(Container* tmpContainer = (*cit)->getContainer()) { queryCount = 0; tmpContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags); n += queryCount; } } } else if(inventoryItem->isStackable() && item->getID() == inventoryItem->getID() && inventoryItem->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) { uint32_t remainder = (g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - inventoryItem->getItemCount()); if(__queryAdd(i, item, remainder, flags) == RET_NOERROR) n += remainder; } } else if(__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR) { if(item->isStackable()) n += g_config.getNumber(ConfigManager::STACK_ITEM_MAX); else n += 1; } } maxQueryCount = n; } else { const Thing* destThing = __getThing(index); const Item* destItem = NULL; if(destThing) destItem = destThing->getItem(); if(destItem) { if(destItem->isStackable() && item->getID() == destItem->getID() && destItem->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) maxQueryCount = g_config.getNumber(ConfigManager::STACK_ITEM_MAX) - destItem->getItemCount(); else maxQueryCount = 0; } else if(__queryAdd(index, item, count, flags) == RET_NOERROR) { if(item->isStackable()) maxQueryCount = g_config.getNumber(ConfigManager::STACK_ITEM_MAX); else maxQueryCount = 1; return RET_NOERROR; } } if(maxQueryCount < count) return RET_NOTENOUGHROOM; return RET_NOERROR; } Procure por __queryDestination e mude para: Spoiler Cylinder* Player::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { if(!index /*drop to capacity window*/ || index == INDEX_WHEREEVER) { *destItem = NULL; const Item* item = thing->getItem(); if(!item) return this; bool autoStack = (flags & FLAG_IGNOREAUTOSTACK) != FLAG_IGNOREAUTOSTACK; if((!autoStack || !item->isStackable()) && backpack.first && backpack.first->__queryAdd(backpack.second, item, item->getItemCount(), flags)) { index = backpack.second; if(backpack.second != INDEX_WHEREEVER) ++backpack.second; return backpack.first; } std::list<std::pair<Container*, int32_t> > containers; std::list<std::pair<Cylinder*, int32_t> > freeSlots; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(Item* invItem = inventory[i]) { if(invItem == item || invItem == tradeItem) continue; if(autoStack && item->isStackable() && __queryAdd(i, item, item->getItemCount(), 0) == RET_NOERROR && invItem->getID() == item->getID() && invItem->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) { *destItem = invItem; index = i; return this; } if(Container* container = invItem->getContainer()) { if(!autoStack && container->__queryAdd( INDEX_WHEREEVER, item, item->getItemCount(), flags) == RET_NOERROR) { index = INDEX_WHEREEVER; backpack = std::make_pair(container, index + 1); return container; } containers.push_back(std::make_pair(container, 0)); } } else if(!autoStack) { if(__queryAdd(i, item, item->getItemCount(), 0) == RET_NOERROR) { index = i; return this; } } else freeSlots.push_back(std::make_pair(this, i)); } int32_t deepness = g_config.getNumber(ConfigManager::PLAYER_DEEPNESS); while(!containers.empty()) { Container* tmpContainer = containers.front().first; int32_t level = containers.front().second; containers.pop_front(); if(!tmpContainer) continue; for(uint32_t n = 0; n < tmpContainer->capacity(); ++n) { if(Item* tmpItem = tmpContainer->getItem(n)) { if(tmpItem == item || tmpItem == tradeItem) continue; if(autoStack && item->isStackable() && tmpContainer->__queryAdd(n, item, item->getItemCount(), 0) == RET_NOERROR && tmpItem->getID() == item->getID() && tmpItem->getItemCount() < g_config.getNumber(ConfigManager::STACK_ITEM_MAX)) { index = n; *destItem = tmpItem; return tmpContainer; } if(Container* container = tmpItem->getContainer()) { if(!autoStack && container->__queryAdd(INDEX_WHEREEVER, item, item->getItemCount(), flags) == RET_NOERROR) { index = INDEX_WHEREEVER; backpack = std::make_pair(container, index + 1); return container; } if(deepness < 0 || level < deepness) containers.push_back(std::make_pair(container, level + 1)); } } else { if(!autoStack) { if(tmpContainer->__queryAdd(n, item, item->getItemCount(), 0) == RET_NOERROR) { index = n; backpack = std::make_pair(tmpContainer, index + 1); return tmpContainer; } } else freeSlots.push_back(std::make_pair(tmpContainer, n)); break; // one slot to check is definitely enough. } } } if(autoStack) { while(!freeSlots.empty()) { Cylinder* tmpCylinder = freeSlots.front().first; int32_t i = freeSlots.front().second; freeSlots.pop_front(); if(!tmpCylinder) continue; if(tmpCylinder->__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR) { index = i; return tmpCylinder; } } } return this; } Thing* destThing = __getThing(index); if(destThing) *destItem = destThing->getItem(); if(Cylinder* subCylinder = dynamic_cast<Cylinder*>(destThing)) { index = INDEX_WHEREEVER; *destItem = NULL; return subCylinder; } return this; } Agora em protocolgame.cpp: Procure por "void ProtocolGame::parseThrow" e mude para: uint16_t count = msg.get<uint16_t>(); Agora em tile.cpp: Procure por "if(item->isStackable() && count != item->getItemCount())" e mude para: Spoiler if(item->isStackable() && count != item->getItemCount()) { uint16_t newCount = (uint16_t)std::max((int32_t)0, (int32_t)(item->getItemCount() - count)); updateTileFlags(item, true); item->setItemCount(newCount); updateTileFlags(item, false); const ItemType& it = Item::items[item->getID()]; onUpdateTileItem(item, it, item, it); } Agora vá em configmanager.cpp: E adicione a seguinte linha: m_confNumber[STACK_ITEM_MAX] = getGlobalNumber("StackItem_Max", 100); Por fim, vá em configmanager.h: E adicione a seguinte linha em "enum number_config_t": STACK_ITEM_MAX, DETALHE, no seu client é necessario ativar a feature: g_game.enableFeature(GameCountU16) e no config.lua adicione a linha: StackItem_Max = 1000 Lembrando que esse STACK é apenas para OTX, caso deseje para TFS 1.x só entrar em contato pelo DC: trint. Qualquer erro só deixar o comentario. Como é meu primeiro topico desde já peço perdão pela forma que foi feito kkkk. 7 Link para o comentário https://tibiadevs.com/forums/topic/957-stack-item-1k-para-otx/ Compartilhar em outros sites Mais opções de compartilhamento...
Moderador Wang 1.739 Postado 7 horas atrás Moderador Compartilhar Postado 7 horas atrás Tópico Aprovado! Somos gratos por sua contribuição ❤️ REP+ Link para o comentário https://tibiadevs.com/forums/topic/957-stack-item-1k-para-otx/#findComment-5004 Compartilhar em outros sites Mais opções de compartilhamento...
Dinho 225 Postado 6 horas atrás Compartilhar Postado 6 horas atrás Otima Contribuição ❤️ Link para o comentário https://tibiadevs.com/forums/topic/957-stack-item-1k-para-otx/#findComment-5006 Compartilhar em outros sites Mais opções de compartilhamento...
Posts Recomendados
Crie uma conta ou entre para comentar
Você precisar ser um membro para fazer um comentário
Criar uma conta
Crie uma nova conta em nossa comunidade. É fácil!
Crie uma nova contaEntrar
Já tem uma conta? Faça o login.
Entrar Agora