Пример #1
0
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();
}
Пример #2
0
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);
		}
	}
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}