Attr_ReadValue Teleport::readAttr(AttrTypes_t attr, PropStream& propStream) { if(attr != ATTR_TELE_DEST) return Item::readAttr(attr, propStream); TeleportDest* dest; if(!propStream.GET_STRUCT(dest)) return ATTR_READ_ERROR; setDestination(Position(dest->_x, dest->_y, dest->_z)); return ATTR_READ_CONTINUE; }
Attr_ReadValue Teleport::readAttr(AttrTypes_t attr, PropStream& propStream) { if (ATTR_TELE_DEST == attr) { TeleportDest* tele_dest; if (!propStream.GET_STRUCT(tele_dest)) { return ATTR_READ_ERROR; } setDestPos(Position(tele_dest->_x, tele_dest->_y, tele_dest->_z)); return ATTR_READ_CONTINUE; } else { return Item::readAttr(attr, propStream); } }
bool IOMap::loadMap(Map* map, const std::string& identifier) { FileLoader f; if(!f.openFile(identifier.c_str(), false, true)) { std::stringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } uint32_t type = 0; NODE root = f.getChildNode((NODE)NULL, type); PropStream propStream; if(!f.getProps(root, propStream)) { setLastErrorString("Could not read root property."); return false; } OTBM_root_header* rootHeader; if(!propStream.GET_STRUCT(rootHeader)) { setLastErrorString("Could not read header."); return false; } uint32_t headerVersion = rootHeader->version; if(headerVersion <= 0) { //In otbm version 1 the count variable after splashes/fluidcontainers and stackables //are saved as attributes instead, this solves alot of problems with items //that is changed (stackable/charges/fluidcontainer/splash) during an update. setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerVersion > 2) { setLastErrorString("Unknown OTBM version detected."); return false; } uint32_t headerMajorItems = rootHeader->majorVersionItems; if(headerMajorItems < 3) { setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerMajorItems > (uint32_t)Items::dwMajorVersion) { setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } uint32_t headerMinorItems = rootHeader->minorVersionItems; if(headerMinorItems < CLIENT_VERSION_810) { setLastErrorString("This map needs an updated items.otb."); return false; } if(headerMinorItems > (uint32_t)Items::dwMinorVersion) setLastErrorString("This map needs an updated items.otb."); std::cout << "> Map size: " << rootHeader->width << "x" << rootHeader->height << "." << std::endl; map->mapWidth = rootHeader->width; map->mapHeight = rootHeader->height; NODE nodeMap = f.getChildNode(root, type); if(type != OTBM_MAP_DATA) { setLastErrorString("Could not read data node."); return false; } if(!f.getProps(nodeMap, propStream)) { setLastErrorString("Could not read map data attributes."); return false; } std::string tmp; uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_DESCRIPTION: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid description tag."); return false; } map->descriptions.push_back(tmp); break; } case OTBM_ATTR_EXT_SPAWN_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid spawnfile tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; } case OTBM_ATTR_EXT_HOUSE_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid housefile tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; } default: { setLastErrorString("Unknown header node."); return false; } } } std::cout << "> Map descriptions: " << std::endl; for(StringVec::iterator it = map->descriptions.begin(); it != map->descriptions.end(); ++it) std::cout << (*it) << std::endl; NODE nodeMapData = f.getChildNode(nodeMap, type); while(nodeMapData != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Invalid map node."); return false; } if(type == OTBM_TILE_AREA) { if(!f.getProps(nodeMapData, propStream)) { setLastErrorString("Invalid map node."); return false; } OTBM_Destination_coords* area_coord; if(!propStream.GET_STRUCT(area_coord)) { setLastErrorString("Invalid map node."); return false; } int32_t base_x = area_coord->_x, base_y = area_coord->_y, base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while(nodeTile != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Could not read node data."); return false; } if(type == OTBM_TILE || type == OTBM_HOUSETILE) { if(!f.getProps(nodeTile, propStream)) { setLastErrorString("Could not read node data."); return false; } OTBM_Tile_coords* tileCoord; if(!propStream.GET_STRUCT(tileCoord)) { setLastErrorString("Could not read tile position."); return false; } Tile* tile = NULL; Item* groundItem = NULL; uint32_t tileflags = 0; uint16_t px = base_x + tileCoord->_x, py = base_y + tileCoord->_y, pz = base_z; House* house = NULL; if(type == OTBM_HOUSETILE) { uint32_t _houseid; if(!propStream.GET_ULONG(_houseid)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if(!house) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); } //read tile attributes uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if(!propStream.GET_ULONG(flags)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) tileflags |= TILESTATE_PROTECTIONZONE; else if((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) tileflags |= TILESTATE_NOPVPZONE; else if((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) tileflags |= TILESTATE_PVPZONE; if((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) tileflags |= TILESTATE_NOLOGOUT; if((flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) { if(house) std::cout << "[x:" << px << ", y:" << py << ", z:" << pz << "] House tile flagged as refreshing!"; tileflags |= TILESTATE_REFRESH; } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: " << house->getHouseId(); std::cout << ", item type: " << item->getID() << ", at position " << px << "/" << py << "/"; std::cout << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } break; } default: { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown tile attribute."; setLastErrorString(ss.str()); return false; } } } NODE nodeItem = f.getChildNode(nodeTile, type); while(nodeItem) { if(type == OTBM_ITEM) { PropStream propStream; f.getProps(nodeItem, propStream); Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(item->unserializeItemNode(f, nodeItem, propStream)) { if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: "; std::cout << house->getHouseId() << ", item type: " << item->getID(); std::cout << ", pos " << px << "/" << py << "/" << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; item = NULL; return false; } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } if(!tile) tile = createTile(groundItem, NULL, px, py, pz); tile->setFlag((tileflags_t)tileflags); map->setTile(px, py, pz, tile); } else { setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if(type == OTBM_TOWNS) { NODE nodeTown = f.getChildNode(nodeMapData, type); while(nodeTown != NO_NODE) { if(type == OTBM_TOWN) { if(!f.getProps(nodeTown, propStream)) { setLastErrorString("Could not read town data."); return false; } uint32_t townId = 0; if(!propStream.GET_ULONG(townId)) { setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townId); if(!town) { town = new Town(townId); Towns::getInstance().addTown(townId, town); } std::string townName = ""; if(!propStream.GET_STRING(townName)) { setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_Destination_coords *town_coords; if(!propStream.GET_STRUCT(town_coords)) { setLastErrorString("Could not read town coordinates."); return false; } town->setTemplePos(Position(town_coords->_x, town_coords->_y, town_coords->_z)); } else { setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if(type == OTBM_WAYPOINTS && headerVersion > 1) { NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while(nodeWaypoint != NO_NODE) { if(type == OTBM_WAYPOINT) { if(!f.getProps(nodeWaypoint, propStream)) { setLastErrorString("Could not read waypoint data."); return false; } std::string name; if(!propStream.GET_STRING(name)) { setLastErrorString("Could not read waypoint name."); return false; } OTBM_Destination_coords* waypoint_coords; if(!propStream.GET_STRUCT(waypoint_coords)) { setLastErrorString("Could not read waypoint coordinates."); return false; } map->waypoints.addWaypoint(WaypointPtr(new Waypoint(name, Position(waypoint_coords->_x, waypoint_coords->_y, waypoint_coords->_z)))); } else { setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else { setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } return true; }
bool IOMap::loadMap(Map* map, const std::string& identifier) { int64_t start = OTSYS_TIME(); FileLoader f; if (!f.openFile(identifier.c_str(), "OTBM", false, true)) { std::ostringstream ss; ss << "Could not open the file " << identifier << '.'; setLastErrorString(ss.str()); return false; } uint32_t type; PropStream propStream; NODE root = f.getChildNode((NODE)nullptr, type); if (!f.getProps(root, propStream)) { setLastErrorString("Could not read root property."); return false; } OTBM_root_header* root_header; if (!propStream.GET_STRUCT(root_header)) { setLastErrorString("Could not read header."); return false; } uint32_t headerVersion = root_header->version; if (headerVersion <= 0) { //In otbm version 1 the count variable after splashes/fluidcontainers and stackables //are saved as attributes instead, this solves alot of problems with items //that is changed (stackable/charges/fluidcontainer/splash) during an update. setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if (headerVersion > 2) { setLastErrorString("Unknown OTBM version detected."); return false; } if (root_header->majorVersionItems < 3) { setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if (root_header->majorVersionItems > (uint32_t)Items::dwMajorVersion) { setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } if (root_header->minorVersionItems < CLIENT_VERSION_810) { setLastErrorString("This map needs to be updated."); return false; } if (root_header->minorVersionItems > (uint32_t)Items::dwMinorVersion) { std::cout << "[Warning - IOMap::loadMap] This map needs an updated items.otb." << std::endl; } std::cout << "> Map size: " << root_header->width << "x" << root_header->height << '.' << std::endl; map->mapWidth = root_header->width; map->mapHeight = root_header->height; NODE nodeMap = f.getChildNode(root, type); if (type != OTBM_MAP_DATA) { setLastErrorString("Could not read data node."); return false; } if (!f.getProps(nodeMap, propStream)) { setLastErrorString("Could not read map data attributes."); return false; } unsigned char attribute; std::string mapDescription; std::string tmp; while (propStream.GET_UCHAR(attribute)) { switch (attribute) { case OTBM_ATTR_DESCRIPTION: if (!propStream.GET_STRING(mapDescription)) { setLastErrorString("Invalid description tag."); return false; } break; case OTBM_ATTR_EXT_SPAWN_FILE: if (!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid spawn tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; case OTBM_ATTR_EXT_HOUSE_FILE: if (!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid house tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; default: setLastErrorString("Unknown header node."); return false; } } NODE nodeMapData = f.getChildNode(nodeMap, type); while (nodeMapData != NO_NODE) { if (f.getError() != ERROR_NONE) { setLastErrorString("Invalid map node."); return false; } if (type == OTBM_TILE_AREA) { if (!f.getProps(nodeMapData, propStream)) { setLastErrorString("Invalid map node."); return false; } OTBM_Destination_coords* area_coord; if (!propStream.GET_STRUCT(area_coord)) { setLastErrorString("Invalid map node."); return false; } int32_t base_x, base_y, base_z; base_x = area_coord->_x; base_y = area_coord->_y; base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while (nodeTile != NO_NODE) { if (f.getError() != ERROR_NONE) { setLastErrorString("Could not read node data."); return false; } if (type == OTBM_TILE || type == OTBM_HOUSETILE) { if (!f.getProps(nodeTile, propStream)) { setLastErrorString("Could not read node data."); return false; } unsigned short px, py, pz; OTBM_Tile_coords* tile_coord; if (!propStream.GET_STRUCT(tile_coord)) { setLastErrorString("Could not read tile position."); return false; } px = base_x + tile_coord->_x; py = base_y + tile_coord->_y; pz = base_z; bool isHouseTile = false; House* house = nullptr; Tile* tile = nullptr; Item* ground_item = nullptr; uint32_t tileflags = TILESTATE_NONE; if (type == OTBM_HOUSETILE) { uint32_t _houseid; if (!propStream.GET_ULONG(_houseid)) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().addHouse(_houseid); if (!house) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); isHouseTile = true; } //read tile attributes while (propStream.GET_UCHAR(attribute)) { switch (attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if (!propStream.GET_ULONG(flags)) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if ((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) { tileflags |= TILESTATE_PROTECTIONZONE; } else if ((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) { tileflags |= TILESTATE_NOPVPZONE; } else if ((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) { tileflags |= TILESTATE_PVPZONE; } if ((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) { tileflags |= TILESTATE_NOLOGOUT; } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if (!item) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if (isHouseTile && !item->isNotMoveable()) { std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl; delete item; item = nullptr; } else { if (item->getItemCount() <= 0) { item->setItemCount(1); } if (tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if (item->isGroundTile()) { delete ground_item; ground_item = item; } else { tile = createTile(ground_item, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } break; } default: std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown tile attribute."; setLastErrorString(ss.str()); return false; } } NODE nodeItem = f.getChildNode(nodeTile, type); while (nodeItem) { if (type == OTBM_ITEM) { PropStream stream; f.getProps(nodeItem, stream); Item* item = Item::CreateItem(stream); if (!item) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if (item->unserializeItemNode(f, nodeItem, stream)) { if (isHouseTile && !item->isNotMoveable()) { std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl; delete item; } else { if (item->getItemCount() <= 0) { item->setItemCount(1); } if (tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if (item->isGroundTile()) { delete ground_item; ground_item = item; } else { tile = createTile(ground_item, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } } else { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to load item " << item->getID() << '.'; setLastErrorString(ss.str()); delete item; return false; } } else { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } if (!tile) { tile = createTile(ground_item, nullptr, px, py, pz); } tile->setFlag((tileflags_t)tileflags); map->setTile(px, py, pz, tile); } else { setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if (type == OTBM_TOWNS) { NODE nodeTown = f.getChildNode(nodeMapData, type); while (nodeTown != NO_NODE) { if (type == OTBM_TOWN) { if (!f.getProps(nodeTown, propStream)) { setLastErrorString("Could not read town data."); return false; } uint32_t townid = 0; if (!propStream.GET_ULONG(townid)) { setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townid); if (!town) { town = new Town(townid); Towns::getInstance().addTown(townid, town); } std::string townName; if (!propStream.GET_STRING(townName)) { setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_Destination_coords* town_coords; if (!propStream.GET_STRUCT(town_coords)) { setLastErrorString("Could not read town coordinates."); return false; } Position pos; pos.x = town_coords->_x; pos.y = town_coords->_y; pos.z = town_coords->_z; town->setTemplePos(pos); } else { setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if (type == OTBM_WAYPOINTS && headerVersion > 1) { NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while (nodeWaypoint != NO_NODE) { if (type == OTBM_WAYPOINT) { if (!f.getProps(nodeWaypoint, propStream)) { setLastErrorString("Could not read waypoint data."); return false; } std::string name; if (!propStream.GET_STRING(name)) { setLastErrorString("Could not read waypoint name."); return false; } OTBM_Destination_coords* waypoint_coords; if (!propStream.GET_STRUCT(waypoint_coords)) { setLastErrorString("Could not read waypoint coordinates."); return false; } map->waypoints[name] = Position(waypoint_coords->_x, waypoint_coords->_y, waypoint_coords->_z); } else { setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else { setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; return true; }
int Items::loadFromOtb(std::string file) { ItemLoader f; if(!f.openFile(file.c_str(), false, true)){ return f.getError(); } unsigned long type,len; const unsigned char* data; NODE node = f.getChildNode(NO_NODE, type); PropStream props; if(f.getProps(node,props)){ //4 byte flags //attributes //0x01 = version data unsigned long flags; if(!props.GET_ULONG(flags)){ return ERROR_INVALID_FORMAT; } attribute_t attr; datasize_t datalen = 0; if(!props.GET_VALUE(attr)){ return ERROR_INVALID_FORMAT; } if(attr == ROOT_ATTR_VERSION){ if(!props.GET_VALUE(datalen)){ return ERROR_INVALID_FORMAT; } if(datalen != sizeof(VERSIONINFO)){ return ERROR_INVALID_FORMAT; } VERSIONINFO *vi; if(!props.GET_STRUCT(vi)){ return ERROR_INVALID_FORMAT; } Items::dwMajorVersion = vi->dwMajorVersion; Items::dwMinorVersion = vi->dwMinorVersion; Items::dwBuildNumber = vi->dwBuildNumber; } } if(Items::dwMinorVersion != CLIENT_VERSION_760){ std::cout << "Not supported items.otb client version." << std::endl; return ERROR_INVALID_FORMAT; } node = f.getChildNode(node, type); while(node != NO_NODE) { data = f.getProps(node, len); if(data == NULL && f.getError() != ERROR_NONE) return f.getError(); flags_t flags; if(data != NULL) { const unsigned char* p = &data[0]; ItemType* iType = new ItemType(); bool loadedFlags = false; while(p < data + len) { iType->group = (itemgroup_t)type; switch(type) { case ITEM_GROUP_NONE: case ITEM_GROUP_GROUND: case ITEM_GROUP_CONTAINER: case ITEM_GROUP_WEAPON: case ITEM_GROUP_AMMUNITION: case ITEM_GROUP_ARMOR: case ITEM_GROUP_RUNE: case ITEM_GROUP_TELEPORT: case ITEM_GROUP_MAGICFIELD: case ITEM_GROUP_WRITEABLE: case ITEM_GROUP_KEY: case ITEM_GROUP_SPLASH: case ITEM_GROUP_FLUID: { if(!loadedFlags) { //read 4 byte flags memcpy((void*)&flags, p, sizeof(flags_t)); p+= sizeof(flags_t); iType->blockSolid = ((flags & FLAG_BLOCK_SOLID) == FLAG_BLOCK_SOLID); iType->blockProjectile = ((flags & FLAG_BLOCK_PROJECTILE) == FLAG_BLOCK_PROJECTILE); iType->blockPathFind = ((flags & FLAG_BLOCK_PATHFIND) == FLAG_BLOCK_PATHFIND); iType->hasHeight = ((flags & FLAG_HAS_HEIGHT) == FLAG_HAS_HEIGHT); iType->useable = ((flags & FLAG_USEABLE) == FLAG_USEABLE); iType->pickupable = ((flags & FLAG_PICKUPABLE) == FLAG_PICKUPABLE); iType->moveable = ((flags & FLAG_MOVEABLE) == FLAG_MOVEABLE); iType->stackable = ((flags & FLAG_STACKABLE) == FLAG_STACKABLE); iType->floorChangeDown = ((flags & FLAG_FLOORCHANGEDOWN) == FLAG_FLOORCHANGEDOWN); iType->floorChangeNorth = ((flags & FLAG_FLOORCHANGENORTH) == FLAG_FLOORCHANGENORTH); iType->floorChangeEast = ((flags & FLAG_FLOORCHANGEEAST) == FLAG_FLOORCHANGEEAST); iType->floorChangeSouth = ((flags & FLAG_FLOORCHANGESOUTH) == FLAG_FLOORCHANGESOUTH); iType->floorChangeWest = ((flags & FLAG_FLOORCHANGEWEST) == FLAG_FLOORCHANGEWEST); iType->alwaysOnTop = ((flags & FLAG_ALWAYSONTOP) == FLAG_ALWAYSONTOP); iType->canDecay = !((flags & FLAG_CANNOTDECAY) == FLAG_CANNOTDECAY); if(type == ITEM_GROUP_WRITEABLE) { iType->RWInfo |= CAN_BE_WRITTEN; } if((flags & FLAG_READABLE) == FLAG_READABLE) iType->RWInfo |= CAN_BE_READ; iType->rotable = ((flags & FLAG_ROTABLE) == FLAG_ROTABLE); if(p >= data + len) //no attributes break; loadedFlags = true; } //attribute attribute_t attrib = *p; p+= sizeof(attribute_t); if(p >= data + len) { delete iType; return ERROR_INVALID_FORMAT; } datasize_t datalen = 0; //size of data memcpy(&datalen, p, sizeof(datasize_t)); p+= sizeof(datalen); if(p >= data + len) { delete iType; return ERROR_INVALID_FORMAT; } switch(attrib) { case ITEM_ATTR_SERVERID: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short serverid = *(unsigned short*)p; if(serverid > 20000 && serverid < 20100) serverid = serverid - 20000; iType->id = serverid; break; } case ITEM_ATTR_CLIENTID: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; memcpy(&iType->clientId, p, sizeof(unsigned short)); break; } case ITEM_ATTR_NAME: { char name[128]; if(datalen >= sizeof(name)) return ERROR_INVALID_FORMAT; memcpy(name, p, datalen); name[datalen] = 0; iType->name = name; break; } case ITEM_ATTR_DESCR: { char descr[128]; if(datalen >= sizeof(descr)) return ERROR_INVALID_FORMAT; memcpy(descr, p, datalen); descr[datalen] = 0; iType->description = descr; break; } case ITEM_ATTR_SPEED: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; memcpy(&iType->speed, p, sizeof(unsigned short)); break; } case ITEM_ATTR_SLOT: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short otb_slot = *(unsigned short*)p; switch(otb_slot){ case OTB_SLOT_DEFAULT: case OTB_SLOT_WEAPON: case OTB_SLOT_HAND: //default break; case OTB_SLOT_HEAD: iType->slot_position = SLOTP_HEAD; break; case OTB_SLOT_BODY: iType->slot_position = SLOTP_ARMOR; break; case OTB_SLOT_LEGS: iType->slot_position = SLOTP_LEGS; break; case OTB_SLOT_BACKPACK: iType->slot_position = SLOTP_BACKPACK; break; case OTB_SLOT_2HAND: iType->slot_position = SLOTP_TWO_HAND; break; case OTB_SLOT_FEET: iType->slot_position = SLOTP_FEET; break; case OTB_SLOT_AMULET: iType->slot_position = SLOTP_NECKLACE; break; case OTB_SLOT_RING: iType->slot_position = SLOTP_RING; break; } iType->slot_position = iType->slot_position | SLOTP_LEFT | SLOTP_RIGHT | SLOTP_AMMO; break; } case ITEM_ATTR_MAXITEMS: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; memcpy(&iType->maxItems, p, sizeof(unsigned short)); break; } case ITEM_ATTR_WEIGHT: { if(datalen != sizeof(double)) return ERROR_INVALID_FORMAT; #ifdef YUR_CONFIG_CAP if (g_config.CAP_SYSTEM) #endif //YUR_CONFIG_CAP memcpy(&iType->weight, p, sizeof(double)); break; } /*case ITEM_ATTR_WEAPON: { if(datalen != sizeof(weaponBlock)) return ERROR_INVALID_FORMAT; weaponBlock wb; memcpy(&wb, p, sizeof(weaponBlock)); iType->weaponType = (WeaponType)wb.weaponType; iType->shootType = (subfight_t)wb.shootType; iType->amuType = (amu_t)wb.amuType; iType->attack = wb.attack; iType->defence = wb.defence; break; } case ITEM_ATTR_AMU: { if(datalen != sizeof(amuBlock)) return ERROR_INVALID_FORMAT; amuBlock ab; memcpy(&ab, p, sizeof(amuBlock)); iType->weaponType = AMO; iType->shootType = (subfight_t)ab.shootType; iType->amuType = (amu_t)ab.amuType; iType->attack = ab.attack; break; } case ITEM_ATTR_ARMOR: { if(datalen != sizeof(armorBlock)) return ERROR_INVALID_FORMAT; armorBlock ab; memcpy(&ab, p, sizeof(armorBlock)); iType->armor = ab.armor; #ifdef YUR_CONFIG_CAP if (g_config.CAP_SYSTEM) #endif //YUR_CONFIG_CAP iType->weight = ab.weight; //ignore this value //iType->slot_position = ab.slot_position; break; }*/ case ITEM_ATTR_MAGLEVEL: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; memcpy(&iType->runeMagLevel, p, sizeof(unsigned short)); break; } case ITEM_ATTR_MAGFIELDTYPE: { if(datalen != sizeof(unsigned char)) return ERROR_INVALID_FORMAT; memcpy(&iType->magicfieldtype, p, sizeof(unsigned char)); break; } /*case ITEM_ATTR_WRITEABLE: { if(datalen != sizeof(writeableBlock)) return ERROR_INVALID_FORMAT; struct writeableBlock wb; memcpy(&wb, p, sizeof(writeableBlock)); iType->readOnlyId = wb.readOnlyId; break; }*/ case ITEM_ATTR_ROTATETO: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; iType->rotateTo = *(unsigned short*)p; break; } /*case ITEM_ATTR_DECAY: { if(datalen != sizeof(decayBlock)) return ERROR_INVALID_FORMAT; decayBlock db; memcpy(&db, p, sizeof(decayBlock)); iType->decayTime = db.decayTime; iType->decayTo = db.decayTo; break; }*/ case ITEM_ATTR_SPRITEHASH: { if(datalen != 16) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_MINIMAPCOLOR: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_07: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_08: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; break; } /*case ITEM_ATTR_LIGHT: { if(datalen != sizeof(lightBlock)) return ERROR_INVALID_FORMAT; lightBlock lb; memcpy(&lb, p, sizeof(lightBlock)); iType->lightLevel = lb.lightLevel; iType->lightColor = lb.lightColor; break; }*/ case ITEM_ATTR_DECAY2: { if(datalen != sizeof(decayBlock2)) return ERROR_INVALID_FORMAT; decayBlock2 db2; memcpy(&db2, p, sizeof(decayBlock2)); iType->decayTime = db2.decayTime; iType->decayTo = db2.decayTo; break; } case ITEM_ATTR_WEAPON2: { if(datalen != sizeof(weaponBlock2)) return ERROR_INVALID_FORMAT; weaponBlock2 wb2; memcpy(&wb2, p, sizeof(weaponBlock2)); iType->weaponType = (WeaponType)wb2.weaponType; iType->shootType = translateOTBsubfight_t((subfightOTB_t)wb2.shootType); iType->amuType = (amu_t)wb2.amuType; iType->attack = wb2.attack; iType->defence = wb2.defence; break; } case ITEM_ATTR_AMU2: { if(datalen != sizeof(amuBlock2)) return ERROR_INVALID_FORMAT; amuBlock2 ab2; memcpy(&ab2, p, sizeof(amuBlock2)); iType->weaponType = AMO; iType->shootType = translateOTBsubfight_t((subfightOTB_t)ab2.shootType); iType->amuType = (amu_t)ab2.amuType; iType->attack = ab2.attack; break; } case ITEM_ATTR_ARMOR2: { if(datalen != sizeof(armorBlock2)) return ERROR_INVALID_FORMAT; armorBlock2 ab2; memcpy(&ab2, p, sizeof(armorBlock2)); iType->armor = ab2.armor; #ifdef YUR_CONFIG_CAP if (g_config.CAP_SYSTEM) #endif //YUR_CONFIG_CAP iType->weight = ab2.weight; //ignore this value //iType->slot_position = (slots_t)ab2.slot_position; break; } case ITEM_ATTR_WRITEABLE2: { if(datalen != sizeof(writeableBlock2)) return ERROR_INVALID_FORMAT; struct writeableBlock2 wb2; memcpy(&wb2, p, sizeof(writeableBlock2)); iType->readOnlyId = wb2.readOnlyId; break; } case ITEM_ATTR_LIGHT2: { if(datalen != sizeof(lightBlock2)) return ERROR_INVALID_FORMAT; lightBlock2 lb2; memcpy(&lb2, p, sizeof(lightBlock2)); iType->lightLevel = lb2.lightLevel; iType->lightColor = lb2.lightColor; break; } default: //ignore unknown attributes //delete iType; //return ERROR_INVALID_FORMAT; break; } p+= datalen; break; } default: return ERROR_INVALID_FORMAT; break; } } //get rune mag level from spells.xml if(iType->group == ITEM_GROUP_RUNE){ std::map<unsigned short, Spell*>::iterator it = spells.getAllRuneSpells()->find(iType->id); if(it != spells.getAllRuneSpells()->end()){ iType->runeMagLevel = it->second->getMagLv(); } else{ iType->runeMagLevel = 0; } } // store the found item items[iType->id] = iType; revItems[iType->clientId] = iType->id; } node = f.getNextNode(node, type); } return ERROR_NONE; }
int32_t Items::loadFromOtb(const std::string& file) { FileLoader f; if (!f.openFile(file.c_str(), "OTBI")) { return f.getError(); } uint32_t type; NODE node = f.getChildNode(NO_NODE, type); PropStream props; if (f.getProps(node, props)) { //4 byte flags //attributes //0x01 = version data uint32_t flags; if (!props.GET_ULONG(flags)) { return ERROR_INVALID_FORMAT; } uint8_t attr; if (!props.GET_VALUE(attr)) { return ERROR_INVALID_FORMAT; } if (attr == ROOT_ATTR_VERSION) { uint16_t datalen; if (!props.GET_VALUE(datalen)) { return ERROR_INVALID_FORMAT; } if (datalen != sizeof(VERSIONINFO)) { return ERROR_INVALID_FORMAT; } VERSIONINFO* vi; if (!props.GET_STRUCT(vi)) { return ERROR_INVALID_FORMAT; } Items::dwMajorVersion = vi->dwMajorVersion; //items otb format file version Items::dwMinorVersion = vi->dwMinorVersion; //client version Items::dwBuildNumber = vi->dwBuildNumber; //revision } } if (Items::dwMajorVersion == 0xFFFFFFFF) { std::cout << "[Warning - Items::loadFromOtb] items.otb using generic client version." << std::endl; } else if (Items::dwMajorVersion != 3) { std::cout << "Old version detected, a newer version of items.otb is required." << std::endl; return ERROR_INVALID_FORMAT; } else if (Items::dwMinorVersion < CLIENT_VERSION_1035) { std::cout << "A newer version of items.otb is required." << std::endl; return ERROR_INVALID_FORMAT; } node = f.getChildNode(node, type); while (node != NO_NODE) { PropStream stream; if (!f.getProps(node, stream)) { return f.getError(); } uint32_t flags; if (!stream.GET_VALUE(flags)) { return ERROR_INVALID_FORMAT; } uint16_t serverId = 0; uint16_t clientId = 0; uint16_t speed = 0; uint16_t lightLevel = 0; uint16_t lightColor = 0; uint16_t wareId = 0; uint8_t alwaysOnTopOrder = 0; uint8_t attrib; while (stream.GET_VALUE(attrib)) { uint16_t datalen; if (!stream.GET_VALUE(datalen)) { return ERROR_INVALID_FORMAT; } switch (attrib) { case ITEM_ATTR_SERVERID: { if (datalen != sizeof(uint16_t)) { return ERROR_INVALID_FORMAT; } if (!stream.GET_USHORT(serverId)) { return ERROR_INVALID_FORMAT; } if (serverId > 30000 && serverId < 30100) { serverId -= 30000; } break; } case ITEM_ATTR_CLIENTID: { if (datalen != sizeof(uint16_t)) { return ERROR_INVALID_FORMAT; } if (!stream.GET_USHORT(clientId)) { return ERROR_INVALID_FORMAT; } break; } case ITEM_ATTR_SPEED: { if (datalen != sizeof(uint16_t)) { return ERROR_INVALID_FORMAT; } if (!stream.GET_USHORT(speed)) { return ERROR_INVALID_FORMAT; } break; } case ITEM_ATTR_LIGHT2: { if (datalen != sizeof(lightBlock2)) { return ERROR_INVALID_FORMAT; } lightBlock2* lb2; if (!stream.GET_STRUCT(lb2)) { return ERROR_INVALID_FORMAT; } lightLevel = lb2->lightLevel; lightColor = lb2->lightColor; break; } case ITEM_ATTR_TOPORDER: { if (datalen != sizeof(uint8_t)) { return ERROR_INVALID_FORMAT; } if (!stream.GET_UCHAR(alwaysOnTopOrder)) { return ERROR_INVALID_FORMAT; } break; } case ITEM_ATTR_WAREID: { if (datalen != sizeof(uint16_t)) { return ERROR_INVALID_FORMAT; } if (!stream.GET_USHORT(wareId)) { return ERROR_INVALID_FORMAT; } break; } default: { //skip unknown attributes if (!stream.SKIP_N(datalen)) { return ERROR_INVALID_FORMAT; } break; } } } if (reverseItemMap.find(clientId) == reverseItemMap.end()) { reverseItemMap[clientId] = serverId; } // store the found item if (serverId >= items.size()) { items.resize(serverId + 1); } ItemType& iType = items[serverId]; iType.group = (itemgroup_t)type; switch (type) { case ITEM_GROUP_CONTAINER: iType.type = ITEM_TYPE_CONTAINER; break; case ITEM_GROUP_DOOR: //not used iType.type = ITEM_TYPE_DOOR; break; case ITEM_GROUP_MAGICFIELD: //not used iType.type = ITEM_TYPE_MAGICFIELD; break; case ITEM_GROUP_TELEPORT: //not used iType.type = ITEM_TYPE_TELEPORT; break; case ITEM_GROUP_NONE: case ITEM_GROUP_GROUND: case ITEM_GROUP_SPLASH: case ITEM_GROUP_FLUID: case ITEM_GROUP_CHARGES: case ITEM_GROUP_DEPRECATED: break; default: return ERROR_INVALID_FORMAT; } iType.blockSolid = hasBitSet(FLAG_BLOCK_SOLID, flags); iType.blockProjectile = hasBitSet(FLAG_BLOCK_PROJECTILE, flags); iType.blockPathFind = hasBitSet(FLAG_BLOCK_PATHFIND, flags); iType.hasHeight = hasBitSet(FLAG_HAS_HEIGHT, flags); iType.useable = hasBitSet(FLAG_USEABLE, flags); iType.pickupable = hasBitSet(FLAG_PICKUPABLE, flags); iType.moveable = hasBitSet(FLAG_MOVEABLE, flags); iType.stackable = hasBitSet(FLAG_STACKABLE, flags); iType.alwaysOnTop = hasBitSet(FLAG_ALWAYSONTOP, flags); iType.isVertical = hasBitSet(FLAG_VERTICAL, flags); iType.isHorizontal = hasBitSet(FLAG_HORIZONTAL, flags); iType.isHangable = hasBitSet(FLAG_HANGABLE, flags); iType.allowDistRead = hasBitSet(FLAG_ALLOWDISTREAD, flags); iType.rotable = hasBitSet(FLAG_ROTABLE, flags); iType.canReadText = hasBitSet(FLAG_READABLE, flags); iType.lookThrough = hasBitSet(FLAG_LOOKTHROUGH, flags); iType.isAnimation = hasBitSet(FLAG_ANIMATION, flags); // iType.walkStack = !hasBitSet(FLAG_FULLTILE, flags); iType.id = serverId; iType.clientId = clientId; iType.speed = speed; iType.lightLevel = lightLevel; iType.lightColor = lightColor; iType.wareId = wareId; iType.alwaysOnTopOrder = alwaysOnTopOrder; node = f.getNextNode(node, type); } items.shrink_to_fit(); return ERROR_NONE; }
Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream& propStream) { switch (attr) { case ATTR_COUNT: { uint8_t _count = 0; if (!propStream.GET_UCHAR(_count)) { return ATTR_READ_ERROR; } setSubType(_count); break; } case ATTR_ACTION_ID: { uint16_t _actionid = 0; if (!propStream.GET_USHORT(_actionid)) { return ATTR_READ_ERROR; } setActionId(_actionid); break; } case ATTR_UNIQUE_ID: { uint16_t _uniqueid; if (!propStream.GET_USHORT(_uniqueid)) { return ATTR_READ_ERROR; } setUniqueId(_uniqueid); break; } case ATTR_TEXT: { std::string _text; if (!propStream.GET_STRING(_text)) { return ATTR_READ_ERROR; } setText(_text); break; } case ATTR_WRITTENDATE: { uint32_t _writtenDate; if (!propStream.GET_ULONG(_writtenDate)) { return ATTR_READ_ERROR; } setDate(_writtenDate); break; } case ATTR_WRITTENBY: { std::string _writer; if (!propStream.GET_STRING(_writer)) { return ATTR_READ_ERROR; } setWriter(_writer); break; } case ATTR_DESC: { std::string _text; if (!propStream.GET_STRING(_text)) { return ATTR_READ_ERROR; } setSpecialDescription(_text); break; } case ATTR_RUNE_CHARGES: { uint8_t _charges = 1; if (!propStream.GET_UCHAR(_charges)) { return ATTR_READ_ERROR; } setSubType(_charges); break; } case ATTR_CHARGES: { uint16_t _charges = 1; if (!propStream.GET_USHORT(_charges)) { return ATTR_READ_ERROR; } setSubType(_charges); break; } case ATTR_DURATION: { uint32_t duration = 0; if (!propStream.GET_ULONG(duration)) { return ATTR_READ_ERROR; } if (((int32_t)duration) < 0) { duration = 0; } setDuration(duration); break; } case ATTR_DECAYING_STATE: { uint8_t state = 0; if (!propStream.GET_UCHAR(state)) { return ATTR_READ_ERROR; } if (state != DECAYING_FALSE) { setDecaying(DECAYING_PENDING); } break; } //these should be handled through derived classes //If these are called then something has changed in the items.xml since the map was saved //just read the values //Depot class case ATTR_DEPOT_ID: { uint16_t _depotId; if (!propStream.GET_USHORT(_depotId)) { return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; } //Door class case ATTR_HOUSEDOORID: { uint8_t _doorId; if (!propStream.GET_UCHAR(_doorId)) { return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; } //Bed class case ATTR_SLEEPERGUID: { uint32_t _guid; if (!propStream.GET_ULONG(_guid)) { return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; } case ATTR_SLEEPSTART: { uint32_t sleep_start; if (!propStream.GET_ULONG(sleep_start)) { return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; } //Teleport class case ATTR_TELE_DEST: { TeleportDest* tele_dest; if (!propStream.GET_STRUCT(tele_dest)) { return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; } //Container class case ATTR_CONTAINER_ITEMS: { uint32_t count; if (!propStream.GET_ULONG(count)) { return ATTR_READ_ERROR; } return ATTR_READ_ERROR; } default: return ATTR_READ_ERROR; } return ATTR_READ_CONTINUE; }
int Items::loadFromOtb(std::string file) { ItemLoader f; if(!f.openFile(file.c_str(), false, true)){ return f.getError(); } unsigned long type; NODE node = f.getChildNode(NO_NODE, type); PropStream props; if(f.getProps(node,props)){ //4 byte flags //attributes //0x01 = version data unsigned long flags; if(!props.GET_ULONG(flags)){ return ERROR_INVALID_FORMAT; } attribute_t attr; if(!props.GET_VALUE(attr)){ return ERROR_INVALID_FORMAT; } if(attr == ROOT_ATTR_VERSION){ datasize_t datalen = 0; if(!props.GET_VALUE(datalen)){ return ERROR_INVALID_FORMAT; } if(datalen != sizeof(VERSIONINFO)){ return ERROR_INVALID_FORMAT; } VERSIONINFO *vi; if(!props.GET_STRUCT(vi)){ return ERROR_INVALID_FORMAT; } Items::dwMajorVersion = vi->dwMajorVersion; //items otb format file version Items::dwMinorVersion = vi->dwMinorVersion; //client version Items::dwBuildNumber = vi->dwBuildNumber; //revision } } if(Items::dwMajorVersion != 1){ std::cout << "Not supported items.otb version." << std::endl; return ERROR_INVALID_FORMAT; } if(Items::dwMinorVersion != CLIENT_VERSION_760){ std::cout << "Not supported items.otb client version." << std::endl; return ERROR_INVALID_FORMAT; } node = f.getChildNode(node, type); while(node != NO_NODE){ PropStream props; if(!f.getProps(node,props)){ return f.getError(); } flags_t flags; ItemType* iType = new ItemType(); iType->group = (itemgroup_t)type; switch(type){ case ITEM_GROUP_NONE: case ITEM_GROUP_GROUND: case ITEM_GROUP_CONTAINER: case ITEM_GROUP_WEAPON: case ITEM_GROUP_AMMUNITION: case ITEM_GROUP_ARMOR: case ITEM_GROUP_RUNE: case ITEM_GROUP_TELEPORT: case ITEM_GROUP_MAGICFIELD: case ITEM_GROUP_WRITEABLE: case ITEM_GROUP_KEY: case ITEM_GROUP_SPLASH: case ITEM_GROUP_FLUID: case ITEM_GROUP_DOOR: break; default: return ERROR_INVALID_FORMAT; break; } //read 4 byte flags if(!props.GET_VALUE(flags)){ return ERROR_INVALID_FORMAT; } iType->blockSolid = ((flags & FLAG_BLOCK_SOLID) == FLAG_BLOCK_SOLID); iType->blockProjectile = ((flags & FLAG_BLOCK_PROJECTILE) == FLAG_BLOCK_PROJECTILE); iType->blockPathFind = ((flags & FLAG_BLOCK_PATHFIND) == FLAG_BLOCK_PATHFIND); iType->hasHeight = ((flags & FLAG_HAS_HEIGHT) == FLAG_HAS_HEIGHT); iType->useable = ((flags & FLAG_USEABLE) == FLAG_USEABLE); iType->pickupable = ((flags & FLAG_PICKUPABLE) == FLAG_PICKUPABLE); iType->moveable = ((flags & FLAG_MOVEABLE) == FLAG_MOVEABLE); iType->stackable = ((flags & FLAG_STACKABLE) == FLAG_STACKABLE); iType->floorChangeDown = ((flags & FLAG_FLOORCHANGEDOWN) == FLAG_FLOORCHANGEDOWN); iType->floorChangeNorth = ((flags & FLAG_FLOORCHANGENORTH) == FLAG_FLOORCHANGENORTH); iType->floorChangeEast = ((flags & FLAG_FLOORCHANGEEAST) == FLAG_FLOORCHANGEEAST); iType->floorChangeSouth = ((flags & FLAG_FLOORCHANGESOUTH) == FLAG_FLOORCHANGESOUTH); iType->floorChangeWest = ((flags & FLAG_FLOORCHANGEWEST) == FLAG_FLOORCHANGEWEST); iType->alwaysOnTop = ((flags & FLAG_ALWAYSONTOP) == FLAG_ALWAYSONTOP); iType->canDecay = !((flags & FLAG_CANNOTDECAY) == FLAG_CANNOTDECAY); iType->isVertical = ((flags & FLAG_VERTICAL) == FLAG_VERTICAL); iType->isHorizontal = ((flags & FLAG_HORIZONTAL) == FLAG_HORIZONTAL); iType->isHangable = ((flags & FLAG_HANGABLE) == FLAG_HANGABLE); iType->allowDistRead = ((flags & FLAG_ALLOWDISTREAD) == FLAG_ALLOWDISTREAD); if(type == ITEM_GROUP_WRITEABLE) { iType->RWInfo |= CAN_BE_WRITTEN; } if((flags & FLAG_READABLE) == FLAG_READABLE) iType->RWInfo |= CAN_BE_READ; iType->rotable = ((flags & FLAG_ROTABLE) == FLAG_ROTABLE); attribute_t attrib; datasize_t datalen = 0; while(props.GET_VALUE(attrib)){ //size of data if(!props.GET_VALUE(datalen)){ delete iType; return ERROR_INVALID_FORMAT; } switch(attrib){ case ITEM_ATTR_SERVERID: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short serverid; if(!props.GET_USHORT(serverid)) return ERROR_INVALID_FORMAT; if(serverid > 20000 && serverid < 20100) serverid = serverid - 20000; iType->id = serverid; break; } case ITEM_ATTR_CLIENTID: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; if(!props.GET_USHORT(iType->clientId)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_NAME: { char name[128]; if(datalen >= sizeof(name)) return ERROR_INVALID_FORMAT; if(!props.GET_NSTRING(datalen, iType->name)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_DESCR: { char descr[128]; if(datalen >= sizeof(descr)) return ERROR_INVALID_FORMAT; if(!props.GET_NSTRING(datalen, iType->description)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_SPEED: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; if(!props.GET_USHORT(iType->speed)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_SLOT: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short otb_slot; if(!props.GET_USHORT(otb_slot)) return ERROR_INVALID_FORMAT; switch(otb_slot){ case OTB_SLOT_DEFAULT: case OTB_SLOT_WEAPON: case OTB_SLOT_HAND: //default break; case OTB_SLOT_HEAD: iType->slot_position = SLOTP_HEAD; break; case OTB_SLOT_BODY: iType->slot_position = SLOTP_ARMOR; break; case OTB_SLOT_LEGS: iType->slot_position = SLOTP_LEGS; break; case OTB_SLOT_BACKPACK: iType->slot_position = SLOTP_BACKPACK; break; case OTB_SLOT_2HAND: iType->slot_position = SLOTP_TWO_HAND; break; case OTB_SLOT_FEET: iType->slot_position = SLOTP_FEET; break; case OTB_SLOT_AMULET: iType->slot_position = SLOTP_NECKLACE; break; case OTB_SLOT_RING: iType->slot_position = SLOTP_RING; break; } iType->slot_position = iType->slot_position | SLOTP_LEFT | SLOTP_RIGHT | SLOTP_AMMO; break; } case ITEM_ATTR_MAXITEMS: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; if(!props.GET_USHORT(iType->maxItems)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_WEIGHT: { if(datalen != sizeof(double)) return ERROR_INVALID_FORMAT; if(!props.GET_VALUE(iType->weight)) return ERROR_INVALID_FORMAT; break; } case ITEM_ATTR_MAGLEVEL: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short maglev; if(!props.GET_USHORT(maglev)) return ERROR_INVALID_FORMAT; iType->runeMagLevel = maglev; break; } case ITEM_ATTR_MAGFIELDTYPE: { if(datalen != sizeof(unsigned char)) return ERROR_INVALID_FORMAT; unsigned char fieldtype; if(!props.GET_UCHAR(fieldtype)) return ERROR_INVALID_FORMAT; iType->magicfieldtype = fieldtype; break; } case ITEM_ATTR_ROTATETO: { if(datalen != sizeof(unsigned short)) return ERROR_INVALID_FORMAT; unsigned short rotate; if(!props.GET_USHORT(rotate)) return ERROR_INVALID_FORMAT; iType->rotateTo = rotate; break; } case ITEM_ATTR_DECAY2: { if(datalen != sizeof(decayBlock2)) return ERROR_INVALID_FORMAT; decayBlock2* db2; if(!props.GET_STRUCT(db2)) return ERROR_INVALID_FORMAT; iType->decayTime = db2->decayTime; iType->decayTo = db2->decayTo; break; } case ITEM_ATTR_WEAPON2: { if(datalen != sizeof(weaponBlock2)) return ERROR_INVALID_FORMAT; weaponBlock2* wb2; if(!props.GET_STRUCT(wb2)) return ERROR_INVALID_FORMAT; iType->weaponType = (WeaponType_t)wb2->weaponType; iType->shootType = translateOTBShootType((ShootTypeOtb_t)wb2->shootType); iType->amuType = (Ammo_t)wb2->amuType; iType->attack = wb2->attack; iType->defence = wb2->defence; break; } case ITEM_ATTR_AMU2: { if(datalen != sizeof(amuBlock2)) return ERROR_INVALID_FORMAT; amuBlock2* ab2; if(!props.GET_STRUCT(ab2)) return ERROR_INVALID_FORMAT; iType->weaponType = WEAPON_AMMO; iType->shootType = translateOTBShootType((ShootTypeOtb_t)ab2->shootType); iType->amuType = (Ammo_t)ab2->amuType; iType->attack = ab2->attack; break; } case ITEM_ATTR_ARMOR2: { if(datalen != sizeof(armorBlock2)) return ERROR_INVALID_FORMAT; armorBlock2* ab2; if(!props.GET_STRUCT(ab2)) return ERROR_INVALID_FORMAT; iType->armor = ab2->armor; iType->weight = ab2->weight; //ignore this value //iType->slot_position = (slots_t)ab2.slot_position; break; } case ITEM_ATTR_WRITEABLE3: { if(datalen != sizeof(writeableBlock3)) return ERROR_INVALID_FORMAT; writeableBlock3* wb3; if(!props.GET_STRUCT(wb3)) return ERROR_INVALID_FORMAT; iType->readOnlyId = wb3->readOnlyId; iType->maxTextLen = wb3->maxTextLen; break; } case ITEM_ATTR_LIGHT2: { if(datalen != sizeof(lightBlock2)) return ERROR_INVALID_FORMAT; lightBlock2* lb2; if(!props.GET_STRUCT(lb2)) return ERROR_INVALID_FORMAT; iType->lightLevel = lb2->lightLevel; iType->lightColor = lb2->lightColor; break; } case ITEM_ATTR_TOPORDER: { if(datalen != sizeof(unsigned char)) return ERROR_INVALID_FORMAT; if(!props.GET_UCHAR(iType->alwaysOnTopOrder)) return ERROR_INVALID_FORMAT; break; } default: //skip unknown attributes if(!props.SKIP_N(datalen)) return ERROR_INVALID_FORMAT; break; } } //get rune mag level from spells.xml if(iType->group == ITEM_GROUP_RUNE){ /* std::map<unsigned short, Spell*>::iterator it = spells.getAllRuneSpells()->find(iType->id); if(it != spells.getAllRuneSpells()->end()){ iType->runeMagLevel = it->second->getMagLv(); } else{ iType->runeMagLevel = 0; } */ } // store the found item items[iType->id] = iType; //revItems[iType->clientId] = iType->id; node = f.getNextNode(node, type); } return ERROR_NONE; }
bool Item::readAttr(AttrTypes_t attr, PropStream& propStream) { switch(attr){ case ATTR_COUNT: { unsigned char _count = 0; if(!propStream.GET_UCHAR(_count)){ return false; } setItemCountOrSubtype(_count); break; } case ATTR_ACTION_ID: { unsigned short _actionid = 0; if(!propStream.GET_USHORT(_actionid)){ return false; } setActionId(_actionid); break; } case ATTR_UNIQUE_ID: { unsigned short _uniqueid; if(!propStream.GET_USHORT(_uniqueid)){ return false; } setUniqueId(_uniqueid); break; } case ATTR_TEXT: { std::string _text; if(!propStream.GET_STRING(_text)){ return false; } setText(_text); break; } case ATTR_DESC: { std::string _text; if(!propStream.GET_STRING(_text)){ return false; } setSpecialDescription(_text); break; } case ATTR_RUNE_CHARGES: { unsigned char _charges = 1; if(!propStream.GET_UCHAR(_charges)){ return false; } setItemCountOrSubtype(_charges); break; } //these should be handled through derived classes //If these are called then something has changed in the items.otb since the map was saved //just read the values //Depot class case ATTR_DEPOT_ID: { unsigned short _depotId; if(!propStream.GET_USHORT(_depotId)){ return false; } return true; } //Door class case ATTR_HOUSEDOORID: { unsigned char _doorId; if(!propStream.GET_UCHAR(_doorId)){ return false; } return true; } //Teleport class case ATTR_TELE_DEST: { TeleportDest* tele_dest; if(!propStream.GET_STRUCT(tele_dest)){ return false; } return true; } default: return false; break; } return true; }
bool IOMapOTBM::loadMap(Map* map, const std::string& identifier) { int64_t start = OTSYS_TIME(); FileLoader f; if(!f.openFile(identifier.c_str(), false, true)){ std::stringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } unsigned long type; PropStream propStream; NODE root = f.getChildNode((NODE)NULL, type); if(!f.getProps(root, propStream)){ setLastErrorString("Could not read root property."); return false; } OTBM_root_header* root_header; if(!propStream.GET_STRUCT(root_header)){ setLastErrorString("Could not read header."); return false; } if(root_header->version > 2){ setLastErrorString("Unknown OTBM version detected, please update your server.");; return false; } if(root_header->majorVersionItems > (unsigned long)Items::dwMajorVersion){ setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } // Prevent load maps saved with items.otb previous to // version 800, because of the change to stackable of // itemid 3965 if(root_header->minorVersionItems < CLIENT_VERSION_760){ setLastErrorString("This map needs to be updated."); return false; } if(root_header->minorVersionItems > (unsigned long)Items::dwMinorVersion){ std::cout << "Warning: [OTBM loader] This map needs an updated items OTB file." <<std::endl; } std::cout << "Map size: " << root_header->width << "x" << root_header->height << std::endl; map->mapWidth = root_header->width; map->mapHeight = root_header->height; NODE nodeMap = f.getChildNode(root, type); if(type != OTBM_MAP_DATA){ setLastErrorString("Could not read data node."); return false; } if(!f.getProps(nodeMap, propStream)){ setLastErrorString("Could not read map data attributes."); return false; } unsigned char attribute; std::string mapDescription; std::string tmp; while(propStream.GET_UCHAR(attribute)){ switch(attribute){ case OTBM_ATTR_DESCRIPTION: if(!propStream.GET_STRING(mapDescription)){ setLastErrorString("Invalid description tag."); return false; } std::cout << "Map description: " << mapDescription << std::endl; break; case OTBM_ATTR_EXT_SPAWN_FILE: if(!propStream.GET_STRING(tmp)){ setLastErrorString("Invalid spawn tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; case OTBM_ATTR_EXT_HOUSE_FILE: if(!propStream.GET_STRING(tmp)){ setLastErrorString("Invalid house tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; default: setLastErrorString("Unknown header node."); return false; break; } } Tile* tile = NULL; NODE nodeMapData = f.getChildNode(nodeMap, type); while(nodeMapData != NO_NODE){ if(f.getError() != ERROR_NONE){ setLastErrorString("Invalid map node."); return false; } if(type == OTBM_TILE_AREA){ if(!f.getProps(nodeMapData, propStream)){ setLastErrorString("Invalid map node."); return false; } OTBM_Tile_area_coords* area_coord; if(!propStream.GET_STRUCT(area_coord)){ setLastErrorString("Invalid map node."); return false; } int base_x, base_y, base_z; base_x = area_coord->_x; base_y = area_coord->_y; base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while(nodeTile != NO_NODE){ if(f.getError() != ERROR_NONE){ setLastErrorString("Could not read node data."); return false; } if(type == OTBM_TILE || type == OTBM_HOUSETILE){ if(!f.getProps(nodeTile, propStream)){ setLastErrorString("Could not read node data."); return false; } unsigned short px, py, pz; OTBM_Tile_coords* tile_coord; if(!propStream.GET_STRUCT(tile_coord)){ setLastErrorString("Could not read tile position."); return false; } px = base_x + tile_coord->_x; py = base_y + tile_coord->_y; pz = base_z; bool isHouseTile = false; House* house = NULL; if(type == OTBM_TILE){ tile = new Tile(px, py, pz); } else if(type == OTBM_HOUSETILE){ uint32_t _houseid; if(!propStream.GET_ULONG(_houseid)){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if(!house){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); isHouseTile = true; } //read tile attributes unsigned char attribute; while(propStream.GET_UCHAR(attribute)){ switch(attribute){ case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if(!propStream.GET_ULONG(flags)){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE){ tile->setFlag(TILESTATE_PROTECTIONZONE); } else if((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE){ tile->setFlag(TILESTATE_NOPVPZONE); } else if((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE){ tile->setFlag(TILESTATE_PVPZONE); } if((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT){ tile->setFlag(TILESTATE_NOLOGOUT); } if((flags & TILESTATE_REFRESH) == TILESTATE_REFRESH){ if(house){ std::cout << "Warning [x:" << px << ", y:" << py << ", z:" << pz << "] " << " House tile flagged as refreshing!"; } tile->setFlag(TILESTATE_REFRESH); } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if(!item){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if(isHouseTile && !item->isNotMoveable()){ std::cout << "Warning: [OTBM loader] Moveable item in house id = " << house->getHouseId() << " Item type = " << item->getID() << std::endl; delete item; item = NULL; } else{ tile->__internalAddThing(item); item->__startDecaying(); } break; } default: std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown tile attribute."; setLastErrorString(ss.str()); return false; break; } } NODE nodeItem = f.getChildNode(nodeTile, type); while(nodeItem){ if(type == OTBM_ITEM){ PropStream propStream; f.getProps(nodeItem, propStream); Item* item = Item::CreateItem(propStream); if(!item){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if(item->unserializeItemNode(f, nodeItem, propStream)){ if(isHouseTile && !item->isNotMoveable()){ std::cout << "Warning: [OTBM loader] Moveable item in house id = " << house->getHouseId() << " Item type = " << item->getID() << std::endl; delete item; } else{ tile->__internalAddThing(item); item->__startDecaying(); // TESTING if(isHouseTile){ Door* door = item->getDoor(); if(door && door->getDoorId() != 0){ house->addDoor(door); } } // } } else{ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; return false; } } else{ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } map->setTile(px, py, pz, tile); } else{ setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if(type == OTBM_TOWNS){ NODE nodeTown = f.getChildNode(nodeMapData, type); while(nodeTown != NO_NODE){ if(type == OTBM_TOWN){ if(!f.getProps(nodeTown, propStream)){ setLastErrorString("Could not read town data."); return false; } uint32_t townid = 0; if(!propStream.GET_ULONG(townid)){ setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townid); if(!town){ town = new Town(townid); Towns::getInstance().addTown(townid, town); } std::string townName = ""; if(!propStream.GET_STRING(townName)){ setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_TownTemple_coords *town_coords; if(!propStream.GET_STRUCT(town_coords)){ setLastErrorString("Could not read town coordinates."); return false; } Position pos; pos.x = town_coords->_x; pos.y = town_coords->_y; pos.z = town_coords->_z; town->setTemplePos(pos); } else{ setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if(type == OTBM_WAYPOINTS && root_header->version >= 2){ NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while(nodeWaypoint != NO_NODE){ if(type == OTBM_WAYPOINT){ if(!f.getProps(nodeWaypoint, propStream)){ setLastErrorString("Could not read town data."); return false; } std::string name; Position pos; if(!propStream.GET_STRING(name)){ setLastErrorString("Could not read waypoint name."); return false; } OTBM_TownTemple_coords* wp_coords; if(!propStream.GET_STRUCT(wp_coords)){ setLastErrorString("Could not read waypoint coordinates."); return false; } pos.x = wp_coords->_x; pos.y = wp_coords->_y; pos.z = wp_coords->_z; Waypoint_ptr wp(new Waypoint(name, pos)); map->waypoints.addWaypoint(wp); } else{ setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else{ setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } std::cout << "Notice: [OTBM Loader] Loading time : " << (OTSYS_TIME() - start)/(1000.) << " s" << std::endl; return true; }