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 /*
24  * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
25  * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
26  */
27 
28 /* Original name: CELER		The unit for updating the screen pics. */
29 
30 #include "avalanche/avalanche.h"
31 #include "avalanche/background.h"
32 
33 namespace Avalanche {
34 
35 const int16 Background::kOnDisk = -1;
36 
Background(AvalancheEngine * vm)37 Background::Background(AvalancheEngine *vm) {
38 	_vm = vm;
39 	_spriteNum = 0;
40 	_nextBell = 0;
41 }
42 
~Background()43 Background::~Background() {
44 	release();
45 }
46 
47 /**
48  * @remarks	Originally called 'pics_link'
49  */
update()50 void Background::update() {
51 	if (_vm->_dropdown->isActive())
52 		return; // No animation when the menus are up.
53 
54 	switch (_vm->_room) {
55 	case kRoomOutsideArgentPub:
56 		if ((_vm->_roomCycles % 12) == 0)
57 			draw(-1, -1, (_vm->_roomCycles / 12) % 4);
58 		break;
59 	case kRoomBrummieRoad:
60 		if ((_vm->_roomCycles % 2) == 0)
61 			draw(-1, -1, (_vm->_roomCycles / 2) % 4);
62 		break;
63 	case kRoomBridge:
64 		if ((_vm->_roomCycles % 2) == 0)
65 			draw(-1, -1, 3 + (_vm->_roomCycles / 2) % 4);
66 		break;
67 	case kRoomYours:
68 		if ((!_vm->_avvyIsAwake) && ((_vm->_roomCycles % 4) == 0))
69 			draw(-1, -1, (_vm->_roomCycles / 12) % 2);
70 		break;
71 	case kRoomArgentPub:
72 		if (((_vm->_roomCycles % 7) == 1) && (_vm->_malagauche != 177)) {
73 			// Malagauche cycle.
74 			_vm->_malagauche++;
75 			switch (_vm->_malagauche) {
76 			case 1:
77 			case 11:
78 			case 21:
79 				draw(-1, -1, 11); // Looks forwards.
80 				break;
81 			case 8:
82 			case 18:
83 			case 28:
84 			case 32:
85 				draw(-1, -1, 10); // Looks at you.
86 				break;
87 			case 30:
88 				draw(-1, -1, 12); // Winks.
89 				break;
90 			case 33:
91 				_vm->_malagauche = 0;
92 				break;
93 			default:
94 				break;
95 			}
96 		}
97 
98 		switch (_vm->_roomCycles % 200) {
99 		case 179:
100 		case 197:
101 			draw(-1, -1, 4); // Dogfood's drinking cycle.
102 			break;
103 		case 182:
104 		case 194:
105 			draw(-1, -1, 5);
106 			break;
107 		case 185:
108 			draw(-1, -1, 6);
109 			break;
110 		case 199:
111 			_vm->_npcFacing = 177; // Impossible value for this.
112 			break;
113 		default:
114 			if (_vm->_roomCycles % 200 <= 178) { // Normally.
115 				byte direction = 1;
116 				uint16 angle = _vm->bearing(1);
117 				if (((angle >= 1) && (angle <= 90)) || ((angle >= 358) && (angle <= 360)))
118 					direction = 3;
119 				else if ((angle >= 293) && (angle <= 357))
120 					direction = 2;
121 				else if ((angle >= 270) && (angle <= 292))
122 					direction = 4;
123 
124 				if (direction != _vm->_npcFacing) { // Dogfood.
125 					draw(-1, -1, direction - 1);
126 					_vm->_npcFacing = direction;
127 				}
128 			}
129 		}
130 		break;
131 	case kRoomWestHall:
132 		if ((_vm->_roomCycles % 3) == 0) {
133 			switch ((_vm->_roomCycles / 3) % 6) {
134 			case 4:
135 				draw(-1, -1, 0);
136 				break;
137 			case 1:
138 			case 3:
139 			case 5:
140 				draw(-1, -1, 1);
141 				break;
142 			case 0:
143 			case 2:
144 				draw(-1, -1, 2);
145 				break;
146 			default:
147 				break;
148 			}
149 		}
150 		break;
151 	case kRoomLustiesRoom:
152 		if (!(_vm->_lustieIsAsleep)) {
153 			byte direction = 0;
154 			uint16 angle = _vm->bearing(1);
155 			if ((_vm->_roomCycles % 45) > 42)
156 				direction = 4; // du Lustie blinks.
157 			// Bearing of Avvy from du Lustie.
158 			else if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
159 					direction = 1; // Middle.
160 			else if ((angle >= 45) && (angle <= 180))
161 					direction = 2; // Left.
162 			else if ((angle >= 181) && (angle <= 314))
163 				direction = 3; // Right.
164 
165 			if (direction != _vm->_npcFacing) { // du Lustie.
166 				draw(-1, -1, direction - 1);
167 				_vm->_npcFacing = direction;
168 			}
169 		}
170 		break;
171 	case kRoomAylesOffice:
172 		if ((!_vm->_aylesIsAwake) && (_vm->_roomCycles % 14 == 0)) {
173 			switch ((_vm->_roomCycles / 14) % 2) {
174 			case 0:
175 				draw(-1, -1, 0);  // Frame 2: EGA.
176 				break;
177 			case 1:
178 				draw(-1, -1, 2); // Frame 1: Natural.
179 				break;
180 			default:
181 				break;
182 			}
183 		}
184 		break;
185 	case kRoomRobins:
186 		if (_vm->_tiedUp) {
187 			switch (_vm->_roomCycles % 54) {
188 			case 20:
189 				draw(-1, -1, 3); // Frame 4: Avalot blinks.
190 				break;
191 			case 23:
192 				draw(-1, -1, 1); // Frame 1: Back to normal.
193 				break;
194 			default:
195 				break;
196 			}
197 		}
198 		break;
199 	case kRoomNottsPub: {
200 		// Bearing of Avvy from Port.
201 		byte direction = 0;
202 		uint16 angle = _vm->bearing(4);
203 		if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
204 			direction = 2; // Middle.
205 		else if ((angle >= 45) && (angle <= 180))
206 			direction = 6; // Left.
207 		else if ((angle >= 181) && (angle <= 314))
208 			direction = 8; // Right.
209 
210 		if ((_vm->_roomCycles % 60) > 57)
211 			direction--; // Blinks.
212 
213 		if (direction != _vm->_npcFacing) { // Port.
214 			draw(-1, -1, direction - 1);
215 			_vm->_npcFacing = direction;
216 		}
217 
218 		switch (_vm->_roomCycles % 50) {
219 		case 45 :
220 			draw(-1, -1, 8); // Spurge blinks.
221 			break;
222 		case 49 :
223 			draw(-1, -1, 9);
224 			break;
225 		default:
226 			break;
227 		}
228 		break;
229 	  }
230 	case kRoomDucks: {
231 		if ((_vm->_roomCycles % 3) == 0) // The fire flickers.
232 			draw(-1, -1, (_vm->_roomCycles / 3) % 3);
233 
234 		// Bearing of Avvy from Duck.
235 		byte direction = 0;
236 		uint16 angle = _vm->bearing(1);
237 		if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
238 			direction = 4; // Middle.
239 		else if ((angle >= 45) && (angle <= 180))
240 			direction = 6; // Left.
241 		else if ((angle >= 181) && (angle <= 314))
242 			direction = 8; // Right.
243 
244 		if ((_vm->_roomCycles % 45) > 42)
245 			direction++; // Duck blinks.
246 
247 		if (direction != _vm->_npcFacing) { // Duck.
248 			draw(-1, -1, direction - 1);
249 			_vm->_npcFacing = direction;
250 		}
251 		break;
252 	   }
253 	default:
254 		break;
255 	}
256 
257 	if ((_vm->_bellsAreRinging) && (_vm->getFlag('B'))) {
258 		// They're ringing the bells.
259 		switch (_vm->_roomCycles % 4) {
260 		case 1:
261 			if (_nextBell < 5)
262 				_nextBell = 12;
263 			_nextBell--;
264 			// CHECKME: 2 is a guess. No length in the original?
265 			_vm->_sound->playNote(_vm->kNotes[_nextBell], 2);
266 			break;
267 		case 2:
268 			_vm->_sound->stopSound();
269 			break;
270 		default:
271 			break;
272 		}
273 	}
274 }
275 
loadSprites(byte number)276 void Background::loadSprites(byte number) {
277 	Common::File f;
278 	_filename = _filename.format("chunk%d.avd", number);
279 	if (!f.open(_filename))
280 		return; // We skip because some rooms don't have sprites in the background.
281 
282 	f.seek(44);
283 	_spriteNum = f.readByte();
284 	for (int i = 0; i < _spriteNum; i++)
285 		_offsets[i] = f.readSint32LE();
286 
287 	for (int i = 0; i < _spriteNum; i++) {
288 		f.seek(_offsets[i]);
289 
290 		SpriteType sprite;
291 		sprite._type = (PictureType)(f.readByte());
292 		sprite._x = f.readSint16LE();
293 		sprite._y = f.readSint16LE();
294 		sprite._width = f.readSint16LE();
295 		sprite._height = f.readSint16LE();
296 		sprite._size = f.readSint32LE();
297 		bool natural = f.readByte();
298 		bool memorize = f.readByte();
299 
300 		if (memorize) {
301 			_sprites[i]._x = sprite._x;
302 			_sprites[i]._width = sprite._width;
303 			_sprites[i]._y = sprite._y;
304 			_sprites[i]._height = sprite._height;
305 			_sprites[i]._type = sprite._type;
306 
307 			if (natural)
308 				_vm->_graphics->getNaturalPicture(_sprites[i]);
309 			else {
310 				_sprites[i]._size = sprite._size;
311 				_sprites[i]._picture = _vm->_graphics->loadPictureRaw(f, _sprites[i]._width * 8, _sprites[i]._height + 1);
312 			}
313 		} else
314 			_sprites[i]._x = kOnDisk;
315 	}
316 	f.close();
317 }
318 
release()319 void Background::release() {
320 	for (int i = 0; i < _spriteNum; i++) {
321 		if (_sprites[i]._x > kOnDisk)
322 			_sprites[i]._picture.free();
323 	}
324 }
325 
326 /**
327  * Draw background animation
328  * @remarks	Originally called 'show_one'
329  */
draw(int16 destX,int16 destY,byte sprId)330 void Background::draw(int16 destX, int16 destY, byte sprId) {
331 	assert(sprId < 40);
332 
333 	if (_sprites[sprId]._x > kOnDisk) {
334 		if (destX < 0) {
335 			destX = _sprites[sprId]._x * 8;
336 			destY = _sprites[sprId]._y;
337 		}
338 		drawSprite(destX, destY, _sprites[sprId]);
339 	} else {
340 		Common::File f;
341 		if (!f.open(_filename)) // Filename was set in loadBackgroundSprites().
342 			return; // We skip because some rooms don't have sprites in the background.
343 
344 		f.seek(_offsets[sprId]);
345 
346 		SpriteType sprite;
347 		sprite._type = (PictureType)(f.readByte());
348 		sprite._x = f.readSint16LE();
349 		sprite._y = f.readSint16LE();
350 		sprite._width = f.readSint16LE();
351 		sprite._height = f.readSint16LE();
352 		sprite._size = f.readSint32LE();
353 		f.skip(2); // Natural and Memorize are used in Load()
354 		sprite._picture = _vm->_graphics->loadPictureRaw(f, sprite._width * 8, sprite._height + 1);
355 
356 		if (destX < 0) {
357 			destX = sprite._x * 8;
358 			destY = sprite._y;
359 		}
360 		drawSprite(destX, destY, sprite);
361 
362 		sprite._picture.free();
363 		f.close();
364 	}
365 }
366 
367 /**
368  * @remarks	Originally called 'display_it'
369  */
drawSprite(int16 x,int16 y,SpriteType & sprite)370 void Background::drawSprite(int16 x, int16 y, SpriteType &sprite) {
371 	// These pictures are practically parts of the background. -10 is for the drop-down menu.
372 	_vm->_graphics->drawBackgroundSprite(x, y - 10, sprite);
373 }
374 
resetVariables()375 void Background::resetVariables() {
376 	_nextBell = 0;
377 }
378 
synchronize(Common::Serializer & sz)379 void Background::synchronize(Common::Serializer &sz) {
380 	sz.syncAsByte(_nextBell);
381 }
382 } // End of namespace Avalanche.
383