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 "common/config-manager.h"
24 #include "common/random.h"
25 
26 #include "engines/util.h"
27 
28 #include "hdb/hdb.h"
29 #include "hdb/ai.h"
30 #include "hdb/file-manager.h"
31 #include "hdb/gfx.h"
32 #include "hdb/input.h"
33 #include "hdb/lua-script.h"
34 #include "hdb/map.h"
35 #include "hdb/menu.h"
36 #include "hdb/sound.h"
37 #include "hdb/mpc.h"
38 #include "hdb/window.h"
39 
40 #define CHEAT_PATCHES 0
41 
42 namespace HDB {
43 
44 HDBGame* g_hdb;
45 
HDBGame(OSystem * syst,const ADGameDescription * gameDesc)46 HDBGame::HDBGame(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
47 	g_hdb = this;
48 	if (isPPC()) {
49 		_screenWidth = 240;
50 		_screenHeight = 320;
51 		_screenDrawWidth = 240;
52 		_screenDrawHeight = 320;
53 		_progressY = 280;
54 	} else {
55 		_screenWidth = 640;
56 		_screenHeight = 480;
57 		_screenDrawWidth = _screenWidth - 160;
58 		_screenDrawHeight = 480;
59 		_progressY = _screenHeight - 64;
60 	}
61 
62 	_format = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
63 	_systemInit = false;
64 
65 	_fileMan = nullptr;
66 	_gfx = nullptr;
67 	_lua = nullptr;
68 	_menu = nullptr;
69 	_map = nullptr;
70 	_ai = nullptr;
71 	_input = nullptr;
72 	_sound = nullptr;
73 	_window = nullptr;
74 	_rnd = new Common::RandomSource("hdb");
75 
76 	_cheating = false;
77 
78 	_currentMapname[0] = _currentLuaName[0] = 0;
79 	_lastMapname[0] = _lastLuaName[0] = 0;
80 	_inMapName[0] = 0;
81 
82 	_timePlayed = _timeSlice = _prevTimeSlice = _timeSeconds = _tiempo = 0;
83 
84 	_currentOutSaveFile = NULL;
85 	_currentInSaveFile = NULL;
86 
87 	_progressActive = false;
88 
89 	_monkeystone7 = STARS_MONKEYSTONE_7_FAKE;
90 	_monkeystone14 = STARS_MONKEYSTONE_14_FAKE;
91 	_monkeystone21 = STARS_MONKEYSTONE_21_FAKE;
92 
93 	_gameShutdown = false;
94 	_progressGfx = nullptr;
95 	_progressMarkGfx = nullptr;
96 	_loadingScreenGfx = nullptr;
97 	_logoGfx = nullptr;
98 	_progressCurrent = -1;
99 	_progressXOffset = -1;
100 	_progressMax = -1;
101 	_gameState = GAME_TITLE;
102 	_actionMode = -1;
103 	_pauseFlag = false;
104 	_debugFlag = -1;
105 	_debugLogo = nullptr;
106 	_dx = 0;
107 	_dy = 0;
108 	_changeLevel = false;
109 	_saveInfo.active = false;
110 	_saveInfo.slot = 0;
111 	_loadInfo.active = false;
112 	_loadInfo.slot = 0;
113 
114 	syncSoundSettings();
115 }
116 
~HDBGame()117 HDBGame::~HDBGame() {
118 	delete _fileMan;
119 	delete _gfx;
120 	delete _lua;
121 	delete _menu;
122 	delete _map;
123 	delete _ai;
124 	delete _input;
125 	delete _sound;
126 	delete _window;
127 	delete _rnd;
128 
129 	delete _progressGfx;
130 	_progressGfx = NULL;
131 	delete _progressMarkGfx;
132 	_progressMarkGfx = NULL;
133 	delete _loadingScreenGfx;
134 	_loadingScreenGfx = NULL;
135 	if (_logoGfx) {
136 		delete _logoGfx;
137 		_logoGfx = NULL;
138 	}
139 	delete _debugLogo;
140 	_debugLogo = NULL;
141 }
142 
init()143 bool HDBGame::init() {
144 	/*
145 		Game Subsystem Initializations
146 	*/
147 
148 	_systemInit = false;
149 	_fileMan = new FileMan;
150 	_gfx = new Gfx;
151 	_lua = new LuaScript;
152 	_menu = new Menu;
153 	_map = new Map;
154 	_ai = new AI;
155 	_input = new Input;
156 	_sound = new Sound;
157 	_window = new Window;
158 
159 	// Init fileMan
160 
161 	_fileMan->openMPC(getGameFile());
162 
163 	_gfx->init();
164 	_sound->init();
165 	_ai->init();
166 	_window->init();
167 	_input->init();
168 	_lua->init();
169 	_menu->init();
170 
171 	_debugLogo = _gfx->loadIcon("icon_debug_logo");
172 	_progressGfx = _gfx->loadPic(PIC_LOADBAR);
173 	_progressMarkGfx = _gfx->loadPic(PIC_LOADSTAR);
174 	_logoGfx = NULL;
175 
176 	_changeLevel = false;
177 	_changeMapname[0] = 0;
178 	_loadInfo.active = _saveInfo.active = false;
179 
180 	_menu->startTitle();
181 
182 	_gameShutdown = false;
183 	_pauseFlag = false;
184 	_systemInit = true;
185 	if (!g_hdb->isPPC())
186 		_loadingScreenGfx = _gfx->loadPic(PIC_LOADSCREEN);
187 	else
188 		_loadingScreenGfx = NULL;
189 
190 	return true;
191 }
192 
initializePath(const Common::FSNode & gamePath)193 void HDBGame::initializePath(const Common::FSNode &gamePath) {
194 	Engine::initializePath(gamePath);
195 	SearchMan.addDirectory("music", gamePath.getChild("music"));
196 }
197 
changeGameState()198 void HDBGame::changeGameState() {
199 
200 	switch (_gameState) {
201 	case GAME_TITLE:
202 		_menu->startMenu();
203 		_gameState = GAME_MENU;
204 		break;
205 	case GAME_MENU:
206 		_menu->freeMenu();
207 		_sound->stopMusic();
208 		_sound->clearPersistent();
209 		_ai->clearPersistent();
210 		_timePlayed = 0;
211 		_timeSeconds = 0;
212 
213 		if (!isDemo()) {
214 			if (!startMap("CINE_INTRO"))
215 				error("Can't load CINE_INTRO");
216 		} else {
217 			if (!startMap("CINE_INTRO_DEMO"))
218 				error("Can't load CINE_INTRO_DEMO");
219 		}
220 		_gameState = GAME_PLAY;
221 		break;
222 	case GAME_PLAY:
223 		_menu->startMenu();
224 		_gameState = GAME_MENU;
225 		break;
226 	case GAME_LOADING:
227 		break;
228 	}
229 }
230 
start()231 void HDBGame::start() {
232 	_gameState = GAME_TITLE;
233 
234 	_debugFlag = 0;
235 }
236 
restartMap()237 bool HDBGame::restartMap() {
238 	if (!_currentMapname[0])
239 		return false;
240 
241 	debug(0, "Starting map %s", _currentMapname);
242 
243 	_gfx->emptyGfxCaches();
244 	_lua->callFunction("level_shutdown", 0);
245 
246 	_gfx->turnOffSnow();
247 	_window->restartSystem();
248 	_ai->restartSystem();
249 	_lua->init();
250 
251 #if CHEAT_PATCHES
252 	if (!strcmp(_currentLuaName, "MAP11.LUA")) {
253 		// Let enter the labs
254 
255 		_lua->saveGlobalNumber("map12_complete", 1);
256 
257 		strcpy(_lastMapname, "MAP12");
258 	}
259 
260 	if (!strcmp(_currentLuaName, "MAP06.LUA")) {
261 		// Have overtime pay for Hanson
262 
263 		_ai->setGemAmount(100);
264 	}
265 
266 	if (!strcmp(_currentLuaName, "MAP29.LUA")) {
267 		// Finish MAP29
268 
269 		_ai->_numGooCups = 8;
270 	}
271 
272 #endif
273 
274 	_lua->loadLua(_currentLuaName);
275 
276 	_sound->markSoundCacheFreeable();
277 	_map->restartSystem();
278 
279 	if (!_map->loadMap(_currentMapname))
280 		return false;
281 
282 	_ai->initAnimInfo();
283 
284 	// Cheat/workarounds
285 #if CHEAT_PATCHES
286 	if (!strcmp(_currentLuaName, "MAP00.LUA")) {
287 		Common::String patch("KillTrigger( \"mannyquest\" )");
288 
289 		_lua->executeChunk(patch, "MAP00 patch");
290 
291 		_ai->addItemToInventory(ITEM_CELL, 1, 0, 0, 0);
292 	}
293 #endif
294 
295 	// if there are Secret Stars here, stick the variable in Lua
296 	if (!_menu->_starWarp && getStarsMonkeystone7() == STARS_MONKEYSTONE_7)
297 		_lua->setLuaGlobalValue("secretstars", 1);
298 	if (_menu->_starWarp == 1 && getStarsMonkeystone14() == STARS_MONKEYSTONE_14)
299 		_lua->setLuaGlobalValue("secretstars", 2);
300 	if (_menu->_starWarp == 2 && getStarsMonkeystone21() == STARS_MONKEYSTONE_21)
301 		_lua->setLuaGlobalValue("secretstars", 3);
302 
303 	_lua->callFunction("level_loaded", 0);
304 	if (!_ai->cinematicsActive())
305 		_gfx->turnOffFade();
306 
307 	// center the player on the screen
308 	int x, y;
309 
310 	_ai->getPlayerXY(&x, &y);
311 	_map->centerMapXY(x + 16, y + 16);
312 
313 	debug(5, "Action List Info:");
314 	for (int k = 0; k < 20; k++) {
315 		debug(5, "Action %d: entityName: %s", k, _ai->_actions[k].entityName);
316 		debug(5, "Action %d: x1: %d, y1: %d", k, _ai->_actions[k].x1, _ai->_actions[k].y1);
317 		debug(5, "Action %d: x2: %d, y2: %d", k, _ai->_actions[k].x2, _ai->_actions[k].y2);
318 		debug(5, "Action %d: luaFuncInit: %s, luaFuncUse: %s", k, _ai->_actions[k].luaFuncInit, _ai->_actions[k].luaFuncUse);
319 	}
320 
321 	return true;
322 }
323 
startMap(const char * name)324 bool HDBGame::startMap(const char *name) {
325 	// save last mapname
326 	Common::strlcpy(_lastMapname, _currentMapname, sizeof(_lastMapname));
327 
328 	// set current mapname
329 	Common::strlcpy(_currentMapname, name, sizeof(_currentMapname));
330 	Common::strlcat(_currentMapname, ".MSM", sizeof(_currentMapname));
331 
332 	// set current luaname
333 	Common::strlcpy(_currentLuaName, name, sizeof(_currentLuaName));
334 	Common::strlcat(_currentLuaName, ".LUA", sizeof(_currentLuaName));
335 
336 	restartMap();
337 
338 	//
339 	// here is where we will be autosaving the start of level
340 	// don't save cine intro/outro/etc...OR map30 (secret star map)
341 	//
342 	if (!scumm_strnicmp(name, "map", 3) && scumm_stricmp(name, "map30")) {
343 		_menu->fillSavegameSlots();
344 		saveGameState(0, Common::String::format("Autosave %s", name)); // we ignore the slot parameter in everything else since we just keep saving...
345 	}
346 	return true;
347 }
348 
paint()349 void HDBGame::paint() {
350 
351 	_tiempo = g_system->getMillis();
352 
353 	switch (_gameState) {
354 	case GAME_TITLE:
355 		_menu->drawTitle();
356 		break;
357 	case GAME_MENU:
358 		_menu->drawMenu();
359 		// fall through
360 	case GAME_PLAY:
361 		_gfx->drawPointer();
362 		break;
363 	case GAME_LOADING:
364 		// clear video, then draw HDB logo
365 		drawLoadingScreen();
366 
367 		// if the graphic has never been loaded, load it now and leave it in memory
368 		if (!_logoGfx)
369 			_logoGfx = _gfx->loadPic(TITLELOGO);
370 		_logoGfx->drawMasked(_screenWidth / 2 - _logoGfx->_width / 2, 10);
371 
372 		int	x = _screenWidth / 2 - _progressGfx->_width / 2;
373 		int pixels = _progressGfx->_width - _progressMarkGfx->_width;
374 		_progressXOffset = (int)(((double)pixels / _progressMax) * (double)_progressCurrent) + x;
375 		break;
376 	}
377 
378 	// Draw FPS on Screen in Debug Mode
379 	if (_debugFlag == 1)
380 		_gfx->drawDebugInfo(_debugLogo, _frames.size());
381 	else if (_debugFlag == 2)
382 		_debugLogo->drawMasked(_screenWidth - 32, 0);
383 
384 	_gfx->updateVideo();
385 }
386 
387 // builds a waypoint list if an entity is not next to player,
388 //	or gives info on an entity, or actually uses an entity
setTargetXY(int x,int y)389 void HDBGame::setTargetXY(int x, int y) {
390 	// if ANY button is pressed
391 	if (_input->getButtons() || _ai->_playerEmerging)
392 		return;
393 
394 	// Check if an entity is next to us
395 	x /= kTileWidth;
396 	y /= kTileHeight;
397 
398 	// Don't ever allow going to X-coord 0
399 	if (!x)
400 		return;
401 
402 	AIEntity *e = _ai->findEntity(x, y);
403 	AIEntity *p = _ai->getPlayer();
404 
405 	if (!p)
406 		return;
407 
408 	int px = p->x / kTileWidth;
409 	int py = p->y / kTileHeight;
410 
411 	// Are we on a touchplate and trying to move within the waiting period?
412 	if (p->touchpWait)
413 		return;
414 
415 	// If we're attacking...don't do anything else
416 	AIState stateList[] = {
417 		STATE_ATK_CLUB_UP,	STATE_ATK_CLUB_DOWN, STATE_ATK_CLUB_LEFT, STATE_ATK_CLUB_RIGHT,
418 		STATE_ATK_STUN_UP,	STATE_ATK_STUN_DOWN, STATE_ATK_STUN_LEFT, STATE_ATK_STUN_RIGHT,
419 		STATE_ATK_SLUG_UP,	STATE_ATK_SLUG_DOWN, STATE_ATK_SLUG_LEFT, STATE_ATK_SLUG_RIGHT,
420 		STATE_PUSHUP,		STATE_PUSHDOWN,		 STATE_PUSHLEFT,	  STATE_PUSHRIGHT};
421 
422 	for (int i = 0; i < 16; i++) {
423 		if (p->state == stateList[i])
424 			return;
425 	}
426 
427 	bool oneTileAway = (abs(px - x) + abs(py - y) < 2);
428 
429 	// If any entity has been targeted
430 	if (e && !_ai->waypointsLeft()) {
431 		// Clicking on a gettable item?
432 		// First check if an iterm is on top of a BLOCKER entity.
433 		// If so, try to find another entity there
434 		if (e->type == AI_NONE) {
435 			AIEntity *temp = g_hdb->_ai->findEntityIgnore(x, y, e);
436 			if (temp)
437 				e = temp;
438 		}
439 
440 		if ((p->level == e->level) && _ai->getTableEnt(e->type)) {
441 			if (g_hdb->_ai->tileDistance(e, p) < 2) {
442 				useEntity(e);
443 				return;
444 			}
445 		}
446 
447 		// Clicking on a Walkthrough Item?
448 		if ((p->level == e->level) && _ai->walkThroughEnt(e->type)) {
449 			_ai->addWaypoint(px, py, x, y, p->level);
450 			return;
451 		}
452 
453 		// Is this an invisible blocker? If so, it probably has a LUA entity under it
454 		if (e->type == AI_NONE && _ai->luaExistAtXY(x, y)) {
455 			// Did player click on a LUA tile?
456 			if (oneTileAway && _ai->checkLuaList(_ai->getPlayer(), x, y))
457 				return;
458 		}
459 
460 		// On the same Level? (Allow pushing on stairs, down only)
461 		if ((p->level != e->level && !(_map->getMapBGTileFlags(e->tileX, e->tileY) & kFlagStairBot)) || (p->level == e->level && _ai->walkThroughEnt(e->type))) {
462 			_ai->addWaypoint(px, py, x, y, p->level);
463 			return;
464 		}
465 
466 		int chx = abs(px - x);
467 		int chy = abs(py - y);
468 
469 		// And its a unit away and the Player's GOALS are done...
470 		if (chx <= 1 && chy <= 1 && !p->goalX) {
471 			// At a horizontal or vertical direction?
472 			if (chx + chy > 1) {
473 				AIEntity *e1, *e2;
474 				uint32 flag1, flag2;
475 
476 				e1 = _ai->findEntity(px, y);
477 				e2 = _ai->findEntity(x, py);
478 				flag1 = _map->getMapBGTileFlags(px, y) & kFlagSolid;
479 				flag2 = _map->getMapBGTileFlags(x, py) & kFlagSolid;
480 				if ((e1 || flag1) && (e2 || flag2))
481 					return;
482 			}
483 
484 			// Check for items that should NOT be picked up or talked to
485 			switch (e->type) {
486 				// USEing a floating crate or barrel?  Just go there.
487 				// Unless it's not floating, in which case you wanna push it.
488 			case AI_CRATE:
489 			case AI_LIGHTBARREL:
490 				// USEing a heavy barrel ONLY means walking on it if it's floating
491 				// *** cannot push a heavy barrel
492 			case AI_HEAVYBARREL:
493 				if (e->state == STATE_FLOATING || e->state == STATE_MELTED)
494 					_ai->addWaypoint(px, py, x, y, p->level);
495 				else
496 					useEntity(e);
497 				return;
498 			default:
499 				useEntity(e);
500 				return;
501 			}
502 		} else {
503 			_ai->addWaypoint(px, py, x, y, p->level);
504 			return;
505 		}
506 	}
507 
508 	// Are we trying to "activate" a touchplate?
509 	// Set a waypoint on it
510 	if (_ai->checkForTouchplate(x, y)) {
511 		_ai->addWaypoint(px, py, x, y, p->level);
512 		return;
513 	}
514 
515 	// Did the player click on an action tile?
516 	if (oneTileAway && _ai->checkActionList(_ai->getPlayer(), x, y, true))
517 		return;
518 
519 	// Did the player click on an auto-action tile?
520 	if (oneTileAway && _ai->checkAutoList(_ai->getPlayer(), x, y))
521 		return;
522 
523 	// we need to add this point to the waypoint list!
524 	// the list is tile coord-based
525 	//
526 	// if the player is not PUSHING anything and has no GOALS,
527 	// it's ok to set up a waypoint
528 	switch (p->state) {
529 	case STATE_PUSHDOWN:
530 	case STATE_PUSHUP:
531 	case STATE_PUSHLEFT:
532 	case STATE_PUSHRIGHT:
533 	case STATE_NONE:
534 		break;
535 	default:
536 		_ai->addWaypoint(px, py, x, y, p->level);
537 		break;
538 	}
539 }
540 
startMoveMap(int x,int y)541 void HDBGame::startMoveMap(int x, int y) {
542 	_dx = x;
543 	_dy = y;
544 }
545 
moveMap(int x,int y)546 void HDBGame::moveMap(int x, int y) {
547 	int	ox, oy;
548 	g_hdb->_map->getMapXY(&ox, &oy);
549 
550 	ox += (_dx - x) / 8;
551 	oy += (_dy - y) / 8;
552 
553 	ox = CLIP(ox, 0, g_hdb->_map->mapPixelWidth() - 240);
554 	oy = CLIP(oy, 0, g_hdb->_map->mapPixelHeight() - 320);
555 
556 	g_hdb->_map->setMapXY(ox, oy);
557 }
558 
559 // PLAYER is trying to use this entity
useEntity(AIEntity * e)560 void HDBGame::useEntity(AIEntity *e) {
561 	AIEntity *p = _ai->getPlayer();
562 	// Check if entity is on same level or if its a stairtop
563 	if ((p->level != e->level) && !(_map->getMapBGTileFlags(p->tileX, p->tileY) & kFlagStairTop))
564 		return;
565 
566 	bool added = false;
567 
568 	AIEntity temp;
569 	if (_ai->getTableEnt(e->type)) {
570 		temp = *e;
571 
572 		_ai->getItemSound(e->type);
573 
574 		added = _ai->addToInventory(e);
575 		if (added) {
576 			e = &temp;
577 
578 			if (temp.aiUse)
579 				temp.aiUse(&temp);
580 
581 			if (temp.luaFuncUse[0])
582 				_lua->callFunction(temp.luaFuncUse, 0);
583 		}
584 	} else {
585 		// These should be run over or run through
586 		if (_ai->walkThroughEnt(e->type) || e->type == AI_NONE)
587 			return;
588 
589 		if (e->aiUse)
590 			e->aiUse(e);
591 
592 		if (e->luaFuncUse[0])
593 			_lua->callFunction(e->luaFuncUse, 0);
594 	}
595 
596 	// PUSHING
597 	// If its a pushable object, push it. Unless it's in/on water.
598 	if (e->type == AI_CRATE || e->type == AI_LIGHTBARREL || e->type == AI_BOOMBARREL || e->type == AI_MAGIC_EGG || e->type == AI_ICE_BLOCK || e->type == AI_FROGSTATUE || e->type == AI_DIVERTER) {
599 		// if it's floating, don't touch!
600 		if (e->state >= STATE_FLOATING && e->state <= STATE_FLOATRIGHT) {
601 			g_hdb->_ai->lookAtEntity(e);
602 			g_hdb->_ai->animGrabbing();
603 			g_hdb->_window->openMessageBar("I can't lift that!", 1);
604 			return;
605 		}
606 
607 		int xDir = 0;
608 		int yDir = 0;
609 		if (p->tileX > e->tileX)
610 			xDir = -2;
611 		else if (p->tileX < e->tileX)
612 			xDir = 2;
613 
614 		if (p->tileY > e->tileY)
615 			yDir = -2;
616 		else if (p->tileY < e->tileY)
617 			yDir = 2;
618 
619 		// no diagonals allowed!
620 		if (xDir && yDir)
621 			return;
622 
623 		int chX = p->tileX + xDir;
624 		int chY = p->tileY + yDir;
625 		uint32 flags;
626 		// are we going to push this over a sliding surface? (ok)
627 		// are we going to push this into a blocking tile? (not ok)
628 		if (e->level == 2) {
629 			int	fg_flags = g_hdb->_map->getMapFGTileFlags(chX, chY);
630 			if (fg_flags & kFlagSolid) {
631 				g_hdb->_sound->playSound(SND_GUY_UHUH);
632 				g_hdb->_ai->lookAtXY(chX, chY);
633 				g_hdb->_ai->animGrabbing();
634 				return;
635 			}
636 
637 			flags = g_hdb->_map->getMapBGTileFlags(chX, chY);
638 			if (((flags & kFlagSolid) == kFlagSolid) && !(fg_flags & kFlagGrating)) {
639 				g_hdb->_sound->playSound(SND_GUY_UHUH);
640 				g_hdb->_ai->lookAtXY(chX, chY);
641 				g_hdb->_ai->animGrabbing();
642 				return;
643 			}
644 		} else {
645 			flags = g_hdb->_map->getMapBGTileFlags(chX, chY);
646 			if (!(flags & kFlagSlide) && (flags & kFlagSolid)) {
647 				g_hdb->_sound->playSound(SND_GUY_UHUH);
648 				g_hdb->_ai->lookAtXY(chX, chY);
649 				g_hdb->_ai->animGrabbing();
650 				return;
651 			}
652 		}
653 
654 		// are we going to push this up the stairs? (not ok)
655 		if (flags & kFlagStairBot) {
656 			flags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY);
657 			if (!(flags & kFlagStairTop)) {
658 				g_hdb->_ai->lookAtEntity(e);
659 				g_hdb->_ai->animGrabbing();
660 				g_hdb->_sound->playSound(SND_GUY_UHUH);
661 				return;
662 			}
663 		}
664 
665 		// is player trying to push across a dangerous floor (where the player would be ON the floor after the push)?
666 		// don't allow it.
667 		flags = g_hdb->_map->getMapBGTileFlags(p->tileX + (xDir >> 1), p->tileY + (yDir >> 1));
668 		if (((flags & kFlagRadFloor) == kFlagRadFloor || (flags & kFlagPlasmaFloor) == kFlagPlasmaFloor) &&
669 			false == g_hdb->_ai->checkFloating(p->tileX + (xDir >> 1), p->tileY + (yDir >> 1))) {
670 			g_hdb->_ai->lookAtEntity(e);
671 			g_hdb->_ai->animGrabbing();
672 			g_hdb->_sound->playSound(SND_NOPUSH_SIZZLE);
673 			return;
674 		}
675 
676 		// are we going to push this into a gem?
677 		// if it's a goodfairy, make it move!
678 		AIEntity *e2 = g_hdb->_ai->findEntityIgnore(chX, chY, &g_hdb->_ai->_dummyLaser);
679 		if (e2 && e2->type == ITEM_GEM_WHITE) {
680 			g_hdb->_ai->addAnimateTarget(e2->x, e2->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH);
681 			g_hdb->_ai->removeEntity(e2);
682 			g_hdb->_sound->playSound(SND_BRIDGE_END);
683 			g_hdb->_ai->animGrabbing();
684 			return;
685 		}
686 
687 		// if so, is it a MELTED or FLOATING entity?  if so, that's cool...
688 		if (e2) {
689 			if (!g_hdb->_ai->checkFloating(e2->tileX, e2->tileY)) {
690 				g_hdb->_ai->lookAtXY(chX, chY);
691 				g_hdb->_ai->animGrabbing();
692 				g_hdb->_sound->playSound(SND_GUY_UHUH);
693 				return;
694 			}
695 		}
696 
697 		// are we trying to push this through a door? (teleporter!)
698 		SingleTele info;
699 		if (true == g_hdb->_ai->findTeleporterDest(chX, chY, &info)) {
700 			g_hdb->_ai->lookAtXY(chX, chY);
701 			g_hdb->_ai->animGrabbing();
702 			g_hdb->_sound->playSound(SND_GUY_UHUH);
703 			return;
704 		}
705 
706 		// everything's clear - time to push!
707 		// set goal for pushed object
708 		if (e->type != AI_DIVERTER)
709 			e->moveSpeed = kPushMoveSpeed;	// push DIVERTERS real fast
710 		g_hdb->_ai->setEntityGoal(e, chX, chY);
711 
712 		// Diverters are very special - don't mess with their direction & state!
713 		if (e->type == AI_DIVERTER) {
714 			switch (e->dir2) {
715 			case DIR_DOWN:
716 				e->state = STATE_DIVERTER_BL;
717 				break;
718 			case DIR_UP:
719 				e->state = STATE_DIVERTER_BR;
720 				break;
721 			case DIR_LEFT:
722 				e->state = STATE_DIVERTER_TL;
723 				break;
724 			case DIR_RIGHT:
725 				e->state = STATE_DIVERTER_TR;
726 				break;
727 			case DIR_NONE:
728 				break;
729 			}
730 		}
731 
732 		// set goal for player
733 		if (xDir)
734 			xDir = xDir >> 1;
735 		if (yDir)
736 			yDir = yDir >> 1;
737 		if (e->type != AI_DIVERTER)			// push DIVERTERS real fast
738 			p->moveSpeed = kPushMoveSpeed;
739 		else
740 			p->moveSpeed = kPlayerMoveSpeed;
741 
742 		g_hdb->_ai->setEntityGoal(p, p->tileX + xDir, p->tileY + yDir);
743 
744 		// need to set the state AFTER the SetEntityGoal!
745 		switch (p->dir) {
746 		case DIR_UP:
747 			p->state = STATE_PUSHUP;
748 			p->drawYOff = -10;
749 			break;
750 		case DIR_DOWN:
751 			p->state = STATE_PUSHDOWN;
752 			p->drawYOff = 9;
753 			break;
754 		case DIR_LEFT:
755 			p->state = STATE_PUSHLEFT;
756 			p->drawXOff = -10;
757 			break;
758 		case DIR_RIGHT:
759 			p->state = STATE_PUSHRIGHT;
760 			p->drawXOff = 10;
761 			break;
762 		case DIR_NONE:
763 			break;
764 		}
765 
766 		// if player is running, keep speed slow since we're pushing
767 		if (g_hdb->_ai->playerRunning()) {
768 			p->xVel = p->xVel >> 1;
769 			p->yVel = p->yVel >> 1;
770 		}
771 
772 		switch (e->type) {
773 		case AI_CRATE:
774 			g_hdb->_sound->playSound(SND_CRATE_SLIDE);
775 			break;
776 		case AI_LIGHTBARREL:
777 		case AI_FROGSTATUE:
778 		case AI_ICE_BLOCK:
779 			g_hdb->_sound->playSound(SND_LIGHT_SLIDE);
780 			break;
781 		case AI_HEAVYBARREL:
782 		case AI_MAGIC_EGG:
783 		case AI_BOOMBARREL:
784 			g_hdb->_sound->playSound(SND_HEAVY_SLIDE);
785 			break;
786 		case AI_DIVERTER:
787 			g_hdb->_sound->playSound(SND_PUSH_DIVERTER);
788 			break;
789 		default:
790 			break;
791 		}
792 
793 		return;
794 	}
795 
796 	// Look at Entity
797 	if (e->type != AI_RAILRIDER_ON)
798 		_ai->lookAtEntity(e);
799 
800 	// Grab animation
801 	if (added)
802 		_ai->animGrabbing();
803 
804 	// Can't push it - make a sound
805 	if (e->type == AI_HEAVYBARREL)
806 		g_hdb->_sound->playSound(SND_GUY_UHUH);
807 }
808 
setupProgressBar(int maxCount)809 void HDBGame::setupProgressBar(int maxCount) {
810 	_progressMax = maxCount;
811 	_progressCurrent = 0;
812 	_progressActive = true;
813 }
814 
drawProgressBar()815 void HDBGame::drawProgressBar() {
816 	if (!_progressActive)
817 		return;
818 
819 	GameState temp = _gameState;
820 	_gameState = GAME_LOADING;
821 	paint();
822 	_gameState = temp;
823 }
824 
checkProgress()825 void HDBGame::checkProgress() {
826 	if (!_progressActive)
827 		return;
828 
829 	int x = _screenWidth / 2 - _progressGfx->_width / 2;
830 	_progressGfx->drawMasked(x, g_hdb->_progressY);
831 	for (int i = x; i < _progressXOffset; i += _progressMarkGfx->_width)
832 		_progressMarkGfx->drawMasked(i, g_hdb->_progressY);
833 	_progressMarkGfx->drawMasked(_progressXOffset, g_hdb->_progressY);
834 }
835 
drawLoadingScreen()836 void HDBGame::drawLoadingScreen() {
837 	if (g_hdb->isPPC())
838 		_gfx->fillScreen(0);
839 	else
840 		_loadingScreenGfx->draw(0, 0);
841 }
842 
843 struct MapName {
844 	const char *fName, *printName;
845 } static mapNames[] = {
846 	{	"MAP00",			"HDS Colby Jack" },
847 	{	"MAP01",			"Servandrones, Inc." },
848 	{	"MAP02",			"Pushbot Storage" },
849 	{	"MAP03",			"Rightbot Problems" },
850 	{	"MAP04",			"Shockbot Secrets" },
851 	{	"MAP05",			"The Drain Pain" },
852 	{	"MAP06",			"Energy Column Tower" },
853 	{	"MAP07",			"Water Supply Systems" },
854 	{	"MAP08",			"Food Supply Systems" },
855 	{	"MAP09",			"Purple Storage Room" },
856 	{	"MAP10",			"Back On The Jack" },
857 	{	"MAP11",			"Bridia" },
858 	{	"MAP12",			"BEAL Offices" },
859 	{	"MAP13",			"BEAL Labs" },
860 	{	"MAP14",			"Earthen Plain" },
861 	{	"MAP15",			"Fatfrog Swamp" },
862 	{	"MAP16",			"Fatfrog Deeps" },
863 	{	"MAP17",			"Glacier West" },
864 	{	"MAP18",			"Glacier East" },
865 	{	"MAP19",			"Mystery Pizza Factory" },
866 	{	"MAP20",			"Colby Jack Attack" },
867 	{	"MAP21",			"Pharitale" },
868 	{	"MAP22",			"Happy Meadow" },
869 	{	"MAP23",			"Water Caves" },
870 	{	"MAP24",			"Rocky Crag" },
871 	{	"MAP25",			"Dragon Deeps" },
872 	{	"MAP26",			"Lower Dragon Deeps" },
873 	{	"MAP27",			"Ice Dragon Valley" },
874 	{	"MAP28",			"Faerie Glade" },
875 	{	"MAP29",			"Palace In The Clouds" },
876 	{	"MAP30",			"Monkeystone Star Zone" },
877 };
878 
setInMapName(const char * name)879 void HDBGame::setInMapName(const char *name) {
880 	for (uint i = 0; i < ARRAYSIZE(mapNames); i++) {
881 		if (!scumm_stricmp(name, mapNames[i].fName)) {
882 			memset(&_inMapName, 0, 32);
883 			strcpy(_inMapName, mapNames[i].printName);
884 			return;
885 		}
886 	}
887 
888 	memset(&_inMapName, 0, 32);
889 	strcpy(_inMapName, name);
890 }
891 
run()892 Common::Error HDBGame::run() {
893 
894 	// Initialize System
895 	if (!_systemInit)
896 		init();
897 
898 	// Initializes Graphics
899 	initGraphics(_screenWidth, _screenHeight, &_format);
900 
901 	start();
902 
903 #if 0
904 	Common::SeekableReadStream *titleStream = _fileMan->findFirstData("monkeylogoscreen", TYPE_PIC);
905 	if (titleStream == NULL) {
906 		debug("The TitleScreen MPC entry can't be found.");
907 		delete titleStream;
908 		return Common::kReadingFailed;
909 	}
910 
911 	Picture *titlePic = new Picture;
912 	titlePic->load(titleStream);
913 	delete titleStream;
914 
915 	Common::SeekableReadStream *tileStream = _fileMan->findFirstData("t32_ground1", TYPE_TILE32);
916 	if (tileStream == NULL) {
917 		debug("The t32_shipwindow_lr MPC entry can't be found.");
918 		delete tileStream;
919 		return Common::kReadingFailed;
920 	}
921 
922 	Tile *tile = new Tile;
923 	tile->load(tileStream);
924 	delete tileStream;
925 #endif
926 
927 	if (ConfMan.hasKey("boot_param")) {
928 		int arg = ConfMan.getInt("boot_param");
929 		int actionMode = MIN(arg / 100, 1);
930 		int level = MIN(arg % 100, 31);
931 
932 		setActionMode(actionMode);
933 
934 		Common::String mapNameString = Common::String::format("MAP%02d", level);
935 
936 		if (level > 30) {
937 			mapNameString = "CINE_OUTRO";
938 		}
939 
940 		if (isDemo()) {
941 			mapNameString += "_DEMO";
942 		}
943 
944 		debug("Starting level %s in %s Mode", mapNameString.c_str(), getActionMode() ? "Action" : "Puzzle");
945 
946 		_ai->clearPersistent();
947 		startMap(mapNameString.c_str());
948 
949 		_gameState = GAME_PLAY;
950 	} else {
951 		if (ConfMan.hasKey("save_slot") && loadGameState(ConfMan.getInt("save_slot")).getCode() == Common::kNoError)
952 			_gameState = GAME_PLAY;
953 	}
954 
955 	//_window->openDialog("Sgt. Filibuster", 0, "You address me as 'sarge' or 'sergeant' or get your snappin' teeth kicked in! Got me?", 0, NULL);
956 
957 #if 0
958 	lua->executeFile("test.lua");
959 #endif
960 
961 	uint32 lastTime = g_system->getMillis();
962 	while (!shouldQuit()) {
963 		Common::Event event;
964 		while (g_system->getEventManager()->pollEvent(event)) {
965 			switch (event.type) {
966 			case Common::EVENT_MOUSEMOVE:
967 				_input->updateMouse(event.mouse.x, event.mouse.y);
968 				break;
969 			case Common::EVENT_LBUTTONDOWN:
970 				_input->updateMouseButtons(1, 0, 0);
971 				break;
972 			case Common::EVENT_LBUTTONUP:
973 				_input->updateMouseButtons(-1, 0, 0);
974 				break;
975 			case Common::EVENT_MBUTTONDOWN:
976 				_input->updateMouseButtons(0, 1, 0);
977 				break;
978 			case Common::EVENT_MBUTTONUP:
979 				_input->updateMouseButtons(0, -1, 0);
980 				break;
981 			case Common::EVENT_RBUTTONDOWN:
982 				_input->updateMouseButtons(0, 0, 1);
983 				break;
984 			case Common::EVENT_RBUTTONUP:
985 				_input->updateMouseButtons(0, 0, -1);
986 				break;
987 			case Common::EVENT_KEYDOWN:
988 				_input->updateKeys(event, true);
989 				break;
990 			case Common::EVENT_KEYUP:
991 				_input->updateKeys(event, false);
992 				break;
993 			default:
994 				break;
995 			}
996 		}
997 
998 		if (_gameState == GAME_PLAY) {
999 			_gfx->drawSky();
1000 
1001 			if (!_pauseFlag) {
1002 				_ai->moveEnts();
1003 				_ai->animateBridges();
1004 				_ai->processCallbackList();
1005 			}
1006 
1007 			_map->draw();
1008 			_ai->processCines();
1009 			//_window->drawDialog();
1010 
1011 			AIEntity *e = _ai->getPlayer();
1012 
1013 			if (e && e->level < 2)
1014 				_ai->drawWayPoints();
1015 
1016 			if (!(g_hdb->isDemo() && g_hdb->isPPC()))
1017 				_map->drawEnts();
1018 
1019 			_map->drawGratings();
1020 
1021 			if (e && e->level == 2)
1022 				_ai->drawWayPoints();
1023 
1024 			_ai->drawLevel2Ents();
1025 
1026 			_map->drawForegrounds();
1027 			_ai->animateTargets();
1028 
1029 			_window->drawDialog();
1030 			_window->drawDialogChoice();
1031 			_window->drawInventory();
1032 			_window->drawMessageBar();
1033 			_window->drawDeliveries();
1034 			_window->drawTryAgain();
1035 			_window->drawPanicZone();
1036 			_window->drawTextOut();
1037 			_window->drawPause();
1038 			_gfx->drawBonusStars();
1039 			_gfx->drawSnow();
1040 
1041 			if (_changeLevel == true) {
1042 				_changeLevel = false;
1043 				startMap(_changeMapname);
1044 			}
1045 
1046 			//
1047 			// should we save the game at this point?
1048 			//
1049 			if (_saveInfo.active == true) {
1050 				_sound->playSound(SND_VORTEX_SAVE);
1051 				_ai->stopEntity(e);
1052 				_menu->fillSavegameSlots();
1053 				saveGameState(_saveInfo.slot, "FIXME"); // Add here date/level name // TODO
1054 				_saveInfo.active = false;
1055 			}
1056 
1057 			// calculate time spent ONLY in the game...
1058 			_timePlayed += g_system->getMillis() - _tiempo;
1059 		}
1060 
1061 		// Update Timer that's NOT used for in-game Timing
1062 		_prevTimeSlice = _timeSlice;
1063 		_timeSlice = g_system->getMillis();
1064 
1065 		paint();
1066 
1067 		if (g_hdb->getDebug()) {
1068 			g_hdb->_frames.push_back(g_system->getMillis());
1069 			while (g_hdb->_frames[0] < g_system->getMillis() - 1000)
1070 				g_hdb->_frames.remove_at(0);
1071 		}
1072 		uint32 curTime = g_system->getMillis();
1073 		uint32 frameTime = curTime - lastTime;
1074 
1075 		uint32 frameCap = 1000 / kGameFPS;
1076 		if (frameTime < frameCap)
1077 			g_system->delayMillis(frameCap - frameTime);
1078 
1079 		lastTime = g_system->getMillis();
1080 	}
1081 
1082 	return Common::kNoError;
1083 }
1084 
1085 } // End of namespace HDB
1086