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 "neverhood/staticdata.h"
24 
25 namespace Neverhood {
26 
StaticData()27 StaticData::StaticData() {
28 }
29 
~StaticData()30 StaticData::~StaticData() {
31 	for (Common::HashMap<uint32, HitRectList*>::iterator i = _hitRectLists.begin(); i != _hitRectLists.end(); ++i)
32 		delete i->_value;
33 	for (Common::HashMap<uint32, RectList*>::iterator i = _rectLists.begin(); i != _rectLists.end(); ++i)
34 		delete i->_value;
35 	for (Common::HashMap<uint32, MessageList*>::iterator i = _messageLists.begin(); i != _messageLists.end(); ++i)
36 		delete i->_value;
37 	for (Common::HashMap<uint32, NavigationList*>::iterator i = _navigationLists.begin(); i != _navigationLists.end(); ++i)
38 		delete i->_value;
39 	for (Common::HashMap<uint32, HallOfRecordsInfo*>::iterator i = _hallOfRecordsInfoItems.begin(); i != _hallOfRecordsInfoItems.end(); ++i)
40 		delete i->_value;
41 	for (Common::HashMap<uint32, TrackInfo*>::iterator i = _trackInfoItems.begin(); i != _trackInfoItems.end(); ++i)
42 		delete i->_value;
43 }
44 
load(const char * filename)45 void StaticData::load(const char *filename) {
46 
47 	Common::File fd;
48 
49 	if (!fd.open(filename))
50 		error("StaticData::load() Could not open %s", filename);
51 
52 	fd.readUint32LE(); // magic
53 	fd.readUint32LE(); // version
54 
55 	// Load message lists
56 	uint32 messageListsCount = fd.readUint32LE();
57 	debug(3, "messageListsCount: %d", messageListsCount);
58 	for (uint32 i = 0; i < messageListsCount; i++) {
59 		MessageList *messageList = new MessageList();
60 		uint32 id = fd.readUint32LE();
61 		uint32 itemCount = fd.readUint32LE();
62 		for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
63 			MessageItem messageItem;
64 			messageItem.messageNum = fd.readUint16LE();
65 			messageItem.messageValue = fd.readUint32LE();
66 			messageList->push_back(messageItem);
67 		}
68 
69 		// WORKAROUND for a problem in two of the game's message lists:
70 		// the message lists used when Klaymen is drinking the wrong potion
71 		// have as a last element the animation itself (message 0x4832).
72 		// However, when processMessageList() reaches the last element in a
73 		// message list, it allows player input, which means that the player
74 		// can erroneously skip these potion drinking animations. We insert
75 		// another message at the end of these lists to prevent player input
76 		// till the animations are finished
77 		if (id == 0x004AF0C8 || id == 0x004B5BD0) {	// wrong potion message lists
78 			MessageItem messageItem;
79 			messageItem.messageNum = 0x4004;	// set Klaymen's state to idle
80 			messageItem.messageValue = 0;
81 			messageList->push_back(messageItem);
82 		}
83 
84 		if(_messageLists.contains(id)) {
85 			warning("Duplicate id %d in _messageLists - freeing older entry", id);
86 			delete _messageLists[id];
87 		}
88 
89 		_messageLists[id] = messageList;
90 	}
91 
92 	// Load rect lists
93 	uint32 rectListsCount = fd.readUint32LE();
94 	debug(3, "rectListsCount: %d", rectListsCount);
95 	for (uint32 i = 0; i < rectListsCount; i++) {
96 		RectList *rectList = new RectList();
97 		uint32 id = fd.readUint32LE();
98 		uint32 itemCount = fd.readUint32LE();
99 		for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
100 			RectItem rectItem;
101 			rectItem.rect.x1 = fd.readUint16LE();
102 			rectItem.rect.y1 = fd.readUint16LE();
103 			rectItem.rect.x2 = fd.readUint16LE();
104 			rectItem.rect.y2 = fd.readUint16LE();
105 			uint32 subItemCount = fd.readUint32LE();
106 			rectItem.subRects.reserve(subItemCount);
107 			for (uint32 subItemIndex = 0; subItemIndex < subItemCount; subItemIndex++) {
108 				SubRectItem subRectItem;
109 				subRectItem.rect.x1 = fd.readUint16LE();
110 				subRectItem.rect.y1 = fd.readUint16LE();
111 				subRectItem.rect.x2 = fd.readUint16LE();
112 				subRectItem.rect.y2 = fd.readUint16LE();
113 				subRectItem.messageListId = fd.readUint32LE();
114 				rectItem.subRects.push_back(subRectItem);
115 			}
116 			rectList->push_back(rectItem);
117 		}
118 
119 		if(_rectLists.contains(id)) {
120 			warning("Duplicate id %d in _rectLists - freeing older entry", id);
121 			delete _rectLists[id];
122 		}
123 
124 		_rectLists[id] = rectList;
125 	}
126 
127 	// Load hit rects
128 	uint32 hitRectListsCount = fd.readUint32LE();
129 	debug(3, "hitRectListsCount: %d", hitRectListsCount);
130 	for (uint32 i = 0; i < hitRectListsCount; i++) {
131 		HitRectList *hitRectList = new HitRectList();
132 		uint32 id = fd.readUint32LE();
133 		uint32 itemCount = fd.readUint32LE();
134 		for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
135 			HitRect hitRect;
136 			hitRect.rect.x1 = fd.readUint16LE();
137 			hitRect.rect.y1 = fd.readUint16LE();
138 			hitRect.rect.x2 = fd.readUint16LE();
139 			hitRect.rect.y2 = fd.readUint16LE();
140 			hitRect.type = fd.readUint16LE();
141 			hitRectList->push_back(hitRect);
142 		}
143 
144 		if(_hitRectLists.contains(id)) {
145 			warning("Duplicate id %d in _hitRectLists - freeing older entry", id);
146 			delete _hitRectLists[id];
147 		}
148 
149 		_hitRectLists[id] = hitRectList;
150 	}
151 
152 	// Load navigation lists
153 	uint32 navigationListsCount = fd.readUint32LE();
154 	debug(3, "navigationListsCount: %d", navigationListsCount);
155 	for (uint32 i = 0; i < navigationListsCount; i++) {
156 		NavigationList *navigationList = new NavigationList();
157 		uint32 id = fd.readUint32LE();
158 		uint32 itemCount = fd.readUint32LE();
159 		for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
160 			NavigationItem navigationItem;
161 			navigationItem.fileHash = fd.readUint32LE();
162 			navigationItem.leftSmackerFileHash = fd.readUint32LE();
163 			navigationItem.rightSmackerFileHash = fd.readUint32LE();
164 			navigationItem.middleSmackerFileHash = fd.readUint32LE();
165 			navigationItem.interactive = fd.readByte();
166 			navigationItem.middleFlag = fd.readByte();
167 			navigationItem.mouseCursorFileHash = fd.readUint32LE();
168 			navigationList->push_back(navigationItem);
169 		}
170 
171 		if(_navigationLists.contains(id)) {
172 			warning("Duplicate id %d in _navigationLists - freeing older entry", id);
173 			delete _navigationLists[id];
174 		}
175 
176 		_navigationLists[id] = navigationList;
177 	}
178 
179 	// Load HallOfRecordsInfo items
180 	uint32 hallOfRecordsInfoItemsCount = fd.readUint32LE();
181 	debug(3, "hallOfRecordsInfoItemsCount: %d", hallOfRecordsInfoItemsCount);
182 	for (uint32 i = 0; i < hallOfRecordsInfoItemsCount; i++) {
183 		HallOfRecordsInfo *hallOfRecordsInfo = new HallOfRecordsInfo();
184 		uint32 id = fd.readUint32LE();
185 		hallOfRecordsInfo->bgFilename1 = fd.readUint32LE();
186 		hallOfRecordsInfo->bgFilename2 = fd.readUint32LE();
187 		hallOfRecordsInfo->txFilename = fd.readUint32LE();
188 		hallOfRecordsInfo->bgFilename3 = fd.readUint32LE();
189 		hallOfRecordsInfo->xPosIndex = fd.readByte();
190 		hallOfRecordsInfo->count = fd.readByte();
191 
192 		if(_hallOfRecordsInfoItems.contains(id)) {
193 			warning("Duplicate id %d in _hallOfRecordsInfoItems - freeing older entry", id);
194 			delete _hallOfRecordsInfoItems[id];
195 		}
196 
197 		_hallOfRecordsInfoItems[id] = hallOfRecordsInfo;
198 	}
199 
200 	// Load TrackInfo items
201 	uint32 trackInfoItemsCount = fd.readUint32LE();
202 	debug(3, "trackInfoItemsCount: %d", trackInfoItemsCount);
203 	for (uint32 i = 0; i < trackInfoItemsCount; i++) {
204 		TrackInfo *trackInfo = new TrackInfo();
205 		uint32 id = fd.readUint32LE();
206 		trackInfo->bgFilename = fd.readUint32LE();
207 		trackInfo->bgShadowFilename = fd.readUint32LE();
208 		trackInfo->dataResourceFilename = fd.readUint32LE();
209 		trackInfo->trackPointsName = fd.readUint32LE();
210 		trackInfo->rectListName = fd.readUint32LE();
211 		trackInfo->exPaletteFilename2 = fd.readUint32LE();
212 		trackInfo->exPaletteFilename1 = fd.readUint32LE();
213 		trackInfo->mouseCursorFilename = fd.readUint32LE();
214 		trackInfo->which1 = fd.readUint16LE();
215 		trackInfo->which2 = fd.readUint16LE();
216 
217 		if(_trackInfoItems.contains(id)) {
218 			warning("Duplicate id %d in _trackInfoItems - freeing older entry", id);
219 			delete _trackInfoItems[id];
220 		}
221 
222 		_trackInfoItems[id] = trackInfo;
223 	}
224 
225 }
226 
getHitRectList(uint32 id)227 HitRectList *StaticData::getHitRectList(uint32 id) {
228 	if (!_hitRectLists[id])
229 		error("StaticData::getHitRectList() HitRectList with id %08X not found", id);
230 	return _hitRectLists[id];
231 }
232 
getRectList(uint32 id)233 RectList *StaticData::getRectList(uint32 id) {
234 	if (!_rectLists[id])
235 		error("StaticData::getRectList() RectList with id %08X not found", id);
236 	return _rectLists[id];
237 }
238 
getMessageList(uint32 id)239 MessageList *StaticData::getMessageList(uint32 id) {
240 	if (!_messageLists[id])
241 		error("StaticData::getMessageList() MessageList with id %08X not found", id);
242 	return _messageLists[id];
243 }
244 
getNavigationList(uint32 id)245 NavigationList *StaticData::getNavigationList(uint32 id) {
246 	if (!_navigationLists[id])
247 		error("StaticData::getNavigationList() NavigationList with id %08X not found", id);
248 	return _navigationLists[id];
249 }
250 
getHallOfRecordsInfoItem(uint32 id)251 HallOfRecordsInfo *StaticData::getHallOfRecordsInfoItem(uint32 id) {
252 	if (!_hallOfRecordsInfoItems[id])
253 		error("StaticData::getHallOfRecordsInfoItem() HallOfRecordsInfo with id %08X not found", id);
254 	return _hallOfRecordsInfoItems[id];
255 }
256 
getTrackInfo(uint32 id)257 TrackInfo *StaticData::getTrackInfo(uint32 id) {
258 	if (!_trackInfoItems[id])
259 		error("StaticData::getTrackInfo() TrackInfo with id %08X not found", id);
260 	return _trackInfoItems[id];
261 }
262 
263 } // End of namespace Neverhood
264