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/nuvie/core/tile_manager.h"
24 #include "ultima/nuvie/core/map.h"
25 #include "ultima/nuvie/core/obj_manager.h"
26 #include "ultima/nuvie/misc/u6_misc.h"
27 #include "ultima/nuvie/files/tmx_map.h"
28
29 namespace Ultima {
30 namespace Nuvie {
31
TMXMap(TileManager * tm,Map * m,ObjManager * om)32 TMXMap::TMXMap(TileManager *tm, Map *m, ObjManager *om) {
33 tile_manager = tm;
34 map = m;
35 obj_manager = om;
36 mapdata = NULL;
37 game_type = NUVIE_GAME_NONE;
38 }
39
~TMXMap()40 TMXMap::~TMXMap() {
41
42 }
43
exportTmxMapFiles(Std::string dir,nuvie_game_t type)44 bool TMXMap::exportTmxMapFiles(Std::string dir, nuvie_game_t type) {
45 savedir = dir;
46 savename = get_game_tag(type);
47 Std::string filename;
48 build_path(savedir, savename + "_tileset.bmp", filename);
49
50
51
52 tile_manager->exportTilesetToBmpFile(filename);
53
54 for (uint8 i = 0; i < 6; i++) {
55 writeRoofTileset(i);
56 exportMapLevel(i);
57 }
58
59 return true;
60 }
61
writeRoofTileset(uint8 level)62 void TMXMap::writeRoofTileset(uint8 level) {
63 if (map->get_roof_data(level) == NULL) {
64 return;
65 }
66
67 Std::string filename = map->getRoofTilesetFilename();
68 Std::string destFilename;
69 build_path(savedir, savename + "_roof_tileset.bmp", destFilename);
70 NuvieIOFileRead read;
71 NuvieIOFileWrite write;
72 read.open(filename);
73 write.open(destFilename);
74 unsigned char *buf = read.readAll();
75 write.writeBuf(buf, read.get_size());
76 write.close();
77 read.close();
78 free(buf);
79 }
80
writeLayer(NuvieIOFileWrite * tmx,uint16 sideLength,Std::string layerName,uint16 gidOffset,uint16 bitsPerTile,const unsigned char * data)81 void TMXMap::writeLayer(NuvieIOFileWrite *tmx, uint16 sideLength, Std::string layerName,
82 uint16 gidOffset, uint16 bitsPerTile, const unsigned char *data) {
83 Std::string slen = sint32ToString((sint32)sideLength);
84 Std::string header = " <layer name=\"" + layerName + "\" width=\"" + slen + "\" height=\""
85 + slen + "\">\n";
86 header += " <data encoding=\"csv\">\n";
87
88 tmx->writeBuf((const unsigned char *)header.c_str(), header.length());
89
90 char buf[5]; // 'nnnn\0'
91
92 uint16 mx, my;
93 for (my = 0; my < sideLength; my++) {
94 for (mx = 0; mx < sideLength; mx++) {
95 uint16 gid = 0;
96 if (bitsPerTile == 8) { //base map is uint8
97 gid = (uint16)data[my * sideLength + mx] + 1 + gidOffset;
98 } else { //everything else is uint16
99 gid = ((const uint16 *)data)[my * sideLength + mx] + 1 + gidOffset;
100 }
101 snprintf(buf, sizeof(buf), "%d", gid);
102 tmx->writeBuf((const unsigned char *)buf, strlen(buf));
103 if (mx < sideLength - 1 || my < sideLength - 1) { //don't write comma after last element in the array.
104 tmx->write1(',');
105 }
106 }
107 tmx->write1('\n');
108 }
109
110 Std::string footer = " </data>\n";
111 footer += " </layer>\n";
112
113 tmx->writeBuf((const unsigned char *)footer.c_str(), footer.length());
114 }
115
writeObjectLayer(NuvieIOFileWrite * tmx,uint8 level)116 void TMXMap::writeObjectLayer(NuvieIOFileWrite *tmx, uint8 level) {
117 Std::string xml = "<objectgroup name=\"Object Layer\">\n";
118 tmx->writeBuf((const unsigned char *)xml.c_str(), xml.length());
119
120 writeObjects(tmx, level, true, false);
121 writeObjects(tmx, level, false, false);
122 writeObjects(tmx, level, false, true);
123
124 xml = "</objectgroup>\n";
125 tmx->writeBuf((const unsigned char *)xml.c_str(), xml.length());
126 }
127
canDrawTile(Tile * t,bool forceLower,bool toptile)128 bool TMXMap::canDrawTile(Tile *t, bool forceLower, bool toptile) {
129 if (forceLower == false && (t->flags3 & 0x4) && toptile == false) //don't display force lower tiles.
130 return false;
131
132 if (forceLower == true && !(t->flags3 & 0x4))
133 return false;
134
135 if ((toptile && !t->toptile) || (!toptile && t->toptile))
136 return false;
137
138 return true;
139 }
140
writeObjectTile(Obj * obj,Std::string nameSuffix,uint16 tile_num,uint16 x,uint16 y,bool forceLower,bool toptile)141 Std::string TMXMap::writeObjectTile(Obj *obj, Std::string nameSuffix, uint16 tile_num, uint16 x, uint16 y, bool forceLower, bool toptile) {
142 Tile *t = tile_manager->get_tile(tile_num);
143
144 if (canDrawTile(t, forceLower, toptile)) {
145 return " <object name=\"" + encode_xml_entity(Std::string(obj_manager->get_obj_name(obj))) + nameSuffix + "\" gid=\"" + sint32ToString(tile_num + 1) + "\" x=\"" + sint32ToString(x * 16) + "\" y=\"" + sint32ToString((y + 1) * 16) + "\" width=\"16\" height=\"16\"/>\n";
146 }
147
148 return Std::string();
149 }
150
writeObjects(NuvieIOFileWrite * tmx,uint8 level,bool forceLower,bool toptiles)151 void TMXMap::writeObjects(NuvieIOFileWrite *tmx, uint8 level, bool forceLower, bool toptiles) {
152 uint16 width = map->get_width(level);
153
154 for (uint16 y = 0; y < width; y++) {
155 for (uint16 x = 0; x < width; x++) {
156 U6LList *list = obj_manager->get_obj_list(x, y, level);
157 if (list) {
158 for (U6Link *link = list->start(); link != NULL; link = link->next) {
159 Obj *obj = (Obj *)link->data;
160 Tile *t = tile_manager->get_original_tile(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n);
161 Std::string s;
162 if (canDrawTile(t, forceLower, toptiles)) {
163 s = " <object name=\"" + encode_xml_entity(Std::string(obj_manager->get_obj_name(obj))) + "\" gid=\"" + sint32ToString(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n + 1) + "\" x=\"" + sint32ToString((x) * 16) + "\" y=\"" + sint32ToString((y + 1) * 16) + "\" width=\"16\" height=\"16\">\n";
164 s += " <properties>\n";
165 s += " <property name=\"obj_n\" value=\"" + sint32ToString(obj->obj_n) + "\"/>\n";
166 s += " <property name=\"frame_n\" value=\"" + sint32ToString(obj->frame_n) + "\"/>\n";
167 s += " <property name=\"qty\" value=\"" + sint32ToString(obj->qty) + "\"/>\n";
168 s += " <property name=\"quality\" value=\"" + sint32ToString(obj->quality) + "\"/>\n";
169 s += " <property name=\"status\" value=\"" + sint32ToString(obj->status) + "\"/>\n";
170 s += " <property name=\"toptile\" value=\"" + boolToString(t->toptile) + "\"/>\n";
171 s += " </properties>\n";
172 s += " </object>\n";
173 }
174 if (t->dbl_width) {
175 s += writeObjectTile(obj, " -x", t->tile_num - 1, x - 1, y, forceLower, toptiles);
176 }
177 if (t->dbl_height) {
178 uint16 tile_num = t->tile_num - 1;
179 if (t->dbl_width) {
180 tile_num--;
181 }
182 s += writeObjectTile(obj, " -y", tile_num, x, y - 1, forceLower, toptiles);
183 }
184 if (t->dbl_width && t->dbl_height) {
185 s += writeObjectTile(obj, " -x,-y", t->tile_num - 3, x - 1, y - 1, forceLower, toptiles);
186 }
187 tmx->writeBuf((const unsigned char *)s.c_str(), s.length());
188 }
189 }
190 }
191 }
192 }
193
exportMapLevel(uint8 level)194 bool TMXMap::exportMapLevel(uint8 level) {
195 NuvieIOFileWrite tmx;
196 uint16 width = map->get_width(level);
197 mapdata = map->get_map_data(level);
198 char level_string[3]; // 'nn\0'
199 Std::string filename;
200 snprintf(level_string, sizeof(level_string), "%d", level);
201 build_path(savedir, savename + "_" + Std::string(level_string) + ".tmx", filename);
202
203 tmx.open(filename);
204 Std::string swidth = sint32ToString((sint32)width);
205 Std::string header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
206 header +=
207 "<map version=\"1.0\" orientation=\"orthogonal\" renderorder=\"right-down\" width=\""
208 + swidth + "\" height=\"" + swidth
209 + "\" tilewidth=\"16\" tileheight=\"16\">\n";
210 header +=
211 " <tileset firstgid=\"1\" name=\"tileset\" tilewidth=\"16\" tileheight=\"16\">\n";
212 header += " <image source=\"" + savename
213 + "_tileset.bmp\" trans=\"00dffc\" width=\"512\" height=\"1024\"/>\n";
214 header += " </tileset>\n";
215
216 if (map->get_roof_data(level) != NULL) {
217 header +=
218 " <tileset firstgid=\"2048\" name=\"roof_tileset\" tilewidth=\"16\" tileheight=\"16\">\n";
219 header += " <image source=\"" + savename + "_roof_tileset.bmp\" trans=\"0070fc\" width=\"80\" height=\"3264\"/>\n";
220 header += " </tileset>\n";
221 }
222
223 tmx.writeBuf((const unsigned char *)header.c_str(), header.length());
224
225 writeLayer(&tmx, width, "BaseLayer", 0, 8, mapdata);
226
227 writeObjectLayer(&tmx, level);
228
229 if (map->get_roof_data(level) != NULL) {
230 writeLayer(&tmx, width, "RoofLayer", 2047, 16, (const unsigned char *)map->get_roof_data(level));
231 }
232
233 Std::string footer = "</map>\n";
234
235
236 tmx.writeBuf((const unsigned char *)footer.c_str(), footer.length());
237
238
239
240 tmx.close();
241
242 return true;
243 }
244
sint32ToString(sint32 value)245 Std::string TMXMap::sint32ToString(sint32 value) {
246 char buf[12];
247 snprintf(buf, sizeof(buf), "%d", value);
248 return Std::string(buf);
249 }
250
boolToString(bool value)251 Std::string TMXMap::boolToString(bool value) {
252 return value ? Std::string("true") : Std::string("false");
253 }
254
255 } // End of namespace Nuvie
256 } // End of namespace Ultima
257