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 "ngi/ngi.h"
24 
25 #include "ngi/objectnames.h"
26 #include "ngi/constants.h"
27 
28 #include "ngi/gameloader.h"
29 #include "ngi/motion.h"
30 #include "ngi/scenes.h"
31 #include "ngi/statics.h"
32 
33 #include "ngi/interaction.h"
34 #include "ngi/behavior.h"
35 
36 #define DBG 0
37 
38 namespace NGI {
39 
40 struct Bat {
41 	StaticANIObject *ani;
42 	double power;
43 	double angle;
44 	double currX;
45 	double currY;
46 	double powerCos;
47 	double powerSin;
48 };
49 
scene27_initScene(Scene * sc)50 void scene27_initScene(Scene *sc) {
51 	g_vars->scene27_hitZone = sc->getPictureObjectById(PIC_SC27_HITZONE2, 0);
52 	g_vars->scene27_driver = sc->getStaticANIObject1ById(ANI_VODILLA, -1);
53 	g_vars->scene27_maid = sc->getStaticANIObject1ById(ANI_MAID, -1);
54 	g_vars->scene27_batHandler = sc->getStaticANIObject1ById(ANI_BITAHANDLER, -1);
55 
56 	g_vars->scene27_balls.clear();
57 	g_vars->scene27_bats.clear();
58 	g_vars->scene27_var07.clear();
59 
60 	g_vars->scene27_driverHasVent = true;
61 	g_vars->scene27_bat = sc->getStaticANIObject1ById(ANI_BITA, -1);
62 
63 	for (int i = 0; i < 4; i++) {
64 		StaticANIObject *newbat = new StaticANIObject(g_vars->scene27_bat);
65 
66 		g_vars->scene27_balls.push_back(newbat);
67 
68 		sc->addStaticANIObject(newbat, 1);
69 	}
70 
71 	g_vars->scene27_dudeIsAiming = false;
72 	g_vars->scene27_maxPhaseReached = false;
73 	g_vars->scene27_wipeIsNeeded = false;
74 	g_vars->scene27_driverPushedButton = false;
75 	g_vars->scene27_numLostBats = 0;
76 	g_vars->scene27_knockCount = 0;
77 	g_vars->scene27_launchPhase = 0;
78 
79 	Scene *oldsc = g_nmi->_currentScene;
80 	g_nmi->_currentScene = sc;
81 
82 	if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithSwab)) {
83 		g_vars->scene27_maid->changeStatics2(ST_MID_SWAB2);
84 	} else if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithBroom)) {
85 		g_vars->scene27_maid->changeStatics2(ST_MID_BROOM);
86 	} else if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithSpade)) {
87 		g_vars->scene27_maid->changeStatics2(ST_MID_SPADE);
88 	}
89 
90 	g_nmi->_currentScene = oldsc;
91 
92 	g_nmi->setArcadeOverlay(PIC_CSR_ARCADE7);
93 }
94 
scene27_updateCursor()95 int scene27_updateCursor() {
96 	g_nmi->updateCursorCommon();
97 
98 	if (g_vars->scene27_dudeIsAiming) {
99 		if (g_nmi->_cursorId != PIC_CSR_DEFAULT_INV && g_nmi->_cursorId != PIC_CSR_ITN_INV)
100 			g_nmi->_cursorId = PIC_CSR_ARCADE7_D;
101 
102 	} else if (g_nmi->_objectIdAtCursor == ANI_MAN) {
103 		if (g_vars->scene27_maxPhaseReached)
104 			if (g_nmi->_cursorId == PIC_CSR_DEFAULT)
105 				g_nmi->_cursorId = PIC_CSR_ITN;
106 	}
107 
108 	return g_nmi->_cursorId;
109 }
110 
sceneHandler27_driverGiveVent()111 void sceneHandler27_driverGiveVent() {
112 	g_vars->scene27_driver->changeStatics2(ST_DRV_VENT);
113 	g_vars->scene27_driver->startMQIfIdle(QU_DRV_GIVEVENT, 1);
114 
115 	g_vars->scene27_driverHasVent = false;
116 
117 	getCurrSceneSc2MotionController()->activate();
118 	getGameLoaderInteractionController()->enableFlag24();
119 
120 	g_nmi->_behaviorManager->setFlagByStaticAniObject(g_nmi->_aniMan, 1);
121 }
122 
sceneHandler27_winArcade()123 void sceneHandler27_winArcade() {
124 	if (g_nmi->getObjectState(sO_Driver) == g_nmi->getObjectEnumState(sO_Driver, sO_WithSteering)) {
125 		g_vars->scene27_dudeIsAiming = false;
126 
127 		g_nmi->_aniMan->_callback2 = 0; // Really NULL
128 		g_nmi->_aniMan->changeStatics2(ST_MAN_RIGHT);
129 
130 		sceneHandler27_driverGiveVent();
131 	}
132 }
133 
sceneHandler27_takeVent()134 void sceneHandler27_takeVent() {
135 	if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithSwab)) {
136 		if (g_vars->scene27_maid->isIdle()) {
137 			if (g_vars->scene27_maid->_flags & 4) {
138 				g_vars->scene27_maid->changeStatics2(ST_MID_SWAB2);
139 				g_vars->scene27_maid->startMQIfIdle(QU_MID_CLEANVENT, 1);
140 			}
141 		}
142 	}
143 }
144 
sceneHandler27_showNextBat()145 void sceneHandler27_showNextBat() {
146 	if (g_vars->scene27_bat) {
147 		MessageQueue *mq = new MessageQueue(g_nmi->_currentScene->getMessageQueueById(QU_SC27_SHOWBET), 0, 1);
148 
149 		mq->setParamInt(-1, g_vars->scene27_bat->_odelay);
150 		mq->chain(0);
151 	}
152 
153 	g_vars->scene27_batHandler->_priority = 1045;
154 }
155 
sceneHandler27_updateScreenCallback()156 int sceneHandler27_updateScreenCallback() {
157 	int res;
158 
159 	res = g_nmi->drawArcadeOverlay(getGameLoaderInteractionController()->_flag24 == 0);
160 
161 	if (!res)
162 		g_nmi->_updateScreenCallback = 0;
163 
164 	return res;
165 }
166 
sceneHandler27_aniManCallback(int * phase)167 void sceneHandler27_aniManCallback(int *phase) {
168 	if (!g_vars->scene27_maxPhaseReached) {
169 		if (*phase >= 5)
170 			g_vars->scene27_maxPhaseReached = true;
171 		else
172 			++*phase;
173 	}
174 }
175 
sceneHandler27_throwBat()176 void sceneHandler27_throwBat() {
177 	if (getGameLoaderInteractionController()->_flag24)
178 		g_nmi->_updateScreenCallback = sceneHandler27_updateScreenCallback;
179 
180 	g_nmi->_aniMan->_callback2 = sceneHandler27_aniManCallback;
181 
182 	g_nmi->_aniMan->startAnim(MV_MAN27_THROWBET, 0, -1);
183 
184 	getCurrSceneSc2MotionController()->deactivate();
185 	getGameLoaderInteractionController()->disableFlag24();
186 
187 	g_nmi->_behaviorManager->setFlagByStaticAniObject(g_nmi->_aniMan, 0);
188 
189 	g_vars->scene27_maxPhaseReached = false;
190 
191 	g_vars->scene27_bat->hide();
192 }
193 
sceneHandler27_clickBat(ExCommand * cmd)194 void sceneHandler27_clickBat(ExCommand *cmd) {
195 	int bx = g_vars->scene27_bat->_ox - 5;
196 	int by = g_vars->scene27_bat->_oy - 71;
197 
198 #if DBG
199 	sceneHandler27_throwBat();
200 	return;
201 #endif
202 
203 	if (ABS(bx - g_nmi->_aniMan->_ox) > 1 || ABS(by - g_nmi->_aniMan->_oy) > 1
204 		|| g_nmi->_aniMan->_movement || g_nmi->_aniMan->_statics->_staticsId != ST_MAN_RIGHT) {
205 		MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_nmi->_aniMan, bx, by, 1, ST_MAN_RIGHT);
206 
207 		if (mq) {
208 			mq->addExCommandToEnd(cmd->createClone());
209 
210 			postExCommand(g_nmi->_aniMan->_id, 2, bx, by, 0, -1);
211 		}
212 	} else {
213 		sceneHandler27_throwBat();
214 	}
215 }
216 
sceneHandler27_maidSwab()217 void sceneHandler27_maidSwab() {
218 #if DBG
219 	return;
220 #endif
221 	if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithSwab))
222 		g_vars->scene27_maid->changeStatics2(ST_MID_SWAB);
223 }
224 
sceneHandler27_startBat(StaticANIObject * bat)225 void sceneHandler27_startBat(StaticANIObject *bat) {
226 	debugC(2, kDebugSceneLogic, "scene27: startBat");
227 
228 	Bat *newbat = new Bat;
229 
230 	newbat->power = g_vars->scene27_launchPhase * 2.5 + 8.0;
231 	newbat->angle = 0;
232 	newbat->ani = bat;
233 	newbat->powerCos = newbat->power * cos(0.0);
234 	newbat->powerSin = newbat->power * sin(0.0);
235 	newbat->currX = newbat->powerCos + (double)g_nmi->_aniMan->_ox + 42.0;
236 	newbat->currY = newbat->powerSin + (double)g_nmi->_aniMan->_oy + 58.0;
237 
238 	bat->_statics = bat->_staticsList[0];
239 	bat->setOXY((int)newbat->currX, (int)newbat->currY);
240 	bat->_flags |= 4;
241 
242 	g_vars->scene27_bats.push_back(newbat);
243 
244 	sceneHandler27_maidSwab();
245 }
246 
sceneHandler27_startAiming()247 void sceneHandler27_startAiming() {
248 	g_vars->scene27_dudeIsAiming = false;
249 	g_vars->scene27_maxPhaseReached = false;
250 
251 	g_nmi->_aniMan->_callback2 = 0; // Really NULL
252 
253 	g_vars->scene27_launchPhase = g_nmi->_aniMan->_movement->_currDynamicPhaseIndex - 6;
254 
255 	int phase = 21 - g_vars->scene27_launchPhase;
256 
257 	if (phase < 14)
258 		phase = 14;
259 
260 	if (phase > 20)
261 		phase = 20;
262 
263 	g_nmi->playSound(SND_27_044, 0);
264 
265 	g_nmi->_aniMan->_movement->setDynamicPhaseIndex(phase);
266 }
267 
sceneHandler27_initAiming(ExCommand * cmd)268 void sceneHandler27_initAiming(ExCommand *cmd) {
269 	g_vars->scene27_aimStartX = cmd->_x;
270 	g_vars->scene27_aimStartY = cmd->_y;
271 	g_vars->scene27_dudeIsAiming = true;
272 	g_vars->scene27_maxPhaseReached = false;
273 }
274 
sceneHandler27_aimDude()275 void sceneHandler27_aimDude() {
276 	int phase = (g_vars->scene27_aimStartX - g_nmi->_mouseScreenPos.x) / 20 + 6;
277 
278 	if (phase < 6)
279 		phase = 6;
280 
281 	if (phase > 11)
282 		phase = 11;
283 
284 	if (g_nmi->_aniMan->_movement)
285 		g_nmi->_aniMan->_movement->setDynamicPhaseIndex(phase);
286 }
287 
sceneHandler27_wipeDo()288 void sceneHandler27_wipeDo() {
289 	debugC(2, kDebugSceneLogic, "scene27: wipeDo");
290 
291 	for (uint i = 0; i < g_vars->scene27_bats.size(); i++) {
292 		if (g_vars->scene27_bats[i]->currX < 800.0) {
293 			g_vars->scene27_bats[i]->angle = atan2(520.0 - g_vars->scene27_bats[i]->currY, 800.0 - g_vars->scene27_bats[i]->currX);
294 			g_vars->scene27_bats[i]->power += 1.0;
295 		}
296 	}
297 }
298 
sceneHandler27_batFallLogic(uint batn)299 bool sceneHandler27_batFallLogic(uint batn) {
300 	Bat *bat = g_vars->scene27_bats[batn];
301 
302 	int y = (int)((bat->currY - 458.0) * 0.4848484848484849 + 734.0);
303 
304 	if (y >= bat->currX)
305 		return false;
306 
307 	if (bat->currX - y > 15.0 || bat->ani->_statics->_staticsId == ST_BTA_FALL) {
308 		bat->ani->_priority = 2020;
309 
310 		g_vars->scene27_var07.push_back(bat);
311 
312 		if (batn != g_vars->scene27_bats.size() - 1)
313 			g_vars->scene27_bats.remove_at(batn);
314 	} else if (!bat->ani->_movement) {
315 		bat->ani->startAnim(MV_BTA_FALL, 0, -1);
316 	}
317 
318 	return true;
319 }
320 
sceneHandler27_batCalcDistance(int bat1,int bat2)321 bool sceneHandler27_batCalcDistance(int bat1, int bat2) {
322 	double at = atan2(g_vars->scene27_bats[bat1]->currY - g_vars->scene27_bats[bat2]->currY, g_vars->scene27_bats[bat1]->currX - g_vars->scene27_bats[bat2]->currX);
323 	double dy = g_vars->scene27_bats[bat1]->currY - g_vars->scene27_bats[bat2]->currY;
324 	double dx = g_vars->scene27_bats[bat1]->currX - g_vars->scene27_bats[bat2]->currX;
325 	double ay = cos(at);
326 	double ax = sin(at);
327 
328 	return sqrt(ax * ax * 0.25 + ay * ay) * 54.0 > sqrt(dx * dx + dy * dy);
329 }
330 
sceneHandler27_knockBats(int bat1n,int bat2n)331 void sceneHandler27_knockBats(int bat1n, int bat2n) {
332 	Bat *bat1 = g_vars->scene27_bats[bat1n];
333 	Bat *bat2 = g_vars->scene27_bats[bat2n];
334 
335 	debugC(2, kDebugSceneLogic, "scene27: knockBats(%d, %d)", bat1n, bat2n);
336 
337 	if (bat1->power != 0.0) {
338 		double rndF = (double)g_nmi->_rnd.getRandomNumber(32767) * 0.03 / 32767.0 - 0.015
339 			+ atan2(bat2->currY - bat1->currY, bat2->currX - bat1->currX);
340 
341 		double pow1x = cos(bat1->angle - rndF) * ((bat2->currX - bat1->currX) >= 0 ? bat1->power : -bat1->power);
342 		double pow1y = sin(bat1->angle - rndF) * ((bat2->currY - bat1->currY) >= 0 ? bat1->power : -bat1->power);
343 
344 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat1 from: powerCos: %f powerSin: %f, power: %f, angle: %f",
345 				bat1->powerCos, bat1->powerSin, bat1->power, bat1->angle);
346 
347 		bat1->powerCos -= pow1x * 1.1;
348 		bat1->powerSin -= pow1y * 1.1;
349 
350 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat1 to: powerCos: %f powerSin: %f", bat1->powerCos, bat1->powerSin);
351 
352 		double rndF2 = (double)g_nmi->_rnd.getRandomNumber(32767) * 0.03 / 32767.0 - 0.015
353 								+ atan2(bat1->currY - bat2->currY, bat1->currX - bat2->currX);
354 		double pow2x = cos(bat2->angle - rndF2) * ((bat1->currX - bat2->currX) >= 0 ? bat2->power : -bat2->power);
355 		double pow2y = sin(bat2->angle - rndF2) * ((bat1->currY - bat2->currY) >= 0 ? bat2->power : -bat2->power);
356 
357 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat2 from: powerCos: %f powerSin: %f, power: %f, angle: %f",
358 				bat2->powerCos, bat2->powerSin, bat2->power, bat2->angle);
359 
360 		bat2->powerCos -= pow2x * 1.1;
361 		bat2->powerSin -= pow2y * 1.1;
362 
363 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat2 to: powerCos: %f powerSin: %f", bat2->powerCos, bat2->powerSin);
364 
365 		double rndCos = cos(rndF);
366 		double rndSin = sin(rndF);
367 
368 		double dy = bat1->currY - bat2->currY;
369 		double dx = bat1->currX - bat2->currX;
370 		double dist = (sqrt(rndSin * rndSin * 0.25 + rndCos * rndCos) * 54.0 - sqrt(dx * dx + dy * dy)) / cos(rndF - bat1->angle);
371 		bat1->currX = bat1->currX - cos(bat1->angle) * (dist + 1.0);
372 		bat1->currY = bat1->currY - sin(bat1->angle) * (dist + 1.0);
373 
374 		bat1->powerCos += pow2x * 0.64;
375 
376 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat1 x: %g y: %g", bat1->currX, bat1->currY);
377 
378 		if (bat1->currX <= 500.0)
379 			bat1->powerSin = 0.0;
380 		else
381 			bat1->powerSin += pow2y * 0.64;
382 
383 		bat1->angle = atan2(bat1->powerSin, bat1->powerCos);
384 		bat1->power = sqrt(bat1->powerCos * bat1->powerCos + bat1->powerSin * bat1->powerSin);
385 
386 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat1 corrected: powerCos: %f powerSin: %f, power: %f, angle: %f",
387 				bat1->powerCos, bat1->powerSin, bat1->power, bat1->angle);
388 
389 		bat2->powerCos += pow1x * 0.64;
390 
391 		if (bat2->currX <= 500.0)
392 			bat2->powerSin = 0.0;
393 		else
394 			bat2->powerSin += pow1y * 0.64;
395 
396 		bat2->angle = atan2(bat2->powerSin, bat2->powerCos);
397 		bat2->power = sqrt(bat2->powerCos * bat2->powerCos + bat2->powerSin * bat2->powerSin);
398 
399 		debugC(3, kDebugSceneLogic, "scene27: knockBats: bat2 corrected: powerCos: %f powerSin: %f, power: %f, angle: %f",
400 				bat2->powerCos, bat2->powerSin, bat2->power, bat2->angle);
401 
402 		g_nmi->playSound(SND_27_026, 0);
403 	}
404 }
405 
sceneHandler27_batSetColors(int batn)406 void sceneHandler27_batSetColors(int batn) {
407 	Bat *bat = g_vars->scene27_bats[batn];
408 
409 	if (g_vars->scene27_hitZone->isPixelHitAtPos((int)bat->currX, (int)bat->currY) ) {
410 		if (bat->ani->_statics->_staticsId == ST_BTA_NORM) {
411 			if (!bat->ani->_movement)
412 				bat->ani->_statics = bat->ani->getStaticsById(ST_BTA_HILITE);
413 		}
414 	} else {
415 		if (bat->ani->_statics->_staticsId == ST_BTA_HILITE) {
416 			if (!bat->ani->_movement)
417 				bat->ani->_statics = bat->ani->getStaticsById(ST_BTA_NORM);
418 		}
419 	}
420 }
421 
sceneHandler27_driverPushButton()422 void sceneHandler27_driverPushButton() {
423 	debugC(2, kDebugSceneLogic, "scene27: driverPushButton");
424 
425 	if (g_nmi->getObjectState(sO_Driver) == g_nmi->getObjectEnumState(sO_Driver, sO_WithSteering)) {
426 		g_vars->scene27_driver->changeStatics2(ST_DRV_VENT);
427 		chainQueue(QU_DRV_PUSHBUTTON, 1);
428 
429 		g_vars->scene27_driverPushedButton = true;
430 	} else {
431 		g_vars->scene27_driver->changeStatics2(ST_DRV_SITNOVENT);
432 
433 
434 		chainQueue(QU_DRV_PUSHBUTTON_NOVENT, 1);
435 
436 		g_vars->scene27_driverPushedButton = true;
437 	}
438 }
439 
sceneHandler27_maidSwitchback()440 void sceneHandler27_maidSwitchback() {
441 #ifndef DBG
442 	if (g_nmi->getObjectState(sO_Maid) == g_nmi->getObjectEnumState(sO_Maid, sO_WithSwab)) {
443 		g_vars->scene27_maid->changeStatics2(ST_MID_SWAB);
444 		g_vars->scene27_maid->startMQIfIdle(QU_MID_SWITCHBACK, 1);
445 	}
446 #endif
447 }
448 
sceneHandler27_batLogic()449 void sceneHandler27_batLogic() {
450 	if (g_vars->scene27_balls.size()) {
451 		g_vars->scene27_bat = g_vars->scene27_balls[0];
452 
453 		g_vars->scene27_balls.remove_at(0);
454 
455 		int mv;
456 
457 		switch (g_vars->scene27_batHandler->_statics->_staticsId) {
458 		case ST_BTH_5:
459 			mv = MV_BTH_5_4;
460 			break;
461 
462 		case ST_BTH_4:
463 			mv = MV_BTH_4_3;
464 			break;
465 
466 		case ST_BTH_3:
467 			mv = MV_BTH_3_2;
468 			break;
469 
470 		case ST_BTH_2:
471 			mv = MV_BTH_2_1;
472 			break;
473 
474 		case ST_BTH_1:
475 			mv = MV_BTH_1_0;
476 			break;
477 
478 		default:
479 			chainQueue(QU_SC27_RESTARTBETS, 1);
480 
481 			getCurrSceneSc2MotionController()->activate();
482 			getGameLoaderInteractionController()->enableFlag24();
483 
484 			g_nmi->_behaviorManager->setFlagByStaticAniObject(g_nmi->_aniMan, 1);
485 
486 			return;
487 		}
488 
489 		MessageQueue *mq = new MessageQueue(g_nmi->_globalMessageQueueList->compact());
490 
491 		mq->setFlags(mq->getFlags() | 1);
492 
493 		ExCommand *ex = new ExCommand(g_vars->scene27_batHandler->_id, 1, mv, 0, 0, 0, 1, 0, 0, 0);
494 		ex->_excFlags |= 2;
495 		mq->addExCommandToEnd(ex);
496 
497 		ex = new ExCommand(0, 17, MSG_SC27_CLICKBET, 0, 0, 0, 1, 0, 0, 0);
498 		ex->_excFlags |= 3;
499 		mq->addExCommandToEnd(ex);
500 
501 		mq->chain(0);
502 	} else {
503 		g_vars->scene27_bat = 0;
504 	}
505 }
506 
sceneHandler27_calcWinArcade()507 void sceneHandler27_calcWinArcade() {
508 	if (!g_vars->scene27_wipeIsNeeded && !g_vars->scene27_driverPushedButton) {
509 		int numHilite = 0;
510 
511 		for (uint i = 0; i < g_vars->scene27_bats.size(); i++) {
512 			if (g_vars->scene27_bats[i]->ani->_statics->_staticsId == ST_BTA_HILITE)
513 				numHilite++;
514 		}
515 
516 		if (numHilite >= 3) {
517 			if (g_nmi->getObjectState(sO_Driver) == g_nmi->getObjectEnumState(sO_Driver, sO_WithSteering)) {
518 				sceneHandler27_driverGiveVent();
519 				sceneHandler27_maidSwitchback();
520 
521 				return;
522 			}
523 		}
524 
525 		if (!g_vars->scene27_balls.size()) {
526 			sceneHandler27_driverPushButton();
527 			sceneHandler27_maidSwitchback();
528 			return;
529 		}
530 
531 		sceneHandler27_batLogic();
532 	}
533 
534 	sceneHandler27_maidSwitchback();
535 }
536 
sceneHandler27_regenBats()537 void sceneHandler27_regenBats() {
538 	debugC(2, kDebugSceneLogic, "scene27: regenBats");
539 
540 	g_vars->scene27_wipeIsNeeded = false;
541 
542 	for (uint i = 0; i < g_vars->scene27_var07.size(); i++) {
543 		g_vars->scene27_var07[i]->ani->hide();
544 
545 		StaticANIObject *newbat = g_vars->scene27_var07[i]->ani;
546 
547 		g_vars->scene27_balls.push_back(newbat);
548 	}
549 
550 	g_vars->scene27_var07.clear();
551 
552 	sceneHandler27_batLogic();
553 
554 	g_vars->scene27_driverPushedButton = false;
555 }
556 
sceneHandler27_animateBats()557 void sceneHandler27_animateBats() {
558 	int oldCount = g_vars->scene27_knockCount;
559 
560 	g_vars->scene27_numLostBats = 0;
561 	g_vars->scene27_knockCount = 0;
562 
563 	for (uint i = 0; i < g_vars->scene27_bats.size(); i++) {
564 		Bat *bat = g_vars->scene27_bats[i];
565 
566 		bat->currX = cos(bat->angle) * bat->power + bat->currX;
567 		bat->currY = sin(bat->angle) * bat->power + bat->currY;
568 
569 		bat->ani->setOXY((int)bat->currX, (int)bat->currY);
570 		bat->ani->_priority = (int)(600.0 - bat->currY);
571 
572 		double powerDelta;
573 
574 		if (cos(bat->angle) >= 0.0 || bat->currX >= 362.0)
575 			powerDelta = bat->power * 0.035;
576 		else
577 			powerDelta = bat->power * 0.4;
578 
579 		bat->power -= powerDelta;
580 		bat->powerCos = cos(bat->angle) * bat->power;
581 		bat->powerSin = sin(bat->angle) * bat->power;
582 
583 		if (bat->power >= 0.5)
584 			g_vars->scene27_knockCount++;
585 		else
586 			bat->power = 0;
587 
588 		sceneHandler27_batSetColors(i);
589 
590 		if (!sceneHandler27_batFallLogic(i) && !g_vars->scene27_wipeIsNeeded) {
591 			for (uint j = 0; j < g_vars->scene27_bats.size(); j++) {
592 				if (i != j && sceneHandler27_batCalcDistance(i, j))
593 					sceneHandler27_knockBats(i, j);
594 			}
595 		}
596 	}
597 
598 	for (uint i = 0; i < g_vars->scene27_var07.size(); i++) {
599 		Bat *bat = g_vars->scene27_var07[i];
600 
601 		if (bat->currY >= 700.0) {
602 			g_vars->scene27_numLostBats++;
603 		} else {
604 			bat->currX = bat->powerCos + bat->currX;
605 			bat->currY = bat->powerSin + bat->currY;
606 			bat->ani->setOXY((int)bat->currX, (int)bat->currY);
607 			bat->powerSin = bat->powerSin + 1.0;
608 		}
609 	}
610 
611 	if (oldCount != g_vars->scene27_knockCount && !g_vars->scene27_knockCount)
612 		sceneHandler27_calcWinArcade();
613 
614 	if (g_vars->scene27_wipeIsNeeded) {
615 		if (g_vars->scene27_numLostBats == 5)
616 			sceneHandler27_regenBats();
617 	}
618 }
619 
sceneHandler27(ExCommand * cmd)620 int sceneHandler27(ExCommand *cmd) {
621 	if (cmd->_messageKind != 17)
622 		return 0;
623 
624 	switch (cmd->_messageNum) {
625 	case MSG_CMN_WINARCADE:
626 		sceneHandler27_winArcade();
627 		break;
628 
629 	case MSG_SC27_TAKEVENT:
630 		sceneHandler27_takeVent();
631 		break;
632 
633 	case MSG_SC27_SHOWNEXTBET:
634 		sceneHandler27_showNextBat();
635 		break;
636 
637 	case MSG_SC27_HANDLERTOFRONT:
638 		g_vars->scene27_batHandler->_priority = 1005;
639 		break;
640 
641 	case MSG_SC27_STARTWIPE:
642 		debugC(2, kDebugSceneLogic, "scene27: STARTWIPE");
643 
644 		g_vars->scene27_wipeIsNeeded = true;
645 
646 		g_nmi->playSound(SND_27_027, 0);
647 		break;
648 
649 	case MSG_SC27_CLICKBET:
650 		sceneHandler27_clickBat(cmd);
651 		break;
652 
653 	case MSG_SC27_STARTBET:
654 		if (g_vars->scene27_bat) {
655 			sceneHandler27_startBat(g_vars->scene27_bat);
656 		}
657 		break;
658 
659 	case 30:
660 		if (g_vars->scene27_dudeIsAiming) {
661 			sceneHandler27_startAiming();
662 		}
663 		break;
664 
665 	case 29:
666 		if (g_nmi->_aniMan == g_nmi->_currentScene->getStaticANIObjectAtPos(g_nmi->_sceneRect.left + cmd->_x, g_nmi->_sceneRect.top + cmd->_y) && g_vars->scene27_maxPhaseReached) {
667 			sceneHandler27_initAiming(cmd);
668 		}
669 		break;
670 
671 	case 33:
672 		if (g_nmi->_aniMan2) {
673 			int x = g_nmi->_aniMan2->_ox;
674 
675 			if (x < g_nmi->_sceneRect.left + 200)
676 				g_nmi->_currentScene->_x = x - 300 - g_nmi->_sceneRect.left;
677 
678 			if (x > g_nmi->_sceneRect.right - 200)
679 				g_nmi->_currentScene->_x = x + 300 - g_nmi->_sceneRect.right;
680 		}
681 
682 		if (g_vars->scene27_dudeIsAiming)
683 			sceneHandler27_aimDude();
684 
685 		if (g_vars->scene27_wipeIsNeeded) {
686 			sceneHandler27_wipeDo();
687 
688 			if (!g_nmi->_aniMan->_movement && g_nmi->_aniMan->_statics->_staticsId == ST_MAN_RIGHT)
689 				g_nmi->_aniMan->startAnim(MV_MAN27_FLOW, 0, -1);
690 		}
691 
692 		sceneHandler27_animateBats();
693 
694 		g_nmi->_behaviorManager->updateBehaviors();
695 		g_nmi->startSceneTrack();
696 
697 		break;
698 
699 	default:
700 		break;
701 	}
702 
703 	return 0;
704 }
705 
706 } // End of namespace NGI
707