#include "map.h" #include #include #include #include #include Map::Map(std::string_view name) : name_(name) { std::string filename = "../res/maps/" + std::string(name) + ".tmx"; tmx::Map mapfile; if (!mapfile.load(filename.c_str())) { throw std::invalid_argument("Could not find map file: " + filename); } const tmx::Vector2u& mapSize = mapfile.getTileCount(); mapSize_.x() = mapSize.x; mapSize_.y() = mapSize.y; const tmx::Vector2u& tileSize = mapfile.getTileSize(); tileSize_.x() = tileSize.x; tileSize_.y() = tileSize.y; int firstGID = 0; // There should only be one tileset. const tmx::Tileset& tileset = mapfile.getTilesets()[0]; firstGID = tileset.getFirstGID(); tilesetFilename_ = tileset.getImagePath(); tilesetColumns_ = tileset.getColumnCount(); for (const auto& layer : mapfile.getLayers()) { if (layer->getType() == tmx::Layer::Type::Tile) { const auto& tileLayer = layer->getLayerAs(); std::vector tilesToStore; for (const auto& maptile : tileLayer.getTiles()) { Tile tile; tile.id = maptile.ID - firstGID; tile.flipHorizontal = (maptile.flipFlags & tmx::TileLayer::Horizontal) != 0; tile.flipVertical = (maptile.flipFlags & tmx::TileLayer::Vertical) != 0; for (const tmx::Property& property : tileset.getTile(maptile.ID)->properties) { if (property.getName() == "solid" && property.getBoolValue()) { tile.blocked = true; } else if (property.getName() == "runSound") { tile.step = stepTypeFromString(property.getStringValue()); } else if (property.getName() == "medium") { if (property.getStringValue() == "ladder") { tile.medium = CharacterMedium::Ladder; } else if (property.getStringValue() == "water") { tile.medium = CharacterMedium::Water; } } } tilesToStore.push_back(std::move(tile)); } bool above = false; for (const tmx::Property& property : tileLayer.getProperties()) { if (property.getName() == "above" && property.getBoolValue()) { above = true; } } if (above) { upperLayers_.push_back(std::move(tilesToStore)); } else { lowerLayers_.push_back(std::move(tilesToStore)); } } else if (layer->getType() == tmx::Layer::Type::Object) { const auto& objectLayer = layer->getLayerAs(); bool masked = false; for (const tmx::Property& property : objectLayer.getProperties()) { if (property.getName() == "masked" && property.getBoolValue()) { masked = true; } } for (const tmx::Object& object : objectLayer.getObjects()) { if (object.getType() == "sprite") { Prototype p; p.name = object.getName(); p.pos.x() = object.getPosition().x; p.pos.y() = object.getPosition().y; p.masked = masked; for (const tmx::Property& property : object.getProperties()) { if (property.getName() == "collisionOffsetX") { p.collisionOffset.x() = property.getIntValue(); } else if (property.getName() == "collisionOffsetY") { p.collisionOffset.y() = property.getIntValue(); } else if (property.getName() == "collisionWidth") { p.collisionSize.w() = property.getIntValue(); } else if (property.getName() == "collisionHeight") { p.collisionSize.h() = property.getIntValue(); } else if (property.getName() == "animation") { p.animationFilename = "../res/sprites/" + property.getStringValue() + "_anim.txt"; } else if (property.getName() == "animName") { p.animName = property.getStringValue(); } else if (property.getName() == "direction") { p.dir = directionFromString(property.getStringValue()); } else if (property.getName() == "interactionScript") { p.interactionScript = property.getStringValue(); } else if (property.getName() == "shadow") { p.shadow = property.getBoolValue(); } else if (property.getName() == "wander") { p.wander = property.getBoolValue(); } else if (property.getName() == "enclosureZone") { p.enclosureZone = property.getStringValue(); } else if (property.getName() == "movementSpeed") { p.movementSpeed = property.getIntValue(); } else if (property.getName() == "mirror") { if (property.getStringValue() == "vertical") { p.mirrorType = MirrorType::Vertical; } } else if (property.getName() == "mirrorAxis") { p.mirrorAxis = property.getIntValue(); } else if (property.getName() == "mirrorSprite") { p.spriteToMirror = property.getStringValue(); } else if (property.getName() == "bumpPlayerScript") { p.bumpPlayerScript = property.getStringValue(); } else if (property.getName() == "backgroundScript") { p.backgroundScript = property.getStringValue(); } else if (property.getName() == "floating") { p.floating = property.getBoolValue(); } } prototypes_.push_back(std::move(p)); } else if (object.getType() == "warp") { vec2i point; point.x() = object.getPosition().x; point.y() = object.getPosition().y; warpPoints_[object.getName()] = std::move(point); } else if (object.getType() == "trigger") { Trigger t; t.name = object.getName(); t.pos.x() = object.getPosition().x; t.pos.y() = object.getPosition().y; t.size.w() = object.getAABB().width; t.size.h() = object.getAABB().height; for (const tmx::Property& property : object.getProperties()) { if (property.getName() == "script") { t.script = property.getStringValue(); } } triggers_.push_back(std::move(t)); } else if (object.getType() == "tileSprite") { Prototype p; p.name = object.getName(); p.pos.x() = std::floor(object.getPosition().x / 16) * 16; p.pos.y() = std::floor(object.getPosition().y / 16) * 16; p.collisionOffset = { 0, 0 }; p.collisionSize = { 16, 16 }; for (const tmx::Property& property : object.getProperties()) { if (property.getName() == "interactionScript") { p.interactionScript = property.getStringValue(); } } prototypes_.push_back(std::move(p)); } else if (object.getType() == "zone") { Zone z; z.ul.x() = object.getPosition().x; z.ul.y() = object.getPosition().y; z.dr.x() = z.ul.x() + object.getAABB().width; z.dr.y() = z.ul.y() + object.getAABB().height; zones_[object.getName()] = std::move(z); } } } } for (const tmx::Property& property : mapfile.getProperties()) { if (property.getName() == "music") { music_ = property.getStringValue(); } else if (property.getName() == "maskZone") { maskZone_ = property.getStringValue(); } else if (property.getName() == "exitArea") { hasExitArea_ = property.getBoolValue(); } } } bool Map::isBlocked(int x, int y) const { if (x < 0 || y < 0 || x >= mapSize_.w() || y >= mapSize_.h()) { return false; } int i = x + y * mapSize_.w(); for (const std::vector& layer : lowerLayers_) { if (layer.at(i).blocked) { return true; } } return false; } StepType Map::getStepType(int x, int y) const { if (x < 0 || y < 0 || x >= mapSize_.w() || y >= mapSize_.h()) { return StepType::none; } int i = x + y * mapSize_.w(); for (const std::vector& layer : lowerLayers_) { if (layer.at(i).step != StepType::none) { return layer.at(i).step; } } return StepType::none; } CharacterMedium Map::getMedium(int x, int y) const { CharacterMedium ret = CharacterMedium::Normal; if (x < 0 || y < 0 || x >= mapSize_.w() || y >= mapSize_.h()) { return ret; } int i = x + y * mapSize_.w(); for (const std::vector& layer : lowerLayers_) { if (layer.at(i).medium > ret) { ret = layer.at(i).medium; } } return ret; }