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 "common/fs.h"
24 #include "common/config-manager.h"
25 
26 #include "prince/prince.h"
27 #include "prince/graphics.h"
28 #include "prince/debugger.h"
29 #include "prince/script.h"
30 #include "prince/hero.h"
31 #include "prince/resource.h"
32 #include "prince/archive.h"
33 
34 namespace Prince {
35 
getDecompressedStream(Common::SeekableReadStream * stream)36 Common::SeekableReadStream *Resource::getDecompressedStream(Common::SeekableReadStream *stream) {
37 	if (!(((PrinceEngine *)g_engine)->getFeatures() & GF_EXTRACTED))
38 		return stream;
39 
40 	byte header[4];
41 
42 	stream->read(header, 4);
43 	stream->seek(0);
44 
45 	if (READ_BE_UINT32(header) == MKTAG('M', 'A', 'S', 'M')) {
46 		byte *buffer = (byte *)malloc(stream->size());
47 		stream->read(buffer, stream->size());
48 
49 		Decompressor dec;
50 		uint32 decompLen = READ_BE_UINT32(buffer + 14);
51 		byte *decompData = (byte *)malloc(decompLen);
52 		dec.decompress(buffer + 18, decompData, decompLen);
53 		free(buffer);
54 
55 		debug(8, "Resource::getDecompressedStream: decompressed %d to %d bytes", stream->size(), decompLen);
56 
57 		return new Common::MemoryReadStream(decompData, decompLen, DisposeAfterUse::YES);
58 	} else {
59 		return stream;
60 	}
61 }
62 
loadFromStream(Common::SeekableReadStream & stream)63 bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) {
64 	int32 pos = stream.pos();
65 
66 	uint16 type = stream.readUint16LE();
67 	if (type == 0xFFFF) {
68 		return false;
69 	}
70 	_type = type;
71 	_fileNumber = stream.readUint16LE();
72 	_startPhase = stream.readUint16LE();
73 	_endPhase = stream.readUint16LE();
74 	_loopPhase = stream.readUint16LE();
75 	_x = stream.readSint16LE();
76 	_y = stream.readSint16LE();
77 	_loopType = stream.readUint16LE();
78 	_nextAnim = stream.readUint16LE();
79 	_flags = stream.readUint16LE();
80 
81 	debug(7, "AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags);
82 	debug(7, "startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase);
83 
84 	// 32 byte aligment
85 	stream.seek(pos + 32);
86 
87 	return true;
88 }
89 
loadLocation(uint16 locationNr)90 bool PrinceEngine::loadLocation(uint16 locationNr) {
91 
92 	blackPalette();
93 
94 	_flicPlayer.close();
95 
96 	memset(_textSlots, 0, sizeof(_textSlots));
97 	freeAllSamples();
98 
99 	debugEngine("PrinceEngine::loadLocation %d", locationNr);
100 	const Common::FSNode gameDataDir(ConfMan.get("path"));
101 	SearchMan.remove(Common::String::format("%02d", _locationNr));
102 
103 	_locationNr = locationNr;
104 	_debugger->_locationNr = locationNr;
105 
106 	_flags->setFlagValue(Flags::CURRROOM, _locationNr);
107 	_interpreter->stopBg();
108 
109 	changeCursor(0);
110 
111 	const Common::String locationNrStr = Common::String::format("%02d", _locationNr);
112 	debugEngine("loadLocation %s", locationNrStr.c_str());
113 
114 	if (!(getFeatures() & GF_EXTRACTED)) {
115 		PtcArchive *locationArchive = new PtcArchive();
116 		if (!locationArchive->open(locationNrStr + "/databank.ptc"))
117 			error("Can't open location %s", locationNrStr.c_str());
118 
119 		SearchMan.add(locationNrStr, locationArchive);
120 	} else {
121 		SearchMan.addSubDirectoryMatching(gameDataDir, locationNrStr);
122 	}
123 
124 	loadMusic(_locationNr);
125 
126 	// load location background, replace old one
127 	Resource::loadResource(_roomBmp, "room", true);
128 	if (_roomBmp->getSurface()) {
129 		_sceneWidth = _roomBmp->getSurface()->w;
130 	}
131 
132 	loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom");
133 	loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2");
134 	loadTrans(_transTable, "trans");
135 	loadPath("path");
136 
137 	for (uint32 i = 0; i < _pscrList.size(); i++) {
138 		delete _pscrList[i];
139 	}
140 	_pscrList.clear();
141 	Resource::loadResource(_pscrList, "pscr.lst", false);
142 
143 	loadMobPriority("mobpri");
144 
145 	_mobList.clear();
146 	if (getGameType() == kPrinceDataDE) {
147 		const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr);
148 		debug(3, "moblist name: %s", mobLstName.c_str());
149 		Resource::loadResource(_mobList, mobLstName.c_str(), false);
150 	} else if (getGameType() == kPrinceDataPL) {
151 		Resource::loadResource(_mobList, "mob.lst", false);
152 	}
153 	if (getFeatures() & GF_TRANSLATED) {
154 		// update Mob texts for translated version
155 		setMobTranslationTexts();
156 	}
157 
158 	_animList.clear();
159 	Resource::loadResource(_animList, "anim.lst", false);
160 
161 	for (uint32 i = 0; i < _objList.size(); i++) {
162 		delete _objList[i];
163 	}
164 	_objList.clear();
165 	Resource::loadResource(_objList, "obj.lst", false);
166 
167 	_room->loadRoom(_script->getRoomOffset(_locationNr));
168 
169 	for (uint i = 0; i < _maskList.size(); i++) {
170 		free(_maskList[i]._data);
171 	}
172 	_maskList.clear();
173 	_script->loadAllMasks(_maskList, _room->_nak);
174 
175 	_picWindowX = 0;
176 
177 	_lightX = _script->getLightX(_locationNr);
178 	_lightY = _script->getLightY(_locationNr);
179 	setShadowScale(_script->getShadowScale(_locationNr));
180 
181 	for (uint i = 0; i < _mobList.size(); i++) {
182 		_mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
183 	}
184 
185 	_script->installObjects(_room->_obj);
186 
187 	freeAllNormAnims();
188 
189 	clearBackAnimList();
190 	_script->installBackAnims(_backAnimList, _room->_backAnim);
191 
192 	_graph->makeShadowTable(70, _graph->_shadowTable70);
193 	_graph->makeShadowTable(50, _graph->_shadowTable50);
194 
195 	_mainHero->freeOldMove();
196 	_secondHero->freeOldMove();
197 
198 	_mainHero->scrollHero();
199 
200 	return true;
201 }
202 
loadAnim(uint16 animNr,bool loop)203 bool PrinceEngine::loadAnim(uint16 animNr, bool loop) {
204 	Common::String streamName = Common::String::format("AN%02d", animNr);
205 	Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName);
206 
207 	if (!flicStream) {
208 		error("Can't open %s", streamName.c_str());
209 		return false;
210 	}
211 
212 	flicStream = Resource::getDecompressedStream(flicStream);
213 
214 	if (!_flicPlayer.loadStream(flicStream)) {
215 		error("Can't load flic stream %s", streamName.c_str());
216 	}
217 
218 	debugEngine("%s loaded", streamName.c_str());
219 	_flicLooped = loop;
220 	_flicPlayer.start();
221 	playNextFLCFrame();
222 	return true;
223 }
224 
loadZoom(byte * zoomBitmap,uint32 dataSize,const char * resourceName)225 bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) {
226 	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
227 	if (!stream) {
228 		delete stream;
229 		return false;
230 	}
231 	stream = Resource::getDecompressedStream(stream);
232 
233 	if (stream->read(zoomBitmap, dataSize) != dataSize) {
234 		free(zoomBitmap);
235 		delete stream;
236 		return false;
237 	}
238 	delete stream;
239 	return true;
240 }
241 
loadShadow(byte * shadowBitmap,uint32 dataSize,const char * resourceName1,const char * resourceName2)242 bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) {
243 	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1);
244 	if (!stream) {
245 		delete stream;
246 		return false;
247 	}
248 
249 	stream = Resource::getDecompressedStream(stream);
250 
251 	if (stream->read(shadowBitmap, dataSize) != dataSize) {
252 		free(shadowBitmap);
253 		delete stream;
254 		return false;
255 	}
256 
257 	Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2);
258 	if (!stream2) {
259 		delete stream;
260 		delete stream2;
261 		return false;
262 	}
263 
264 	stream2 = Resource::getDecompressedStream(stream2);
265 
266 	byte *shadowBitmap2 = shadowBitmap + dataSize;
267 	if (stream2->read(shadowBitmap2, dataSize) != dataSize) {
268 		free(shadowBitmap);
269 		delete stream;
270 		delete stream2;
271 		return false;
272 	}
273 
274 	delete stream;
275 	delete stream2;
276 	return true;
277 }
278 
loadTrans(byte * transTable,const char * resourceName)279 bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) {
280 	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
281 	if (!stream) {
282 		delete stream;
283 		for (int i = 0; i < 256; i++) {
284 			for (int j = 0; j < 256; j++) {
285 				transTable[i * 256 + j] = j;
286 			}
287 		}
288 		return true;
289 	}
290 
291 	stream = Resource::getDecompressedStream(stream);
292 
293 	if (stream->read(transTable, kTransTableSize) != kTransTableSize) {
294 		delete stream;
295 		return false;
296 	}
297 	delete stream;
298 	return true;
299 }
300 
loadPath(const char * resourceName)301 bool PrinceEngine::loadPath(const char *resourceName) {
302 	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
303 	if (!stream) {
304 		delete stream;
305 		return false;
306 	}
307 
308 	stream = Resource::getDecompressedStream(stream);
309 
310 	if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) {
311 		delete stream;
312 		return false;
313 	}
314 	delete stream;
315 	return true;
316 }
317 
loadAllInv()318 bool PrinceEngine::loadAllInv() {
319 	for (int i = 0; i < kMaxInv; i++) {
320 		InvItem tempInvItem;
321 
322 		const Common::String invStreamName = Common::String::format("INV%02d", i);
323 		Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName);
324 		if (!invStream) {
325 			delete invStream;
326 			return true;
327 		}
328 
329 		invStream = Resource::getDecompressedStream(invStream);
330 
331 		tempInvItem._x = invStream->readUint16LE();
332 		tempInvItem._y = invStream->readUint16LE();
333 		int width = invStream->readUint16LE();
334 		int height = invStream->readUint16LE();
335 		tempInvItem._surface = new Graphics::Surface();
336 		tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
337 
338 		for (int h = 0; h < tempInvItem._surface->h; h++) {
339 			invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w);
340 		}
341 
342 		_allInvList.push_back(tempInvItem);
343 		delete invStream;
344 	}
345 
346 	return true;
347 }
348 
loadMobPriority(const char * resourceName)349 bool PrinceEngine::loadMobPriority(const char *resourceName) {
350 	Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
351 	if (!stream) {
352 		delete stream;
353 		return false;
354 	}
355 
356 	stream = Resource::getDecompressedStream(stream);
357 
358 	_mobPriorityList.clear();
359 	uint mobId;
360 	while (1) {
361 		mobId = stream->readUint32LE();
362 		if (mobId == 0xFFFFFFFF) {
363 			break;
364 		}
365 		_mobPriorityList.push_back(mobId);
366 	}
367 	delete stream;
368 	return true;
369 }
370 
371 } // End of namespace Prince
372