/* ScummVM - Scumm Interpreter * Copyright (C) 2004 Ivan Dubrov * Copyright (C) 2004-2006 The ScummVM project * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ * */ #include "common/stdafx.h" #include "common/endian.h" #include "gob/gob.h" #include "gob/global.h" #include "gob/inter.h" #include "gob/util.h" #include "gob/scenery.h" #include "gob/parse.h" #include "gob/game.h" #include "gob/draw.h" #include "gob/mult.h" #include "gob/goblin.h" #include "gob/cdrom.h" #include "gob/map.h" namespace Gob { Inter::Inter(GobEngine *vm) : _vm(vm) { int i; _noBusyWait = false; _terminate = false; _breakFlag = false; for (i = 0; i < 8; i++) { _animPalLowIndex[i] = 0; _animPalHighIndex[i] = 0; _animPalDir[i] = 0; } _soundEndTimeKey = 0; _soundStopVal = 0; _breakFromLevel = 0; _nestLevel = 0; memset(_pasteBuf, 0, 300); memset(_pasteSizeBuf, 0, 300); _pastePos = 0; } int16 Inter::load16(void) { int16 tmp = (int16)READ_LE_UINT16(_vm->_global->_inter_execPtr); _vm->_global->_inter_execPtr += 2; return tmp; } char Inter::evalExpr(int16 *pRes) { byte token; // _vm->_parse->printExpr(99); _vm->_parse->parseExpr(99, &token); if (pRes == 0) return token; switch (token) { case 20: *pRes = _vm->_global->_inter_resVal; break; case 22: case 23: *pRes = 0; break; case 24: *pRes = 1; break; } return token; } char Inter::evalBoolResult() { byte token; _vm->_parse->printExpr(99); _vm->_parse->parseExpr(99, &token); if (token == 24 || (token == 20 && _vm->_global->_inter_resVal != 0)) return 1; else return 0; } void Inter::funcBlock(int16 retFlag) { char cmdCount; int16 counter; byte cmd; byte cmd2; if (_vm->_global->_inter_execPtr == 0) return; _breakFlag = false; _vm->_global->_inter_execPtr++; cmdCount = *_vm->_global->_inter_execPtr++; _vm->_global->_inter_execPtr += 2; if (cmdCount == 0) { _vm->_global->_inter_execPtr = 0; return; } int startaddr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; counter = 0; do { if (_terminate) break; // WORKAROUND: // The EGA version of gob1 doesn't add a delay after showing // images between levels. We manually add it here. if ((_vm->_features & GF_GOB1) && (_vm->_features & GF_EGA)) { int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || (startaddr == 0x1299 && addr == 0x139A && // Dungeon !strncmp(_vm->_game->_curTotFile, "avt006.tot", 10)) || (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) || (startaddr == 0x09F2 && addr == 0x0AF3 && // Statue !strncmp(_vm->_game->_curTotFile, "avt016.tot", 10)) || (startaddr == 0x0B92 && addr == 0x0C93 && // Castle !strncmp(_vm->_game->_curTotFile, "avt019.tot", 10)) || (startaddr == 0x17D9 && addr == 0x18DA && // Finale !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10))) { _vm->_util->longDelay(5000); } } // (end workaround) cmd = (byte)*_vm->_global->_inter_execPtr; if ((cmd >> 4) >= 12) { cmd2 = 16 - (cmd >> 4); cmd &= 0xf; } else cmd2 = 0; _vm->_global->_inter_execPtr++; counter++; if (cmd2 == 0) cmd >>= 4; if (executeFuncOpcode(cmd2, cmd, cmdCount, counter, retFlag)) return; if (_vm->_quitRequested) break; if (_breakFlag) { if (retFlag != 2) break; if (*_breakFromLevel == -1) _breakFlag = false; break; } } while (counter != cmdCount); _vm->_global->_inter_execPtr = 0; return; } void Inter::checkSwitchTable(char **ppExec) { int16 i; int16 len; char found; int32 value; char notFound; char defFlag; found = 0; notFound = 1; *ppExec = 0; value = _vm->_parse->parseVarIndex(); value = VAR_OFFSET(value); do { len = *(int8*)_vm->_global->_inter_execPtr++; // must be a signed char typ and char is not default signed on all platforms. if (len == -5) break; for (i = 0; i < len; i++) { evalExpr(0); if (_terminate) return; if (_vm->_global->_inter_resVal == value) { found = 1; notFound = 0; } } if (found != 0) *ppExec = _vm->_global->_inter_execPtr; _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; found = 0; } while (len != -5); if (len != -5) _vm->_global->_inter_execPtr++; defFlag = *_vm->_global->_inter_execPtr; defFlag >>= 4; if (defFlag != 4) return; _vm->_global->_inter_execPtr++; if (notFound) *ppExec = _vm->_global->_inter_execPtr; _vm->_global->_inter_execPtr += READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; } void Inter::callSub(int16 retFlag) { int16 block; while (!_vm->_quitRequested && _vm->_global->_inter_execPtr != 0 && (char *)_vm->_global->_inter_execPtr != _vm->_game->_totFileData) { block = *_vm->_global->_inter_execPtr; if (block == 1) { funcBlock(retFlag); } else if (block == 2) { _vm->_game->collisionsBlock(); } } if ((char *)_vm->_global->_inter_execPtr == _vm->_game->_totFileData) _terminate = true; } void Inter::initControlVars(char full) { int i; *_nestLevel = 0; *_breakFromLevel = -1; *_vm->_scenery->_pCaptureCounter = 0; _breakFlag = false; _terminate = false; if (full == 1) { for (i = 0; i < 8; i++) _animPalDir[i] = 0; _soundEndTimeKey = 0; } } void Inter::renewTimeInVars(void) { struct tm *t; time_t now = time(NULL); t = localtime(&now); WRITE_VAR(5, 1900 + t->tm_year); WRITE_VAR(6, t->tm_mon + 1); WRITE_VAR(7, 0); WRITE_VAR(8, t->tm_mday); WRITE_VAR(9, t->tm_hour); WRITE_VAR(10, t->tm_min); WRITE_VAR(11, t->tm_sec); } void Inter::manipulateMap(int16 xPos, int16 yPos, int16 item) { for (int16 y = 0; y < _vm->_map->_mapHeight; y++) { for (int16 x = 0; x < _vm->_map->_mapWidth; x++) { if ((_vm->_map->_itemsMap[y][x] & 0xff) == item) { _vm->_map->_itemsMap[y][x] &= 0xff00; } else if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8) == item) { _vm->_map->_itemsMap[y][x] &= 0xff; } } } if (xPos < _vm->_map->_mapWidth - 1) { if (yPos > 0) { if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 || (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) != 0 || (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff00) != 0 || (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xff00) != 0) { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) + item; _vm->_map->_itemsMap[yPos - 1][xPos] = (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) + item; _vm->_map->_itemsMap[yPos][xPos + 1] = (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff00) + item; _vm->_map->_itemsMap[yPos - 1][xPos + 1] = (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xff00) + item; } else { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff) + (item << 8); _vm->_map->_itemsMap[yPos - 1][xPos] = (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff) + (item << 8); _vm->_map->_itemsMap[yPos][xPos + 1] = (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff) + (item << 8); _vm->_map->_itemsMap[yPos - 1][xPos + 1] = (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xff) + (item << 8); } } else { if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 || (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff00) != 0) { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) + item; _vm->_map->_itemsMap[yPos][xPos + 1] = (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff00) + item; } else { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff) + (item << 8); _vm->_map->_itemsMap[yPos][xPos + 1] = (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xff) + (item << 8); } } } else { if (yPos > 0) { if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0 || (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) != 0) { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) + item; _vm->_map->_itemsMap[yPos - 1][xPos] = (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff00) + item; } else { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff) + (item << 8); _vm->_map->_itemsMap[yPos - 1][xPos] = (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xff) + (item << 8); } } else { if ((_vm->_map->_itemsMap[yPos][xPos] & 0xff00) != 0) { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff00) + item; } else { _vm->_map->_itemsMap[yPos][xPos] = (_vm->_map->_itemsMap[yPos][xPos] & 0xff) + (item << 8); } } } if (item < 0 || item >= 20) return; if (xPos > 1 && _vm->_map->getPass(xPos - 2, yPos) == 1) { _vm->_map->_itemPoses[item].x = xPos - 2; _vm->_map->_itemPoses[item].y = yPos; _vm->_map->_itemPoses[item].orient = 4; return; } if (xPos < _vm->_map->_mapWidth - 2 && _vm->_map->getPass(xPos + 2, yPos) == 1) { _vm->_map->_itemPoses[item].x = xPos + 2; _vm->_map->_itemPoses[item].y = yPos; _vm->_map->_itemPoses[item].orient = 0; return; } if (xPos < _vm->_map->_mapWidth - 1 && _vm->_map->getPass(xPos + 1, yPos) == 1) { _vm->_map->_itemPoses[item].x = xPos + 1; _vm->_map->_itemPoses[item].y = yPos; _vm->_map->_itemPoses[item].orient = 0; return; } if (xPos > 0 && _vm->_map->getPass(xPos - 1, yPos) == 1) { _vm->_map->_itemPoses[item].x = xPos - 1; _vm->_map->_itemPoses[item].y = yPos; _vm->_map->_itemPoses[item].orient = 4; return; } } } // End of namespace Gob