/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ultima/ultima4/map/tile.h" #include "ultima/ultima4/core/config.h" #include "ultima/ultima4/game/context.h" #include "ultima/ultima4/game/creature.h" #include "ultima/ultima4/gfx/image.h" #include "ultima/ultima4/gfx/imagemgr.h" #include "ultima/ultima4/gfx/screen.h" #include "ultima/ultima4/map/location.h" #include "ultima/ultima4/core/settings.h" #include "ultima/ultima4/map/tileanim.h" #include "ultima/ultima4/map/tilemap.h" #include "ultima/ultima4/map/tileset.h" #include "ultima/ultima4/core/utils.h" namespace Ultima { namespace Ultima4 { TileId Tile::_nextId = 0; Tile::Tile(Tileset *tileset) : _id(_nextId++) , _name() , _tileSet(tileset) , _w(0) , _h(0) , _frames(0) , _scale(1) , _anim(nullptr) , _opaque(false) , _foreground() , _waterForeground() , rule(nullptr) , _imageName() , _looksLike() , _image(nullptr) , _tiledInDungeon(false) , _directions() , _animationRule("") { } Tile::~Tile() { deleteImage(); } void Tile::loadProperties(const ConfigElement &conf) { if (conf.getName() != "tile") return; _name = conf.getString("name"); // Get the name of the tile // Get the animation for the tile, if one is specified if (conf.exists("animation")) { _animationRule = conf.getString("animation"); } // See if the tile is opaque _opaque = conf.getBool("opaque"); _foreground = conf.getBool("usesReplacementTileAsBackground"); _waterForeground = conf.getBool("usesWaterReplacementTileAsBackground"); /* find the rule that applies to the current tile, if there is one. if there is no rule specified, it defaults to the "default" rule */ if (conf.exists("rule")) { rule = g_tileRules->findByName(conf.getString("rule")); if (rule == nullptr) rule = g_tileRules->findByName("default"); } else { rule = g_tileRules->findByName("default"); } // Get the number of frames the tile has _frames = conf.getInt("frames", 1); // Get the name of the image that belongs to this tile if (conf.exists("image")) _imageName = conf.getString("image"); else _imageName = Common::String("tile_") + _name; _tiledInDungeon = conf.getBool("tiledInDungeon"); if (conf.exists("directions")) { Common::String dirs = conf.getString("directions"); if (dirs.size() != (unsigned) _frames) error("Error: %ld directions for tile but only %d frames", (long) dirs.size(), _frames); for (unsigned i = 0; i < dirs.size(); i++) { if (dirs[i] == 'w') _directions.push_back(DIR_WEST); else if (dirs[i] == 'n') _directions.push_back(DIR_NORTH); else if (dirs[i] == 'e') _directions.push_back(DIR_EAST); else if (dirs[i] == 's') _directions.push_back(DIR_SOUTH); else error("Error: unknown direction specified by %c", dirs[i]); } } } Image *Tile::getImage() { if (!_image) loadImage(); return _image; } void Tile::loadImage() { if (!_image) { _scale = settings._scale; SubImage *subimage = nullptr; ImageInfo *info = imageMgr->get(_imageName); if (!info) { subimage = imageMgr->getSubImage(_imageName); if (subimage) info = imageMgr->get(subimage->_srcImageName); } if (!info) { // IF still no info loaded warning("Error: couldn't load image for tile '%s'", _name.c_str()); return; } /* FIXME: This is a hack to address the fact that there are 4 frames for the guard in VGA mode, but only 2 in EGA. Is there a better way to handle this? */ if (_name == "guard") { if (settings._videoType == "EGA") _frames = 2; else _frames = 4; } if (info->_image) info->_image->alphaOff(); if (info) { // Draw the tile from the image we found to our tile image Image *tiles = info->_image; assert(tiles); _w = (subimage ? subimage->width() *_scale : info->_width * _scale / info->_prescale); _h = (subimage ? (subimage->height() * _scale) / _frames : (info->_height * _scale / info->_prescale) / _frames); _image = Image::create(_w, _h * _frames, tiles->format()); if (_image->isIndexed()) _image->setPaletteFromImage(tiles); //info->image->alphaOff(); if (subimage) { tiles->drawSubRectOn(_image, 0, 0, subimage->left * _scale, subimage->top * _scale, subimage->width() * _scale, subimage->height() * _scale); } else { tiles->drawOn(_image, 0, 0); } } if (_animationRule.size() > 0) { _anim = nullptr; if (g_screen->_tileAnims) _anim = g_screen->_tileAnims->getByName(_animationRule); if (_anim == nullptr) warning("Warning: animation style '%s' not found", _animationRule.c_str()); } /* if we have animations, we always used 'animated' to draw from */ //if (anim) // image->alphaOff(); } } void Tile::deleteImage() { if (_image) { delete _image; _image = nullptr; } _scale = settings._scale; } bool Tile::isDungeonFloor() const { Tile *floor = _tileSet->getByName("brick_floor"); if (_id == floor->_id) return true; return false; } bool Tile::isOpaque() const { return g_context->_opacity ? _opaque : false; } bool Tile::isForeground() const { return (rule->_mask & MASK_FOREGROUND); } Direction Tile::directionForFrame(int frame) const { if (static_cast(frame) >= _directions.size()) return DIR_NONE; else return _directions[frame]; } int Tile::frameForDirection(Direction d) const { for (int i = 0; (unsigned) i < _directions.size() && i < _frames; i++) { if (_directions[i] == d) return i; } return -1; } } // End of namespace Ultima4 } // End of namespace Ultima