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. Se chance for igual a maxRange, 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