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