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 "scumm/scumm.h"
24 #include "scumm/actor.h"
25 #include "scumm/charset.h"
26 #include "scumm/scumm_v7.h"
27
28 #include "common/util.h"
29
30 namespace Scumm {
31
setCameraAtEx(int at)32 void ScummEngine::setCameraAtEx(int at) {
33 if (_game.version < 7) {
34 camera._mode = kNormalCameraMode;
35 camera._cur.x = at;
36 setCameraAt(at, 0);
37 camera._movingToActor = false;
38 }
39 }
40
setCameraAt(int pos_x,int pos_y)41 void ScummEngine::setCameraAt(int pos_x, int pos_y) {
42 if (camera._mode != kFollowActorCameraMode || ABS(pos_x - camera._cur.x) > (_screenWidth / 2)) {
43 camera._cur.x = pos_x;
44 }
45 camera._dest.x = pos_x;
46
47 if (VAR_CAMERA_MIN_X != 0xFF && camera._cur.x < VAR(VAR_CAMERA_MIN_X))
48 camera._cur.x = (short) VAR(VAR_CAMERA_MIN_X);
49
50 if (VAR_CAMERA_MAX_X != 0xFF && camera._cur.x > VAR(VAR_CAMERA_MAX_X))
51 camera._cur.x = (short) VAR(VAR_CAMERA_MAX_X);
52
53 if (VAR_SCROLL_SCRIPT != 0xFF && VAR(VAR_SCROLL_SCRIPT)) {
54 VAR(VAR_CAMERA_POS_X) = camera._cur.x;
55 runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
56 }
57
58 // If the camera moved and text is visible, remove it
59 if (camera._cur.x != camera._last.x && _charset->_hasMask && _game.version > 3)
60 stopTalk();
61 }
62
setCameraFollows(Actor * a,bool setCamera)63 void ScummEngine::setCameraFollows(Actor *a, bool setCamera) {
64
65 int t, i;
66
67 camera._mode = kFollowActorCameraMode;
68 camera._follows = a->_number;
69
70 if (!a->isInCurrentRoom()) {
71 startScene(a->getRoom(), 0, 0);
72 camera._mode = kFollowActorCameraMode;
73 camera._cur.x = a->getPos().x;
74 setCameraAt(camera._cur.x, 0);
75 }
76
77 t = a->getPos().x / 8 - _screenStartStrip;
78
79 if (t < camera._leftTrigger || t > camera._rightTrigger || setCamera == true)
80 setCameraAt(a->getPos().x, 0);
81
82 for (i = 1; i < _numActors; i++) {
83 if (_actors[i]->isInCurrentRoom())
84 _actors[i]->_needRedraw = true;
85 }
86 runInventoryScript(0);
87 }
88
clampCameraPos(Common::Point * pt)89 void ScummEngine::clampCameraPos(Common::Point *pt) {
90 pt->x = CLIP<short>(pt->x, VAR(VAR_CAMERA_MIN_X), VAR(VAR_CAMERA_MAX_X));
91 pt->y = CLIP<short>(pt->y, VAR(VAR_CAMERA_MIN_Y), VAR(VAR_CAMERA_MAX_Y));
92 }
93
moveCamera()94 void ScummEngine::moveCamera() {
95 int pos = camera._cur.x;
96 int t;
97 Actor *a = NULL;
98 const bool snapToX = (_snapScroll || (VAR_CAMERA_FAST_X != 0xFF && VAR(VAR_CAMERA_FAST_X)));
99
100 camera._cur.x &= 0xFFF8;
101
102 if (VAR_CAMERA_MIN_X != 0xFF && camera._cur.x < VAR(VAR_CAMERA_MIN_X)) {
103 if (snapToX)
104 camera._cur.x = (short) VAR(VAR_CAMERA_MIN_X);
105 else
106 camera._cur.x += 8;
107 cameraMoved();
108 return;
109 }
110
111 if (VAR_CAMERA_MAX_X != 0xFF && camera._cur.x > VAR(VAR_CAMERA_MAX_X)) {
112 if (snapToX)
113 camera._cur.x = (short) VAR(VAR_CAMERA_MAX_X);
114 else
115 camera._cur.x -= 8;
116 cameraMoved();
117 return;
118 }
119
120 if (camera._mode == kFollowActorCameraMode) {
121 a = derefActor(camera._follows, "moveCamera");
122
123 int actorx = a->getPos().x;
124 t = actorx / 8 - _screenStartStrip;
125
126 if (t < camera._leftTrigger || t > camera._rightTrigger) {
127 if (snapToX) {
128 if (t > 40-5)
129 camera._dest.x = actorx + 80;
130 if (t < 5)
131 camera._dest.x = actorx - 80;
132 } else
133 camera._movingToActor = true;
134 }
135 }
136
137 if (camera._movingToActor) {
138 a = derefActor(camera._follows, "moveCamera(2)");
139 camera._dest.x = a->getPos().x;
140 }
141
142 if (VAR_CAMERA_MIN_X != 0xFF && camera._dest.x < VAR(VAR_CAMERA_MIN_X))
143 camera._dest.x = (short) VAR(VAR_CAMERA_MIN_X);
144
145 if (VAR_CAMERA_MAX_X != 0xFF && camera._dest.x > VAR(VAR_CAMERA_MAX_X))
146 camera._dest.x = (short) VAR(VAR_CAMERA_MAX_X);
147
148 if (snapToX) {
149 camera._cur.x = camera._dest.x;
150 } else {
151 if (camera._cur.x < camera._dest.x)
152 camera._cur.x += 8;
153 if (camera._cur.x > camera._dest.x)
154 camera._cur.x -= 8;
155 }
156
157 /* Actor 'a' is set a bit above */
158 if (camera._movingToActor && (camera._cur.x / 8) == (a->getPos().x / 8)) {
159 camera._movingToActor = false;
160 }
161
162 cameraMoved();
163
164 if (VAR_SCROLL_SCRIPT != 0xFF && VAR(VAR_SCROLL_SCRIPT) && pos != camera._cur.x) {
165 VAR(VAR_CAMERA_POS_X) = camera._cur.x;
166 runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
167 }
168 }
169
cameraMoved()170 void ScummEngine::cameraMoved() {
171 int screenLeft;
172 if (_game.version >= 7) {
173 assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
174 } else {
175 if (camera._cur.x < (_screenWidth / 2)) {
176 camera._cur.x = (_screenWidth / 2);
177 } else if (camera._cur.x > _roomWidth - (_screenWidth / 2)) {
178 camera._cur.x = _roomWidth - (_screenWidth / 2);
179 }
180 }
181
182 _screenStartStrip = camera._cur.x / 8 - _gdi->_numStrips / 2;
183 _screenEndStrip = _screenStartStrip + _gdi->_numStrips - 1;
184
185 _screenTop = camera._cur.y - (_screenHeight / 2);
186 if (_game.version >= 7) {
187 screenLeft = camera._cur.x - (_screenWidth / 2);
188 } else {
189 screenLeft = _screenStartStrip * 8;
190 }
191
192 _virtscr[kMainVirtScreen].xstart = screenLeft;
193 }
194
panCameraTo(int x,int y)195 void ScummEngine::panCameraTo(int x, int y) {
196 camera._dest.x = x;
197 camera._mode = kPanningCameraMode;
198 camera._movingToActor = false;
199 }
200
actorFollowCamera(int act)201 void ScummEngine::actorFollowCamera(int act) {
202 if (_game.version < 7) {
203 int old;
204
205 old = camera._follows;
206 setCameraFollows(derefActor(act, "actorFollowCamera"));
207 if (camera._follows != old)
208 runInventoryScript(0);
209
210 camera._movingToActor = false;
211 }
212 }
213
214 #ifdef ENABLE_SCUMM_7_8
setCameraAt(int pos_x,int pos_y)215 void ScummEngine_v7::setCameraAt(int pos_x, int pos_y) {
216 Common::Point old;
217
218 old = camera._cur;
219
220 camera._cur.x = pos_x;
221 camera._cur.y = pos_y;
222
223 clampCameraPos(&camera._cur);
224
225 camera._dest = camera._cur;
226 VAR(VAR_CAMERA_DEST_X) = camera._dest.x;
227 VAR(VAR_CAMERA_DEST_Y) = camera._dest.y;
228
229 assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
230
231 if (camera._cur.x != old.x || camera._cur.y != old.y) {
232 if (VAR(VAR_SCROLL_SCRIPT)) {
233 VAR(VAR_CAMERA_POS_X) = camera._cur.x;
234 VAR(VAR_CAMERA_POS_Y) = camera._cur.y;
235 runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
236 }
237
238 // Even though cameraMoved() is called automatically, we may
239 // need to know at once that the camera has moved, or text may
240 // be printed at the wrong coordinates. See bugs #795938 and
241 // #929242
242 cameraMoved();
243 }
244 }
245
setCameraFollows(Actor * a,bool setCamera)246 void ScummEngine_v7::setCameraFollows(Actor *a, bool setCamera) {
247
248 byte oldfollow = camera._follows;
249 int ax, ay;
250
251 camera._follows = a->_number;
252 VAR(VAR_CAMERA_FOLLOWED_ACTOR) = a->_number;
253
254 if (!a->isInCurrentRoom()) {
255 startScene(a->getRoom(), 0, 0);
256 }
257
258 ax = ABS(a->getPos().x - camera._cur.x);
259 ay = ABS(a->getPos().y - camera._cur.y);
260
261 if (ax > VAR(VAR_CAMERA_THRESHOLD_X) || ay > VAR(VAR_CAMERA_THRESHOLD_Y) || ax > (_screenWidth / 2) || ay > (_screenHeight / 2)) {
262 setCameraAt(a->getPos().x, a->getPos().y);
263 }
264
265 if (a->_number != oldfollow)
266 runInventoryScript(0);
267 }
268
moveCamera()269 void ScummEngine_v7::moveCamera() {
270 Common::Point old = camera._cur;
271 Actor *a = NULL;
272
273 if (camera._follows) {
274 a = derefActor(camera._follows, "moveCamera");
275 if (ABS(camera._cur.x - a->getPos().x) > VAR(VAR_CAMERA_THRESHOLD_X) ||
276 ABS(camera._cur.y - a->getPos().y) > VAR(VAR_CAMERA_THRESHOLD_Y)) {
277 camera._movingToActor = true;
278 if (VAR(VAR_CAMERA_THRESHOLD_X) == 0)
279 camera._cur.x = a->getPos().x;
280 if (VAR(VAR_CAMERA_THRESHOLD_Y) == 0)
281 camera._cur.y = a->getPos().y;
282 clampCameraPos(&camera._cur);
283 }
284 } else {
285 camera._movingToActor = false;
286 }
287
288 if (camera._movingToActor) {
289 VAR(VAR_CAMERA_DEST_X) = camera._dest.x = a->getPos().x;
290 VAR(VAR_CAMERA_DEST_Y) = camera._dest.y = a->getPos().y;
291 }
292
293 assert(camera._cur.x >= (_screenWidth / 2) && camera._cur.y >= (_screenHeight / 2));
294
295 clampCameraPos(&camera._dest);
296
297 if (camera._cur.x < camera._dest.x) {
298 camera._cur.x += (short) VAR(VAR_CAMERA_SPEED_X);
299 if (camera._cur.x > camera._dest.x)
300 camera._cur.x = camera._dest.x;
301 }
302
303 if (camera._cur.x > camera._dest.x) {
304 camera._cur.x -= (short) VAR(VAR_CAMERA_SPEED_X);
305 if (camera._cur.x < camera._dest.x)
306 camera._cur.x = camera._dest.x;
307 }
308
309 if (camera._cur.y < camera._dest.y) {
310 camera._cur.y += (short) VAR(VAR_CAMERA_SPEED_Y);
311 if (camera._cur.y > camera._dest.y)
312 camera._cur.y = camera._dest.y;
313 }
314
315 if (camera._cur.y > camera._dest.y) {
316 camera._cur.y -= (short) VAR(VAR_CAMERA_SPEED_Y);
317 if (camera._cur.y < camera._dest.y)
318 camera._cur.y = camera._dest.y;
319 }
320
321 if (camera._cur.x == camera._dest.x && camera._cur.y == camera._dest.y) {
322
323 camera._movingToActor = false;
324 camera._accel.x = camera._accel.y = 0;
325 VAR(VAR_CAMERA_SPEED_X) = VAR(VAR_CAMERA_SPEED_Y) = 0;
326 } else {
327
328 camera._accel.x += (short) VAR(VAR_CAMERA_ACCEL_X);
329 camera._accel.y += (short) VAR(VAR_CAMERA_ACCEL_Y);
330
331 VAR(VAR_CAMERA_SPEED_X) += camera._accel.x / 100;
332 VAR(VAR_CAMERA_SPEED_Y) += camera._accel.y / 100;
333
334 if (VAR(VAR_CAMERA_SPEED_X) > 8)
335 VAR(VAR_CAMERA_SPEED_X) = 8;
336
337 if (VAR(VAR_CAMERA_SPEED_Y) > 8)
338 VAR(VAR_CAMERA_SPEED_Y) = 8;
339
340 }
341
342 cameraMoved();
343
344 if (camera._cur.x != old.x || camera._cur.y != old.y) {
345 VAR(VAR_CAMERA_POS_X) = camera._cur.x;
346 VAR(VAR_CAMERA_POS_Y) = camera._cur.y;
347
348 if (VAR(VAR_SCROLL_SCRIPT))
349 runScript(VAR(VAR_SCROLL_SCRIPT), 0, 0, 0);
350 }
351 }
352
panCameraTo(int x,int y)353 void ScummEngine_v7::panCameraTo(int x, int y) {
354 VAR(VAR_CAMERA_FOLLOWED_ACTOR) = camera._follows = 0;
355 VAR(VAR_CAMERA_DEST_X) = camera._dest.x = x;
356 VAR(VAR_CAMERA_DEST_Y) = camera._dest.y = y;
357 }
358 #endif
359
360 } // End of namespace Scumm
361