Vamos lá, eu fiz isso pq era um saco esses comandos que você tinha que editar no config.lua, num sei onde, num sei nas sources e sempre muito limitado. Com esse não, você tem um grande leque de opções, com nome e podendo editar tudo dentro do próprio jogo, sem mecher na xml, mas você também pode editar por ela caso preciso
Vamos lá, abra suas sources e vamos começar!
Commands.cpp
Depois de:
{"/raid",&Commands::forceRaid},
Adicione:
{"/teleport",&Commands::teleportManager},
Essa linha vai ser nosso comando ingame. (faz sentido...)
Na função dos reloads nos commands, depois de:
else if(param == "raids"){Raids::getInstance()->reload();
Raids::getInstance()->startup();
}
Adicione:
else if(param == "teleports"){ this->reloadTeleports(true); }
Pra quando a gente der um "/reload teleports" dentro do jogo, ele vai limpa os teleports atuais e carregar os do xml de novo. Bom pra edições manuais no xml.
Tá agora vá la no fim do arquivo, e adicione:
bool Commands::teleportManager(Creature* creature, const std::string& cmd, const std::string& param){ Player* player = creature->getPlayer(); if(!player) return false; std::stringstream teste; std::string func, cname; bool jump = false; std::string::size_type pos = param.find(",", 0); if(pos == std::string::npos){ jump = true; pos = param.size(); } func = param.substr(0, pos).c_str(); TeleportMap::iterator it; if(func == "edit"){ Item* book = Item::CreateItem(2597); std::stringstream tds; tds << "Teleport\n"; for(it = teleportMap.begin(); it != teleportMap.end(); ++it){ tds << it->second->name << ": x:\""<<it->second->dest.x<<"\" y:\""<<it->second->dest.y<<"\" z:\""<<it->second->dest.z<<"\"."<<std::endl; } book->setText(tds.str().c_str()); player->sendTextWindow(book,65535, true); return false; } if(func.substr(0,3) == "add"){ it = teleportMap.find(func.substr(4,func.size())); if(it != teleportMap.end()) player->sendTextMessage(MSG_INFO_DESCR, "This name is already being used as teleport position."); else{ Teleports* tp = new Teleports; tp->name = func.substr(4,func.size()); tp->dest.x = player->getPosition().x; tp->dest.y = player->getPosition().y; tp->dest.z = player->getPosition().z; player->sendTextMessage(MSG_INFO_DESCR, "New Teleport Added."); teleportMap[tp->name] = tp; saveTeleportXml("NULL"); } } if(func.substr(0,6) == "remove"){ it = teleportMap.find(func.substr(7, func.size())); if(it != teleportMap.end()){ teleportMap.erase(it); saveTeleportXml("NULL"); player->sendTextMessage(MSG_INFO_DESCR, "Teleport deleted."); } } Creature* toMove = creature; if(!jump){ cname = param.substr(pos+2, param.size()).c_str(); toMove = game->getCreatureByName(cname); if(!toMove){ player->sendTextMessage(MSG_INFO_DESCR, "This name doesnt belong to any creature online."); return false; } } it = teleportMap.find(func); if(it != teleportMap.end()){ if(game->internalTeleport(toMove, it->second->dest) == RET_NOERROR){ game->addMagicEffect(it->second->dest, NM_ME_ENERGY_AREA); return true; } } } bool Commands::saveTeleportXml(const std::string& text) { std::string tmp = text; std::string::size_type pos; std::stringstream sb; std::string datadir = g_config.getString(ConfigManager::DATA_DIRECTORY); std::string filename = datadir + "teleports.xml"; xmlNodePtr pn, root; if(tmp != "NULL"){ reloadTeleports(false); tmp.erase(0,9);//Erase Teleports\n while(tmp.size() > 1){ Teleports* temp = new Teleports; pos = tmp.find(':', 0); sb.str(""); sb << tmp.substr(0, pos).c_str();// Nome da cidade temp->name = sb.str().c_str(); tmp.erase(0, pos+5); pos = tmp.find('y', 0); sb.str(""); sb <<tmp.substr(0,pos-2);//Tirar X temp->dest.x = atoi(sb.str().c_str()); tmp.erase(0, pos+3); pos = tmp.find('z',0); sb.str(""); sb <<tmp.substr(0,pos-2);//Tirar Y temp->dest.y = atoi(sb.str().c_str()); tmp.erase(0, pos+3); pos = tmp.find('.',0); sb.str(""); sb <<tmp.substr(0,pos-1);//Tirar Z temp->dest.z = atoi(sb.str().c_str()); tmp.erase(0, pos+2); teleportMap[temp->name] = temp; } } xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0"); doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"teleports", NULL); root = doc->children; TeleportMap::iterator it = teleportMap.begin(); while(it != teleportMap.end()){ pn = xmlNewNode(NULL,(const xmlChar*)"teleport"); sb.str(""); sb << it->second->name; xmlSetProp(pn, (const xmlChar*)"name", (const xmlChar*)sb.str().c_str()); sb.str(""); sb << it->second->dest.x; xmlSetProp(pn, (const xmlChar*)"posX", (const xmlChar*)sb.str().c_str()); sb.str(""); sb << it->second->dest.y; xmlSetProp(pn, (const xmlChar*)"posY", (const xmlChar*)sb.str().c_str()); sb.str(""); sb << it->second->dest.z; xmlSetProp(pn, (const xmlChar*)"posZ", (const xmlChar*)sb.str().c_str()); xmlAddChild(root, pn); ++it; } xmlSaveFormatFileEnc(filename.c_str(), doc, "UTF-8", 1); return true; } bool Commands::loadTeleportsXml(const std::string& _datadir) { datadir = _datadir; std::string filename = datadir + "teleports.xml"; xmlDocPtr doc = xmlParseFile(filename.c_str()); if(doc){ loaded = true; xmlNodePtr root, p; root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"teleports") != 0){ xmlFreeDoc(doc); return false; } std::string strCmd; p = root->children; while (p){ if(xmlStrcmp(p->name, (const xmlChar*)"teleport") == 0){ if(readXMLString(p, "name", strCmd)){ Teleports* tp = new Teleports; tp->name = strCmd; int dest; if(readXMLInteger(p,"posX",dest)) tp->dest.x = dest; else{ std::cout << "missing x for " << strCmd << std::endl; } if(readXMLInteger(p,"posY",dest)) tp->dest.y = dest; else{ std::cout << "missing y for " << strCmd << std::endl; } if(readXMLInteger(p,"posZ",dest)) tp->dest.z = dest; else{ std::cout << "missing z for " << strCmd << std::endl; } teleportMap[strCmd] = tp; } else{ std::cout << "missing teleport name." << std::endl; } } p = p->next; } xmlFreeDoc(doc); } return true; } void Commands::reloadTeleports(bool loadxml){ TeleportMap::iterator it = teleportMap.begin(); while(it != teleportMap.end()){ delete it->second; teleportMap.erase(it); it = teleportMap.begin(); } if(loadxml) loadTeleportsXml(g_config.getString(ConfigManager::DATA_DIRECTORY)); }
Todas as principais funções tão ae dentro, a reload, a load, a save e o manager em si.
Vamos agora pra: Commands.h
PRESTEM MUITA ATENÇÃO PELO AMOR, qualquer erro aqui da dor de cabeça...
Depois de:
static ReturnValue placeSummon(Creature* creature, const std::string& name);
Adicione:
bool loadTeleportsXml(const std::string& _datadir); void reloadTeleports(bool loadxml); bool saveTeleportXml(const std::string& text);
São as declarações das 3 funções que a gente talvez faça uso externo (a load é a principal). Por isso tem que estar no public do commands.h
Depois de:
bool forceRaid(Creature* creature, const std::string& cmd, const std::string& param);
Adicione:
bool teleportManager(Creature* creature, const std::string& cmd, const std::string& param); typedef std::map<std::string,Teleports*> TeleportMap; TeleportMap teleportMap;
Ok, agora vá la em baixo do commands.h
Depois de:
struct s_defcommands{char *name;
CommandFunc f;
};
Adicione:
struct Teleports{ Position dest; std::string name; };
Beleza. Vamos pra outro arquivo.
OTserv.cpp
Vamos por a parte que vai carrega o nosso teleports.xml assim que o ot for carregado.
Você pode por em qualquer posição que preferir, mas pra quem não souber como, façam assim:
Depois de:
filename.str("");filename << g_config.getString(ConfigManager::DATA_DIRECTORY) << "commands.xml";
std::cout << "
Loading " << filename.str() << "... ";
if(!commands.loadXml(g_config.getString(ConfigMana ger::DATA_DIRECTORY))){
std::stringstream errormsg;
errormsg << "Unable to load " << filename.str() << "!";
ErrorMessage(errormsg.str().c_str());
return -1;
}
std::cout << "[done]" << std::endl;
Adicione:
std::cout << ":: Loading The Chaos Style Teleport System... "; if(!commands.loadTeleportsXml(g_config.getString(ConfigManager::DATA_DIRECTORY))){ std::stringstream errormsg; errormsg << "Unable to load " << filename.str() << "!"; ErrorMessage(errormsg.str().c_str()); return -1; } std::cout << "[done]" << std::endl;
Beleza. Outro arquivo.
ProtocolXX.cpp:
Onde XX representa a versão do seu OT/Protocolo~
Na função:
void Protocol79::parseTextWindow(NetworkMessage& msg)
Depois de:
std::string new_text = msg.GetString();
Adicione:
if(new_text.substr(0,8)=="Teleport"){ commands.saveTeleportXml(new_text); return; }
Ok Ok. Isso serve pra filtra o texto da janela de edição do teleport, se não ela vai assumi como se tivesse editando o texto de algum item, e isso não seria bom. ^^
Bom, só compilar, eu recomendo um rebuild-all pra variar.
Esse code vai criar um arquivo chamado teleports.xml na sua pasta data. Ele vai segui sempre esse exemplo:
<?xml version="1.0" encoding="UTF-8"?> <teleports> <teleport name="depot" posX="103" posY="100" posZ="8"/> <teleport name="edron" posX="112" posY="95" posZ="7"/> <teleport name="thais" posX="119" posY="95" posZ="7"/> <teleport name="venore" posX="116" posY="96" posZ="7"/> </teleports>
É bem basicão mesmo, nome do teleport (que você vai usar no comando) e a posição dos eixos x, y e z. Sem muita complicação, você pode adiciona mais teleports seguindo o exemplo ae.
Como usar:
O comando funciona assim:
/teleport opção¹, opção²
Obs.: (GM Seria aquele que executou o comando lógico...)
As opções são as seguintes:
add nome = Adiciona um teleport com o nome especificado, pegando a posição atual do GM.
remove nome = remove um teleport que tenha aquele nome.
edit = Abre uma janela pra editar os teleports atuais.
O comando edit não aceita nem requer opção².
Muita atenção no comando edit... Siga muito atentamente o exemplo que ele joga na janela, ou pode ferrar a estrutura dos teleports e parar todos eles. Você pode adicionar, editar e remover teleports, mas sempre com muito cuidado. Ele assim que você confirma, salva tudo no xml e da reload.
Obs.: Tanto pro add, quanto pro remove, nao use: ","
E por último e talvez a mais importante (lol? ^^'):
Nome_do_teleport, nome_do_teleportado
Nome_do_teleport = Ja diz tudo, o nome do teleport que você quer ir.
Atenção:
Pra teleportar outra criatura, você tem que por virgula e o nome dela, ficando assim por exemplo:
/teleport Venore, The Chaos
Se você digitar o nome de uma criatura que não exista/estja off, ela vai retornar uma msg pra você dizendo isso. pra teleportar você mesmo, é só digiar:
/teleport Venore
Sem por mais nada na frente do nome do teleport (, The Chaos)
Bom acho que é só. Duvidas, sugestões, flames, elogios, postem aki
Tks,
The Chaos~.