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