Tutorial: Adicionando Surprise Bags no Drop de Monstros
Código foi criado para uma versão 8.60 do Crystal Server. provavelmente funciona em TFS 0.4/0.3
Passo 1: Atualize o configmanager.cpp
No arquivo configmanager.cpp
, adicione o seguinte código para permitir que a configuração de SURPRISE_BAGS
seja ativada/desativada no config.lua
:
m_confBool[SURPRISE_BAGS] = getGlobalBool("dropSurpriseBagsFromMonsters", false);
Passo 2: Atualize o configmanager.h
No arquivo configmanager.h
, defina a variável SURPRISE_BAGS na parte dos booleans
:
SURPRISE_BAGS,
Passo 3: Modifique o items.cpp
No arquivo items.cpp
, na função bool Items::reload()
, adicione a chamada para a nova função loadSurpriseBags()
para carregar as configurações das Surprise Bags
.
Coloque essa linha de código logo acima da função void Items::parseRandomizationBlock(...)
:
if(!loadSurpriseBags()) return false;
Passo 4: Crie a Função loadSurpriseBags
Ainda em items.cpp
, adicione a implementação da função bool Items::loadSurpriseBags()
para carregar as informações das bags a partir do XML:
bool Items::loadSurpriseBags() { xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_OTHER, "items/bags.xml").c_str()); if(!doc) { std::clog << "[Warning - Items::loadBags] Cannot load bags file." << std::endl << getLastXMLError() << std::endl; return false; } xmlNodePtr root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"bags")) { xmlFreeDoc(doc); std::clog << "[Warning - Items::loadBags] Malformed bags file." << std::endl; return false; } std::string strValue; int32_t intValue; for(xmlNodePtr node = root->children; node; node = node->next) { if(xmlStrcmp(node->name, (const xmlChar*)"bag")) continue; uint16_t itemId = 0; std::string itemName; uint32_t chance = 0, minAmount = 1, maxAmount = 1; uint64_t minRange = 0, maxRange = 0; if(readXMLString(node, "name", strValue)) itemName = strValue; if(readXMLInteger(node, "itemid", intValue)) itemId = intValue; if(readXMLInteger(node, "chance", intValue)) chance = intValue; if(readXMLInteger(node, "minAmount", intValue)) minAmount = intValue; if(readXMLInteger(node, "maxAmount", intValue)) maxAmount = intValue; if(readXMLInteger(node, "minRange", intValue)) minRange = intValue; if(readXMLInteger(node, "maxRange", intValue)) maxRange = intValue; setItemBag(itemId, itemName, chance, minAmount, maxAmount, minRange, maxRange); } xmlFreeDoc(doc); return true; }
Passo 5: Atualize o items.h
Em items.h
, defina a estrutura BagItemInfo
para armazenar as informações dos itens de bag:
struct BagItemInfo { std::string name; uint16_t id; uint32_t chance; uint32_t minAmount; uint32_t maxAmount; uint64_t minRange; uint64_t maxRange; };
Adicione a função loadSurpriseBags()
e métodos adicionais para gerenciar as Surprise Bags
:
bool loadSurpriseBags(); std::vector<const BagItemInfo*> getAllBagItems() const { std::vector<const BagItemInfo*> allBagItems; for(std::map<int32_t, BagItemInfo>::const_iterator it = bagItems.begin(); it != bagItems.end(); ++it) allBagItems.push_back(&(it->second)); return allBagItems; } void setItemBag(uint16_t itemId, const std::string &itemName, uint32_t chance, uint32_t minAmount, uint32_t maxAmount, uint64_t minRange, uint64_t maxRange) { BagItemInfo itemInfo; itemInfo.name = itemName; itemInfo.id = itemId; itemInfo.chance = chance; itemInfo.minAmount = minAmount; itemInfo.maxAmount = maxAmount; itemInfo.minRange = minRange; itemInfo.maxRange = maxRange; bagItems[itemId] = itemInfo; }
Adicione o mapa bagItems
na classe Items abaixo de RandomizationMap randomizationMap;
:
std::map<int32_t, BagItemInfo> bagItems;
Passo 6: Modifique o otserv.cpp
Em otserv.cpp
, adicione o carregamento das bags no início da execução, logo acima de std::clog << "Loading groups" << std::endl;
:
if(g_config.getBool(ConfigManager::SURPRISE_BAGS)) { std::clog << "Loading surprise bags" << std::endl; if(!Item::items.loadSurpriseBags()) { std::clog << "Unable to load surprise bags! Continue? (y/N)" << std::endl; char buffer = OTSYS_getch(); if(buffer != 121 && buffer != 89) startupErrorMessage("Unable to load surprise bags!"); } }
Passo 7: Atualize monsters.cpp
No arquivo monsters.cpp
, na função void MonsterType::dropLoot(Container* corpse)
, adicione o código para verificar e adicionar as Surprise Bags
ao loot. Coloque-o logo após o código abaixo
Item* tmpItem = *iit; if(Container* container = tmpItem->getContainer()) { if(createChildLoot(container, *it)) corpse->__internalAddThing(tmpItem); else delete container; } else corpse->__internalAddThing(tmpItem);
Adicione
if(g_config.getBool(ConfigManager::SURPRISE_BAGS)) { const std::vector<const Items::BagItemInfo*> allBagItems = Item::items.getAllBagItems(); std::vector<const Items::BagItemInfo*> validBagItems; for(std::vector<const Items::BagItemInfo*>::const_iterator it = allBagItems.begin(); it != allBagItems.end(); ++it) { const Items::BagItemInfo* bagItem = *it; if(bagItem->chance > 0) validBagItems.push_back(bagItem); } if(!validBagItems.empty()) { for(std::vector<const Items::BagItemInfo*>::const_iterator it = validBagItems.begin(); it != validBagItems.end(); ++it) { const Items::BagItemInfo* bagItem = *it; uint64_t minChance = bagItem->minRange; uint64_t maxChance = bagItem->maxRange; if(random_range(minChance, maxChance) <= bagItem->chance) { uint16_t chosenBagId = bagItem->id; uint32_t minAmount = bagItem->minAmount; uint32_t maxAmount = bagItem->maxAmount; uint16_t dropAmount = static_cast<uint16_t>(random_range(minAmount, maxAmount, DISTRO_UNIFORM)); if(chosenBagId != 0) { Item* newItem = NULL; if(dropAmount > 1) { newItem = Item::CreateItem(chosenBagId, dropAmount); if(newItem) { if(g_game.internalAddItem(NULL, corpse, newItem) != RET_NOERROR) corpse->__internalAddThing(newItem); } } else { newItem = Item::CreateItem(chosenBagId, 1); if(newItem) { if(g_game.internalAddItem(NULL, corpse, newItem) != RET_NOERROR) corpse->__internalAddThing(newItem); } } } } } } }
Passo 8: Atualize o config.lua
Por fim, no arquivo config.lua
, adicione a configuração que permite ativar ou desativar o drop das Surprise Bags
:
-- Surprise Bags
-- NOTE: Set dropSurpriseBagsFromMonsters to false to disable surprise bag drops from monsters..
dropSurpriseBagsFromMonsters = false
Para finalizar
va na pasta data/items e crie um arquivo bags.xml e cole isso dentro
<?xml version="1.0" encoding="UTF-8"?> <bags> <!-- If chance and maxRange have the same value, the item will always drop. --> <bag name="Blue Surprise Bag" itemid="6570" chance="100" maxRange="10000"/> <bag name="Red Surprise Bag" itemid="6571" chance="100" maxRange="1000"/> </bags>
Explicação do Funcionamento
O sistema lê as informações de cada itens do arquivo XML bags.xml
, que segue a seguinte estrutura acima:
Cada <bag>
representa uma bag/item que pode ser dropada de monstros com as seguintes propriedades:
-
name
: Nome descritivo da bag/item (opcional para identificação). -
itemid
: ID do item representando a bag/item no jogo. -
chance
: Chance de dropar a sacola. Valores mais altos aumentam a chance. -
maxRange
: Define o intervalo máximo de chance. Sechance
for igual amaxRange
, a sacola sempre será derrubada. -
Quando menor o a distancia da chance para o range, mais fácil o item dropa.
Créditos:
Zorzin pela ideia do código na versão 7.9
Tryller: Criação do código do tópico