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