From e29ec6e79c325bcea2c95ecbfeb3a64c80a30630 Mon Sep 17 00:00:00 2001 From: Paweł Kołodziejski Date: Wed, 5 May 2004 07:25:32 +0000 Subject: adding initial code for Another World engine svn-id: r13783 --- awe/logic.cpp | 512 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 awe/logic.cpp (limited to 'awe/logic.cpp') diff --git a/awe/logic.cpp b/awe/logic.cpp new file mode 100644 index 0000000000..64733e67f3 --- /dev/null +++ b/awe/logic.cpp @@ -0,0 +1,512 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "stdafx.h" + +#include "awe.h" +#include "logic.h" +#include "resource.h" +#include "video.h" +#include "serializer.h" +#include "systemstub.h" + +namespace Awe { + +Logic::Logic(Resource *res, Video *vid, SystemStub *stub) + : _res(res), _vid(vid), _stub(stub) { +} + +void Logic::init() { + memset(_scriptVars, 0, sizeof(_scriptVars)); + _scriptVars[0x54] = 0x81; + _scriptVars[VAR_RANDOM_SEED] = time(0); + _fastMode = false; +} + +void Logic::op_movConst() { + uint8 i = _scriptPtr.fetchByte(); + int16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_movConst(0x%02X, %d)", i, n); + _scriptVars[i] = n; +} + +void Logic::op_mov() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_mov(0x%02X, 0x%02X)", i, j); + _scriptVars[i] = _scriptVars[j]; +} + +void Logic::op_add() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_add(0x%02X, 0x%02X)", i, j); + _scriptVars[i] += _scriptVars[j]; +} + +void Logic::op_addConst() { + uint8 i = _scriptPtr.fetchByte(); + int16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_addConst(0x%02X, %d)", i, n); + _scriptVars[i] += n; +} + +void Logic::op_call() { + uint16 off = _scriptPtr.fetchWord(); + uint8 sp = _stackPtr; + debug(DBG_LOGIC, "Logic::op_call(0x%X)", off); + _scriptStackCalls[sp] = _scriptPtr.pc - _res->_segCode; + ++_stackPtr; + _scriptPtr.pc = _res->_segCode + off; +} + +void Logic::op_ret() { + debug(DBG_LOGIC, "Logic::op_ret()"); + --_stackPtr; + uint8 sp = _stackPtr; + _scriptPtr.pc = _res->_segCode + _scriptStackCalls[sp]; +} + +void Logic::op_break() { + debug(DBG_LOGIC, "Logic::op_break()"); + _scriptHalted = true; +} + +void Logic::op_jmp() { + uint16 off = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_jmp(0x%02X)", off); + _scriptPtr.pc = _res->_segCode + off; +} + +void Logic::op_setScriptPos() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_setScriptPos(0x%X, 0x%X)", i, n); + _scriptPos[1][i] = n; +} + +void Logic::op_jnz() { + uint8 i = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_jnz(0x%02X)", i); + --_scriptVars[i]; + if (_scriptVars[i] != 0) { + op_jmp(); + } else { + _scriptPtr.fetchWord(); + } +} + +void Logic::op_condJmp() { +#ifdef BYPASS_PROTECTION + if (_res->_curPtrsId == 0x3E80 && _scriptPtr.pc == _res->_segCode + 0xCB9) { + // (0x0CB8) condJmp(0x80, VAR(41), VAR(30), 0xCD3) + *(_scriptPtr.pc + 0x00) = 0x81; + *(_scriptPtr.pc + 0x03) = 0x0D; + *(_scriptPtr.pc + 0x04) = 0x24; + // (0x0D4E) condJmp(0x4, VAR(50), 6, 0xDBC) + *(_scriptPtr.pc + 0x99) = 0x0D; + *(_scriptPtr.pc + 0x9A) = 0x5A; + ::warning("Logic::op_condJmp() bypassing protection"); + } +#endif + uint8 op = _scriptPtr.fetchByte(); + int16 b = _scriptVars[_scriptPtr.fetchByte()]; + int16 a = _scriptPtr.fetchByte(); + if (op & 0x80) { + a = _scriptVars[a]; + } else { + if (op & 0x40) { + a = (a << 8) | _scriptPtr.fetchByte(); + } + } + debug(DBG_LOGIC, "Logic::op_condJmp(%d, 0x%02X, 0x%02X)", op, b, a); + bool expr = false; + switch (op & 7) { + case 0: // jz + expr = (b == a); + break; + case 1: // jnz + expr = (b != a); + break; + case 2: // jg + expr = (b > a); + break; + case 3: // jge + expr = (b >= a); + break; + case 4: // jl + expr = (b < a); + break; + case 5: // jle + expr = (b <= a); + break; + default: + ::warning("Logic::op_condJmp() invalid condition %d", (op & 7)); + break; + } + if (expr) { + op_jmp(); + } else { + _scriptPtr.fetchWord(); + } +} + +void Logic::op_setPalette() { + uint16 i = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_changePalette(%d)", i); + _vid->_newPal = i >> 8; +} + +void Logic::op_resetScript() { + uint8 j = _scriptPtr.fetchByte(); + uint8 i = _scriptPtr.fetchByte(); + int8 n = (i & 0x3F) - j; + if (n < 0) { + ::warning("Logic::op_resetScript() ec=0x%X (n < 0)", 0x880); + return; + } + ++n; + uint8 _al = _scriptPtr.fetchByte(); + + debug(DBG_LOGIC, "Logic::op_resetScript(%d, %d, %d)", j, i, _al); + + if (_al == 2) { + uint16 *_si = &_scriptPos[1][j]; + while (n--) { + *_si = 0xFFFE; + ++_si; + } + } else if (_al < 2) { + uint8 *_si = &_scriptPaused[1][j]; + while (n--) { + *_si = _al; + ++_si; + } + } +} + +void Logic::op_selectPage() { + uint8 i = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_selectPage(%d)", i); + _vid->changePagePtr1(i); +} + +void Logic::op_fillPage() { + uint8 screen = _scriptPtr.fetchByte(); + uint8 color = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_fillPage(%d, %d)", screen, color); + _vid->fillPage(screen, color); +} + +void Logic::op_copyPage() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_copyPage(%d, %d)", i, j); + _vid->copyPage(i, j, _scriptVars[VAR_SCROLL_Y]); +} + +void Logic::op_updateDisplay() { + uint8 page = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_updateDisplay(%d)", page); + inp_handleSpecialKeys(); + if (_res->_curPtrsId == 0x3E80 && _scriptVars[0x67] == 1) { + _scriptVar_0xBF = _scriptVars[0xBF]; + _scriptVars[0xDC] = 0x21; + } + + static uint32 tstamp = 0; + if (!_fastMode) { + // XXX experimental + int32 delay = _stub->getTimeStamp() - tstamp; + int32 pause = _scriptVars[VAR_PAUSE_SLICES] * 20 - delay; + if (pause > 0) { + _stub->sleep(pause); + } + } + _scriptVars[0xF7] = 0; + + _vid->updateDisplay(page); + tstamp = _stub->getTimeStamp(); +} + +void Logic::op_halt() { + debug(DBG_LOGIC, "Logic::op_halt()"); + _scriptPtr.pc = _res->_segCode + 0xFFFF; + _scriptHalted = true; +} + +void Logic::op_drawString() { + uint16 strId = _scriptPtr.fetchWord(); + uint16 x = _scriptPtr.fetchByte(); + uint16 y = _scriptPtr.fetchByte(); + uint16 col = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_drawString(0x%03X, %d, %d, %d)", strId, x, y, col); + _vid->drawString(col, x, y, strId); +} + +void Logic::op_sub() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_sub(0x%02X, 0x%02X)", i, j); + _scriptVars[i] -= _scriptVars[j]; +} + +void Logic::op_and() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_and(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] & n; +} + +void Logic::op_or() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_or(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] | n; +} + +void Logic::op_shl() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_shl(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] << n; +} + +void Logic::op_shr() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_shr(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] >> n; +} + +void Logic::op_soundUnk1() { + uint16 b = _scriptPtr.fetchWord(); + uint16 c = _scriptPtr.fetchWord(); + uint8 a = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_soundUnk1(0x%X, 0x%X, %d)", b, c, a); + // XXX +} + +void Logic::op_updateMemList() { + uint16 num = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_updateMemList(%d)", num); + _res->update(num); +} + +void Logic::op_soundUnk2() { + uint16 b = _scriptPtr.fetchWord(); + uint16 c = _scriptPtr.fetchWord(); + uint8 a = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_soundUnk2(0x%X, 0x%X, %d)", b, c, a); + // XXX +} + +void Logic::restartAt(uint16 ptrId) { + // XXX + _scriptVars[0xE4] = 0x14; + _res->setupPtrs(ptrId); + memset((uint8 *)_scriptPos, 0xFF, sizeof(_scriptPos)); + memset((uint8 *)_scriptPaused, 0, sizeof(_scriptPaused)); + _scriptPos[0][0] = 0; +} + +void Logic::setupScripts() { + if (_res->_newPtrsId != 0) { + restartAt(_res->_newPtrsId); + _res->_newPtrsId = 0; + } + for (int i = 0; i < 0x40; ++i) { + _scriptPaused[0][i] = _scriptPaused[1][i]; + uint16 n = _scriptPos[1][i]; + if (n != 0xFFFF) { + _scriptPos[0][i] = (n == 0xFFFE) ? 0xFFFF : n; + _scriptPos[1][i] = 0xFFFF; + } + } +} + +void Logic::runScripts() { + for (int i = 0; i < 0x40; ++i) { + if (_scriptPaused[0][i] == 0) { + uint16 n = _scriptPos[0][i]; + if (n != 0xFFFF) { + _scriptPtr.pc = _res->_segCode + n; + _stackPtr = 0; + _scriptHalted = false; + debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X n=0x%02X *p=0x%02X", i, n, *_scriptPtr.pc); + executeScript(); + _scriptPos[0][i] = _scriptPtr.pc - _res->_segCode; + debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X pos=0x%X", i, _scriptPos[0][i]); + if (_stub->_pi.quit) { + break; + } + } + } + } +} + +void Logic::executeScript() { + while (!_scriptHalted) { + uint8 opcode = _scriptPtr.fetchByte(); + if (opcode & 0x80) { + uint16 off = ((opcode << 8) | _scriptPtr.fetchByte()) * 2; + _res->_useSegVideo2 = false; + int16 x = _scriptPtr.fetchByte(); + int16 y = _scriptPtr.fetchByte(); + int16 h = y - 199; + if (h > 0) { + y = 199; + x += h; + } + debug(DBG_VIDEO, "vid_opcd_0x80 : opcode=0x%X off=0x%X x=%d y=%d", opcode, off, x, y); + _vid->setDataBuffer(_res->_segVideo1, off); + _vid->drawShape(0xFF, 0x40, Point(x,y)); + } else if (opcode & 0x40) { + int16 x, y; + uint16 off = _scriptPtr.fetchWord() * 2; + x = _scriptPtr.fetchByte(); + _res->_useSegVideo2 = false; + if (!(opcode & 0x20)) { + if (!(opcode & 0x10)) { + x = (x << 8) | _scriptPtr.fetchByte(); + } else { + x = _scriptVars[x]; + } + } else { + if (opcode & 0x10) { + x += 0x100; + } + } + y = _scriptPtr.fetchByte(); + if (!(opcode & 8)) { + if (!(opcode & 4)) { + y = (y << 8) | _scriptPtr.fetchByte(); + } else { + y = _scriptVars[y]; + } + } + uint16 zoom = _scriptPtr.fetchByte(); + if (!(opcode & 2)) { + if (!(opcode & 1)) { + --_scriptPtr.pc; + zoom = 0x40; + } else { + zoom = _scriptVars[zoom]; + } + } else { + if (opcode & 1) { + _res->_useSegVideo2 = true; + --_scriptPtr.pc; + zoom = 0x40; + } + } + debug(DBG_VIDEO, "vid_opcd_0x40 : off=0x%X x=%d y=%d", off, x, y); + _vid->setDataBuffer(_res->_useSegVideo2 ? _res->_segVideo2 : _res->_segVideo1, off); + _vid->drawShape(0xFF, zoom, Point(x, y)); + } else { + if (opcode > 0x1A) { + ::error("Logic::executeScript() ec=0x%X invalid opcode=0x%X", 0xFFF, opcode); + } else { + (this->*_opTable[opcode])(); + } + } + } +} + +void Logic::inp_updatePlayer() { + _stub->processEvents(); + if (_res->_curPtrsId == 0x3E89) { + char c = _stub->_pi.lastChar; + if (c == 8 || /*c == 0xD ||*/ c == 0 || (c >= 'a' && c <= 'z')) { + _scriptVars[VAR_LAST_KEYCHAR] = c & ~0x20; + _stub->_pi.lastChar = 0; + } + } + int16 lr = 0; + int16 m = 0; + int16 ud = 0; + if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) { + lr = 1; + m |= 1; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) { + lr = -1; + m |= 2; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + ud = 1; + m |= 4; + } + _scriptVars[VAR_HERO_POS_UP_DOWN] = ud; + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _scriptVars[VAR_HERO_POS_UP_DOWN] = -1; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { // inpJump + ud = -1; + m |= 8; + } + _scriptVars[VAR_HERO_POS_JUMP_DOWN] = ud; + _scriptVars[VAR_HERO_POS_LEFT_RIGHT] = lr; + _scriptVars[VAR_HERO_POS_MASK] = m; + int16 button = 0; + if (_stub->_pi.button) { // inpButton + button = 1; + m |= 0x80; + } + _scriptVars[VAR_HERO_ACTION] = button; + _scriptVars[VAR_HERO_ACTION_POS_MASK] = m; +} + +void Logic::inp_handleSpecialKeys() { + if (_stub->_pi.pause) { + if (_res->_curPtrsId != 0x3E80 && _res->_curPtrsId != 0x3E81) { + _stub->_pi.pause = false; + while (!_stub->_pi.pause) { + _stub->processEvents(); + _stub->sleep(200); + } + } + _stub->_pi.pause = false; + } + if (_stub->_pi.code) { + _stub->_pi.code = false; + if (_res->_curPtrsId != 0x3E89 && _res->_curPtrsId != 0x3E80) { + _res->_newPtrsId = 0x3E89; + } + } + // XXX + if (_scriptVars[0xC9] == 1) { + ::warning("Logic::inp_handleSpecialKeys() unhandled case (_scriptVars[0xC9] == 1)"); + } +} + +void Logic::saveOrLoad(Serializer &ser) { + Serializer::Entry entries[] = { + SE_ARRAY(_scriptVars, 0x100, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptStackCalls, 0x100, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptPos, 0x40 * 2, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptPaused, 0x40 * 2, Serializer::SES_INT8, VER(1)), + SE_END() + }; + ser.saveOrLoadEntries(entries); +} + +} -- cgit v1.2.3