intereçante, eu não vou usar, mais gostei do script e é bem criativo, parabéns •
- Fórum
- OTServ
- Recursos
- Linguagens de Programação
- Salvar Mapa In Game
info
Grupo: Campones
Registrado: 09/08/10
Posts: 71
Reputação: +2
Char no Tibia: Eduardo of Honera

info
Grupo: Campones
Registrado: 03/12/07
Posts: 76
Reputação: +8
Char no Tibia: So Logo Para Mata

poho mano meu repe não teste mais veleu por compartilha com o xtibia velho isso vai ser utill para muitos ![]()
info
Grupo: Artesão
Registrado: 09/12/10
Posts: 138
Reputação: +23
Char no Tibia: Loh Pabllitooh

olha bem legal vc se vc criar um auto boarder da pra fazer um sistema de contruçao de casas muit limdo com telhado e tudo
info
Grupo: Barão
Registrado: 18/06/11
Posts: 230
Reputação: +32
Char no Tibia: Louco Do Gole

é intereçante de botar num server.
Mais como to sem server num momento entao vo ficar sem usar mais parabens
info
Grupo: Campones
Registrado: 11/05/08
Posts: 21
Reputação: +3
Char no Tibia: Admin Necrox

Legal, não sabia que era possivel de se fazer isso.
Bem útil para alguns, Parabéns pela criatividade. se o script for seu!
Tá salvando towns agora
info
Grupo: Herói
Registrado: 17/02/08
Posts: 2.5k
Reputação: +193

Isso sem dúvidas abre uma porção de possibilidades pra quem é dono, tanto quanto para o jogador. Ótimo código!
Parabéns ![]()
Abraços.
info
Grupo: Visconde
Registrado: 07/08/11
Posts: 301
Reputação: +70

Editar mapas in game? Para isso e mto fino, script ainda por Capaverde.
Muito bom para corrigir bugs do mapa in game.
Eis a função equivalente, puramente em Lua. Coloque-a no seu global.lua:
bit32 = bit print = debugPrint --SPECIAL CHARACTERS NODE_START = 0xfe NODE_END = 0xff ESCAPE_CHAR = 0xfd --OTBM NODE TYPES OTBM_ROOTV1 = 1 OTBM_MAP_DATA = 2 OTBM_ITEM_DEF = 3 OTBM_TILE_AREA = 4 OTBM_TILE = 5 OTBM_ITEM = 6 OTBM_TILE_SQUARE = 7 OTBM_TILE_REF = 8 OTBM_SPAWNS = 9 OTBM_SPAWN_AREA = 10 OTBM_MONSTER = 11 OTBM_TOWNS = 12 OTBM_TOWN = 13 OTBM_HOUSETILE = 14 --OTBM ATTR TYPES OTBM_ATTR_DESCRIPTION = 1 OTBM_ATTR_EXT_FILE = 2 OTBM_ATTR_TILE_FLAGS = 3 OTBM_ATTR_ACTION_ID = 4 OTBM_ATTR_UNIQUE_ID = 5 OTBM_ATTR_TEXT = 6 OTBM_ATTR_DESC = 7 OTBM_ATTR_TELE_DEST = 8 OTBM_ATTR_ITEM = 9 OTBM_ATTR_DEPOT_ID = 10 OTBM_ATTR_EXT_SPAWN_FILE = 11 OTBM_ATTR_RUNE_CHARGES = 12 OTBM_ATTR_EXT_HOUSE_FILE = 13 OTBM_ATTR_HOUSEDOORID = 14 OTBM_ATTR_COUNT = 15 OTBM_ATTR_DURATION = 16 OTBM_ATTR_DECAYING_STATE = 17 OTBM_ATTR_WRITTENDATE = 18 OTBM_ATTR_WRITTENBY = 19 OTBM_ATTR_SLEEPERGUID = 20 OTBM_ATTR_SLEEPSTART = 21 OTBM_ATTR_CHARGES = 22 function lchar(i) s="" while i>0 do s=s..string.char(i%256) i=math.floor(i/256) end return s end function format(s,size) local len = #s for x=1,size/8-len do s=s.."\0" end return s end function writeData(f,data,size,unescape) local thestr if type(data) == "string" then thestr = format(data,size) elseif type(data) == "number" then thestr = format(lchar(data),size) elseif type(data) == "table" then for k,v in pairs(data) do print(k,v) end return else print(data) return end for x=1,size/8 do local c = thestr:sub(x,x) --print(#thestr,size,string.byte(c)) --if c == string.char(0x0D) then error("daonde") end if unescape and (c==string.char(NODE_START) or c==string.char(NODE_END) or c==string.char(ESCAPE_CHAR)) then f:write(string.char(ESCAPE_CHAR)) end f:write(c) end end function addU8(f,data) writeData(f,data,8,true) end function addByte(f,data) writeData(f,data,8,false) end function addU16(f,data) writeData(f,data,16,true) end function addU32(f,data) writeData(f,data,32,false) end function addString(f,data) if #data > 0xffff then return false end addU16(f,#data) writeData(f,data,#data*8,false) end function startNode(f,c) --c is a char writeData(f,NODE_START,8,false) writeData(f,c,8,true) end function endNode(f) writeData(f,NODE_END,8,false) end WIDTH = 128 --put here the dimensions of your map HEIGHT = 128 -- ITEMDWMAJORVERSION = 2 ITEMDWMINORVERSION = 8 function saveMap(name) --e.g. "map.otbm" local minv = math.huge local maxv = 0 print("saveMap start") f = io.open(name,"wb") addU32(f,0); --version startNode(f,0) addU32(f,0); --version again :O addU16(f,WIDTH) addU16(f,HEIGHT) addU32(f,ITEMDWMAJORVERSION) addU32(f,ITEMDWMINORVERSION) startNode(f,OTBM_MAP_DATA) --addByte(f,OTBM_ATTR_DESCRIPTION) --addString(f,"Created with saveMap script, a translation of Remere's") local first = true local l_x=-1 local l_y=-1 local l_Z=-1 for z=0,7 do for xi=0,WIDTH-1,256 do for yi=0,HEIGHT-1,256 do for x=xi,math.min(xi+256-1,WIDTH-1) do for y=yi,math.min(yi+256-1,HEIGHT-1) do if x<l_x or x>=l_x+256 or y<l_y or y>=l_y+256 or z~=l_z then if not first then endNode(f) end first = false --start new node startNode(f,OTBM_TILE_AREA) l_x=bit32.band(x,0xff00) l_y=bit32.band(y,0xff00) l_z=z addU16(f,l_x) addU16(f,l_y) addU8(f,l_z) end startNode(f,OTBM_TILE) addU8(f,bit32.band(x,0xff)) addU8(f,bit32.band(y,0xff)) for stackpos=0,10 do local pos = {x=x,y=y,z=z,stackpos=stackpos} local thing = getTileThingByPos(pos) if (thing.itemid==0 and stackpos==0) then --no tile, so we can skip it break end if thing.itemid > 0 and stackpos ~= 253 then --TODO: save item counts, save containers addByte(f,OTBM_ATTR_ITEM) addU16(f,thing.itemid) end end endNode(f) end end end end end if not first then endNode(f) end endNode(f) endNode(f) f:close() print(minv,maxv) end
Dessa forma não precisa-se editar uma linha do source ou recompilar
info
Grupo: Infante
Registrado: 22/12/12
Posts: 2k
Reputação: +736
Gênero: Masculino
Char no Tibia: Marley

info
Grupo: Visconde
Registrado: 21/05/13
Posts: 303
Reputação: +25

Em 28/10/2017 em 05:36, Capaverde disse:Eis a função equivalente, puramente em Lua. Coloque-a no seu global.lua:
bit32 = bit print = debugPrint --SPECIAL CHARACTERS NODE_START = 0xfe NODE_END = 0xff ESCAPE_CHAR = 0xfd --OTBM NODE TYPES OTBM_ROOTV1 = 1 OTBM_MAP_DATA = 2 OTBM_ITEM_DEF = 3 OTBM_TILE_AREA = 4 OTBM_TILE = 5 OTBM_ITEM = 6 OTBM_TILE_SQUARE = 7 OTBM_TILE_REF = 8 OTBM_SPAWNS = 9 OTBM_SPAWN_AREA = 10 OTBM_MONSTER = 11 OTBM_TOWNS = 12 OTBM_TOWN = 13 OTBM_HOUSETILE = 14 --OTBM ATTR TYPES OTBM_ATTR_DESCRIPTION = 1 OTBM_ATTR_EXT_FILE = 2 OTBM_ATTR_TILE_FLAGS = 3 OTBM_ATTR_ACTION_ID = 4 OTBM_ATTR_UNIQUE_ID = 5 OTBM_ATTR_TEXT = 6 OTBM_ATTR_DESC = 7 OTBM_ATTR_TELE_DEST = 8 OTBM_ATTR_ITEM = 9 OTBM_ATTR_DEPOT_ID = 10 OTBM_ATTR_EXT_SPAWN_FILE = 11 OTBM_ATTR_RUNE_CHARGES = 12 OTBM_ATTR_EXT_HOUSE_FILE = 13 OTBM_ATTR_HOUSEDOORID = 14 OTBM_ATTR_COUNT = 15 OTBM_ATTR_DURATION = 16 OTBM_ATTR_DECAYING_STATE = 17 OTBM_ATTR_WRITTENDATE = 18 OTBM_ATTR_WRITTENBY = 19 OTBM_ATTR_SLEEPERGUID = 20 OTBM_ATTR_SLEEPSTART = 21 OTBM_ATTR_CHARGES = 22 function lchar(i) s="" while i>0 do s=s..string.char(i%256) i=math.floor(i/256) end return s end function format(s,size) local len = #s for x=1,size/8-len do s=s.."\0" end return s end function writeData(f,data,size,unescape) local thestr if type(data) == "string" then thestr = format(data,size) elseif type(data) == "number" then thestr = format(lchar(data),size) elseif type(data) == "table" then for k,v in pairs(data) do print(k,v) end return else print(data) return end for x=1,size/8 do local c = thestr:sub(x,x) --print(#thestr,size,string.byte(c)) --if c == string.char(0x0D) then error("daonde") end if unescape and (c==string.char(NODE_START) or c==string.char(NODE_END) or c==string.char(ESCAPE_CHAR)) then f:write(string.char(ESCAPE_CHAR)) end f:write(c) end end function addU8(f,data) writeData(f,data,8,true) end function addByte(f,data) writeData(f,data,8,false) end function addU16(f,data) writeData(f,data,16,true) end function addU32(f,data) writeData(f,data,32,false) end function addString(f,data) if #data > 0xffff then return false end addU16(f,#data) writeData(f,data,#data*8,false) end function startNode(f,c) --c is a char writeData(f,NODE_START,8,false) writeData(f,c,8,true) end function endNode(f) writeData(f,NODE_END,8,false) end WIDTH = 128 --put here the dimensions of your map HEIGHT = 128 -- ITEMDWMAJORVERSION = 2 ITEMDWMINORVERSION = 8 function saveMap(name) --e.g. "map.otbm" local minv = math.huge local maxv = 0 print("saveMap start") f = io.open(name,"wb") addU32(f,0); --version startNode(f,0) addU32(f,0); --version again :O addU16(f,WIDTH) addU16(f,HEIGHT) addU32(f,ITEMDWMAJORVERSION) addU32(f,ITEMDWMINORVERSION) startNode(f,OTBM_MAP_DATA) --addByte(f,OTBM_ATTR_DESCRIPTION) --addString(f,"Created with saveMap script, a translation of Remere's") local first = true local l_x=-1 local l_y=-1 local l_Z=-1 for z=0,7 do for xi=0,WIDTH-1,256 do for yi=0,HEIGHT-1,256 do for x=xi,math.min(xi+256-1,WIDTH-1) do for y=yi,math.min(yi+256-1,HEIGHT-1) do if x<l_x or x>=l_x+256 or y<l_y or y>=l_y+256 or z~=l_z then if not first then endNode(f) end first = false --start new node startNode(f,OTBM_TILE_AREA) l_x=bit32.band(x,0xff00) l_y=bit32.band(y,0xff00) l_z=z addU16(f,l_x) addU16(f,l_y) addU8(f,l_z) end startNode(f,OTBM_TILE) addU8(f,bit32.band(x,0xff)) addU8(f,bit32.band(y,0xff)) for stackpos=0,10 do local pos = {x=x,y=y,z=z,stackpos=stackpos} local thing = getTileThingByPos(pos) if (thing.itemid==0 and stackpos==0) then --no tile, so we can skip it break end if thing.itemid > 0 and stackpos ~= 253 then --TODO: save item counts, save containers addByte(f,OTBM_ATTR_ITEM) addU16(f,thing.itemid) end end endNode(f) end end end end end if not first then endNode(f) end endNode(f) endNode(f) f:close() print(minv,maxv) end
Dessa forma não precisa-se editar uma linha do source ou recompilar
sera que alguem pode dar uma ajudinha explicando como eu instalo e uso isso?






info
Grupo: Campones
Registrado: 21/08/06
Posts: 12
Reputação: +5
Gênero: Masculino
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:
luascript.cpp, dentro de registerFunctions():
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();:
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:
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:
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.
Editado Outubro 10 por Capaverde