void Game::useWith(const ItemPtr& item, const ThingPtr& toThing) { if(!canPerformGameAction() || !item || !toThing) return; Position pos = item->getPosition(); if(!pos.isValid()) // virtual item pos = Position(0xFFFF, 0, 0); // means that is a item in inventory if(toThing->isCreature()) m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackpos(), toThing->getId()); else m_protocolGame->sendUseItemWith(pos, item->getId(), item->getStackpos(), toThing->getPosition(), toThing->getId(), toThing->getStackpos()); }
int Game::open(const ItemPtr& item, const ContainerPtr& previousContainer) { if(!canPerformGameAction() || !item) return -1; int id = 0; if(!previousContainer) id = findEmptyContainerId(); else id = previousContainer->getId(); m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackPos(), id); return id; }
void Game::open(const ItemPtr& item, const ContainerPtr& previousContainer) { if(!canPerformGameAction() || !item) return; int id = 0; if(!previousContainer) { // find a free container id while(m_containers[id] != nullptr) id++; } else { id = previousContainer->getId(); } m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), id); }
void Map::saveOtcm(const std::string& fileName) { #if 0 try { g_clock.update(); FileStreamPtr fin = g_resources.createFile(fileName); fin->cache(); //TODO: compression flag with zlib uint32 flags = 0; // header fin->addU32(OTCM_SIGNATURE); fin->addU16(0); // data start, will be overwritten later fin->addU16(OTCM_VERSION); fin->addU32(flags); // version 1 header fin->addString("OTCM 1.0"); // map description fin->addU32(g_things.getDatSignature()); fin->addU16(g_game.getClientVersion()); fin->addString(g_game.getWorldName()); // go back and rewrite where the map data starts uint32 start = fin->tell(); fin->seek(4); fin->addU16(start); fin->seek(start); for(auto& pair : m_tiles) { const TilePtr& tile = pair.second; if(!tile || tile->isEmpty()) continue; Position pos = pair.first; fin->addU16(pos.x); fin->addU16(pos.y); fin->addU8(pos.z); const auto& list = tile->getThings(); auto first = std::find_if(list.begin(), list.end(), [](const ThingPtr& thing) { return thing->isItem(); }); for(auto it = first, end = list.end(); it != end; ++it) { const ThingPtr& thing = *it; if(thing->isItem()) { ItemPtr item = thing->static_self_cast<Item>(); fin->addU16(item->getId()); fin->addU8(item->getCountOrSubType()); } } // end of tile fin->addU16(0xFFFF); } // end of file Position invalidPos; fin->addU16(invalidPos.x); fin->addU16(invalidPos.y); fin->addU8(invalidPos.z); fin->flush(); fin->close(); } catch(stdext::exception& e) { g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); } #endif }
void Map::loadOtbm(const std::string& fileName) { FileStreamPtr fin = g_resources.openFile(fileName); if(!fin) stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName)); fin->cache(); if(!g_things.isOtbLoaded()) stdext::throw_exception("OTB isn't loaded yet to load a map."); if(fin->getU32()) stdext::throw_exception("Unknown file version detected"); BinaryTreePtr root = fin->getBinaryTree(); if(root->getU8()) stdext::throw_exception("could not read root property!"); uint32 headerVersion = root->getU32(); if(!headerVersion || headerVersion > 3) stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); setWidth(root->getU16()); setHeight(root->getU16()); uint32 headerMajorItems = root->getU8(); if(headerMajorItems < 3) { stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", headerMajorItems, g_things.getOtbMajorVersion())); } if(headerMajorItems > g_things.getOtbMajorVersion()) { stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", headerMajorItems, g_things.getOtbMajorVersion())); } root->skip(3); uint32 headerMinorItems = root->getU32(); if(headerMinorItems > g_things.getOtbMinorVersion()) { g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d or less", headerMinorItems, g_things.getOtbMinorVersion())); } BinaryTreePtr node = root->getChildren()[0]; if(node->getU8() != OTBM_MAP_DATA) stdext::throw_exception("Could not read root data node"); while (node->canRead()) { uint8 attribute = node->getU8(); std::string tmp = node->getString(); switch (attribute) { case OTBM_ATTR_DESCRIPTION: setDescription(tmp); break; case OTBM_ATTR_SPAWN_FILE: setSpawnFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); break; case OTBM_ATTR_HOUSE_FILE: setHouseFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); break; default: stdext::throw_exception(stdext::format("Invalid attribute '%d'", (int)attribute)); } } for(const BinaryTreePtr &nodeMapData : node->getChildren()) { uint8 mapDataType = nodeMapData->getU8(); if(mapDataType == OTBM_TILE_AREA) { Position basePos = nodeMapData->getPosition(); for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { uint8 type = nodeTile->getU8(); if(type != OTBM_TILE && type != OTBM_HOUSETILE) stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); HousePtr house = nullptr; uint32 flags = TILESTATE_NONE; Position pos = basePos + nodeTile->getPoint(); if(type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); TilePtr tile = getOrCreateTile(pos); if(!(house = m_houses.getHouse(hId))) { house = HousePtr(new House(hId)); m_houses.addHouse(house); } house->setTile(tile); } while(nodeTile->canRead()) { uint8 tileAttr = nodeTile->getU8(); switch (tileAttr) { case OTBM_ATTR_TILE_FLAGS: { uint32 _flags = nodeTile->getU32(); if((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) flags |= TILESTATE_PROTECTIONZONE; else if((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) flags |= TILESTATE_OPTIONALZONE; else if((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) flags |= TILESTATE_HARDCOREZONE; if((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) flags |= TILESTATE_NOLOGOUT; if((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) flags |= TILESTATE_REFRESH; break; } case OTBM_ATTR_ITEM: { addThing(Item::createFromOtb(nodeTile->getU16()), pos); break; } default: { stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s", (int)tileAttr, stdext::to_string(pos))); } } } for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { if(nodeItem->getU8() != OTBM_ITEM) stdext::throw_exception("invalid item node"); ItemPtr item = Item::createFromOtb(nodeItem->getU16()); item->unserializeItem(nodeItem); if(item->isContainer()) { for(const BinaryTreePtr& containerItem : nodeItem->getChildren()) { if(containerItem->getU8() != OTBM_ITEM) stdext::throw_exception("invalid container item node"); ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); cItem->unserializeItem(containerItem); //item->addContainerItem(cItem); } } if(house && item->isMoveable()) { g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), stdext::to_string(pos))); item.reset(); } addThing(item, pos); } if(const TilePtr& tile = getTile(pos)) tile->setFlags((tileflags_t)flags); } } else if(mapDataType == OTBM_TOWNS) { TownPtr town = nullptr; for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { if(nodeTown->getU8() != OTBM_TOWN) stdext::throw_exception("invalid town node."); uint32 townId = nodeTown->getU32(); std::string townName = nodeTown->getString(); Position townCoords = nodeTown->getPosition(); if(!(town = m_towns.getTown(townId))) { town = TownPtr(new Town(townId, townName, townCoords)); m_towns.addTown(town); } } } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { if(nodeWaypoint->getU8() != OTBM_WAYPOINT) stdext::throw_exception("invalid waypoint node."); std::string name = nodeWaypoint->getString(); Position waypointPos = nodeWaypoint->getPosition(); if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end()) m_waypoints.insert(std::make_pair(waypointPos, name)); } } else stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); } g_logger.debug("OTBM read successfully."); fin->close(); loadSpawns(getSpawnFile()); // m_houses.load(getHouseFile()); }
void Map::saveOtcm(const std::string& fileName) { try { stdext::timer saveTimer; FileStreamPtr fin = g_resources.createFile(fileName); fin->cache(); //TODO: compression flag with zlib uint32 flags = 0; // header fin->addU32(OTCM_SIGNATURE); fin->addU16(0); // data start, will be overwritten later fin->addU16(OTCM_VERSION); fin->addU32(flags); // version 1 header fin->addString("OTCM 1.0"); // map description fin->addU32(g_things.getDatSignature()); fin->addU16(g_game.getProtocolVersion()); fin->addString(g_game.getWorldName()); // go back and rewrite where the map data starts uint32 start = fin->tell(); fin->seek(4); fin->addU16(start); fin->seek(start); for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { for(const auto& it : m_tileBlocks[z]) { const TileBlock& block = it.second; for(const TilePtr& tile : block.getTiles()) { if(!tile || tile->isEmpty()) continue; Position pos = tile->getPosition(); fin->addU16(pos.x); fin->addU16(pos.y); fin->addU8(pos.z); for(const ThingPtr& thing : tile->getThings()) { if(thing->isItem()) { ItemPtr item = thing->static_self_cast<Item>(); fin->addU16(item->getId()); fin->addU8(item->getCountOrSubType()); } } // end of tile fin->addU16(0xFFFF); } } } // end of file Position invalidPos; fin->addU16(invalidPos.x); fin->addU16(invalidPos.y); fin->addU8(invalidPos.z); fin->flush(); fin->close(); } catch(stdext::exception& e) { g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); } }
void Game::requestTrade(const ItemPtr& item, const CreaturePtr& creature) { if(!canPerformGameAction() || !item || !creature) return; m_protocolGame->sendRequestTrade(item->getPosition(), item->getId(), item->getStackpos(), creature->getId()); }
void Game::sellItem(const ItemPtr& item, int amount, bool ignoreEquipped) { if(!canPerformGameAction() || !item) return; m_protocolGame->sendSellItem(item->getId(), item->getSubType(), amount, ignoreEquipped); }
void Game::buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack) { if(!canPerformGameAction() || !item) return; m_protocolGame->sendBuyItem(item->getId(), item->getSubType(), amount, ignoreCapacity, buyWithBackpack); }
void Game::inspectNpcTrade(const ItemPtr& item) { if(!canPerformGameAction() || !item) return; m_protocolGame->sendInspectNpcTrade(item->getId(), item->getCount()); }
void Game::requestItemInfo(const ItemPtr& item, int index) { if(!canPerformGameAction()) return; m_protocolGame->sendRequestItemInfo(item->getId(), item->getSubType(), index); }
void Game::equipItem(const ItemPtr& item) { if(!canPerformGameAction()) return; m_protocolGame->sendEquipItem(item->getId(), item->getCountOrSubType()); }