1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/ultima4/map/tile.h"
24 #include "ultima/ultima4/core/config.h"
25 #include "ultima/ultima4/game/context.h"
26 #include "ultima/ultima4/game/creature.h"
27 #include "ultima/ultima4/gfx/image.h"
28 #include "ultima/ultima4/gfx/imagemgr.h"
29 #include "ultima/ultima4/gfx/screen.h"
30 #include "ultima/ultima4/map/location.h"
31 #include "ultima/ultima4/core/settings.h"
32 #include "ultima/ultima4/map/tileanim.h"
33 #include "ultima/ultima4/map/tilemap.h"
34 #include "ultima/ultima4/map/tileset.h"
35 #include "ultima/ultima4/core/utils.h"
36
37 namespace Ultima {
38 namespace Ultima4 {
39
40 TileId Tile::_nextId = 0;
41
Tile(Tileset * tileset)42 Tile::Tile(Tileset *tileset)
43 : _id(_nextId++)
44 , _name()
45 , _tileSet(tileset)
46 , _w(0)
47 , _h(0)
48 , _frames(0)
49 , _scale(1)
50 , _anim(nullptr)
51 , _opaque(false)
52 , _foreground()
53 , _waterForeground()
54 , rule(nullptr)
55 , _imageName()
56 , _looksLike()
57 , _image(nullptr)
58 , _tiledInDungeon(false)
59 , _directions()
60 , _animationRule("") {
61 }
62
~Tile()63 Tile::~Tile() {
64 deleteImage();
65 }
66
loadProperties(const ConfigElement & conf)67 void Tile::loadProperties(const ConfigElement &conf) {
68 if (conf.getName() != "tile")
69 return;
70
71 _name = conf.getString("name"); // Get the name of the tile
72
73 // Get the animation for the tile, if one is specified
74 if (conf.exists("animation")) {
75 _animationRule = conf.getString("animation");
76 }
77
78 // See if the tile is opaque
79 _opaque = conf.getBool("opaque");
80
81 _foreground = conf.getBool("usesReplacementTileAsBackground");
82 _waterForeground = conf.getBool("usesWaterReplacementTileAsBackground");
83
84 /* find the rule that applies to the current tile, if there is one.
85 if there is no rule specified, it defaults to the "default" rule */
86 if (conf.exists("rule")) {
87 rule = g_tileRules->findByName(conf.getString("rule"));
88 if (rule == nullptr)
89 rule = g_tileRules->findByName("default");
90 } else {
91 rule = g_tileRules->findByName("default");
92 }
93
94 // Get the number of frames the tile has
95 _frames = conf.getInt("frames", 1);
96
97 // Get the name of the image that belongs to this tile
98 if (conf.exists("image"))
99 _imageName = conf.getString("image");
100 else
101 _imageName = Common::String("tile_") + _name;
102
103 _tiledInDungeon = conf.getBool("tiledInDungeon");
104
105 if (conf.exists("directions")) {
106 Common::String dirs = conf.getString("directions");
107 if (dirs.size() != (unsigned) _frames)
108 error("Error: %ld directions for tile but only %d frames", (long) dirs.size(), _frames);
109 for (unsigned i = 0; i < dirs.size(); i++) {
110 if (dirs[i] == 'w')
111 _directions.push_back(DIR_WEST);
112 else if (dirs[i] == 'n')
113 _directions.push_back(DIR_NORTH);
114 else if (dirs[i] == 'e')
115 _directions.push_back(DIR_EAST);
116 else if (dirs[i] == 's')
117 _directions.push_back(DIR_SOUTH);
118 else
119 error("Error: unknown direction specified by %c", dirs[i]);
120 }
121 }
122 }
123
getImage()124 Image *Tile::getImage() {
125 if (!_image)
126 loadImage();
127 return _image;
128 }
129
loadImage()130 void Tile::loadImage() {
131 if (!_image) {
132 _scale = settings._scale;
133
134 SubImage *subimage = nullptr;
135
136 ImageInfo *info = imageMgr->get(_imageName);
137 if (!info) {
138 subimage = imageMgr->getSubImage(_imageName);
139 if (subimage)
140 info = imageMgr->get(subimage->_srcImageName);
141 }
142 if (!info) { // IF still no info loaded
143 warning("Error: couldn't load image for tile '%s'", _name.c_str());
144 return;
145 }
146
147 /* FIXME: This is a hack to address the fact that there are 4
148 frames for the guard in VGA mode, but only 2 in EGA. Is there
149 a better way to handle this? */
150 if (_name == "guard") {
151 if (settings._videoType == "EGA")
152 _frames = 2;
153 else
154 _frames = 4;
155 }
156
157
158 if (info->_image)
159 info->_image->alphaOff();
160
161 if (info) {
162 _w = (subimage ? subimage->width() *_scale : info->_width * _scale / info->_prescale);
163 _h = (subimage ? (subimage->height() * _scale) / _frames : (info->_height * _scale / info->_prescale) / _frames);
164 _image = Image::create(_w, _h * _frames, false, Image::HARDWARE);
165
166
167 //info->image->alphaOff();
168
169 // Draw the tile from the image we found to our tile image
170 Image *tiles = info->_image;
171 assert(tiles);
172
173 if (subimage) {
174 tiles->drawSubRectOn(_image, 0, 0,
175 subimage->left * _scale, subimage->top * _scale,
176 subimage->width() * _scale, subimage->height() * _scale);
177 } else {
178 tiles->drawOn(_image, 0, 0);
179 }
180 }
181
182 if (_animationRule.size() > 0) {
183 _anim = nullptr;
184 if (g_screen->_tileAnims)
185 _anim = g_screen->_tileAnims->getByName(_animationRule);
186 if (_anim == nullptr)
187 warning("Warning: animation style '%s' not found", _animationRule.c_str());
188 }
189
190 /* if we have animations, we always used 'animated' to draw from */
191 //if (anim)
192 // image->alphaOff();
193
194
195 }
196 }
197
deleteImage()198 void Tile::deleteImage() {
199 if (_image) {
200 delete _image;
201 _image = nullptr;
202 }
203 _scale = settings._scale;
204 }
205
isDungeonFloor() const206 bool Tile::isDungeonFloor() const {
207 Tile *floor = _tileSet->getByName("brick_floor");
208 if (_id == floor->_id)
209 return true;
210 return false;
211 }
212
isOpaque() const213 bool Tile::isOpaque() const {
214 return g_context->_opacity ? _opaque : false;
215 }
216
isForeground() const217 bool Tile::isForeground() const {
218 return (rule->_mask & MASK_FOREGROUND);
219 }
220
directionForFrame(int frame) const221 Direction Tile::directionForFrame(int frame) const {
222 if (static_cast<unsigned>(frame) >= _directions.size())
223 return DIR_NONE;
224 else
225 return _directions[frame];
226 }
227
frameForDirection(Direction d) const228 int Tile::frameForDirection(Direction d) const {
229 for (int i = 0; (unsigned) i < _directions.size() && i < _frames; i++) {
230 if (_directions[i] == d)
231 return i;
232 }
233 return -1;
234 }
235
236 } // End of namespace Ultima4
237 } // End of namespace Ultima
238