void InventoryState::btnApplyTemplateClick(Action *) { // don't accept clicks when moving items // it's ok if the template is empty -- it will just result in clearing the // unit's inventory if (_inv->getSelectedItem() != 0) { return; } BattleUnit *unit = _battleGame->getSelectedUnit(); std::vector<BattleItem*> *unitInv = unit->getInventory(); Tile *groundTile = unit->getTile(); std::vector<BattleItem*> *groundInv = groundTile->getInventory(); RuleInventory *groundRuleInv = _game->getMod()->getInventory("STR_GROUND"); _clearInventory(_game, unitInv, groundTile); // attempt to replicate inventory template by grabbing corresponding items // from the ground. if any item is not found on the ground, display warning // message, but continue attempting to fulfill the template as best we can bool itemMissing = false; std::vector<EquipmentLayoutItem*>::iterator templateIt; for (templateIt = _curInventoryTemplate.begin(); templateIt != _curInventoryTemplate.end(); ++templateIt) { // search for template item in ground inventory std::vector<BattleItem*>::iterator groundItem; const bool needsAmmo = !_game->getMod()->getItem((*templateIt)->getItemType())->getCompatibleAmmo()->empty(); bool found = false; bool rescan = true; while (rescan) { rescan = false; const std::string targetAmmo = (*templateIt)->getAmmoItem(); BattleItem *matchedWeapon = NULL; BattleItem *matchedAmmo = NULL; for (groundItem = groundInv->begin(); groundItem != groundInv->end(); ++groundItem) { // if we find the appropriate ammo, remember it for later for if we find // the right weapon but with the wrong ammo const std::string groundItemName = (*groundItem)->getRules()->getType(); if (needsAmmo && targetAmmo == groundItemName) { matchedAmmo = *groundItem; } if ((*templateIt)->getItemType() == groundItemName) { // if the loaded ammo doesn't match the template item's, // remember the weapon for later and continue scanning BattleItem *loadedAmmo = (*groundItem)->getAmmoItem(); if ((needsAmmo && loadedAmmo && targetAmmo != loadedAmmo->getRules()->getType()) || (needsAmmo && !loadedAmmo)) { // remember the last matched weapon for simplicity (but prefer empty weapons if any are found) if (!matchedWeapon || matchedWeapon->getAmmoItem()) { matchedWeapon = *groundItem; } continue; } // move matched item from ground to the appropriate inv slot (*groundItem)->setOwner(unit); (*groundItem)->setSlot(_game->getMod()->getInventory((*templateIt)->getSlot())); (*groundItem)->setSlotX((*templateIt)->getSlotX()); (*groundItem)->setSlotY((*templateIt)->getSlotY()); (*groundItem)->setFuseTimer((*templateIt)->getFuseTimer()); unitInv->push_back(*groundItem); groundInv->erase(groundItem); found = true; break; } } // if we failed to find an exact match, but found unloaded ammo and // the right weapon, unload the target weapon, load the right ammo, and use it if (!found && matchedWeapon && (!needsAmmo || matchedAmmo)) { // unload the existing ammo (if any) from the weapon BattleItem *loadedAmmo = matchedWeapon->getAmmoItem(); if (loadedAmmo) { groundTile->addItem(loadedAmmo, groundRuleInv); matchedWeapon->setAmmoItem(NULL); } // load the correct ammo into the weapon if (matchedAmmo) { matchedWeapon->setAmmoItem(matchedAmmo); groundTile->removeItem(matchedAmmo); } // rescan and pick up the newly-loaded/unloaded weapon rescan = true; } } if (!found) { itemMissing = true; } } if (itemMissing) { _inv->showWarning(tr("STR_NOT_ENOUGH_ITEMS_FOR_TEMPLATE")); } // refresh ui _inv->arrangeGround(false); updateStats(); _refreshMouse(); // give audio feedback _game->getMod()->getSoundByDepth(_battleGame->getDepth(), Mod::ITEM_DROP)->play(); }
void GUI::FillDoodadPreviewBuffer() { DoodadBrush* brush = dynamic_cast<DoodadBrush*>(current_brush); if(!brush) return; doodad_buffer_map->clear(); if(brush->isEmpty(GetBrushVariation())) return; int object_count = 0; int area; if(GetBrushShape() == BRUSHSHAPE_SQUARE) { area = 2*GetBrushSize(); area = area*area + 1; } else { if(GetBrushSize() == 1) { // There is a huge deviation here with the other formula. area = 5; } else { area = int(0.5 + GetBrushSize() * GetBrushSize() * PI); } } const int object_range = (use_custom_thickness? int(area*custom_thickness_mod) : brush->getThickness() * area / max(1, brush->getThicknessCeiling())); const int final_object_count = max(1, object_range + random(object_range)); Position center_pos(0x8000, 0x8000, 0x8); if(brush_size > 0 && !brush->oneSizeFitsAll()) { while(object_count < final_object_count) { int retries = 0; bool exit = false; // Try to place objects 5 times while(retries < 5 && !exit) { int pos_retries = 0; int xpos = 0, ypos = 0; bool found_pos = false; if(GetBrushShape() == BRUSHSHAPE_CIRCLE) { while(pos_retries < 5 && !found_pos) { xpos = random(-brush_size, brush_size); ypos = random(-brush_size, brush_size); float distance = sqrt(float(xpos*xpos) + float(ypos*ypos)); if(distance < g_gui.GetBrushSize() + 0.005) { found_pos = true; } else { ++pos_retries; } } } else { found_pos = true; xpos = random(-brush_size, brush_size); ypos = random(-brush_size, brush_size); } if(!found_pos) { ++retries; continue; } // Decide whether the zone should have a composite or several single objects. bool fail = false; if(random(brush->getTotalChance(GetBrushVariation())) <= brush->getCompositeChance(GetBrushVariation())) { // Composite const CompositeTileList& composites = brush->getComposite(GetBrushVariation()); // Figure out if the placement is valid for(CompositeTileList::const_iterator composite_iter = composites.begin(); composite_iter != composites.end(); ++composite_iter) { Position pos = center_pos + composite_iter->first + Position(xpos, ypos, 0); if(Tile* tile = doodad_buffer_map->getTile(pos)) { if(tile->size() > 0) { fail = true; break; } } } if(fail) { ++retries; break; } // Transfer items to the stack for(CompositeTileList::const_iterator composite_iter = composites.begin(); composite_iter != composites.end(); ++composite_iter) { Position pos = center_pos + composite_iter->first + Position(xpos, ypos, 0); const ItemVector& items = composite_iter->second; Tile* tile = doodad_buffer_map->getTile(pos); if(!tile) tile = doodad_buffer_map->allocator(doodad_buffer_map->createTileL(pos)); for(ItemVector::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) { tile->addItem((*item_iter)->deepCopy()); } doodad_buffer_map->setTile(tile->getPosition(), tile); } exit = true; } else if(brush->hasSingleObjects(GetBrushVariation())) { Position pos = center_pos + Position(xpos, ypos, 0); Tile* tile = doodad_buffer_map->getTile(pos); if(tile) { if(tile->size() > 0) { fail = true; break; } } else { tile = doodad_buffer_map->allocator(doodad_buffer_map->createTileL(pos)); } int variation = GetBrushVariation(); brush->draw(doodad_buffer_map, tile, &variation); //std::cout << "\tpos: " << tile->getPosition() << std::endl; doodad_buffer_map->setTile(tile->getPosition(), tile); exit = true; } if(fail) { ++retries; break; } } ++object_count; } } else { if(brush->hasCompositeObjects(GetBrushVariation()) && random(brush->getTotalChance(GetBrushVariation())) <= brush->getCompositeChance(GetBrushVariation())) { // Composite const CompositeTileList& composites = brush->getComposite(GetBrushVariation()); // All placement is valid... // Transfer items to the buffer for(CompositeTileList::const_iterator composite_iter = composites.begin(); composite_iter != composites.end(); ++composite_iter) { Position pos = center_pos + composite_iter->first; const ItemVector& items = composite_iter->second; Tile* tile = doodad_buffer_map->allocator(doodad_buffer_map->createTileL(pos)); //std::cout << pos << " = " << center_pos << " + " << buffer_tile->getPosition() << std::endl; for(ItemVector::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) { tile->addItem((*item_iter)->deepCopy()); } doodad_buffer_map->setTile(tile->getPosition(), tile); } } else if(brush->hasSingleObjects(GetBrushVariation())) { Tile* tile = doodad_buffer_map->allocator(doodad_buffer_map->createTileL(center_pos)); int variation = GetBrushVariation(); brush->draw(doodad_buffer_map, tile, &variation); doodad_buffer_map->setTile(center_pos, tile); } } }
bool Map::convert(const ConversionMap& rm, bool showdialog) { if(showdialog) gui.CreateLoadBar(wxT("Converting map ...")); uint64_t tiles_done = 0; std::vector<uint16_t> id_list; //std::ofstream conversions("converted_items.txt"); for(MapIterator miter = begin(); miter != end(); ++miter) { Tile* tile = (*miter)->get(); ASSERT(tile); if(tile->size() == 0) continue; // id_list try MTM conversion id_list.clear(); if(tile->ground) id_list.push_back(tile->ground->getID()); for(ItemVector::const_iterator item_iter = tile->items.begin(); item_iter != tile->items.end(); ++item_iter) if((*item_iter)->isBorder()) id_list.push_back((*item_iter)->getID()); std::sort(id_list.begin(), id_list.end()); ConversionMap::MTM::const_iterator cfmtm = rm.mtm.end(); while(id_list.size()) { cfmtm = rm.mtm.find(id_list); if(cfmtm != rm.mtm.end()) break; id_list.pop_back(); } // Keep track of how many items have been inserted at the bottom size_t inserted_items = 0; if(cfmtm != rm.mtm.end()) { const std::vector<uint16_t>& v = cfmtm->first; if(tile->ground && std::find(v.begin(), v.end(), tile->ground->getID()) != v.end()) { delete tile->ground; tile->ground = nullptr; } for(ItemVector::iterator item_iter = tile->items.begin(); item_iter != tile->items.end(); ) { if(std::find(v.begin(), v.end(), (*item_iter)->getID()) != v.end()) { delete *item_iter; item_iter = tile->items.erase(item_iter); } else ++item_iter; } const std::vector<uint16_t>& new_items = cfmtm->second; for(std::vector<uint16_t>::const_iterator iit = new_items.begin(); iit != new_items.end(); ++iit) { Item* item = Item::Create(*iit); if(item->isGroundTile()) tile->ground = item; else { tile->items.insert(tile->items.begin(), item); ++inserted_items; } } } if(tile->ground) { ConversionMap::STM::const_iterator cfstm = rm.stm.find(tile->ground->getID()); if(cfstm != rm.stm.end()) { uint16_t aid = tile->ground->getActionID(); uint16_t uid = tile->ground->getUniqueID(); delete tile->ground; tile->ground = nullptr; const std::vector<uint16_t>& v = cfstm->second; //conversions << "Converted " << tile->getX() << ":" << tile->getY() << ":" << tile->getZ() << " " << id << " -> "; for(std::vector<uint16_t>::const_iterator iit = v.begin(); iit != v.end(); ++iit) { Item* item = Item::Create(*iit); //conversions << *iit << " "; if(item->isGroundTile()) { item->setActionID(aid); item->setUniqueID(uid); tile->addItem(item); } else { tile->items.insert(tile->items.begin(), item); ++inserted_items; } } //conversions << std::endl; } } for(ItemVector::iterator replace_item_iter = tile->items.begin() + inserted_items; replace_item_iter != tile->items.end(); ) { uint16_t id = (*replace_item_iter)->getID(); ConversionMap::STM::const_iterator cf = rm.stm.find(id); if(cf != rm.stm.end()) { //uint16_t aid = (*replace_item_iter)->getActionID(); //uint16_t uid = (*replace_item_iter)->getUniqueID(); delete *replace_item_iter; replace_item_iter = tile->items.erase(replace_item_iter); const std::vector<uint16_t>& v = cf->second; for(std::vector<uint16_t>::const_iterator iit = v.begin(); iit != v.end(); ++iit) { replace_item_iter = tile->items.insert(replace_item_iter, Item::Create(*iit)); //conversions << "Converted " << tile->getX() << ":" << tile->getY() << ":" << tile->getZ() << " " << id << " -> " << *iit << std::endl; ++replace_item_iter; } } else ++replace_item_iter; } ++tiles_done; if(showdialog && tiles_done % 0x10000 == 0) { gui.SetLoadDone(int(tiles_done / double(getTileCount()) * 100.0)); } } if(showdialog) gui.DestroyLoadBar(); return true; }
Tile* LiveSocket::readTile(BinaryNode* node, Editor& editor, const Position* position) { ASSERT(node != nullptr); Map& map = editor.map; uint8_t tileType; node->getByte(tileType); if(tileType != OTBM_TILE && tileType != OTBM_HOUSETILE) { return nullptr; } Position pos; if(position) { pos = *position; } else { uint16_t x; node->getU16(x); pos.x = x; uint16_t y; node->getU16(y); pos.y = y; uint8_t z; node->getU8(z); pos.z = z; } Tile* tile = map.allocator( map.createTileL(pos) ); if(tileType == OTBM_HOUSETILE) { uint32_t houseId; if(!node->getU32(houseId)) { //warning(wxT("House tile without house data, discarding tile")); delete tile; return nullptr; } if(houseId) { House* house = map.houses.getHouse(houseId); if(house) { tile->setHouse(house); } } else { //warning(wxT("Invalid house id from tile %d:%d:%d"), pos.x, pos.y, pos.z); } } uint8_t attribute; while(node->getU8(attribute)) { switch (attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags = 0; if(!node->getU32(flags)) { //warning(wxT("Invalid tile flags of tile on %d:%d:%d"), pos.x, pos.y, pos.z); } tile->setMapFlags(flags); break; } case OTBM_ATTR_ITEM: { Item* item = Item::Create_OTBM(mapVersion, node); if(!item) { //warning(wxT("Invalid item at tile %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); break; } default: //warning(wxT("Unknown tile attribute at %d:%d:%d"), pos.x, pos.y, pos.z); break; } } //for(BinaryNode* itemNode = node->getChild(); itemNode; itemNode->advance()) { BinaryNode* itemNode = node->getChild(); if(itemNode) do { uint8_t itemType; if(!itemNode->getByte(itemType)) { //warning(wxT("Unknown item type %d:%d:%d"), pos.x, pos.y, pos.z); delete tile; return nullptr; } if(itemType == OTBM_ITEM) { Item* item = Item::Create_OTBM(mapVersion, itemNode); if(item) { if(!item->unserializeItemNode_OTBM(mapVersion, itemNode)) { //warning(wxT("Couldn't unserialize item attributes at %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); } } else { //warning(wxT("Unknown type of tile child node")); } //} } while(itemNode->advance()); return tile; }
bool IOMapOTMM::loadMap(Map& map, NodeFileReadHandle& f, const FileName& identifier, bool showdialog) { BinaryNode* root = f.getRootNode(); if(!root) { error(wxT("Could not read root node.")); return false; } root->skip(1); // Skip the type byte uint8_t u8; uint16_t u16; uint32_t u32; if(!root->getU32(u32) || u32 != 1) { // Version error(wxT("Unsupported or damaged map version.")); return false; } if(!root->getU16(u16)) { error(wxT("Could not read root header.")); return false; } map.width = u16; if(!root->getU16(u16)) { error(wxT("Could not read root header.")); return false; } map.height = u16; if(!root->getU32(u32) || u32 > (unsigned long)item_db.MajorVersion) { // OTB major version if(queryUser(wxT("Map error"), wxT("The loaded map appears to be a items.otb format that deviates from the items.otb loaded by the editor. Do you still want to attempt to load the map?"))) { warning(wxT("Unsupported or damaged map version")); } else { error(wxT("Outdated items.otb, could not load map.")); return false; } } if(!root->getU32(u32) || u32 > (unsigned long)item_db.MinorVersion) { // OTB minor version warning(wxT("The editor needs an updated items.otb version.")); } BinaryNode* mapHeaderNode = root->getChild(); if(mapHeaderNode == NULL || !mapHeaderNode->getByte(u8) || u8 != OTMM_MAP_DATA) { error(wxT("Could not get root child node. Cannot recover from fatal error!")); return false; } int nodes_loaded = 0; BinaryNode* mapNode = mapHeaderNode->getChild(); if(mapNode) do { ++nodes_loaded; if(showdialog && nodes_loaded % 15 == 0) { gui.SetLoadDone(int(100.0 * f.tell() / f.size())); } uint8_t node_type; if(!mapNode->getByte(node_type)) { warning(wxT("Invalid map node")); continue; } switch(node_type) { case OTMM_EDITOR: { } break; case OTMM_DESCRIPTION: { std::string desc; mapNode->getString(desc); map.setMapDescription(desc); } break; case OTMM_TILE_DATA: { BinaryNode* tileNode = mapNode->getChild(); if(tileNode) do { Tile* tile = NULL; uint8_t tile_type; if(!tileNode->getByte(tile_type)) { warning(wxT("Invalid tile type")); continue; } if(tile_type != OTMM_TILE && tile_type != OTMM_HOUSETILE) { warning(wxT("Unknown type of tile node")); continue; } uint16_t x_offset, y_offset; uint8_t z_offset; if(!tileNode->getU16(x_offset) || !tileNode->getU16(y_offset) || !tileNode->getU8(z_offset) ) { warning(wxT("Could not read position of tile")); continue; } const Position pos(x_offset, y_offset, z_offset); if(map.getTile(pos)) { warning(wxT("Duplicate tile at %d:%d:%d, discarding duplicate"), pos.x, pos.y, pos.z); continue; } tile = map.allocator(pos); House* house = NULL; if(tile_type == OTMM_HOUSETILE) { uint32_t house_id; if(!tileNode->getU32(house_id)) { warning(wxT("House tile without house data, discarding tile")); continue; } if(house_id) { house = map.houses.getHouse(house_id); if(!house) { house = newd House(map); house->id = house_id; map.houses.addHouse(house); } } else { warning(wxT("Invalid house id from tile %d:%d:%d"), pos.x, pos.y, pos.z); } } uint16_t ground_id; tileNode->getU16(ground_id); if(ground_id != 0) { tile->addItem(Item::Create(ground_id)); } uint8_t attribute; while(tileNode->getU8(attribute)) { switch(attribute) { case OTMM_ATTR_TILE_FLAGS: { uint32_t flags = 0; if(!tileNode->getU32(flags)) { warning(wxT("Invalid tile flags of tile on %d:%d:%d"), pos.x, pos.y, pos.z); } tile->setMapFlags(flags); } break; default: { warning(wxT("Unknown tile attribute at %d:%d:%d"), pos.x, pos.y, pos.z); } break; } } BinaryNode* itemNode = tileNode->getChild(); if(itemNode) do { Item* item = NULL; uint8_t item_type; if(!itemNode->getByte(item_type)) { warning(wxT("Unknown item type %d:%d:%d"), pos.x, pos.y, pos.z); continue; } if(item_type == OTMM_ITEM) { item = Item::Create_OTMM(*this, itemNode); if(item) { if(item->unserializeItemNode_OTMM(*this, itemNode) == false) { warning(wxT("Couldn't unserialize item attributes at %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); } } else { warning(wxT("Unknown type of tile child node")); } } while(itemNode->advance()); tile->update(); if(house) { house->addTile(tile); } map.setTile(pos, tile); } while(tileNode->advance()); } break; case OTMM_SPAWN_DATA: { BinaryNode* spawnNode = mapNode->getChild(); if(spawnNode) do { uint8_t spawn_type; if(!spawnNode->getByte(spawn_type)) { warning(wxT("Could not read spawn type.")); continue; } if(spawn_type != OTMM_SPAWN_AREA) { warning(wxT("Invalid spawn type.")); continue; } // Read position uint16_t spawn_x, spawn_y; uint8_t spawn_z; uint32_t radius; if(!spawnNode->getU16(spawn_x) || !spawnNode->getU16(spawn_y) || !spawnNode->getU8(spawn_z) ) { warning(wxT("Could not read spawn position.")); continue; } const Position spawnpos(spawn_x, spawn_y, spawn_z); // Read radius if(!spawnNode->getU32(radius)) { warning(wxT("Could not read spawn radius.")); continue; } // Adjust radius radius = min(radius, uint32_t(settings.getInteger(Config::MAX_SPAWN_RADIUS))); // Create and assign spawn Tile* spawn_tile = map.getTile(spawnpos); if(spawn_tile && spawn_tile->spawn) { warning(wxT("Duplicate spawn on position %d:%d:%d\n"), spawn_tile->getX(), spawn_tile->getY(), spawn_tile->getZ()); continue; } Spawn* spawn = newd Spawn(radius); if(!spawn_tile) { spawn_tile = map.allocator(spawnpos); map.setTile(spawnpos, spawn_tile); } spawn_tile->spawn = spawn; map.addSpawn(spawn_tile); // Read any creatures associated with the spawn BinaryNode* creatureNode = spawnNode->getChild(); if(creatureNode) do { uint8_t creature_type; if(!creatureNode->getByte(creature_type)) { warning(wxT("Could not read type of creature node.")); continue; } bool isNPC; std::string name; uint32_t spawntime = 0; // Only applicable for monsters if(creature_type == OTMM_NPC) { isNPC = true; if(!creatureNode->getString(name)) { warning(wxT("Could not read name of NPC.")); return false; } } else if(creature_type == OTMM_MONSTER) { isNPC = false; if(!creatureNode->getString(name)) { warning(wxT("Could not read name of monster.")); return false; } if(!creatureNode->getU32(spawntime)) { warning(wxT("Could not read spawn time of monster.")); return false; } } else { warning(wxT("Unknown creature node type (0x%.2x)."), creature_type); return false; } // Read creature position uint16_t creature_x, creature_y; uint8_t creature_z; if(!creatureNode->getU16(creature_x) || !creatureNode->getU16(creature_y) || !creatureNode->getU8(creature_z) ) { warning(wxT("Could not read creature position.")); continue; } const Position creaturepos(creature_x, creature_y, creature_z); // Check radius if(uint32_t(abs(creaturepos.x - spawnpos.x)) > radius || uint32_t(abs(creaturepos.y - spawnpos.y)) > radius) { // Outside of the spawn... } // Create creature and put on map Tile* creature_tile; if(creaturepos == spawnpos) { creature_tile = spawn_tile; } else { creature_tile = map.getTile(creaturepos); } if(!creature_tile) { warning(wxT("Discarding creature \"%s\" at %d:%d:%d due to invalid position"), name.c_str(), creaturepos.x, creaturepos.y, creaturepos.z); break; } if(creature_tile->creature) { warning(wxT("Duplicate creature \"%s\" at %d:%d:%d, discarding"), name.c_str(), creaturepos.x, creaturepos.y, creaturepos.z); break; } CreatureType* type = creature_db[name]; if(!type) { type = creature_db.addMissingCreatureType(name, isNPC); } Creature* creature = newd Creature(type); creature->setSpawnTime(spawntime); creature_tile->creature = creature; if(creature_tile->spawn_count == 0) { // No spawn, create a newd one (this happends if the radius of the spawn has been decreased due to settings) ASSERT(creature_tile->spawn == NULL); Spawn* spawn = newd Spawn(5); creature_tile->spawn = spawn; map.addSpawn(creature_tile); } } while(creatureNode->advance()); } while(spawnNode->advance()); } break; case OTMM_TOWN_DATA: { BinaryNode* townNode = mapNode->getChild(); if(townNode) do { uint8_t town_type; if(!townNode->getByte(town_type)) { warning(wxT("Could not read town type")); continue; } if(town_type != OTMM_TOWN) { warning(wxT("Unknown town type")); continue; } uint32_t town_id; if(!townNode->getU32(town_id)) { warning(wxT("Invalid town id")); continue; } Town* town = map.towns.getTown(town_id); if(town) { warning(wxT("Duplicate town id %d, discarding duplicate"), town_id); continue; } else { town = newd Town(town_id); if(!map.towns.addTown(town)) { delete town; continue; } } std::string town_name; if(!townNode->getString(town_name)) { warning(wxT("Invalid town name")); continue; } town->setName(town_name); Position pos; uint16_t x; uint16_t y; uint8_t z; if(!townNode->getU16(x) || !townNode->getU16(y) || !townNode->getU8(z)) { warning(wxT("Invalid town temple position")); continue; } pos.x = x; pos.y = y; pos.z = z; town->setTemplePosition(pos); } while(townNode->advance()); } break; case OTMM_HOUSE_DATA: { BinaryNode* houseNode = mapNode->getChild(); if(houseNode) do { uint8_t house_type; if(!houseNode->getByte(house_type)) { warning(wxT("Could not read house type")); continue; } if(house_type != OTMM_HOUSE) { warning(wxT("Unknown house type.")); continue; } uint32_t house_id; if(!houseNode->getU32(house_id)) { warning(wxT("Could not read house id.")); continue; } House* house = map.houses.getHouse(house_id); if(!house) { continue; } std::string house_name; if(!houseNode->getString(house_name)) { warning(wxT("Could not read house name.")); continue; } uint32_t town_id; if(!houseNode->getU32(town_id)) { warning(wxT("Could not read house town id.")); continue; } uint32_t rent; if(!houseNode->getU32(rent)) { warning(wxT("Could not read house rent.")); continue; } house->name = house_name; house->townid = town_id; house->rent = rent; uint16_t x; uint16_t y; uint8_t z; if(!houseNode->getU16(x) || !houseNode->getU16(y) || !houseNode->getU8(z)) { warning(wxT("Invalid town temple position")); continue; } house->setExit(Position(x, y, z)); } while(houseNode->advance()); } break; } } while(mapNode->advance()); return true; }