/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "got/game/back.h" #include "common/file.h" #include "got/events.h" #include "got/game/boss1.h" #include "got/game/boss2.h" #include "got/game/boss3.h" #include "got/game/move.h" #include "got/game/object.h" #include "got/game/script.h" #include "got/gfx/image.h" #include "got/vars.h" namespace Got { const char *OBJECT_NAMES[] = { "Shrub", "Child's Doll", "UNUSED", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE", "FUTURE"}; const char *ITEM_NAMES[] = { "Enchanted Apple", "Lightning Power", "Winged Boots", "Wind Power", "Amulet of Protection", "Thunder Power"}; static const char *odinEndMessage; void showLevel(const int newLevel) { if (_G(area) == 2 && newLevel == 105) { // Shovel Maze _G(thorInfo)._armor = 2; // eyeballs mode loadNewThor(); _G(eyeballs) = 1; } else if (_G(eyeballs) == 1) { _G(setup).f25 = 0; _G(thorInfo)._armor = 1; loadNewThor(); _G(eyeballs) = 0; } _G(bossActive) = false; if (!_G(shieldOn)) _G(actor[2])._active = false; _G(slipping) = false; if (_G(scrn)._iconGrid[_G(thor)->_centerY][_G(thor)->_centerX] == 154) _G(thor)->_dir = 0; // The original copied 130 bytes from _G(scrn).static_object onwards into sd_data. // This doesn't make sense, because that would put the ending in the middle of _staticY. // Plus, it follows with an entire copy of scrn into sd_data anyway, so the first // move seems entirely redundant. _G(scrn).save(_G(currentLevel)); _G(scrn).load(_G(newLevel)); _G(levelMusic) = _G(scrn)._music; _G(thor)->_nextFrame = 0; showObjects(); showEnemies(); // The original was probably shortly displaying Thor in direction 0 before switching back to its prior position. // This behavior wasn't noticed during initial playthrough by Dreammaster - Warning has been added so it can be checked eventually. if (_G(scrn)._iconGrid[_G(thor)->_centerY][_G(thor)->_centerX] == 154) warning("showLevel - Potential short move missing"); if (_G(warpFlag)) _G(currentLevel) = newLevel - 5; // Force phase _G(warpFlag) = false; if (_G(warpScroll)) { _G(warpScroll) = false; if (_G(thor)->_dir == 0) _G(currentLevel) = newLevel + 10; else if (_G(thor)->_dir == 1) _G(currentLevel) = newLevel - 10; else if (_G(thor)->_dir == 2) _G(currentLevel) = newLevel + 1; else if (_G(thor)->_dir == 3) _G(currentLevel) = newLevel - 1; } if (!_G(setup)._scrollFlag) _G(currentLevel) = newLevel; // Force no scroll switch (_G(newLevel) - _G(currentLevel)) { case 0: // Nothing to do showLevelDone(); break; case -1: _G(gameMode) = MODE_AREA_CHANGE; _G(transitionDir) = DIR_LEFT; break; case 1: _G(gameMode) = MODE_AREA_CHANGE; _G(transitionDir) = DIR_RIGHT; break; case -10: _G(gameMode) = MODE_AREA_CHANGE; _G(transitionDir) = DIR_UP; break; case 10: _G(gameMode) = MODE_AREA_CHANGE; _G(transitionDir) = DIR_DOWN; break; default: _G(gameMode) = MODE_AREA_CHANGE; _G(transitionDir) = DIR_PHASED; break; } } void showLevelDone() { _G(currentLevel) = _G(newLevel); _G(thorInfo)._lastHealth = _G(thor)->_health; _G(thorInfo)._lastMagic = _G(thorInfo)._magic; _G(thorInfo)._lastJewels = _G(thorInfo)._jewels; _G(thorInfo)._lastKeys = _G(thorInfo)._keys; _G(thorInfo)._lastScore = _G(thorInfo)._score; _G(thorInfo)._lastItem = _G(thorInfo)._selectedItem; _G(thorInfo)._lastScreen = _G(currentLevel); _G(thorInfo)._lastIcon = ((_G(thor)->_x + 8) / 16) + (((_G(thor)->_y + 14) / 16) * 20); _G(thorInfo)._lastDir = _G(thor)->_dir; _G(thorInfo)._lastInventory = _G(thorInfo)._inventory; _G(thorInfo)._lastObject = _G(thorInfo)._object; _G(thorInfo)._lastObjectName = _G(thorInfo)._objectName; _G(lastSetup) = _G(setup); bool f = true; if (GAME1 && _G(newLevel) == BOSS_LEVEL1 && !_G(setup)._bossDead[0]) { boss1SetupLevel(); f = false; } if (GAME2 && _G(newLevel) == BOSS_LEVEL2 && !_G(setup)._bossDead[1]) { boss2SetupLevel(); f = false; } if (GAME3) { if (_G(newLevel) == BOSS_LEVEL3 && !_G(setup)._bossDead[2]) { boss3SetupLevel(); f = false; } if (_G(currentLevel) == ENDING_SCREEN) { endingScreen(); f = false; } } if (_G(startup)) f = false; if (f) musicPlay(_G(levelMusic), false); } static void odin_speaks_end() { // In case Thor is now dead, flag as such if (!_G(thor)->_health) { _G(thor)->_show = 0; _G(exitFlag) = 2; } // If there's an end message, pass it on to the view hierarchy. // This is used in cases like the game end where multiple // odinSpeaks are done in sequence if (odinEndMessage) g_events->send(GameMessage(odinEndMessage)); } void odinSpeaks(const int index, int item, const char *endMessage) { odinEndMessage = endMessage; executeScript((long)index, _G(odin), odin_speaks_end); } int switchIcons() { playSound(WOOP, false); for (int y = 0; y < 12; y++) { for (int x = 0; x < 20; x++) { const int ix = x * 16; const int iy = y * 16; if (_G(scrn)._iconGrid[y][x] == 93) { placeTile(x, y, 144); } else if (_G(scrn)._iconGrid[y][x] == 144) { placeTile(x, y, 93); killEnemies(iy, ix); } if (_G(scrn)._iconGrid[y][x] == 94) { placeTile(x, y, 146); } else if (_G(scrn)._iconGrid[y][x] == 146) { placeTile(x, y, 94); killEnemies(iy, ix); } } } return 0; } int rotateArrows() { playSound(WOOP, false); for (int y = 0; y < 12; y++) { for (int x = 0; x < 20; x++) { if (_G(scrn)._iconGrid[y][x] == 205) placeTile(x, y, 208); else if (_G(scrn)._iconGrid[y][x] == 206) placeTile(x, y, 207); else if (_G(scrn)._iconGrid[y][x] == 207) placeTile(x, y, 205); else if (_G(scrn)._iconGrid[y][x] == 208) placeTile(x, y, 206); } } return 0; } void killEnemies(const int iy, const int ix) { int x1, y1, x2, y2; for (int i = 3; i < MAX_ACTORS; i++) { if (_G(actor[i])._active) { x1 = _G(actor[i])._x; y1 = _G(actor[i])._y + _G(actor[i])._sizeY - 2; x2 = (_G(actor[i])._x + _G(actor[i])._sizeX); y2 = _G(actor[i])._y + _G(actor[i])._sizeY - 1; if (pointWithin(x1, y1, ix, iy, ix + 15, iy + 15) || pointWithin(x2, y1, ix, iy, ix + 15, iy + 15) || pointWithin(x1, y2, ix, iy, ix + 15, iy + 15) || pointWithin(x2, y2, ix, iy, ix + 15, iy + 15)) actorDestroyed(&_G(actor[i])); } } x1 = _G(thor)->_x; y1 = _G(thor)->_y + 11; x2 = x1 + 13; y2 = y1 + 5; if (pointWithin(x1, y1, ix, iy, ix + 15, iy + 15) || pointWithin(x2, y1, ix, iy, ix + 15, iy + 15) || pointWithin(x1, y2, ix, iy, ix + 15, iy + 15) || pointWithin(x2, y2, ix, iy, ix + 15, iy + 15)) { if (!_G(cheats)._freezeHealth) { _G(thor)->_health = 0; g_events->send(GameMessage("THOR_DIES")); } } } void removeObjects(const int y, const int x) { const int p = (y * 20) + x; if (_G(objectMap[p]) > 0) { _G(objectMap[p]) = 0; _G(objectIndex[p]) = 0; } } void placeTile(const int x, const int y, const int tile) { _G(scrn)._iconGrid[y][x] = tile; removeObjects(y, x); } int backgroundTile(int x, int y) { if (x < 0 || x >= 319 || y < 0 || y >= 191) return 0; x = (x + 1) >> 4; y = (y + 1) >> 4; return _G(scrn)._iconGrid[y][x]; } void selectItem() { // Only allow opening the dialog if something isn't currently going on if (g_engine->canSaveAutosaveCurrently()) { g_events->addView("SelectItem"); } } void actorSpeaks(const Actor *actor, int index, int item) { if (actor->_type != 4) return; const int v = atoi(actor->_name); if (v < 1 || v > 20) return; long lind = (long)_G(currentLevel); lind = lind * 1000; lind += (long)actor->_actorNum; const Common::String str = Common::String::format("FACE%d", v); if (Common::File::exists(Common::Path(str))) { Gfx::Pics pics(str, 262); executeScript(lind, pics); } else { executeScript(lind, _G(odin)); } if (!_G(thor)->_health) { _G(thor)->_show = 0; _G(exitFlag) = 2; } } } // namespace Got