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 "prince/prince.h"
24 
25 #include "prince/mob.h"
26 #include "prince/animation.h"
27 #include "prince/font.h"
28 
29 namespace Prince {
30 
loadFromStream(Common::SeekableReadStream & stream)31 bool Mob::loadFromStream(Common::SeekableReadStream &stream) {
32 	int32 pos = stream.pos();
33 
34 	uint16 visible = stream.readUint16LE();
35 
36 	if (visible == 0xFFFF)
37 		return false;
38 
39 	_visible = visible;
40 	_type = stream.readUint16LE();
41 	_rect.left = stream.readUint16LE();
42 	_rect.top = stream.readUint16LE();
43 	_rect.right = stream.readUint16LE();
44 	_rect.bottom = stream.readUint16LE();
45 
46 	_mask = stream.readUint16LE();
47 
48 	_examPosition.x = stream.readUint16LE();
49 	_examPosition.y = stream.readUint16LE();
50 	_examDirection = (Direction)stream.readUint16LE();
51 
52 	_usePosition.x = stream.readByte();
53 	_usePosition.y = stream.readByte();
54 	_useDirection = (Direction)stream.readUint16LE();
55 
56 	uint32 nameOffset = stream.readUint32LE();
57 	uint32 examTextOffset = stream.readUint32LE();
58 
59 	byte c;
60 	stream.seek(nameOffset);
61 	_name.clear();
62 	while ((c = stream.readByte()))
63 		_name += c;
64 
65 	stream.seek(examTextOffset);
66 	_examText.clear();
67 	c = stream.readByte();
68 	if (c) {
69 		_examText += c;
70 		do {
71 			c = stream.readByte();
72 			_examText += c;
73 		} while (c != 255);
74 	}
75 	stream.seek(pos + 32);
76 
77 	return true;
78 }
79 
setData(AttrId dataId,uint16 value)80 void Mob::setData(AttrId dataId, uint16 value) {
81 	switch (dataId) {
82 	case kMobExamDir:
83 		_examDirection = (Direction)value;
84 		break;
85 	case kMobExamX:
86 		_examPosition.x = value;
87 		break;
88 	case kMobExamY:
89 		_examPosition.y = value;
90 		break;
91 	default:
92 		assert(false);
93 	}
94 }
95 
getData(AttrId dataId)96 uint16 Mob::getData(AttrId dataId) {
97 	switch (dataId) {
98 	case kMobVisible:
99 		return _visible;
100 	case kMobExamDir:
101 		return _examDirection;
102 	case kMobExamX:
103 		return _examPosition.x;
104 	case kMobExamY:
105 		return _examPosition.y;
106 	default:
107 		assert(false);
108 		return 0;
109 	}
110 }
111 
getMob(Common::Array<Mob> & mobList,bool usePriorityList,int posX,int posY)112 int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
113 
114 	Common::Point pointPos(posX, posY);
115 
116 	int mobListSize;
117 	if (usePriorityList) {
118 		mobListSize = _mobPriorityList.size();
119 	} else {
120 		mobListSize = mobList.size();
121 	}
122 
123 	for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
124 		Mob *mob = nullptr;
125 		if (usePriorityList) {
126 			mob = &mobList[_mobPriorityList[mobNumber]];
127 		} else {
128 			mob = &mobList[mobNumber];
129 		}
130 
131 		if (mob->_visible) {
132 			continue;
133 		}
134 
135 		int type = mob->_type & 7;
136 		switch (type) {
137 		case 0:
138 		case 1:
139 			//normal_mob
140 			if (!mob->_rect.contains(pointPos)) {
141 				continue;
142 			}
143 			break;
144 		case 3:
145 			//mob_obj
146 			if (mob->_mask < kMaxObjects) {
147 				int nr = _objSlot[mob->_mask];
148 				if (nr != 0xFF) {
149 					Object &obj = *_objList[nr];
150 					Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
151 					if (objectRect.contains(pointPos)) {
152 						Graphics::Surface *objSurface = obj.getSurface();
153 						byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
154 						if (*pixel != 255) {
155 							break;
156 						}
157 					}
158 				}
159 			}
160 			continue;
161 			break;
162 		case 2:
163 		case 5:
164 			//check_ba_mob
165 			if (!_backAnimList[mob->_mask].backAnims.empty()) {
166 				int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
167 				Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
168 				if (backAnim._animData != nullptr) {
169 					if (!backAnim._state) {
170 						Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
171 						if (backAnimRect.contains(pointPos)) {
172 							int phase = backAnim._showFrame;
173 							int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
174 							Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
175 							byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
176 							if (pixel != 255) {
177 								if (type == 5) {
178 									if (mob->_rect.contains(pointPos)) {
179 										break;
180 									}
181 								} else {
182 									break;
183 								}
184 							}
185 						}
186 					}
187 				}
188 			}
189 			continue;
190 			break;
191 		default:
192 			//not_part_ba
193 			continue;
194 			break;
195 		}
196 
197 		if (usePriorityList) {
198 			return _mobPriorityList[mobNumber];
199 		} else {
200 			return mobNumber;
201 		}
202 	}
203 	return -1;
204 }
205 
checkMob(Graphics::Surface * screen,Common::Array<Mob> & mobList,bool usePriorityList)206 int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
207 	if (_mouseFlag == 0 || _mouseFlag == 3) {
208 		return -1;
209 	}
210 	Common::Point mousePos = _system->getEventManager()->getMousePos();
211 	int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
212 
213 	if (mobNumber != -1) {
214 		Common::String mobName = mobList[mobNumber]._name;
215 
216 		if (getLanguage() == Common::DE_DEU) {
217 			for (uint i = 0; i < mobName.size(); i++) {
218 				switch (mobName[i]) {
219 				case '\xc4':
220 					mobName.setChar('\x83', i);
221 					break;
222 				case '\xd6':
223 					mobName.setChar('\x84', i);
224 					break;
225 				case '\xdc':
226 					mobName.setChar('\x85', i);
227 					break;
228 				case '\xdf':
229 					mobName.setChar('\x7f', i);
230 					break;
231 				case '\xe4':
232 					mobName.setChar('\x80', i);
233 					break;
234 				case '\xf6':
235 					mobName.setChar('\x81', i);
236 					break;
237 				case '\xfc':
238 					mobName.setChar('\x82', i);
239 					break;
240 				default:
241 					break;
242 				}
243 			}
244 		}
245 
246 		uint16 textW = getTextWidth(mobName.c_str());
247 
248 		uint16 x = mousePos.x - textW / 2;
249 		if (x > screen->w) {
250 			x = 0;
251 		}
252 
253 		if (x + textW > screen->w) {
254 			x = screen->w - textW;
255 		}
256 
257 		uint16 y = mousePos.y - _font->getFontHeight();
258 		if (y > screen->h) {
259 			y = _font->getFontHeight() - 2;
260 		}
261 
262 		_font->drawString(screen, mobName, x, y, screen->w, 216);
263 	}
264 
265 	return mobNumber;
266 }
267 
268 } // End of namespace Prince
269