Atualmente - Versão 0.3.2.1
Atualizada em: 05/09/07 - 12:30
SVN
ChangeLog da v0.1 pra 0.2b:
Arrumados alguns bugs.
Opção de Teleport.
Opção de Mensagem.
Melhora nos items.
Descrição especial nos items.
E mais algumas coisas.
ChangeLog da v0.2 pra 0.3.2:
Re-Escrito.
Limpo (tem muito pra limpa ainda...)
É possivel por os items de recompensa dentro de containers agora (um bom numero). Respeite sempre a capacidade do container, eu não coloquei nenhum check pra isso...
Colocar o ActionID do item.
E mais algumas coisas..
-------------------------------------------------------------------
Olá de novo. Como eu disse eu ia tentar fazer, não está completo ainda mas a base principal ta feita. O dovia do Vitor disse que ia re-escreve, mas nao fez nada
então eu refiz. Eu tava tentando testa meu C++ (que ta horrivel como todos podem ver), mas até que saiu a bagaça
Todo:
Limpeza?
Achar e corrigir bugs.
Melhorar as listas que eu fiz uma zona....
Definir que os players só podem realizar a quest 1x. [done]
Melhorar Containers [done]
Teleports [done]
Setar ActionID nas recompensas [done]
Opção de movimentar (moveable) [done]
Bom, não está completa ainda, então ela TEM bugs
Features:
Nome da quest: quando o player der look no item, ele vai ver o nome da quest (pode ser setado no xml o nome lógico e você pode ligar/desligar essa opção por lá também).
Quest ID: é a chave das nossas quests, devem ser sempre unicas a não ser que ela tenha segmentos.
Segment: é uma parte da quest, você pode ter X segmentos dentro da quest principal. sempre seguindo em ordem crescente.
X, Y, Z: É a localização do item no map, pode ser QUALQUER ITEM.
Moveable: Se vai poder mover ou não o item (DEFAULT = 1 = MOVEABLE, 0 = NOTMOVEABLE - não pode mover)
backpack: Pode dar items dentro de containers, como o Tibia da Cip. Foi mudado:
*Você tem que por o id da backpack, se não por, ela vai usa o id padrão.
*Quando você por pra dar o item dentro de uma bp, vai ligar essa opção automaticamente no id padrão (bp marrom).
Type: pode ser o id do item ou o nome dele. Preste atenção pra items que tem o mesmo nome...
Desc: Adiciona uma descrição especial ao item.
Ex: 19:28 You see a boots of haste.It weighs 7.5 oz. It was made by and old and unknow guy. A rare masterpiece.
Message: Manda uma mensagem pro player quando ele 'realiza a quest'.
Teleport: teleporta o player quando ele 'realiza a quest'.
ActionId: define uma actionID pro item de recompensa (cada recompensa pode ter o seu).
Container ID: vai dar o item definido em um container que você deve ter posto acima:
Ex:
<backpack type="1988"/><backpack type="1995"/>
<item type="warrior helmet" desc="It was made by and old and unknow guy. A rare masterpiece." containerId="2"/>
O warrior helmet vai ir no container 2 (o de id 1995)
Eu acho que é tudo, vamo pro code.
-------------------------------------------------------------------
Actions.cpp
Depois de:
#include "actions.h"
Adicione:
#ifdef _QUEST_XML_ #include "quest.h" extern Quests quests; #endif
Na função:
ReturnValue Actions::internalUseItem(Player* player, const Position& pos, uint8_t index, Item* item)
Depois de:
if(Door* door = item->getDoor()){if(!door->canUse(player)){
return RET_CANNOTUSETHISOBJECT;
}
}
Adicione:
#ifdef _QUEST_XML_
Quests* quest = quests.getQuest(item->getPosition());
if(quest && item && item->quest){
std::stringstream message;
int32_t value;
player->getStorageValue((uint32_t)quest->id, value);
if(value){
if(value >= quest->sgId){
player->sendTextMessage(MSG_INFO_DESCR, "Its empty.");
return RET_NOERROR;
}
if(value != quest->sgId-1){
player->sendTextMessage(MSG_INFO_DESCR, "You are not prepared yet.");
return RET_NOERROR;
}
}
else{
if(quest->sgId != 1){
player->sendTextMessage(MSG_INFO_DESCR, "You are not prepared yet.");
return RET_NOERROR;
}
}
Container* backpack = NULL;
Container* rewarded = NULL;
std::list<Container*> listContainer;//Vo usar no rewarded.
std::list<Container*> adicionar;
std::list<Container*>::iterator Adding;
std::list<Item*> removel; //I couldnt find any other way...
bool error = false;
ReturnValue ret = RET_NOERROR, ret2 = RET_NOERROR, ret3 = RET_NOERROR, ret4 = RET_NOERROR;
int nova=1;
int bpcids;
if(quest->bId != 0 || quest->containers != 0){
backpack = Item::CreateItem(quest->bId != 0 ? quest->bId : 1988)->getContainer();
removel.push_back(backpack);
}
RewardList2::iterator get = quest->rewardList.begin();
if(quest->containers != 0){
int atd;
for(atd = 0; atd < quest->containers; atd++){
rewarded = Item::CreateItem(quest->bpType[atd])->getContainer();
if(rewarded) {
listContainer.push_back(rewarded);
}
}
}
for(get; get != quest->rewardList.end(); ++get){
Item* reward = Item::CreateItem((*get).first->getID(), (*get).first->getItemCountOrSubtype());
if(reward){
if((*get).first->getSpecialDescription() != "")
reward->setSpecialDescription((*get).first->getSpecialDescription());
if((*get).first->getActionId() != 0)
reward->setActionId((*get).first->getActionId());
}
if((*get).second != 0){
Adding = listContainer.begin();
int add=0;
while(Adding != listContainer.end()){
add++;
if((*get).second == add){
Container* toAdd = (*Adding);
toAdd->__addThing(reward);
}
Adding++;
}
}
else if(backpack)
backpack->__addThing(reward);
else{
ret = g_game.internalAddItem(player, reward); //Nao da pra usar o test, pois ele não ocupa o slot...
if(ret != RET_NOERROR)
error = true;
else{
removel.push_back(reward);
message << "You have found " << reward->getDescription(2);
player->sendTextMessage(MSG_INFO_DESCR, message.str().c_str());
}
}
}
if(backpack){
for(Adding = listContainer.begin(); Adding != listContainer.end(); Adding++){
Container* toAdd2 = (*Adding);
backpack->__addThing(toAdd2);
}
ret2 = g_game.internalAddItem(player, backpack, INDEX_WHEREEVER, 0, true);
if(ret2 == RET_NOERROR){
g_game.internalAddItem(player, backpack);
message << "You have found " << backpack->getDescription(2);
player->sendTextMessage(MSG_INFO_DESCR, message.str().c_str());
}
else return ret2;
}
if(error){//Then we Add it...
for(std::list<Item*>::iterator remove = removel.begin(); remove != removel.end(); ++remove){
ret3 = g_game.internalRemoveItem((*remove), (*remove)->getItemCount(), true);//Testing befre, if we get an error it could crash the server
if(ret3 == RET_NOERROR)
g_game.internalRemoveItem((*remove), (*remove)->getItemCount());
else{//Ok, this should not happen...
std::stringstream bug;
bug << "Atention!!! Player: "<<player->getName()<<" bugged the quest: "<<quest->name<<".";
for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it){
if((*it).second && (*it).second->getAccessLevel() > 0)
(*it).second->sendTextMessage(MSG_STATUS_WARNING, bug.str().c_str());
}
player->sendTextMessage(MSG_STATUS_WARNING, "You have bugged the quest, we are contacting a gm now (you should do it also)");
return ret3;
}
}
return RET_CANNOTUSETHISOBJECT;
}
player->addStorageValue(quest->id, quest->sgId);
if(quest->teleport.x != 0xFFFF){
if(g_game.internalTeleport(player,quest->teleport) == RET_NOERROR)
g_game.addMagicEffect(quest->teleport, NM_ME_ENERGY_AREA);
}
if(quest->questDesc != "")
player->sendTextMessage(MSG_INFO_DESCR, quest->questDesc);
return ret;
}
#endif
Actions.h
Depois de:
LuaScriptInterface m_scriptInterface;
Adcione:
#ifdef _QUEST_XML_ typedef std::list<std::pair<Item*, int> > RewardList2; typedef RewardList2::value_type RewardList2_Pair; RewardList2 rewardList2; #endif
Otserv.cpp
Depois de:
#include "raids.h"
Adicione:
#ifdef _QUEST_XML_ #include "quest.h" Quests quests; #endif
Depois de:
Raids::getInstance()->startup();
Adicione:
#ifdef _QUEST_XML_ std::cout << ":: Loading The Chaos Style Quest System "; if(!quests.loadQuests()) std::cout << ":: Unable to load!"; else std::cout << "[done]" << std::endl; #endif
Game.cpp:
Na função:
ReturnValue Game::internalMoveItem(Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index,Item* item, uint32_t count, uint32_t flags /*= 0*/)
{
Depois de:
if(item == toItem){return RET_NOERROR; //silently ignore move
}
Adicione:
#ifdef _QUEST_XML_ //Nova linha if(toItem && toItem->quest && item->getID() == toItem->getID() && item->isStackable()) return RET_CANNOTTHROW; #endif
Item.h
Mude:
bool isNotMoveable() const {return !items[id].moveable;}
Para:
#ifndef _QUEST_XML_
bool isNotMoveable() const {return !items[id].moveable;}
#else
bool isNotMoveable() const;
#endif
Item.cpp:
Na função:
Item::Item(const unsigned short _type, unsigned short _count /*= 0*/) :ItemAttributes()
Depois de:
count = 1;
Adicione:
#ifdef _QUEST_XML_ quest = false; questmoveable = true; #endif
Na função:
Item::Item(const Item &i) :Thing(), ItemAttributes()
{
Depois de:
fluid = i.fluid;
Adicione:
#ifdef _QUEST_XML_ quest = false; questmoveable = true; #endif
No fim do arquivo adicione:
#ifdef _QUEST_XML_
bool Item::isNotMoveable() const{
if(quest && !questmoveable)
return true;
return !items[id].moveable;
}
#endif
Agora crie 2 arquivos no seu projeto:
quest.cpp
#ifdef _QUEST_XML_
//////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
//////////////////////////////////////////////////////////////////////
// Quests system loaded on XML base - By The Chaos
// Thanks to LooS!k for help also.
//////////////////////////////////////////////////////////////////////
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//////////////////////////////////////////////////////////////////////
#include <string>
#include <sstream>
#include "quest.h"
#include "configmanager.h"
#include "game.h"
extern Game g_game;
extern ConfigManager g_config;
Quests::Quests(){
id = 0;
sgId = 1;
containers = 0;
}
bool Quests::loadQuests()
{
std::string filename = g_config.getString(ConfigManager::DATA_DIRECTORY) + "quests.xml";
xmlDocPtr doc;
doc = xmlParseFile(filename.c_str());
std::stringstream desc;
int itId, itCount, bpId;
std::string Ident;
std::string strCmd;
int intValue;
if( doc )
{
xmlNodePtr root,p;
root = xmlDocGetRootElement(doc);
if( xmlStrcmp(root->name,(const xmlChar*) "quests") != 0 )
{
std::cout << "- Problem: Check the quests.xml file."<< std::endl;
return false;
}
p = root->children;
while( p )
{
if( xmlStrcmp(p->name, (const xmlChar*) "quest") == 0 )
{
Quests* quest = new Quests;
if( readXMLString(p, "name", strCmd) )
{
quest->name = strCmd;
}
else
{
std::cout << "missing name for quest..." << std::endl;
strCmd = "unknown";
}
if( readXMLInteger(p, "showname", intValue) )
{
quest->showName = (bool)intValue;
}
else
{
quest->showName = false;
}
if( readXMLInteger(p,"questId",intValue) )
{
quest->id = intValue;
}
else
{
std::cout << "Error: Missing questId for quest: " << quest->name << std::endl;
return false;
}
if( readXMLInteger(p,"segment",intValue) )
{
quest->sgId = intValue;
}
else
{
std::cout << "Error: Missing segment value for quest: " << quest->name << std::endl;
return false;
}
if( readXMLInteger(p,"x",intValue) )
{
quest->pos.x = intValue;
}
else
{
std::cout << "Error: Missing X Value for quest: " << quest->name << std::endl;
return false;
}
if( readXMLInteger(p,"y",intValue) )
{
quest->pos.y = intValue;
}
else
{
std::cout << "Error: Missing Y Value for quest: " << quest->name << std::endl;
return false;
}
if( readXMLInteger(p,"z",intValue) )
{
quest->pos.z = intValue;
}
else
{
std::cout << "Error: Missing Z Value for quest: " << quest->name << std::endl;
return false;
}
if( readXMLInteger(p,"backpack",intValue) )
{
quest->bId = intValue;
}
else
{
quest->bId = 0;
}
Tile* thatTile = g_game.getTile(quest->pos.x, quest->pos.y, quest->pos.z);
if( !thatTile )
{
std::cout << "Error: Tile not found on quest: "<< quest->name << std::endl;
return false;
}
Item *thatItem = thatTile->getTopThing()->getItem();
if( !thatItem )
{
std::cout << "Error: Internal error - check map on: " << quest->pos.x << "/" << quest->pos.y <<"/"<< quest->pos.z << std::endl;
return false;
}
thatItem->quest = true;
if( readXMLInteger(p,"moveable",intValue) )
{
thatItem->questmoveable = (bool)intValue;
}
else
{
thatItem->questmoveable = true;
}
if( quest->name != "unknown" && quest->showName )
{
desc << " It seems to be sealed somehow. You can read "<< quest->name << " on it.";
thatItem->setSpecialDescription(desc.str());
desc.str("");
}
xmlNodePtr tmp = p->children;
while( tmp )
{
if( xmlStrcmp(tmp->name, (const xmlChar*) "reward") == 0 )
{
xmlNodePtr slot = tmp->children;
while( slot )
{
if( xmlStrcmp(slot->name, (const xmlChar*)"item") == 0 )
{
itId = 0, itCount = 0;
if( readXMLString(slot,"type",strCmd) )
{
Ident = strCmd;
}
if( isdigit(Ident[0]) )
{
itId = atoi(Ident.c_str());
}
else
{
itId = Item::items.getItemIdByName(Ident);
}
if( readXMLInteger(slot,"count",intValue) )
{
itCount = intValue;
}
else
{
itCount = 1;
}
if( itCount > 100 )
{
itCount = 100;
std::cout << "Warning: Count on " << Ident << " is higher than 100. Quest: " << quest->name << std::endl;
}
Item* reward = Item::CreateItem(itId, itCount);
if( !reward )
{
std::cout << "Error: Error while creating reward item." << quest->name << std::endl;
return false;
}
if( readXMLString(slot, "desc", strCmd) )
{
reward->setSpecialDescription(strCmd.c_str());
}
if( readXMLInteger(slot,"actId",intValue) )
{
reward->setActionId(intValue);
}
/* container id*/
int cid = 0;
if( readXMLInteger(slot,"containerId", intValue) )
{
cid = intValue;
}
quest->rewardList.push_back( RewardList_Pair(reward, cid) );
}
slot = slot->next;
}
}
if( xmlStrcmp(tmp->name, (const xmlChar*) "message") == 0 )
{
if(readXMLString(tmp, "value", strCmd))
{
quest->questDesc += strCmd;
}
}
if( xmlStrcmp(tmp->name, (const xmlChar*) "backpack") == 0 )
{
if( readXMLString(tmp,"id",strCmd) )
{
Ident = strCmd;
}
if( isdigit(Ident[0]) )
{
bpId = atoi(Ident.c_str());
}
else
{
bpId = Item::items.getItemIdByName(Ident);
}
quest->bpType[quest->containers] = bpId;
quest->containers++;
}
if( xmlStrcmp(tmp->name, (const xmlChar*) "teleport") == 0 )
{
if( readXMLInteger(tmp,"x",intValue) )
{
quest->teleport.x = intValue;
}
if( readXMLInteger(tmp,"y",intValue) )
{
quest->teleport.y = intValue;
}
if( readXMLInteger(tmp,"z",intValue) )
{
quest->teleport.z = intValue;
}
}
tmp = tmp->next;
}
questMap[quest->pos] = quest;
}
p=p->next;
}
xmlFreeDoc(doc);
}
else
{
std::cout << filename << " not found!" << std::endl;
return false;
}
return true;
}
Quests::~Quests()
{
//std::cout << "Quest " << this->name << std::endl;
QuestMap::iterator it = questMap.find(this->pos);
if(it != questMap.end())
{
delete it->second;
questMap.erase(it);
}
}
void Quests::erase(bool loadxml)
{
QuestMap::iterator it = questMap.begin();
while(it != questMap.end())
{
delete it->second;
questMap.erase(it);
it = questMap.begin();
}
if(loadxml){
if(!loadQuests()){
std::cout << "\n::Error while reloading the quests.xml. "<<std::endl;
return;
}
}
}
Quests* Quests::getQuest(Position pos)
{
QuestMap::iterator it = questMap.find(pos);
while(it != questMap.end())
{
return it->second;
}
return NULL;
}
#endif
E quest.h
#ifdef _QUEST_XML_
//////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
//////////////////////////////////////////////////////////////////////
// Quests system loaded on XML base - By The Chaos
//////////////////////////////////////////////////////////////////////
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//////////////////////////////////////////////////////////////////////
/*#include <string>
#include <map>*/
#include "position.h"
#include "definitions.h"
#include "item.h"
class Quests{
public:
Quests();
~Quests();
bool showName;
int bpType[99], sgId, bId, containers; //Não deve ter mais que 99 containers... pelo amor...
uint32_t id;
std::string questDesc, name;
Position teleport, pos; //Centalizar na posição da quest na action... vai facilitar e nao meche no items...
bool loadQuests();
void erase(bool loadxml);
typedef std::list<std::pair<Item* , int> > RewardList;
typedef RewardList::value_type RewardList_Pair;
RewardList rewardList;
//std::list<Item *> rewardList;
Quests* getQuest(Position pos);
typedef std::map<Position,Quests*> QuestMap;
QuestMap questMap;
protected:
};
#endif
Adicione nas opções do seu projeto:
-D_QUEST_XML_
E DE REBUILD ALL.
Crie um arquivo chamado quests.xml na sua pasta DATA e siga o exemplo::
<quests> <quest name="DelOownage" showname="1" questId="803" segment="1" x="121" y="92" z="7" movement="0"> <backpack type="1988"/> <backpack type="1995"/> <message is="Uhuulll"/> <reward> <item type="knight axe" containerId="1"/> <item type="warrior helmet" desc="It was made by and old and unknow guy. A rare masterpiece." containerId="2"/> <item type="royal helmet" desc="Este item tem uma action" containerId="1" actId="9876"/> </reward> </quest> </quests>
Como vocês podem ver, você pode por nome na quest, mudar pra mostar o nome ou não, a posição você TEM que por, pois ela é essencial, se os items vão vim em containers, e por ae vai (obedeça a cap do container...), colocar actionID e mais coisinhas.
There is nothing important that i remember right now, so start the tests and remember, its not finished yet.
Signed,
The Chaos.
Ps.: Se alguem tiver bugs ou lag, qualquer coisa anormal, poste aqui por favor pra gente ta vendo.
E eu gostaria de algumas ideias ![]()
Ps².: Eu sei que muitos adoram e acham facil por lua, mas eu prefiro ainda desse jeito e sei que muita gente vai ter mais facilidade, apesar de saber que o lua tem mais funcionalidades e talz. Oka?
Atualizado pra versão v0.3.2 em 31Ago07










