-
Total de itens
12 -
Registro em
-
Última visita
Posts postados por Capaverde
-
-
O projeto não é um OTServer, mas um jogo independente inspirado em Tibia
Demo:
Está usando placeholders e seria bom um redraw de quase todos os sprites, para ficar com um estilo próprio.
O código é em javascript e utiliza NW.js para gerar o executável. Ele será open-source no futuro.
Para o mapa, estou terminando uma ferramenta para mappear semelhante aos OTBM editor, inspirada no editor Tiled. Essa ferramenta também será open-source. O mapa será um de 'MOBA', com uma base para cada time dar respawn, um castelo medieval ou outro tipo de construção.
Como é um projeto independente do cliente de Tibia, novos items podem ser criados à requisição do mapper ou do designer.
Interessados postem aqui ou me contatem por mensagem particular.
-
O prob é que ele usa uma variável global pra armazenar a posição, aí se tiver mais de um player com ring of the skies um vai sobreescrever o outro.
Eu corrigi isso usando doSetItemText e getItemText
-
Tá salvando towns agora
-
Fiz isso com a idéia de permitir aos players construir casas no meio do mato e salvar essas casas e tal
Não consegui fazer salvar towns ainda (temple positions), daí você teria que editar o otbm e adicionar elas depois
Como eu fiz? Peguei o saveMap do remere (que é open source) e modifiquei um pouco, adaptando ao que o otserver tem.
Testei e funcionou em theforgottenserver 0.2rc9
Bom, vamos ao código
luascript.h:
static int32_t luaSaveMap(lua_State* L);
luascript.cpp, dentro de registerFunctions():
//saveMap() lua_register(m_luaState, "saveMap", LuaScriptInterface::luaSaveMap);
luascript.cpp:
int32_t LuaScriptInterface::luaSaveMap(lua_State* L) { //saveMap() g_game.saveMapzord(); }
game.h(public):
void saveMapzord(){map->saveMapzord();}
map.h, embaixo de bool saveMap();:
bool saveMapzord();
map.cpp:
bool Map::saveMapzord() { IOMap* loader = new IOMap(); bool saved = false; for(uint32_t tries = 0; tries < 3; tries++) { if(loader->saveMap(this, "eai.otbm", false)) { saved = true; break; } } return saved; }
iomap.h:
bool saveMap(Map* map, const std::string& identifier, bool showdialog);
iomap.cpp:
bool IOMap::saveMap(Map* map, const std::string& identifier, bool showdialog) { /* STOP! * Before you even think about modifying this, please reconsider. * while adding stuff to the binary format may be "cool", you'll * inevitably make it incompatible with any future releases of * the map editor, meaning you cannot reuse your map. Before you * try to modify this, PLEASE consider using an external file * like spawns.xml or houses.xml, as that will be MUCH easier * to port to newer versions of the editor than a custom binary * format. */ /*if(Items::dwMajorVersion < 3) { version = 0; } else { version = 1; }*/ FileLoader f; f.openFile(identifier.c_str(), true, false); f.startNode(0); { f.addU32(0); // Version f.addU16((uint16_t)map->mapWidth); f.addU16((uint16_t)map->mapHeight); f.addU32(Items::dwMajorVersion); f.addU32(Items::dwMinorVersion); f.startNode(OTBM_MAP_DATA); { f.addByte(OTBM_ATTR_DESCRIPTION); // Neither SimOne's nor OpenTibia cares for additional description tags f.addString("Saved with Remere's Map Editor "); f.addU8(OTBM_ATTR_DESCRIPTION); f.addString("Esse mapa é maneiro."); /*f.addU8(OTBM_ATTR_EXT_SPAWN_FILE); FileName fn(wxstr(map->spawnfile)); f.addString(std::string((const char*)fn.GetFullName().mb_str(wxConvUTF8))); if(gui.GetCurrentVersion() > CLIENT_VERSION_760) { f.addU8(OTBM_ATTR_EXT_HOUSE_FILE); fn.Assign(wxstr(map->housefile)); f.addString(std::string((const char*)fn.GetFullName().mb_str(wxConvUTF8))); }*/ // Start writing tiles //uint64_t tiles_saved = 0; bool first = true; int local_x = -1, local_y = -1, local_z = -1; for (uint64_t z=0; z<=15; ++z) for (uint64_t xi = 0; xi<map->mapWidth; xi+=256) for (uint64_t yi = 0; yi<map->mapHeight; yi+=256) for (uint64_t x = xi; x<xi+256; x++) for (uint64_t y = yi; y<yi+256; y++){ //MapIterator map_iterator = map.begin(); //while(map_iterator != map.end()) { // Update progressbar //++tiles_saved; //if(showdialog && tiles_saved % 8192 == 0) { //gui.SetLoadDone(int(tiles_saved / double(map.getTileCount()) * 100.0)); //} // Get tile Tile* save_tile = map->getTile(x,y,z); //Tile* save_tile = *map_iterator; if (!save_tile) continue; const Position& pos = save_tile->getPosition(); /*// Is it an empty tile that we can skip? (Leftovers...) if(save_tile->size() == 0) { ++map_iterator; continue; }*/ // Decide if new node should be created if(pos.x < local_x || pos.x >= local_x + 256 || pos.y < local_y || pos.y >= local_y + 256 || pos.z != local_z) { // End last node if(!first) { f.endNode(); } first = false; // Start new node f.startNode(OTBM_TILE_AREA); f.addU16(local_x = pos.x & 0xFF00); f.addU16(local_y = pos.y & 0xFF00); f.addU8( local_z = pos.z); } //HouseTile* houseTile = dynamic_cast<HouseTile*>(save_tile); f.startNode(/*houseTile? OTBM_HOUSETILE : */OTBM_TILE); f.addU8(pos.x & 0xFF); f.addU8(pos.y & 0xFF); /*if(houseTile) { f.addU32(houseTile->getHouse()->getHouseId()); }*/ /*if(save_tile->getMapFlags()) { f.addByte(OTBM_ATTR_TILE_FLAGS); f.addU32(save_tile->getMapFlags()); }*/ if(save_tile->ground) { Item* ground = save_tile->ground; /*if(ground->hasBorderEquivalent()) { bool found = false; for(ItemVector::iterator it = save_tile->items.begin(); it != save_tile->items.end(); ++it) { if((*it)->getGroundEquivalent() == ground->getID()) { // Do nothing // Found equivalent found = true; break; } } if(found == false) { ground->serializeItemNode_OTBM(*this, f); } } else*/ if(ground->isComplex()) { ground->serializeItemNode_OTBM(f); } else { f.addByte(OTBM_ATTR_ITEM); ground->serializeItemCompact_OTBM(f); } } for(ItemVector::reverse_iterator it = save_tile->downItems.rbegin(); it != save_tile->downItems.rend(); ++it) { //if(!(*it)->isMetaItem()) { (*it)->serializeItemNode_OTBM(f); //} } for(ItemVector::iterator it = save_tile->topItems.begin(); it != save_tile->topItems.end(); ++it) { //if(!(*it)->isMetaItem()) { (*it)->serializeItemNode_OTBM(f); //} } f.endNode(); //++map_iterator; } // Only close the last node if one has actually been created if(!first) { f.endNode(); } f.startNode(OTBM_TOWNS); { //for(TownMap::const_iterator it = townMap.begin(); it != townMap.end(); ++it) { for(TownMap::const_iterator it = Towns::getInstance().getFirstTown(); it != Towns::getInstance().getLastTown(); ++it){ Town* town = it->second; f.startNode(OTBM_TOWN); f.addU32(town->getTownID()); f.addString(town->getName()); f.addU16(town->getTemplePosition().x); f.addU16(town->getTemplePosition().y); f.addU8 (town->getTemplePosition().z); f.endNode(); } } f.endNode(); } f.endNode(); //std::cout << tiles_saved << std::endl; } f.endNode(); /*if(showdialog) gui.SetLoadDone(100, wxT("Saving spawns...")); saveSpawns(map, identifier); if(gui.GetCurrentVersion() > CLIENT_VERSION_760) { if(showdialog) gui.SetLoadDone(100, wxT("Saving houses...")); saveHouses(map, identifier); }*/ return true; }
item.h, public da class Item:
//map-saving virtual bool serializeItemNode_OTBM(FileLoader& f) const; // Will write this item to the stream supplied in the argument virtual void serializeItemCompact_OTBM(FileLoader& f) const; virtual void serializeItemAttributes_OTBM(FileLoader& f) const;
item.h, public da class ItemAttributes:
virtual bool isComplex() const {return (15 & m_attributes) != 0;}
item.cpp:
bool Item::serializeItemNode_OTBM(FileLoader& f) const { f.startNode(OTBM_ITEM); f.addU16(id); //if(maphandle.version == 0) { /*const ItemType& iType = items[id]; if(iType.stackable || iType.isSplash() || iType.isFluidContainer()){ f.addU8(getSubType()); }*/ //} serializeItemAttributes_OTBM(f); f.endNode(); return true; } void Item::serializeItemAttributes_OTBM(FileLoader& stream) const { //if(maphandle.version > 0) { const ItemType& iType = items[id]; if(iType.stackable || iType.isSplash() || iType.isFluidContainer()){ //stream.addU8(OTBM_ATTR_COUNT); stream.addU8(getItemCountOrSubtype()); } //}*/ /* if(items.dwMinorVersion >= CLIENT_VERSION_820 && isCharged()) { stream.addU8(OTBM_ATTR_CHARGES); stream.addU16(getSubtype()); }*/ if(getActionId()) { stream.addU8(OTBM_ATTR_ACTION_ID); stream.addU16(getActionId()); } if(getUniqueId()) { stream.addU8(OTBM_ATTR_UNIQUE_ID); stream.addU16(getUniqueId()); } if(getText().length() > 0) { stream.addU8(OTBM_ATTR_TEXT); stream.addString(getText()); } if(getSpecialDescription().length() > 0) { stream.addU8(OTBM_ATTR_DESC); stream.addString(getSpecialDescription()); } } void Item::serializeItemCompact_OTBM(FileLoader& stream) const { stream.addU16(id); /* This is impossible const ItemType& iType = item_db[id]; if(iType.stackable || iType.isSplash() || iType.isFluidContainer()){ stream.addU8(getSubtype()); } */ }
fileloader.cpp:
troca as funções addU8 e addU16 por essas(ou o mapa gerado vai tá corrompido, aconteceu comigo):
bool FileLoader::addU8(uint8_t u8) { writeData(&u8, sizeof(u8), true); //unescape=true, or else some FEsomething itemid might be recognized as the start of a node return m_lastError == ERROR_NONE; } bool FileLoader::addU16(uint16_t u16) { writeData(reinterpret_cast<uint8_t*>(&u16), sizeof(u16), true); return m_lastError == ERROR_NONE; }
Como usa isso? Só colocar saveMap() em algum script, mas olha que vai lagar.
Dá pra facilmente criar um npc que salva o mapa de x em x horas, e se você for reiniciar o server por algum motivo é só kickar todo mundo e usar uma talkaction que salve.
-
te teleporta de volta pro lugar que voce salvou
-
-
descubra as funções que existem no seu global environment ingame, com essa action legal
local function sittable(k,v) table.insert(tabela,{k,v}) end local function sorttable(a,b) return string.byte(a[1],1) < string.byte(b[1],1) end function onUse(cid, item, frompos, item2, topos) tabela = {} table.foreach(_G,sittable) table.sort(tabela,sorttable) for k,v in ipairs(tabela) do if type(v[2]) == "function" then doPlayerSendTextMessage(cid,22,v[1]) end end return 1 end
se quiser ver as tables só substitua essa linha:
if type(v[2]) == "function" then
por
if type(v[2]) == "table" then
a mesma coisa para ver number, strings e threads
if type(v[2]) == "number" then -- number if type(v[2]) == "string" then -- string if type(v[2]) == "thread" then -- thread
espero q achem rox
~Capaverde
-
mas daih o cara ia ter q ficar tirando e colocando o ring
eh mais facil soh dar use
-
function onUse(cid, item, frompos, item2, topos) text = getItemText(item.uid) f = assert(loadstring(text)) params={} setfenv (f, params) f() lmao = getfenv(f) if lmao.teleport == 1 then doTeleportThing(cid, {x=lmao.x, y=lmao.y, z=lmao.z}, 0) doSetItemText(item.uid,"teleport=0") else mpos = getThingPos(item.uid) newtext = table.concat({"x=",mpos.x,"y=",mpos.y,"z=",mpos.z,"teleport=1"}," ") doSetItemText(item.uid,newtext) end end
A principal diferença é que agora o ring grava a posição do item no item, com doSetItemText, e não mais com uma variável global, que tornava o ring instável quando várias pessoas o usavam ao mesmo tempo.
Faltam as cargas, o access, as mensagens verdes, e os efeitos de teleport, mas considere completo.
postando aqui porque o pessoal da [Retirado] é boiola e não aprovou meu topico
-
Esse é um code pra 7.9 100% by me
Primeiro, vá em data\movements\scripts
Crie um arquivo de nome scarab coin.lua com o seguinte conteúdo:
function onAddItem(moveitem, tileitem, pos)beforepos = {x=1085,y=1171,z=9,stackpos=253}
before = getThingfromPos(beforepos)
telepos = {x=1083,y=1171,z=9}
apos = {x=1085,y=1170,z=9}
if moveitem.itemid == 2159 then
if pos.x == apos.x and pos.y == apos.y and pos.z == apos.z then
if before.itemid > 0 then
doTeleportThing(before.uid,telepos)
doSendMagicEffect(beforepos,12)
doSendMagicEffect(telepos,10)
doSendMagicEffect(pos,15)
doRemoveItem(moveitem.uid,moveitem.type)
else
doSendMagicEffect(pos,15)
doRemoveItem(moveitem.uid,moveitem.type)
end
end
end
return 1
end
Legendas:
Posição do fogo azul (deixe a stackpos como está)
Posição para onde o player vai ser teleportado
Posição do coal basin
Agora, abra o movements.xml e adicione a tag
<movevent event="AddItem" itemid="2159" script="scarab coin.lua" />
rode seu ot e se divirta
~Capaverde
-
Que vergonha!
Esses codes tão bugados e não vão funcionar.
Fiz uma listinha dos erros:
tablepos = {x=posx, y=posy, z=posz, stackpos=253}- a stackpos tah errada, o certo seria 255, pq 253 soh retorna criaturas.
- isso na verdade não chega a ser um erro, mas é desnecessário, a função de teleportar nao necessita que seja especificada a stackpos, o certo serianewplayerpos = x=posx, y=posy, z=posz, stackpos=253}newplayerpos = {x=posx, y=posy, z=posz}
(faltou o abrir chaves tb)
Aí se tiver o tal item encima da mesa a alavanca virada pra direita vai se transformar numa alavanca virada pra esquerda e o player vai ser teleportado, até ai ok, mas se o tal item não tiver encima da mesa a alavanca virada pra direita vai se transformar num green fungi, se der use no green fungi ele vai se transformar no item abaixo dele, e assim vai.if tableitem.itemid == <id do item> thendoTransformItem(item.uid,item.itemid+1)
doTeleportThing(cid,newplayerpos)
else
doTransformItem(item.uid,item.itemid-1)
end
Pra corrigir esse erro coloque algo do tipo:
if tableitem.itemid == <id do item> then if item.itemid == 1945 then doTransformItem(item.uid,item.itemid+1) doTeleportThing(cid,newplayerpos) else doTransformItem(item.uid,item.itemid-1) end elseif tableitem.itemid ~= <id do item> then if item.itemid == 1945 then doTransformItem(item.uid,item.itemid+1) else doTransformItem(item.uid,item.itemid-1) end end
- denovo, a stackpos é desnecessária.bosspos = {x=posx, y=posy, z=posz, stackpos=253}e o alavboss tah estranho, acho q pra fazer o q vc quer o melhor é deixar:
function onUse(cid, item, frompos, item2, topos) a1pos = {x=posx, y=posy, z=posz} --tem q mudar o posx, posy e posz pra onde a alavanca 1 vai teleportar a2pos = {x=posx, y=posy, z=posz} --tem q mudar o posx, posy e posz pra onde a alavanca 2 vai teleportar a3pos = {x=posx, y=posy, z=posz} --tem q mudar o posx, posy e posz pra onde a alavanca 3 vai teleportar if item.itemid == 1945 and item.uid == 5002 then doTransformItem(item.uid,item.itemid+1) doTeleportThing(cid,a1pos) elseif item.itemid == 1945 and item.uid == 5003 then doTransformItem(item.uid,item.itemid+1) doTeleportThing(cid,a2pos) elseif item.itemid == 1945 and item.uid == 5004 then doTransformItem(item.uid,item.itemid+1) doTeleportThing(cid,a3pos) else doTransformItem(item.uid,item.itemid-1) end return 1 end
é isso, espero que vc aprenda a não postar codes sem antes testá-los e ter certeza de que eles estão funcionando.
~Capaverde
-
Quem Está Navegando 0 membros estão online
- Nenhum usuário registrado visualizando esta página.
Salvar Mapa In Game
em Linguagens de Programação
Postado
Eis a função equivalente, puramente em Lua. Coloque-a no seu global.lua:
Dessa forma não precisa-se editar uma linha do source ou recompilar