Initial commit
This commit is contained in:
3
engines/trecision/POTFILES
Normal file
3
engines/trecision/POTFILES
Normal file
@@ -0,0 +1,3 @@
|
||||
engines/trecision/detection.cpp
|
||||
engines/trecision/metaengine.cpp
|
||||
engines/trecision/saveload.cpp
|
||||
481
engines/trecision/actor.cpp
Normal file
481
engines/trecision/actor.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/trecision.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
Actor::Actor(TrecisionEngine *vm) : _vm(vm) {
|
||||
_vertex = nullptr;
|
||||
_face = nullptr;
|
||||
_light = nullptr;
|
||||
_camera = nullptr;
|
||||
_textures = nullptr;
|
||||
_textureData = nullptr;
|
||||
|
||||
_vertexNum = 0;
|
||||
_faceNum = 0;
|
||||
_lightNum = 0;
|
||||
|
||||
_px = _pz = 0.0f;
|
||||
_dx = _dz = 0.0f;
|
||||
_theta = 0.0f;
|
||||
|
||||
for (uint8 i = 0; i < 6; ++i)
|
||||
_area[i] = 0;
|
||||
|
||||
_curFrame = 0;
|
||||
_curAction = 0;
|
||||
|
||||
for (uint16 i = 0; i < MAXFACE; ++i) {
|
||||
for (uint8 j = 0; j < 3; ++j) {
|
||||
_textureCoord[i][j][0] = 0;
|
||||
_textureCoord[i][j][1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_characterArea = nullptr;
|
||||
_textureData = _vm->readData("textur.bm");
|
||||
|
||||
initTextures();
|
||||
readModel("jm.om");
|
||||
|
||||
for (int i = 0; i < MAXLIGHT; ++i)
|
||||
_lightArea[i].clear();
|
||||
|
||||
_cameraArea.clear();
|
||||
|
||||
_light = (SLight *)&_lightArea;
|
||||
_camera = (SCamera *)&_cameraArea;
|
||||
}
|
||||
|
||||
Actor::~Actor() {
|
||||
delete[] _characterArea;
|
||||
delete[] _face;
|
||||
delete[] _textureData;
|
||||
}
|
||||
|
||||
void Actor::initTextures() {
|
||||
for (int i = 0; i < MAXMAT; ++i)
|
||||
_textureArea[i].clear();
|
||||
|
||||
// head
|
||||
_textureArea[0].set(300 / 2, 208 / 2, _textureData);
|
||||
|
||||
// body
|
||||
_textureArea[1].set(300, 300, _textureData + (300 * 208 / 4));
|
||||
|
||||
// arms
|
||||
_textureArea[2].set(300, 150, _textureData + (300 * 208 / 4) + (300 * 300));
|
||||
|
||||
_textures = (STexture *)&_textureArea[0];
|
||||
}
|
||||
|
||||
void Actor::updateStepSound() {
|
||||
_vm->_soundMgr->soundStep((_area[1] + _area[0]) / 2, (_area[5] + _area[4]) / 2, _curAction, _curFrame);
|
||||
}
|
||||
|
||||
static const float _vertsCorr[104][3] = {
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000001f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, -0.061717f, 0.833191f}, {0.000000f, -0.120163f, 0.330445f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, -0.432022f, 0.216004f}, {0.000000f, -0.030041f, 0.360489f},
|
||||
{0.310895f, 0.000000f, 0.000000f}, {0.312943f, 0.000000f, 0.000000f},
|
||||
{0.114858f, 0.000000f, 0.000000f}, {0.000000f, 1.051431f, 0.300415f},
|
||||
{0.000000f, 0.000000f, 0.246856f}, {0.000000f, 0.120163f, 0.480652f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.180247f, 0.600815f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.530074f, 0.041892f, 0.670273f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.060081f, 0.540726f}, {0.000000f, -0.318127f, -0.249817f},
|
||||
{0.000000f, 0.180244f, 0.540741f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, -0.922172f, 0.201188f}, {0.000000f, -0.442684f, -0.328400f},
|
||||
{0.353384f, 1.047291f, -1.005401f}, {0.000000f, -0.646931f, -0.933030f},
|
||||
{0.000000f, 2.283107f, -0.420562f}, {0.412281f, -1.633775f, -1.193909f},
|
||||
{0.312389f, 0.000000f, 0.000000f}, {0.000000f, 0.020947f, -0.083786f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, -1.021390f, -1.141556f},
|
||||
{0.000000f, 0.020946f, -0.146637f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.020946f, -0.146637f}, {0.000000f, 0.020947f, -0.146637f},
|
||||
{0.000000f, 0.020946f, -0.083786f}, {0.000000f, 0.020946f, -0.125687f},
|
||||
{0.000000f, 0.020947f, -0.146637f}, {0.000000f, 0.020947f, -0.125687f},
|
||||
{0.000000f, 0.020946f, -0.083786f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.020947f, -0.125687f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.020947f, -0.125686f}, {0.000000f, 0.020946f, -0.125687f},
|
||||
{0.000000f, 0.020946f, -0.083786f}, {0.000000f, 0.020946f, -0.146637f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, -0.061717f, 0.833191f}, {0.000000f, -0.090122f, 0.330460f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, -0.432022f, 0.185150f},
|
||||
{-0.310895f, 0.000000f, 0.000000f}, {-0.312943f, 0.000001f, 0.000000f},
|
||||
{-0.114858f, 0.000000f, 0.000000f}, {0.000000f, 1.051431f, 0.270371f},
|
||||
{0.000000f, -0.030858f, 0.246856f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{-0.647869f, 0.041892f, 0.628372f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, -0.442684f, -0.328400f}, {-0.294485f, 1.026345f, -1.005401f},
|
||||
{-0.353383f, -1.633775f, -1.214859f}, {-0.312389f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.020947f, -0.146637f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.020946f, -0.146637f},
|
||||
{0.000000f, 0.020946f, -0.083786f}, {0.000000f, 0.020947f, -0.146637f},
|
||||
{0.000000f, 0.020947f, -0.125687f}, {0.000000f, 0.020947f, -0.083786f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.020947f, -0.125687f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.020946f, -0.125687f},
|
||||
{0.000000f, 0.020946f, -0.146637f}, {0.000000f, 0.000000f, 0.000000f},
|
||||
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f}};
|
||||
|
||||
static const int _vertsCorrList[84] = {
|
||||
289, 290, 293, 294, 295, 296, 297, 298,
|
||||
299, 300, 300, 302, 303, 304, 305, 305,
|
||||
307, 307, 309, 310, 311, 312, 313, 314,
|
||||
315, 316, 317, 318, 319, 320, 321, 322,
|
||||
323, 324, 325, 326, 327, 328, 329, 330,
|
||||
331, 332, 333, 334, 335, 336, 337, 338,
|
||||
339, 340, 341, 349, 350, 352, 353, 354,
|
||||
355, 356, 357, 358, 359, 360, 361, 362,
|
||||
363, 364, 365, 366, 367, 368, 369, 370,
|
||||
371, 372, 373, 374, 375, 376, 377, 378,
|
||||
379, 380, 381, 382};
|
||||
|
||||
/**********************************************
|
||||
Microprose head correction
|
||||
**********************************************/
|
||||
void Actor::microproseHeadFix(uint32 actionNum) {
|
||||
static const uint16 idx1 = 306;
|
||||
static const uint16 idx2 = 348;
|
||||
static const uint16 idx3 = 288;
|
||||
|
||||
double v1[3], v2[3], v[3], q[3], m1[3][3], m2[3][3];
|
||||
|
||||
v1[0] = _vertex[idx2]._x - _vertex[idx1]._x;
|
||||
v1[1] = _vertex[idx2]._y - _vertex[idx1]._y;
|
||||
v1[2] = _vertex[idx2]._z - _vertex[idx1]._z;
|
||||
double s = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
|
||||
v1[0] /= s;
|
||||
v1[1] /= s;
|
||||
v1[2] /= s;
|
||||
|
||||
v2[0] = _vertex[idx3]._x - _vertex[idx1]._x;
|
||||
v2[1] = _vertex[idx3]._y - _vertex[idx1]._y;
|
||||
v2[2] = _vertex[idx3]._z - _vertex[idx1]._z;
|
||||
s = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
|
||||
v2[0] /= s;
|
||||
v2[1] /= s;
|
||||
v2[2] /= s;
|
||||
|
||||
m1[1][0] = v2[1] * v1[2] - v1[1] * v2[2];
|
||||
m1[1][1] = v2[2] * v1[0] - v1[2] * v2[0];
|
||||
m1[1][2] = v2[0] * v1[1] - v1[0] * v2[1];
|
||||
s = sqrt(m1[1][0] * m1[1][0] + m1[1][1] * m1[1][1] + m1[1][2] * m1[1][2]);
|
||||
m1[1][0] /= s;
|
||||
m1[1][1] /= s;
|
||||
m1[1][2] /= s;
|
||||
|
||||
m1[2][0] = m1[1][1] * v1[2] - v1[1] * m1[1][2];
|
||||
m1[2][1] = m1[1][2] * v1[0] - v1[2] * m1[1][0];
|
||||
m1[2][2] = m1[1][0] * v1[1] - v1[0] * m1[1][1];
|
||||
s = sqrt(m1[2][0] * m1[2][0] + m1[2][1] * m1[2][1] + m1[2][2] * m1[2][2]);
|
||||
m1[2][0] /= s;
|
||||
m1[2][1] /= s;
|
||||
m1[2][2] /= s;
|
||||
|
||||
m1[0][0] = v1[0];
|
||||
m1[0][1] = v1[1];
|
||||
m1[0][2] = v1[2];
|
||||
|
||||
for (uint i = 0; i < actionNum; ++i) {
|
||||
SVertex *sv = &_vertex[i * _vertexNum];
|
||||
|
||||
v1[0] = sv[idx2]._x - sv[idx1]._x;
|
||||
v1[1] = sv[idx2]._y - sv[idx1]._y;
|
||||
v1[2] = sv[idx2]._z - sv[idx1]._z;
|
||||
s = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
|
||||
v1[0] /= s;
|
||||
v1[1] /= s;
|
||||
v1[2] /= s;
|
||||
|
||||
v2[0] = sv[idx3]._x - sv[idx1]._x;
|
||||
v2[1] = sv[idx3]._y - sv[idx1]._y;
|
||||
v2[2] = sv[idx3]._z - sv[idx1]._z;
|
||||
s = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
|
||||
v2[0] /= s;
|
||||
v2[1] /= s;
|
||||
v2[2] /= s;
|
||||
|
||||
m2[1][0] = v2[1] * v1[2] - v1[1] * v2[2];
|
||||
m2[1][1] = v2[2] * v1[0] - v1[2] * v2[0];
|
||||
m2[1][2] = v2[0] * v1[1] - v1[0] * v2[1];
|
||||
s = sqrt(m2[1][0] * m2[1][0] + m2[1][1] * m2[1][1] + m2[1][2] * m2[1][2]);
|
||||
m2[1][0] /= s;
|
||||
m2[1][1] /= s;
|
||||
m2[1][2] /= s;
|
||||
|
||||
m2[2][0] = m2[1][1] * v1[2] - v1[1] * m2[1][2];
|
||||
m2[2][1] = m2[1][2] * v1[0] - v1[2] * m2[1][0];
|
||||
m2[2][2] = m2[1][0] * v1[1] - v1[0] * m2[1][1];
|
||||
s = sqrt(m2[2][0] * m2[2][0] + m2[2][1] * m2[2][1] + m2[2][2] * m2[2][2]);
|
||||
m2[2][0] /= s;
|
||||
m2[2][1] /= s;
|
||||
m2[2][2] /= s;
|
||||
|
||||
m2[0][0] = v1[0];
|
||||
m2[0][1] = v1[1];
|
||||
m2[0][2] = v1[2];
|
||||
|
||||
v2[0] = sv[idx1]._x;
|
||||
v2[1] = sv[idx1]._y;
|
||||
v2[2] = sv[idx1]._z;
|
||||
|
||||
v1[0] = _vertex[idx1]._x;
|
||||
v1[1] = _vertex[idx1]._y;
|
||||
v1[2] = _vertex[idx1]._z;
|
||||
|
||||
for (int j = 279; j < 383; ++j) {
|
||||
int f;
|
||||
for (f = 0; f < 84; ++f) {
|
||||
if (_vertsCorrList[f] == j)
|
||||
break;
|
||||
}
|
||||
if (f == 84)
|
||||
continue;
|
||||
|
||||
v[0] = _vertsCorr[j - 279][0];
|
||||
v[1] = _vertsCorr[j - 279][2];
|
||||
v[2] = _vertsCorr[j - 279][1];
|
||||
|
||||
q[0] = 0.0;
|
||||
q[1] = 0.0;
|
||||
q[2] = 0.0;
|
||||
for (int d = 0; d < 3; ++d) {
|
||||
for (int c = 0; c < 3; ++c)
|
||||
q[c] += m1[c][d] * v[d];
|
||||
}
|
||||
v[0] = 0.0;
|
||||
v[1] = 0.0;
|
||||
v[2] = 0.0;
|
||||
for (int d = 0; d < 3; ++d) {
|
||||
for (int c = 0; c < 3; ++c)
|
||||
v[c] += m2[d][c] * q[d];
|
||||
}
|
||||
|
||||
if (i < 42) {
|
||||
sv[j]._x += _vertsCorr[j - 279][0];
|
||||
sv[j]._y += _vertsCorr[j - 279][2];
|
||||
sv[j]._z += _vertsCorr[j - 279][1];
|
||||
} else {
|
||||
sv[j]._x += v[0];
|
||||
sv[j]._y += v[1];
|
||||
sv[j]._z += v[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::readModel(const char *filename) {
|
||||
Common::SeekableReadStreamEndian *ff = _vm->readEndian(_vm->_dataFile.createReadStreamForMember(filename));
|
||||
if (ff == nullptr)
|
||||
error("readModel - Error opening file %s", filename);
|
||||
|
||||
uint32 actionNum = ff->readUint32();
|
||||
_vertexNum = ff->readUint32();
|
||||
|
||||
_characterArea = new SVertex[_vertexNum * actionNum];
|
||||
for (uint i = 0; i < _vertexNum * actionNum; ++i) {
|
||||
_characterArea[i]._x = ff->readFloat();
|
||||
_characterArea[i]._y = ff->readFloat();
|
||||
_characterArea[i]._z = ff->readFloat();
|
||||
_characterArea[i]._nx = ff->readFloat();
|
||||
_characterArea[i]._ny = ff->readFloat();
|
||||
_characterArea[i]._nz = ff->readFloat();
|
||||
}
|
||||
_vertex = _characterArea;
|
||||
_faceNum = ff->readUint32();
|
||||
delete ff;
|
||||
|
||||
ff = _vm->readEndian(_vm->_dataFile.createReadStreamForMember("mat.tex"));
|
||||
if (ff == nullptr)
|
||||
error("readModel - Error opening file mat.tex");
|
||||
|
||||
_vm->_graphicsMgr->readTexture(ff);
|
||||
|
||||
for (uint16 i = 0; i < MAXFACE; ++i) {
|
||||
for (uint16 j = 0; j < 3; ++j) {
|
||||
_textureCoord[i][j][0] = ff->readSint16();
|
||||
_textureCoord[i][j][1] = ff->readSint16();
|
||||
}
|
||||
}
|
||||
|
||||
_face = new SFace[_faceNum];
|
||||
for (uint i = 0; i < _faceNum; ++i) {
|
||||
_face[i]._a = ff->readUint16();
|
||||
_face[i]._b = ff->readUint16();
|
||||
_face[i]._c = ff->readUint16();
|
||||
_face[i]._mat = ff->readUint16();
|
||||
}
|
||||
|
||||
delete ff;
|
||||
|
||||
_curFrame = 0;
|
||||
_curAction = hSTAND;
|
||||
|
||||
microproseHeadFix(actionNum);
|
||||
}
|
||||
|
||||
void Actor::syncGameStream(Common::Serializer &ser) {
|
||||
float unused = 0;
|
||||
|
||||
ser.syncAsFloatLE(_px);
|
||||
ser.syncAsFloatLE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX);
|
||||
ser.syncAsFloatLE(_pz);
|
||||
ser.syncAsFloatLE(_dx);
|
||||
ser.syncAsFloatLE(_dz);
|
||||
ser.syncAsFloatLE(_theta);
|
||||
}
|
||||
|
||||
void Actor::actorDoAction(int action) {
|
||||
if (action > hLAST)
|
||||
error("error in actorDoAction, invalid action (should be called as an animation)");
|
||||
|
||||
_vm->_pathFind->_curStep = 1;
|
||||
float px = _px + _dx;
|
||||
float pz = _pz + _dz;
|
||||
float theta = _theta;
|
||||
|
||||
_vm->_pathFind->reset(0, px, pz, theta);
|
||||
|
||||
float t = ((270.0f - theta) * M_PI * 2) / 360.0f;
|
||||
float ox = cos(t);
|
||||
float oz = sin(t);
|
||||
|
||||
SVertex *v = _characterArea;
|
||||
float firstFrame = frameCenter(v);
|
||||
|
||||
int cfp = 0;
|
||||
int cur = 0;
|
||||
|
||||
while (cur < action)
|
||||
cfp += defActionLen[cur++];
|
||||
v = &_characterArea[cfp * _vertexNum];
|
||||
|
||||
if (action == hWALKOUT)
|
||||
v = &_characterArea[_vertexNum];
|
||||
else if (action == hLAST)
|
||||
v = _characterArea;
|
||||
|
||||
int len = defActionLen[action];
|
||||
|
||||
int stepIdx;
|
||||
for (stepIdx = _vm->_pathFind->_curStep; stepIdx < len + _vm->_pathFind->_curStep; ++stepIdx) {
|
||||
float curLen = frameCenter(v) - firstFrame;
|
||||
|
||||
SStep *curStep = &_vm->_pathFind->_step[stepIdx];
|
||||
curStep->_dx = curLen * ox;
|
||||
curStep->_dz = curLen * oz;
|
||||
curStep->_px = px;
|
||||
curStep->_pz = pz;
|
||||
curStep->_curAction = action;
|
||||
curStep->_curFrame = stepIdx - _vm->_pathFind->_curStep;
|
||||
curStep->_theta = theta;
|
||||
curStep->_curPanel = _vm->_pathFind->_curPanel;
|
||||
|
||||
v += _vertexNum;
|
||||
|
||||
if (action == hLAST)
|
||||
v = _characterArea;
|
||||
}
|
||||
|
||||
_vm->_pathFind->reset(stepIdx, px, pz, theta);
|
||||
|
||||
_vm->_pathFind->_lastStep = stepIdx; // Last step
|
||||
|
||||
// Starts action
|
||||
if (_vm->_obj[_vm->_curObj].isFlagRoomOut())
|
||||
_vm->_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERGOTOEXIT, MP_DEFAULT, _vm->_obj[_vm->_curObj]._goRoom, 0, _vm->_obj[_vm->_curObj]._ninv, _vm->_curObj);
|
||||
else
|
||||
_vm->_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERDOACTION, MP_DEFAULT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Actor::actorStop() {
|
||||
_vm->_pathFind->reset(0, _px + _dx, _pz + _dz, _theta);
|
||||
_vm->_pathFind->_characterGoToPosition = -1;
|
||||
_vm->_pathFind->_curStep = 0;
|
||||
_vm->_pathFind->_lastStep = 0;
|
||||
}
|
||||
|
||||
void Actor::read3D(Common::SeekableReadStreamEndian *ff) {
|
||||
// read rooms and lights
|
||||
SCamera *cam = _camera;
|
||||
cam->_ex = ff->readFloat();
|
||||
cam->_ey = ff->readFloat();
|
||||
cam->_ez = ff->readFloat();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
cam->_e1[i] = ff->readFloat();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
cam->_e2[i] = ff->readFloat();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
cam->_e3[i] = ff->readFloat();
|
||||
cam->_fovX = ff->readFloat();
|
||||
cam->_fovY = ff->readFloat();
|
||||
|
||||
_lightNum = ff->readUint32();
|
||||
if (_lightNum > MAXLIGHT)
|
||||
error("read3D(): Too many lights");
|
||||
|
||||
for (uint32 i = 0; i < _lightNum; ++i) {
|
||||
_light[i]._x = ff->readFloat();
|
||||
_light[i]._y = ff->readFloat();
|
||||
_light[i]._z = ff->readFloat();
|
||||
_light[i]._dx = ff->readFloat();
|
||||
_light[i]._dy = ff->readFloat();
|
||||
_light[i]._dz = ff->readFloat();
|
||||
_light[i]._inr = ff->readFloat();
|
||||
_light[i]._outr = ff->readFloat();
|
||||
_light[i]._hotspot = ff->readByte();
|
||||
_light[i]._fallOff = ff->readByte();
|
||||
_light[i]._inten = ff->readSByte();
|
||||
_light[i]._position = ff->readSByte();
|
||||
}
|
||||
}
|
||||
|
||||
float Actor::frameCenter(SVertex *v) {
|
||||
return (-v[86]._z - v[164]._z) / 2.0;
|
||||
}
|
||||
|
||||
bool Actor::actorRectIsValid() const {
|
||||
return _area[0] < _area[1] && _area[2] < _area[3];
|
||||
}
|
||||
|
||||
Common::Rect Actor::getActorRect() const {
|
||||
return Common::Rect(_area[0], _area[2], _area[1], _area[3]);
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
86
engines/trecision/actor.h
Normal file
86
engines/trecision/actor.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_ACTOR_H
|
||||
#define TRECISION_ACTOR_H
|
||||
|
||||
#include "trecision/struct.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
#define MAXLIGHT 40
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class Actor {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
SLight _lightArea[MAXLIGHT];
|
||||
SCamera _cameraArea;
|
||||
uint8 *_textureData;
|
||||
STexture _textureArea[MAXMAT];
|
||||
|
||||
void initTextures();
|
||||
void readModel(const char *filename);
|
||||
void microproseHeadFix(uint32 actionNum);
|
||||
|
||||
public:
|
||||
Actor(TrecisionEngine *vm);
|
||||
~Actor();
|
||||
|
||||
SVertex *_characterArea;
|
||||
SVertex *_vertex;
|
||||
|
||||
SFace *_face;
|
||||
SLight *_light;
|
||||
SCamera *_camera;
|
||||
STexture *_textures;
|
||||
|
||||
int16 _textureCoord[MAXFACE][3][2];
|
||||
|
||||
uint32 _vertexNum;
|
||||
uint32 _faceNum;
|
||||
uint32 _lightNum;
|
||||
|
||||
float _px, _pz;
|
||||
float _dx, _dz;
|
||||
float _theta;
|
||||
|
||||
int _area[6];
|
||||
|
||||
int _curFrame;
|
||||
int _curAction;
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void actorDoAction(int action);
|
||||
void actorStop();
|
||||
void read3D(Common::SeekableReadStreamEndian *ff);
|
||||
float frameCenter(SVertex *v);
|
||||
void updateStepSound();
|
||||
bool actorRectIsValid() const;
|
||||
Common::Rect getActorRect() const;
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
578
engines/trecision/animmanager.cpp
Normal file
578
engines/trecision/animmanager.cpp
Normal file
@@ -0,0 +1,578 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
AnimManager::AnimManager(TrecisionEngine *vm) : _vm(vm) {
|
||||
for (int i = 0; i < MAXACTIVEANIM; ++i) {
|
||||
_animations[i] = nullptr;
|
||||
_playingAnims[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXANIM; ++i) {
|
||||
_animTab[i]._flag = 0;
|
||||
_animTab[i]._name[0] = '\0';
|
||||
}
|
||||
|
||||
_curCD = 1;
|
||||
swapCD(_curCD);
|
||||
|
||||
_bgAnimRestarted = false;
|
||||
}
|
||||
|
||||
AnimManager::~AnimManager() {
|
||||
for (int i = 0; i < MAXACTIVEANIM; ++i) {
|
||||
delete _animations[i];
|
||||
_animations[i] = nullptr;
|
||||
_animFile[i].close();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::playMovie(const Common::Path &filename, int startFrame, int endFrame, bool singleChoice) {
|
||||
NightlongVideoDecoder *videoDecoder;
|
||||
|
||||
if (!_vm->isAmiga())
|
||||
videoDecoder = new NightlongSmackerDecoder();
|
||||
else
|
||||
videoDecoder = new NightlongAmigaDecoder();
|
||||
|
||||
if (!videoDecoder->loadFile(filename)) {
|
||||
warning("playMovie: File %s not found", filename.toString().c_str());
|
||||
delete videoDecoder;
|
||||
_vm->_dialogMgr->afterChoice();
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Event event;
|
||||
bool skipVideo = false;
|
||||
uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
|
||||
uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
|
||||
_vm->_drawText._text.clear();
|
||||
|
||||
videoDecoder->start();
|
||||
|
||||
// WORKAROUND: If the video has a single choice, and it starts from
|
||||
// the beginning, ignore the calculated end frame and play all of it
|
||||
if (singleChoice && startFrame < 10 && endFrame < (int)videoDecoder->getFrameCount() - 1)
|
||||
endFrame = videoDecoder->getFrameCount() - 1;
|
||||
|
||||
setVideoRange(videoDecoder, startFrame, endFrame);
|
||||
|
||||
while (!_vm->shouldQuit() && startFrame != endFrame && !videoDecoder->endOfVideo() && !skipVideo) {
|
||||
if (videoDecoder->needsUpdate()) {
|
||||
drawFrame(videoDecoder, x, y, true);
|
||||
}
|
||||
|
||||
while (_vm->getEventManager()->pollEvent(event)) {
|
||||
if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END && event.customType == kActionSkipVideo)
|
||||
skipVideo = true;
|
||||
}
|
||||
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
delete videoDecoder;
|
||||
|
||||
_vm->_mouseLeftBtn = _vm->_mouseRightBtn = false;
|
||||
_vm->freeKey();
|
||||
_vm->_dialogMgr->afterChoice();
|
||||
}
|
||||
|
||||
void AnimManager::setVideoRange(NightlongVideoDecoder *smkDecoder, int &startFrame, int &endFrame) {
|
||||
// Trecision starts at 1 but ScummVM starts at 0
|
||||
startFrame = CLIP<int32>(startFrame - 1, 0, smkDecoder->getFrameCount() - 1);
|
||||
endFrame = CLIP<int32>(endFrame - 1, 0, smkDecoder->getFrameCount() - 1);
|
||||
|
||||
// If choices are attached
|
||||
if (startFrame > 0 && startFrame > smkDecoder->getCurFrame()) {
|
||||
smkDecoder->forceSeekToFrame(startFrame - 1);
|
||||
}
|
||||
smkDecoder->setEndFrame(endFrame);
|
||||
}
|
||||
|
||||
void AnimManager::drawFrame(NightlongVideoDecoder *smkDecoder, uint16 x, uint16 y, bool updateScreen) {
|
||||
const Graphics::Surface *frame = smkDecoder->decodeNextFrame();
|
||||
if (frame) {
|
||||
Graphics::Surface *frame16 = frame->convertTo(g_system->getScreenFormat(), smkDecoder->getPalette());
|
||||
drawFrameSubtitles(frame16, smkDecoder->getCurFrame());
|
||||
g_system->copyRectToScreen(frame16->getPixels(), frame16->pitch, x, y, frame16->w, frame16->h);
|
||||
frame16->free();
|
||||
delete frame16;
|
||||
|
||||
if (updateScreen)
|
||||
_vm->_system->updateScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::drawFrameSubtitles(Graphics::Surface *surface, int frameNum) {
|
||||
if (!ConfMan.getBool("subtitles"))
|
||||
return;
|
||||
|
||||
_vm->_dialogMgr->dialogHandler(frameNum);
|
||||
if (_vm->_drawText._text.empty())
|
||||
return;
|
||||
|
||||
// Subtitles can be placed in different coordinates in the video,
|
||||
// which are set inside dialogHandler(), but are then reset to
|
||||
// fixed coordinates
|
||||
_vm->_drawText._rect.left = 20;
|
||||
_vm->_drawText._rect.top = 380 - TOP;
|
||||
_vm->_drawText._rect.setWidth(MAXX - 40);
|
||||
_vm->_drawText._rect.setHeight(_vm->_drawText.calcHeight(_vm));
|
||||
_vm->_drawText._subtitleRect = Common::Rect(MAXX, MAXY);
|
||||
_vm->_drawText.draw(_vm, false, surface);
|
||||
}
|
||||
|
||||
void AnimManager::openSmkAnim(int slot, const Common::Path &name) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Open the animation, or swap the 3 CDs to find it
|
||||
if (_animFile[slot].hasFile(name)) {
|
||||
openSmk(slot, name);
|
||||
return;
|
||||
}
|
||||
|
||||
_curCD = _curCD < 3 ? _curCD + 1 : 1;
|
||||
swapCD(_curCD);
|
||||
}
|
||||
|
||||
error("openSmkAnim(): File %s not found", name.toString().c_str());
|
||||
}
|
||||
|
||||
void AnimManager::openSmk(int slot, const Common::Path &name) {
|
||||
Common::SeekableReadStream *stream =_animFile[slot].createReadStreamForMember(name);
|
||||
if (!stream) {
|
||||
warning("Can't open SMK file");
|
||||
closeSmk(slot);
|
||||
return;
|
||||
}
|
||||
if (!_vm->isAmiga()) {
|
||||
_animations[slot] = new NightlongSmackerDecoder();
|
||||
if (!_animations[slot]->loadStream(stream)) {
|
||||
warning("Invalid SMK file");
|
||||
closeSmk(slot);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
NightlongAmigaDecoder *amigaDecoder = new NightlongAmigaDecoder();
|
||||
_animations[slot] = amigaDecoder;
|
||||
if (!_animations[slot]->loadStream(stream)) {
|
||||
warning("Invalid SMK file");
|
||||
closeSmk(slot);
|
||||
return;
|
||||
}
|
||||
Common::String baseName("a" + name.baseName());
|
||||
Common::Path audioPath = name.getParent().appendComponent(baseName);
|
||||
|
||||
if (Common::File::exists(audioPath)) {
|
||||
amigaDecoder->addAudioSideTrack(audioPath);
|
||||
}
|
||||
}
|
||||
|
||||
_animations[slot]->start();
|
||||
}
|
||||
|
||||
void AnimManager::closeSmk(int slot) {
|
||||
delete _animations[slot];
|
||||
_animations[slot] = nullptr;
|
||||
}
|
||||
|
||||
void AnimManager::smkGoto(int slot, int frame) {
|
||||
if (_animations[slot] == nullptr)
|
||||
return;
|
||||
|
||||
_animations[slot]->forceSeekToFrame(frame);
|
||||
}
|
||||
|
||||
void AnimManager::smkToggleTrackAudio(int slot, int track, bool on) {
|
||||
if (_animations[slot] == nullptr)
|
||||
return;
|
||||
|
||||
_animations[slot]->muteTrack(track, !on);
|
||||
}
|
||||
|
||||
void AnimManager::smkToggleAudio(int slot, bool on) {
|
||||
if (_animations[slot] == nullptr)
|
||||
return;
|
||||
|
||||
_animations[slot]->setMute(!on);
|
||||
}
|
||||
|
||||
int16 AnimManager::smkCurFrame(int slot) {
|
||||
if (_animations[slot] == nullptr)
|
||||
return -1;
|
||||
|
||||
return _animations[slot]->getCurFrame();
|
||||
}
|
||||
|
||||
void AnimManager::startSmkAnim(uint16 animation) {
|
||||
int slot;
|
||||
uint16 animFlag = _animTab[animation]._flag;
|
||||
|
||||
// choose the buffer to use
|
||||
if (animFlag & SMKANIM_BKG)
|
||||
slot = kSmackerBackground;
|
||||
else if (animFlag & SMKANIM_ICON)
|
||||
slot = kSmackerIcon;
|
||||
else
|
||||
slot = kSmackerAction;
|
||||
|
||||
smkStop(slot);
|
||||
|
||||
_playingAnims[slot] = animation;
|
||||
|
||||
// choose how to open
|
||||
if (slot == kSmackerBackground) {
|
||||
openSmkAnim(kSmackerBackground, _animTab[animation]._name);
|
||||
_bgAnimRestarted = false;
|
||||
|
||||
toggleMuteBgAnim(animation);
|
||||
} else if (slot == kSmackerIcon) {
|
||||
openSmkAnim(kSmackerIcon, _animTab[animation]._name);
|
||||
} else {
|
||||
uint32 st = _vm->readTime();
|
||||
openSmkAnim(kSmackerAction, _animTab[animation]._name);
|
||||
_vm->_nextRefresh += _vm->readTime() - st; // fixup opening time
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::toggleMuteBgAnim(uint16 animation) {
|
||||
const bool area1Shown = _animTab[animation].isAnimAreaShown(1);
|
||||
const bool area2Shown = _animTab[animation].isAnimAreaShown(2);
|
||||
const bool area4Shown = _animTab[animation].isAnimAreaShown(4);
|
||||
NightlongVideoDecoder *decoder = _animations[kSmackerBackground];
|
||||
if (decoder == nullptr)
|
||||
return;
|
||||
|
||||
// Turns off when not needed
|
||||
if (animation == aBKG11 && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG14 && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG1C && _vm->_obj[oFAX17].isFlagExtra()) {
|
||||
_animTab[animation].toggleAnimArea(1, false);
|
||||
decoder->muteTrack(1, true);
|
||||
} else if (animation == aBKG1D && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG22 && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG48 && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG4P && !area1Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG28 && area4Shown)
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG37 && !_vm->_room[_vm->_curRoom].hasExtra())
|
||||
decoder->muteTrack(1, true);
|
||||
else if (animation == aBKG2E && area2Shown)
|
||||
decoder->muteTrack(2, true);
|
||||
else if (animation == aBKG2G && _vm->_dialogMgr->isDialogFinished(556))
|
||||
decoder->muteTrack(2, true);
|
||||
else if (animation == aBKG34 && // If it's BKG 34 and
|
||||
(_vm->_dialogMgr->isDialogFinished(616) || // if the FMV is already done or
|
||||
_vm->isObjectVisible(oTUBOT34) || // if the whole tube is available or
|
||||
_vm->isObjectVisible(oTUBOFT34) || // if the outside of the tube is available or
|
||||
_vm->isObjectVisible(oVALVOLAC34))) // if the valve is closed
|
||||
decoder->muteTrack(2, true);
|
||||
}
|
||||
|
||||
void AnimManager::smkStop(uint16 slot) {
|
||||
_playingAnims[slot] = 0;
|
||||
|
||||
closeSmk(slot);
|
||||
|
||||
_vm->_lightIcon = 0xFF;
|
||||
}
|
||||
|
||||
void AnimManager::stopAllSmkAnims() {
|
||||
for (int slot = 0; slot < MAXACTIVEANIM; slot++) {
|
||||
if (_playingAnims[slot])
|
||||
smkStop(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::startFullMotion() {
|
||||
stopAllSmkAnims();
|
||||
|
||||
_vm->_flagDialogActive = true;
|
||||
_vm->_flagShowCharacter = false;
|
||||
|
||||
_vm->_textStatus = TEXT_OFF;
|
||||
_vm->_inventoryStatus = INV_OFF;
|
||||
_vm->_inventoryCounter = INVENTORY_HIDE;
|
||||
|
||||
_vm->_textMgr->clearTextStack();
|
||||
_vm->_graphicsMgr->clearScreen();
|
||||
|
||||
_vm->_scheduler->resetQueues();
|
||||
_vm->_actor->actorStop();
|
||||
_vm->_graphicsMgr->hideCursor();
|
||||
}
|
||||
|
||||
void AnimManager::stopFullMotion() {
|
||||
const uint16 curDialog = _vm->_dialogMgr->getCurDialog();
|
||||
|
||||
_vm->_flagDialogActive = false;
|
||||
_vm->_flagDialogMenuActive = false;
|
||||
_vm->_flagSomeoneSpeaks = false;
|
||||
_vm->_lightIcon = 0xFF;
|
||||
_vm->_graphicsMgr->showCursor();
|
||||
|
||||
if (curDialog == dFCRED) {
|
||||
_vm->quitGame();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((curDialog == dSHOPKEEPER1A) && _vm->_dialogMgr->getCurChoice() == 185)) {
|
||||
if ((curDialog == dF582) || (curDialog == dFLOG) || (curDialog == dINTRO) || (curDialog == dF362) || (curDialog == dC381) || (curDialog == dF381) ||
|
||||
(curDialog == dF491) || ((curDialog == dC581) && !_vm->_dialogMgr->isDialogFinished(886) && _vm->_dialogMgr->isDialogFinished(258)) ||
|
||||
((curDialog == dC5A1) && _vm->_room[kRoom5A].hasExtra()))
|
||||
_vm->_flagShowCharacter = false;
|
||||
else
|
||||
_vm->redrawRoom();
|
||||
|
||||
if (curDialog == dF582)
|
||||
_vm->_soundMgr->stopAllExceptMusic();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::refreshAnim(int box) {
|
||||
for (int i = 0; i < MAXACTIVEANIM; i++) {
|
||||
if (_playingAnims[i] != 0 && box == BOX_BACKGROUND && i != kSmackerAction) {
|
||||
refreshSmkAnim(_playingAnims[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::refreshSmkAnim(uint16 animation) {
|
||||
if (animation == 0)
|
||||
return;
|
||||
|
||||
if (_animTab[animation]._flag & SMKANIM_ICON) {
|
||||
drawSmkIconFrame(_vm->_inventoryRefreshStartIcon, animation);
|
||||
} else if (_animTab[animation]._flag & SMKANIM_BKG) {
|
||||
drawSmkBackgroundFrame(animation);
|
||||
handleEndOfVideo(animation, kSmackerBackground);
|
||||
} else {
|
||||
drawSmkActionFrame();
|
||||
handleEndOfVideo(animation, kSmackerAction);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < MAXAREA; i++) {
|
||||
if (_animTab[animation].isAnimAreaShown(i + 1) && _animTab[animation]._area[i].bottom != 0) {
|
||||
_vm->_graphicsMgr->addDirtyRect(_animTab[animation]._area[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::handleEndOfVideo(int animation, int slot) {
|
||||
const bool isLoopingOrBackground = (_animTab[animation]._flag & SMKANIM_LOOP) || (_animTab[animation]._flag & SMKANIM_BKG);
|
||||
|
||||
if (_animations[slot] == nullptr) {
|
||||
smkStop(slot);
|
||||
return;
|
||||
}
|
||||
if (!_animations[slot]->endOfFrames())
|
||||
return;
|
||||
|
||||
if (!isLoopingOrBackground) {
|
||||
smkStop(slot);
|
||||
_vm->_flagPaintCharacter = true;
|
||||
} else {
|
||||
_animations[slot]->rewind();
|
||||
_vm->_animTypeMgr->init(animation, 0);
|
||||
_bgAnimRestarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rectsIntersect(Common::Rect r1, Common::Rect r2) {
|
||||
return (r1.left <= r2.right) && (r1.right >= r2.left) && (r1.top <= r2.bottom) && (r1.bottom >= r2.top);
|
||||
}
|
||||
|
||||
bool AnimManager::shouldShowAnim(int animation, Common::Rect curRect) {
|
||||
for (int32 i = 0; i < MAXAREA; i++) {
|
||||
const bool intersect = rectsIntersect(_animTab[animation]._area[i], curRect);
|
||||
if (intersect && !_animTab[animation].isAnimAreaShown(i + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimManager::drawSmkBackgroundFrame(int animation) {
|
||||
NightlongVideoDecoder *videoDecoder = _animations[kSmackerBackground];
|
||||
if (videoDecoder == nullptr)
|
||||
return;
|
||||
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
const Common::Rect *lastRect = videoDecoder->getNextDirtyRect();
|
||||
const byte *palette = videoDecoder->getPalette();
|
||||
|
||||
if (videoDecoder->getCurFrame() == 0 && shouldShowAnim(animation, *lastRect) && !_bgAnimRestarted) {
|
||||
_vm->_graphicsMgr->blitToScreenBuffer(frame, 0, TOP, palette, true);
|
||||
} else {
|
||||
while (lastRect) {
|
||||
if (videoDecoder->getCurFrame() > 0 && shouldShowAnim(animation, *lastRect)) {
|
||||
Graphics::Surface anim = frame->getSubArea(*lastRect);
|
||||
_vm->_graphicsMgr->blitToScreenBuffer(&anim, lastRect->left, lastRect->top + TOP, palette, true);
|
||||
}
|
||||
|
||||
lastRect = videoDecoder->getNextDirtyRect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::drawSmkIconFrame(uint16 startIcon, uint16 iconNum) {
|
||||
NightlongVideoDecoder *videoDecoder = _animations[kSmackerIcon];
|
||||
if (videoDecoder == nullptr)
|
||||
return;
|
||||
|
||||
int stx = ICONMARGSX;
|
||||
uint a;
|
||||
for (a = 0; a < ICONSHOWN; ++a) {
|
||||
if (a + startIcon >= _vm->_inventory.size())
|
||||
break;
|
||||
|
||||
if (_vm->_inventory[a + startIcon] == iconNum - FIRST_INV_ITEM + 1) {
|
||||
stx = a * ICONDX + ICONMARGSX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a == ICONSHOWN)
|
||||
return;
|
||||
|
||||
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
_vm->_graphicsMgr->copyToScreenBuffer(frame, stx, FIRSTLINE, videoDecoder->getPalette());
|
||||
|
||||
if (videoDecoder->endOfVideo())
|
||||
videoDecoder->rewind();
|
||||
}
|
||||
|
||||
void AnimManager::drawSmkActionFrame() {
|
||||
NightlongVideoDecoder *smkDecoder = _animations[kSmackerAction];
|
||||
if (smkDecoder == nullptr)
|
||||
return;
|
||||
const Graphics::Surface *frame = smkDecoder->decodeNextFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
const byte *palette = smkDecoder->getPalette();
|
||||
|
||||
if (smkDecoder->getCurFrame() == 0) {
|
||||
_animRect = *smkDecoder->getNextDirtyRect();
|
||||
}
|
||||
|
||||
if (_animRect.width() > 0 && _animRect.height() > 0) {
|
||||
Graphics::Surface anim = frame->getSubArea(_animRect);
|
||||
_vm->_graphicsMgr->blitToScreenBuffer(&anim, _animRect.left, _animRect.top + TOP, palette, false);
|
||||
_vm->_graphicsMgr->addDirtyRect(_animRect, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::swapCD(int cd) {
|
||||
Common::Path animFileName(Common::String::format("nlanim.cd%d", cd));
|
||||
for (uint8 i = 0; i < MAXACTIVEANIM; ++i) {
|
||||
_animFile[i].close();
|
||||
_animFile[i].open(_vm, animFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::syncGameStream(Common::Serializer &ser) {
|
||||
for (int i = 0; i < MAXANIM; i++) {
|
||||
SAnim *cur = &_animTab[i];
|
||||
ser.syncBytes((byte *)cur->_name, 14);
|
||||
ser.syncAsUint16LE(cur->_flag);
|
||||
for (uint8 j = 0; j < MAXAREA; ++j) {
|
||||
ser.syncAsUint16LE(cur->_area[j].left);
|
||||
ser.syncAsUint16LE(cur->_area[j].top);
|
||||
ser.syncAsUint16LE(cur->_area[j].right);
|
||||
ser.syncAsUint16LE(cur->_area[j].bottom);
|
||||
}
|
||||
ser.syncAsByte(cur->_nbox);
|
||||
ser.skip(1, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX);
|
||||
for (uint8 j = 0; j < MAXATFRAME; ++j) {
|
||||
ser.syncAsByte(cur->_atFrame[j]._type);
|
||||
ser.syncAsByte(cur->_atFrame[j]._area);
|
||||
ser.syncAsUint16LE(cur->_atFrame[j]._numFrame);
|
||||
ser.syncAsUint16LE(cur->_atFrame[j]._index);
|
||||
}
|
||||
}
|
||||
|
||||
patchAnimTab();
|
||||
}
|
||||
|
||||
void AnimManager::loadAnimTab(Common::SeekableReadStreamEndian *stream) {
|
||||
for (uint16 i = 0; i < MAXANIM; ++i) {
|
||||
stream->read(&_animTab[i]._name, 14);
|
||||
|
||||
_animTab[i]._flag = stream->readUint16();
|
||||
|
||||
for (uint8 j = 0; j < MAXAREA; ++j) {
|
||||
_animTab[i]._area[j].left = stream->readUint16();
|
||||
_animTab[i]._area[j].top = stream->readUint16();
|
||||
_animTab[i]._area[j].right = stream->readUint16();
|
||||
_animTab[i]._area[j].bottom = stream->readUint16();
|
||||
}
|
||||
|
||||
_animTab[i]._nbox = stream->readByte();
|
||||
stream->readByte(); // Padding
|
||||
|
||||
for (uint8 j = 0; j < MAXATFRAME; ++j) {
|
||||
_animTab[i]._atFrame[j]._type = stream->readByte();
|
||||
_animTab[i]._atFrame[j]._area = stream->readByte();
|
||||
_animTab[i]._atFrame[j]._numFrame = stream->readUint16();
|
||||
_animTab[i]._atFrame[j]._index = stream->readUint16();
|
||||
}
|
||||
}
|
||||
|
||||
patchAnimTab();
|
||||
}
|
||||
|
||||
void AnimManager::patchAnimTab() {
|
||||
_animTab[aBKG28]._area[3].left = 308; // Patch the brazier animation rect in kRoom28 - bug #12628
|
||||
_animTab[aBKG35]._area[0].right = 200; // Patch the terrorist animation rect in kRoom35
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
106
engines/trecision/animmanager.h
Normal file
106
engines/trecision/animmanager.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_ANIMMANAGER_H
|
||||
#define TRECISION_ANIMMANAGER_H
|
||||
|
||||
#include "trecision/fastfile.h"
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
#define MAXANIM 750
|
||||
#define MAXACTIVEANIM 3
|
||||
|
||||
// SMACKER ANIMATION FLAGS
|
||||
#define SMKANIM_BKG 1
|
||||
#define SMKANIM_ICON 2
|
||||
#define SMKANIM_LOOP 4
|
||||
#define SMKANIM_OLD 8
|
||||
#define SMKANIM_ON 16
|
||||
|
||||
enum SmackerType {
|
||||
kSmackerBackground = 0, // Scene background animations
|
||||
kSmackerAction = 1, // Main character action animations
|
||||
kSmackerIcon = 2 // Smacker inventory animations
|
||||
};
|
||||
|
||||
class TrecisionEngine;
|
||||
class NightlongVideoDecoder;
|
||||
|
||||
class AnimManager {
|
||||
public:
|
||||
AnimManager(TrecisionEngine *vm);
|
||||
~AnimManager();
|
||||
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
NightlongVideoDecoder *_animations[MAXACTIVEANIM];
|
||||
uint16 _playingAnims[MAXACTIVEANIM];
|
||||
|
||||
FastFile _animFile[MAXACTIVEANIM]; // nlanim.cd1 / nlanim.cd2 / nlanim.cd3
|
||||
int _curCD;
|
||||
bool _bgAnimRestarted;
|
||||
|
||||
void openSmk(int slot, const Common::Path &name);
|
||||
void openSmkAnim(int slot, const Common::Path &name);
|
||||
void toggleMuteBgAnim(uint16 animation);
|
||||
void closeSmk(int slot);
|
||||
void drawFrame(NightlongVideoDecoder *smkDecoder, uint16 x, uint16 y, bool updateScreen);
|
||||
void drawFrameSubtitles(Graphics::Surface *surface, int frameNum);
|
||||
void setVideoRange(NightlongVideoDecoder *smkDecoder, int &startFrame, int &endFrame);
|
||||
void refreshSmkAnim(uint16 animation);
|
||||
void handleEndOfVideo(int animation, int slot);
|
||||
bool shouldShowAnim(int animation, Common::Rect curRect);
|
||||
|
||||
void drawSmkBackgroundFrame(int animation);
|
||||
void drawSmkIconFrame(uint16 startIcon, uint16 iconNum);
|
||||
void drawSmkActionFrame();
|
||||
void swapCD(int cd);
|
||||
void patchAnimTab();
|
||||
|
||||
public:
|
||||
Common::Rect _animRect;
|
||||
SAnim _animTab[MAXANIM];
|
||||
|
||||
void smkGoto(int slot, int frame);
|
||||
void smkToggleAudio(int slot, bool on);
|
||||
void smkToggleTrackAudio(int slot, int track, bool on);
|
||||
int16 smkCurFrame(int slot);
|
||||
void smkStop(uint16 slot);
|
||||
void refreshActionAnimation() { refreshSmkAnim(_playingAnims[kSmackerAction]); }
|
||||
bool isActionActive() const { return _playingAnims[kSmackerAction] != 0; }
|
||||
void playMovie(const Common::Path &filename, int startFrame = 0, int endFrame = -1, bool singleChoice = false);
|
||||
void startFullMotion();
|
||||
void stopFullMotion();
|
||||
|
||||
void refreshAnim(int box);
|
||||
void startSmkAnim(uint16 animation);
|
||||
void stopAllSmkAnims();
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void loadAnimTab(Common::SeekableReadStreamEndian *stream);
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
379
engines/trecision/animtype.cpp
Normal file
379
engines/trecision/animtype.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
#define ATF_WAITTEXT 1
|
||||
|
||||
AnimTypeManager::AnimTypeManager(TrecisionEngine *vm) : _vm(vm) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
_animType[i]._curFrame = 1;
|
||||
_animType[i]._lastFrame = 0;
|
||||
_animType[i]._object = 0;
|
||||
_animType[i]._status = 0;
|
||||
_animType[i]._curAnim = nullptr;
|
||||
}
|
||||
|
||||
_oneSpeakDialogCount = 0;
|
||||
}
|
||||
|
||||
AnimTypeManager::~AnimTypeManager() {
|
||||
|
||||
}
|
||||
|
||||
void AnimTypeManager::executeAtFrameDoit(ATFHandle *h, int doit, uint16 objectId) {
|
||||
SAnim *anim = &_vm->_animMgr->_animTab[_vm->_room[_vm->_curRoom]._bkgAnim];
|
||||
|
||||
switch (doit) {
|
||||
case fCLROBJSTATUS:
|
||||
_vm->setObjectVisible(objectId, false);
|
||||
break;
|
||||
case fSETOBJSTATUS:
|
||||
_vm->setObjectVisible(objectId, true);
|
||||
break;
|
||||
case fONETIME:
|
||||
_vm->setObjectAnim(objectId, 0);
|
||||
break;
|
||||
case fCREPACCIO:
|
||||
if (_vm->_room[kRoom2E].hasExtra())
|
||||
_vm->_obj[oCRACK2E]._position = 7;
|
||||
else
|
||||
_vm->_obj[oCRACK2E]._position = 6;
|
||||
break;
|
||||
case fSERPVIA:
|
||||
_vm->_scheduler->doEvent(_vm->_snake52._class, _vm->_snake52._event, _vm->_snake52._priority, _vm->_snake52._u16Param1, _vm->_snake52._u16Param2, _vm->_snake52._u8Param, _vm->_snake52._u32Param);
|
||||
break;
|
||||
case fPIRANHA:
|
||||
_vm->setObjectAnim(oLUCCHETTO53, 0);
|
||||
_vm->setObjectAnim(oGRATAC53, 0);
|
||||
_vm->setObjectAnim(oGRATAA53, 0);
|
||||
_vm->_obj[oLUCCHETTO53]._action = 1240;
|
||||
_vm->_obj[oGRATAC53]._action = 1243;
|
||||
_vm->_obj[oGRATAA53]._action = 1246;
|
||||
_vm->_obj[oLAGO53]._examine = 1237;
|
||||
break;
|
||||
case fMOREAU:
|
||||
_vm->setObjectAnim(oWINDOWB58, 0);
|
||||
_vm->_obj[oWINDOWB58]._action = 1358;
|
||||
break;
|
||||
case fDOOR58:
|
||||
_vm->_scheduler->leftClick(468, 180 + TOP);
|
||||
break;
|
||||
case fHELLEN:
|
||||
_vm->_scheduler->leftClick(336, 263 + TOP);
|
||||
break;
|
||||
case fVALVEON34:
|
||||
if (!(_vm->_dialogMgr->isDialogFinished(616)) && // if the fmv is not done
|
||||
(_vm->isObjectVisible(oTUBOA34)) && // if there's a cut pipe
|
||||
!(_vm->isObjectVisible(oTUBOFT34))) // if there's not tube outside
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
|
||||
break;
|
||||
case fVALVEOFF34:
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
|
||||
break;
|
||||
|
||||
case fCHARACTEROFF:
|
||||
_vm->_flagShowCharacter = false;
|
||||
break;
|
||||
case fCHARACTERON:
|
||||
_vm->_flagShowCharacter = true;
|
||||
break;
|
||||
case fCHARACTERFOREGROUND:
|
||||
_vm->_pathFind->setForcedActorPos(BOX_FOREGROUND);
|
||||
break;
|
||||
case fCHARACTERBACKGROUND:
|
||||
_vm->_pathFind->setForcedActorPos(BOX_BACKGROUND);
|
||||
break;
|
||||
case fCHARACTERNORM:
|
||||
_vm->_pathFind->setForcedActorPos(BOX_NORMAL);
|
||||
break;
|
||||
case fSETEXTRA:
|
||||
_vm->_obj[objectId].setFlagExtra(true);
|
||||
break;
|
||||
case fCLREXTRA:
|
||||
_vm->_obj[objectId].setFlagExtra(false);
|
||||
break;
|
||||
|
||||
case fANIMOFF1:
|
||||
anim->toggleAnimArea(1, false);
|
||||
if (_vm->_curRoom == kRoom11 ||
|
||||
_vm->_curRoom == kRoom1D ||
|
||||
_vm->_curRoom == kRoom14 ||
|
||||
_vm->_curRoom == kRoom22 ||
|
||||
_vm->_curRoom == kRoom48 ||
|
||||
_vm->_curRoom == kRoom4P)
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
|
||||
break;
|
||||
case fANIMOFF2:
|
||||
anim->toggleAnimArea(2, false);
|
||||
if (_vm->_curRoom == kRoom2E)
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
|
||||
break;
|
||||
case fANIMOFF3:
|
||||
anim->toggleAnimArea(3, false);
|
||||
break;
|
||||
case fANIMOFF4:
|
||||
anim->toggleAnimArea(4, false);
|
||||
if (_vm->_curRoom == kRoom28)
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
|
||||
break;
|
||||
|
||||
case fANIMON1:
|
||||
anim->toggleAnimArea(1, true);
|
||||
if (_vm->_curRoom == kRoom14 || _vm->_curRoom == kRoom1D || _vm->_curRoom == kRoom22 || _vm->_curRoom == kRoom48 || _vm->_curRoom == kRoom4P) {
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
|
||||
}
|
||||
break;
|
||||
case fANIMON2:
|
||||
anim->toggleAnimArea(2, true);
|
||||
if (_vm->_curRoom == kRoom2E)
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
|
||||
break;
|
||||
case fANIMON3:
|
||||
anim->toggleAnimArea(3, true);
|
||||
break;
|
||||
case fANIMON4:
|
||||
anim->toggleAnimArea(4, true);
|
||||
break;
|
||||
case fENDDEMO:
|
||||
_vm->demoOver();
|
||||
_vm->quitGame();
|
||||
break;
|
||||
case fSTOP2TXT:
|
||||
h->_status |= ATF_WAITTEXT;
|
||||
// Sets a flag that is always cleared when you finish speaking
|
||||
// if the flag is cleared the anim no longer plays
|
||||
// (to be done in the smacker player)
|
||||
// also the counters in next() stops
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTypeManager::processAtFrame(ATFHandle *h, int type, int atf) {
|
||||
const uint16 index = h->_curAnim->_atFrame[atf]._index;
|
||||
|
||||
switch (type) {
|
||||
case ATFTEXT:
|
||||
_vm->_textMgr->characterSayInAction(index);
|
||||
break;
|
||||
case ATFTEXTACT:
|
||||
_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._action);
|
||||
break;
|
||||
case ATFTEXTEX:
|
||||
_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._examine);
|
||||
break;
|
||||
case ATFCLR:
|
||||
_vm->setObjectVisible(index, false);
|
||||
break;
|
||||
case ATFCLRI:
|
||||
_vm->removeIcon(index);
|
||||
break;
|
||||
case ATFCEX:
|
||||
_vm->_obj[h->_object]._examine = index;
|
||||
break;
|
||||
case ATFCACT:
|
||||
_vm->_obj[h->_object]._action = index;
|
||||
break;
|
||||
case ATFSET:
|
||||
_vm->setObjectVisible(index, true);
|
||||
break;
|
||||
case ATFSETI:
|
||||
_vm->addIcon(index);
|
||||
break;
|
||||
case ATFDO:
|
||||
executeAtFrameDoit(h, index, h->_object);
|
||||
break;
|
||||
case ATFROOM:
|
||||
_vm->changeRoom(index);
|
||||
break;
|
||||
case ATFSETPOS:
|
||||
_vm->_pathFind->setPosition(index);
|
||||
break;
|
||||
case ATFDIALOG:
|
||||
_vm->_dialogMgr->playDialog(index);
|
||||
break;
|
||||
case ATFCOBJANIM:
|
||||
_vm->_obj[h->_object]._anim = index;
|
||||
break;
|
||||
case ATFCOBJBOX:
|
||||
_vm->_obj[h->_object]._nbox = index;
|
||||
break;
|
||||
case ATFCOBJPOS:
|
||||
_vm->_obj[h->_object]._position = index;
|
||||
break;
|
||||
case ATFSETFORE:
|
||||
_vm->_obj[index]._nbox = BOX_FOREGROUND;
|
||||
break;
|
||||
case ATFSETBACK:
|
||||
_vm->_obj[index]._nbox = BOX_BACKGROUND;
|
||||
break;
|
||||
case ATFSWITCH:
|
||||
_vm->setObjectVisible(index, !_vm->isObjectVisible(index));
|
||||
break;
|
||||
case ATFSETROOMT:
|
||||
_vm->_logicMgr->setupAltRoom(index, true);
|
||||
break;
|
||||
case ATFSETROOMF:
|
||||
_vm->_logicMgr->setupAltRoom(index, false);
|
||||
break;
|
||||
case ATFREADBOX:
|
||||
switch (index) {
|
||||
case 1: {
|
||||
const Common::Path filename(Common::String::format("%s.3d", _vm->_room[_vm->_curRoom]._baseName));
|
||||
_vm->read3D(filename);
|
||||
_vm->_room[_vm->_curRoom].setExtra(false);
|
||||
}
|
||||
break;
|
||||
case 2: {
|
||||
const Common::Path filename(Common::String::format("%s2.3d", _vm->_room[_vm->_curRoom]._baseName));
|
||||
_vm->read3D(filename);
|
||||
_vm->_room[_vm->_curRoom].setExtra(true);
|
||||
if (_vm->_curRoom == kRoom37)
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ATFONESPEAK:
|
||||
switch (index) {
|
||||
case 1: // Storekeeper's wife
|
||||
if (_vm->_room[kRoom1D].hasExtra())
|
||||
break;
|
||||
|
||||
// Quotes spoken by the storekeeper's wife while she is in the cellar
|
||||
_vm->_textMgr->someoneSay(307 + _oneSpeakDialogCount, oDONNA1D);
|
||||
if (_oneSpeakDialogCount < 6)
|
||||
++_oneSpeakDialogCount;
|
||||
break;
|
||||
|
||||
case 2: // Storekeeper
|
||||
// Quote when you enter the liquor store: "Ah, it's you again... look round
|
||||
// if you want, but don't disturb me, I've got a lot to do"
|
||||
_vm->_textMgr->someoneSay(1788, ocNEGOZIANTE1A);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ATFEND:
|
||||
_vm->demoOver();
|
||||
_vm->quitGame();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTypeManager::init(uint16 an, uint16 obj) {
|
||||
SAnim *anim = &_vm->_animMgr->_animTab[an];
|
||||
ATFHandle *handle = &_animType[kAnimTypeCharacter];
|
||||
|
||||
if (anim->_flag & SMKANIM_BKG)
|
||||
handle = &_animType[kAnimTypeBackground];
|
||||
if (anim->_flag & SMKANIM_ICON)
|
||||
handle = &_animType[kAnimTypeIcon];
|
||||
|
||||
handle->_curAnim = anim;
|
||||
handle->_object = obj ? obj : _vm->_curObj;
|
||||
handle->_curFrame = 0;
|
||||
handle->_lastFrame = -1;
|
||||
handle->_status = 0;
|
||||
}
|
||||
|
||||
void AnimTypeManager::next() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (!(_animType[i]._status & ATF_WAITTEXT) || !_vm->_flagCharacterSpeak)
|
||||
++_animType[i]._curFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTypeManager::end(int type) {
|
||||
ATFHandle *h = &_animType[type];
|
||||
SAnim *anim = h->_curAnim;
|
||||
h->_curFrame = 0;
|
||||
|
||||
// if this ATFrame has already been handled
|
||||
if (h->_curFrame == h->_lastFrame)
|
||||
return;
|
||||
|
||||
h->_lastFrame = h->_curFrame;
|
||||
|
||||
for (int32 i = 0; i < MAXATFRAME; ++i) {
|
||||
// if it's time to run this AtFrame
|
||||
if (anim->_atFrame[i]._numFrame == 0 && anim->_atFrame[i]._type) {
|
||||
const uint8 area = anim->_atFrame[i]._area;
|
||||
if ( area == 0 ||
|
||||
(area == 1 && anim->isAnimAreaShown(1)) ||
|
||||
(area == 2 && anim->isAnimAreaShown(2)) ||
|
||||
(area == 3 && anim->isAnimAreaShown(3)) ||
|
||||
(area == 4 && anim->isAnimAreaShown(4)))
|
||||
processAtFrame(h, anim->_atFrame[i]._type, i);
|
||||
}
|
||||
}
|
||||
|
||||
h->_curAnim = nullptr;
|
||||
}
|
||||
|
||||
void AnimTypeManager::handler(int type) {
|
||||
ATFHandle *h = &_animType[type];
|
||||
SAnim *anim = h->_curAnim;
|
||||
if (anim == nullptr)
|
||||
return;
|
||||
|
||||
if (h->_curFrame == 0)
|
||||
++h->_curFrame;
|
||||
// if this ATFrame has already been applied
|
||||
if (h->_curFrame <= h->_lastFrame)
|
||||
return;
|
||||
|
||||
for (int32 i = 0; i < MAXATFRAME; ++i) {
|
||||
// if it's time to run this AtFrame
|
||||
if (anim->_atFrame[i]._numFrame > h->_lastFrame &&
|
||||
anim->_atFrame[i]._numFrame <= h->_curFrame &&
|
||||
anim->_atFrame[i]._numFrame != 0) {
|
||||
const uint8 child = anim->_atFrame[i]._area;
|
||||
if ( child == 0 ||
|
||||
(child == 1 && anim->isAnimAreaShown(1)) ||
|
||||
(child == 2 && anim->isAnimAreaShown(2)) ||
|
||||
(child == 3 && anim->isAnimAreaShown(3)) ||
|
||||
(child == 4 && anim->isAnimAreaShown(4)))
|
||||
processAtFrame(h, anim->_atFrame[i]._type, i);
|
||||
}
|
||||
}
|
||||
|
||||
// set _lastFrame
|
||||
h->_lastFrame = h->_curFrame;
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
60
engines/trecision/animtype.h
Normal file
60
engines/trecision/animtype.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_ANIMTYPE_H
|
||||
#define TRECISION_ANIMTYPE_H
|
||||
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
class TrecisionEngine;
|
||||
|
||||
struct ATFHandle {
|
||||
int16 _curFrame;
|
||||
int16 _lastFrame;
|
||||
uint16 _object;
|
||||
uint16 _status;
|
||||
SAnim *_curAnim;
|
||||
};
|
||||
|
||||
class AnimTypeManager {
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
void executeAtFrameDoit(ATFHandle *h, int doit, uint16 obj);
|
||||
void processAtFrame(ATFHandle *h, int type, int atf);
|
||||
|
||||
ATFHandle _animType[3];
|
||||
int _oneSpeakDialogCount;
|
||||
|
||||
public:
|
||||
AnimTypeManager(TrecisionEngine *vm);
|
||||
~AnimTypeManager();
|
||||
|
||||
void init(uint16 an, uint16 obj);
|
||||
void next();
|
||||
void end(int type);
|
||||
void handler(int type);
|
||||
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
3
engines/trecision/configure.engine
Normal file
3
engines/trecision/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine trecision "Trecision Adventure Module" yes "" "" "highres 16bit"
|
||||
194
engines/trecision/console.cpp
Normal file
194
engines/trecision/console.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "gui/debugger.h"
|
||||
|
||||
#include "trecision/console.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
Console::Console(TrecisionEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
registerCmd("room", WRAP_METHOD(Console, Cmd_Room));
|
||||
registerCmd("dumpanim", WRAP_METHOD(Console, Cmd_DumpAnim));
|
||||
registerCmd("dumpfile", WRAP_METHOD(Console, Cmd_DumpFile));
|
||||
registerCmd("dialog", WRAP_METHOD(Console, Cmd_Dialog));
|
||||
registerCmd("item", WRAP_METHOD(Console, Cmd_Item));
|
||||
registerCmd("say", WRAP_METHOD(Console, Cmd_Say));
|
||||
registerCmd("position", WRAP_METHOD(Console, Cmd_Position));
|
||||
registerCmd("toggle_object", WRAP_METHOD(Console, Cmd_ToggleObject));
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
}
|
||||
|
||||
bool Console::Cmd_Room(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Current room: %d\n", _vm->_curRoom);
|
||||
debugPrintf("Use %s <roomId> to teleport\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const int newRoom = atoi(argv[1]);
|
||||
_vm->changeRoom(newRoom);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_DumpAnim(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: %s <file name>\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
FastFile animFile;
|
||||
|
||||
Common::Path fileName(argv[1]);
|
||||
|
||||
bool found = false;
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
Common::Path animFileName(Common::String::format("nlanim.cd%d", i));
|
||||
animFile.open(_vm, animFileName);
|
||||
|
||||
if (animFile.hasFile(fileName)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
debugPrintf("File not found\n");
|
||||
animFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *dataFile = animFile.createReadStreamForMember(fileName);
|
||||
|
||||
Common::DumpFile outFile;
|
||||
Common::Path outName = fileName.append(".dump");
|
||||
outFile.open(outName);
|
||||
outFile.writeStream(dataFile, dataFile->size());
|
||||
outFile.finalize();
|
||||
outFile.close();
|
||||
|
||||
animFile.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::Cmd_DumpFile(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: %s <file name>\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Path fileName(argv[1]);
|
||||
|
||||
if (!_vm->_dataFile.hasFile(fileName)) {
|
||||
debugPrintf("File not found\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *dataFile = fileName.baseName().hasSuffix(".cr") ? _vm->_dataFile.createReadStreamForCompressedMember(fileName) : _vm->_dataFile.createReadStreamForMember(fileName);
|
||||
|
||||
Common::DumpFile outFile;
|
||||
Common::Path outName = fileName.append(".dump");
|
||||
outFile.open(outName);
|
||||
outFile.writeStream(dataFile, dataFile->size());
|
||||
outFile.finalize();
|
||||
outFile.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::Cmd_Dialog(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <dialogId> to start a dialog\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const int dialogId = atoi(argv[1]);
|
||||
_vm->_dialogMgr->playDialog(dialogId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_Item(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <itemId> to add an item to the inventory\n", argv[0]);
|
||||
debugPrintf("Use %s <itemId> remove to remove an item from the inventory\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const int itemId = atoi(argv[1]);
|
||||
if (argc >= 3 && !scumm_stricmp(argv[2], "remove")) {
|
||||
_vm->removeIcon(itemId);
|
||||
} else {
|
||||
_vm->addIcon(itemId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_Say(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <sentenceId> to hear a sentence from Joshua\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint16 sentenceId = (uint16)atoi(argv[1]);
|
||||
_vm->_textMgr->characterSay(sentenceId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_Position(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Use %s <positionId> to set Joshua's position\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint16 positionId = (uint16)atoi(argv[1]);
|
||||
_vm->_pathFind->setPosition(positionId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_ToggleObject(int argc, const char **argv) {
|
||||
if (argc < 3) {
|
||||
debugPrintf("Use %s <objectId> <status> to show or hide an object\n", argv[0]);
|
||||
debugPrintf("Status can be true (or 1) to show an object, or false (or 0) to hide it\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint16 objectId = (uint16)atoi(argv[1]);
|
||||
const bool visible = !strcmp(argv[2], "1") || !scumm_stricmp(argv[2], "true");
|
||||
_vm->setObjectVisible(objectId, visible);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
50
engines/trecision/console.h
Normal file
50
engines/trecision/console.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_CONSOLE_H
|
||||
#define TRECISION_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
public:
|
||||
Console(TrecisionEngine *vm);
|
||||
~Console(void) override;
|
||||
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
bool Cmd_Room(int argc, const char **argv);
|
||||
bool Cmd_DumpAnim(int argc, const char **argv);
|
||||
bool Cmd_DumpFile(int argc, const char **argv);
|
||||
bool Cmd_Dialog(int argc, const char **argv);
|
||||
bool Cmd_Item(int argc, const char **argv);
|
||||
bool Cmd_Say(int argc, const char **argv);
|
||||
bool Cmd_Position(int argc, const char **argv);
|
||||
bool Cmd_ToggleObject(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
6
engines/trecision/credits.pl
Normal file
6
engines/trecision/credits.pl
Normal file
@@ -0,0 +1,6 @@
|
||||
begin_section("Trecision");
|
||||
add_person("Daniel Albano", "SupSuper", "");
|
||||
add_person("Arnaud Boutonné", "Strangerke", "");
|
||||
add_person("Thomas Fach-Pedersen", "madmoose", "Smacker video support");
|
||||
add_person("Filippos Karapetis", "bluegr", "");
|
||||
end_section();
|
||||
2501
engines/trecision/defines.h
Normal file
2501
engines/trecision/defines.h
Normal file
File diff suppressed because it is too large
Load Diff
243
engines/trecision/detection.cpp
Normal file
243
engines/trecision/detection.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
#include "common/translation.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "trecision/detection.h"
|
||||
|
||||
static const PlainGameDescriptor trecisionGames[] = {
|
||||
{"aot", "Ark of Time"},
|
||||
{"nl", "Nightlong: Union City Conspiracy"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
#define AD_NL_ENTRY(md5, size) \
|
||||
{ \
|
||||
{"data.nl", 0, md5, size}, \
|
||||
{"nlanim.cd1", 0, nullptr, AD_NO_SIZE}, \
|
||||
{"nlanim.cd2", 0, nullptr, AD_NO_SIZE}, \
|
||||
{"nlanim.cd3", 0, nullptr, AD_NO_SIZE}, \
|
||||
AD_LISTEND \
|
||||
}
|
||||
|
||||
#define AD_NL_DEMO_ENTRY(md5, size) \
|
||||
{ \
|
||||
{"data.nl", 0, md5, size}, \
|
||||
{"nlanim.cd1", 0, nullptr, AD_NO_SIZE}, \
|
||||
AD_LISTEND \
|
||||
}
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 436228),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 436598),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 457299),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 436697),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 456209),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 446634),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 432900),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
// bug #12619
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 429370),
|
||||
Common::HU_HUN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
// bug #12619
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 429731),
|
||||
Common::HU_HUN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
"Demo",
|
||||
AD_NL_DEMO_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 392950),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
"Demo",
|
||||
AD_NL_DEMO_ENTRY("7665db13ad2a1ceb576531be3e1efb30", 413651),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("2bfc3f5cc1ee5c7e80058db853296416", 436807),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("2bfc3f5cc1ee5c7e80058db853296416", 457508),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("2bfc3f5cc1ee5c7e80058db853296416", 436842),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("2bfc3f5cc1ee5c7e80058db853296416", 456354),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"nl",
|
||||
0,
|
||||
AD_NL_ENTRY("2bfc3f5cc1ee5c7e80058db853296416", 446779),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO0()
|
||||
},
|
||||
{
|
||||
"aot",
|
||||
MetaEngineDetection::GAME_NOT_IMPLEMENTED,
|
||||
{
|
||||
{"dialogue.dat", 0, "afc71fe29b1be3a9b145b8d61dfa4539", 166155130},
|
||||
{"sentence.dat", 0, "f38afcd22e7de14f9a2343e911eaa126", 75668232},
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSUPPORTED,
|
||||
GUIO0()
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"autorun",
|
||||
"data",
|
||||
0
|
||||
};
|
||||
|
||||
class TrecisionMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
TrecisionMetaEngineDetection() : AdvancedMetaEngineDetection(Trecision::gameDescriptions, trecisionGames) {
|
||||
_maxScanDepth = 2;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
_guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_ORIGINAL_SAVELOAD);
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "trecision";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Trecision Adventure Module";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "(C) 1993-98 Trecision S.p.A.";
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TRECISION_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TrecisionMetaEngineDetection);
|
||||
27
engines/trecision/detection.h
Normal file
27
engines/trecision/detection.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_DETECTION_H
|
||||
#define TRECISION_DETECTION_H
|
||||
|
||||
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
|
||||
|
||||
#endif
|
||||
796
engines/trecision/dialog.cpp
Normal file
796
engines/trecision/dialog.cpp
Normal file
@@ -0,0 +1,796 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
void Dialog::clear() {
|
||||
_flag = 0;
|
||||
_interlocutor = 0;
|
||||
memset(_startAnim, 0, 14);
|
||||
_startLen = 0;
|
||||
_firstChoice = 0;
|
||||
_choiceNumb = 0;
|
||||
for (uint16 i = 0; i < MAXNEWSMKPAL; ++i)
|
||||
_newPal[i] = 0;
|
||||
}
|
||||
|
||||
void DialogSubTitle::clear() {
|
||||
_sentence = 0;
|
||||
_x = _y = 0;
|
||||
_color = 0;
|
||||
_startFrame = 0;
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
void DialogChoice::clear() {
|
||||
_flag = 0;
|
||||
_sentenceIndex = 0;
|
||||
_firstSubTitle = _subTitleNumb = 0;
|
||||
for (int i = 0; i < MAXDISPCHOICES; ++i) {
|
||||
_on[i] = _off[i] = 0;
|
||||
}
|
||||
|
||||
_startFrame = 0;
|
||||
_nextDialog = 0;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
DialogManager::DialogManager(TrecisionEngine *vm) : _vm(vm) {
|
||||
_curDialog = 0;
|
||||
_curChoice = 0;
|
||||
_curSubTitle = 0;
|
||||
_curDispChoice = 0;
|
||||
_curPos = -1;
|
||||
_lastPos = -1;
|
||||
|
||||
for (int i = 0; i < MAXDIALOG; ++i)
|
||||
_dialog[i].clear();
|
||||
|
||||
for (int i = 0; i < MAXCHOICE; ++i)
|
||||
_choice[i].clear();
|
||||
|
||||
for (int i = 0; i < MAXSUBTITLES; ++i)
|
||||
_subTitles[i].clear();
|
||||
|
||||
for (int i = 0; i < MAXDISPCHOICES; ++i)
|
||||
_dispChoice[i] = 0;
|
||||
}
|
||||
|
||||
DialogManager::~DialogManager() {}
|
||||
|
||||
void DialogManager::dialogPrint(int x, int y, int c, const Common::String &txt) {
|
||||
SDText curChoice;
|
||||
curChoice.set(
|
||||
Common::Rect(x, y, _vm->textLength(txt) + x, y),
|
||||
Common::Rect(0, 0, MAXX, MAXY),
|
||||
c,
|
||||
txt
|
||||
);
|
||||
curChoice.draw(_vm);
|
||||
}
|
||||
|
||||
void DialogManager::showChoices(uint16 i) {
|
||||
assert(i < MAXDIALOG);
|
||||
|
||||
Dialog *dialog = &_dialog[i];
|
||||
|
||||
int x = 10;
|
||||
int y = 5;
|
||||
_curPos = -1;
|
||||
_lastPos = -1;
|
||||
_vm->_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
for (int c = 0; c < MAXDISPCHOICES; ++c)
|
||||
_dispChoice[c] = 0;
|
||||
|
||||
_curDispChoice = 0;
|
||||
for (int c = dialog->_firstChoice; c < dialog->_firstChoice + dialog->_choiceNumb; ++c) {
|
||||
if (isChoiceVisible(c)) {
|
||||
_dispChoice[_curDispChoice] = c;
|
||||
++_curDispChoice;
|
||||
dialogPrint(x, y, HWHITE, _vm->_sentence[_choice[c]._sentenceIndex]);
|
||||
y += CARHEI;
|
||||
}
|
||||
}
|
||||
|
||||
_vm->_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
_vm->_flagDialogMenuActive = true;
|
||||
_vm->_graphicsMgr->showCursor();
|
||||
}
|
||||
|
||||
void DialogManager::updateChoices(int16 dmx, int16 dmy) {
|
||||
if ((dmy >= MAXDISPCHOICES) && (dmy < CARHEI * _curDispChoice + 5))
|
||||
_curPos = (dmy - 5) / CARHEI;
|
||||
else
|
||||
_curPos = -1;
|
||||
|
||||
if ((_curPos != _lastPos) && ((_curPos != -1) || (_lastPos != -1))) {
|
||||
for (int c = 0; c < MAXDISPCHOICES; ++c) {
|
||||
if (_dispChoice[c] != 0) {
|
||||
if (c == _curPos)
|
||||
dialogPrint(10, 5 + c * CARHEI, HGREEN, _vm->_sentence[_choice[_dispChoice[c]]._sentenceIndex]);
|
||||
else
|
||||
dialogPrint(10, 5 + c * CARHEI, HWHITE, _vm->_sentence[_choice[_dispChoice[c]]._sentenceIndex]);
|
||||
}
|
||||
}
|
||||
_vm->_graphicsMgr->copyToScreen(0, 5, MAXX, (_curDispChoice)*CARHEI + 5);
|
||||
}
|
||||
_lastPos = _curPos;
|
||||
}
|
||||
|
||||
void DialogManager::selectChoice(int16 dmx, int16 dmy) {
|
||||
updateChoices(dmx, dmy);
|
||||
|
||||
if (_curPos != -1) {
|
||||
_vm->_flagDialogMenuActive = false;
|
||||
playChoice(_dispChoice[_curPos], false);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogManager::playDialog(uint16 i) {
|
||||
_vm->closeInventoryImmediately();
|
||||
|
||||
_curDialog = i;
|
||||
_curChoice = 0;
|
||||
_curSubTitle = 0;
|
||||
|
||||
if (_curDialog == dSHOPKEEPER1A)
|
||||
_dialog[_curDialog]._startLen = 0;
|
||||
|
||||
_vm->_animMgr->startFullMotion();
|
||||
|
||||
bool skip = false;
|
||||
int curChoice = 0;
|
||||
for (int c = _dialog[_curDialog]._firstChoice; c < _dialog[_curDialog]._firstChoice + _dialog[_curDialog]._choiceNumb; ++c) {
|
||||
if (isChoiceVisible(c))
|
||||
++curChoice;
|
||||
}
|
||||
|
||||
if ((_curDialog == dC581 && isChoiceVisible(262)) ||
|
||||
(_curDialog == dC581 && curChoice == 1) ||
|
||||
(_curDialog == dSHOPKEEPER1A && curChoice == 1))
|
||||
skip = true;
|
||||
// if there's a pre-dialog
|
||||
if (_dialog[i]._startLen > 0 && !skip) {
|
||||
_vm->_animMgr->playMovie(_dialog[i]._startAnim, 1, _dialog[i]._startLen);
|
||||
} else {
|
||||
_vm->_animMgr->smkToggleAudio(1, false);
|
||||
afterChoice();
|
||||
}
|
||||
|
||||
if (_curDialog == dSHOPKEEPER1A)
|
||||
_dialog[_curDialog]._startLen = 1;
|
||||
}
|
||||
|
||||
void DialogManager::toggleChoice(uint16 choice, bool enable) {
|
||||
if (enable)
|
||||
_choice[choice]._flag &= ~DLGCHOICE_HIDE;
|
||||
else
|
||||
_choice[choice]._flag |= DLGCHOICE_HIDE;
|
||||
}
|
||||
|
||||
void DialogManager::clearExitFlag(uint16 choice) {
|
||||
_choice[choice]._flag &= ~DLGCHOICE_EXITDLG;
|
||||
}
|
||||
|
||||
bool DialogManager::isChoiceVisible(uint16 choice) const {
|
||||
return !(_choice[choice]._flag & DLGCHOICE_HIDE);
|
||||
}
|
||||
|
||||
bool DialogManager::isDialogFinished(uint16 choice) const {
|
||||
return _choice[choice]._flag & kObjFlagDone;
|
||||
}
|
||||
|
||||
void DialogManager::afterChoice() {
|
||||
Dialog *dialog = &_dialog[_curDialog];
|
||||
|
||||
_vm->_graphicsMgr->clearScreenBufferTop();
|
||||
_vm->_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
switch (_curDialog) {
|
||||
case dTRAMP171:
|
||||
if (_curChoice == 80) {
|
||||
_vm->_obj[ocTRAMP17]._action = 213;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
} else if (_curChoice == 77) {
|
||||
_vm->_obj[ocTRAMP17]._action = 211;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case dTRAMP1714:
|
||||
if (_curChoice == 106) {
|
||||
_vm->_obj[ocTRAMP17]._action = 213;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case dTRAMP1713:
|
||||
if (_curChoice == 91) {
|
||||
_vm->_obj[ocTRAMP17]._action = 212;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case dTRAMP1716:
|
||||
if (_curChoice == 122) {
|
||||
_vm->_obj[ocTRAMP17]._action = 212;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case dTRAMP1717:
|
||||
if (_curChoice == 136) {
|
||||
_vm->setObjectVisible(ocTRAMP17, false);
|
||||
_vm->setObjectVisible(oTRAMPD17, true);
|
||||
_vm->_room[kRoom17]._bkgAnim = aBKG17B;
|
||||
_vm->addIcon(kItemSkate);
|
||||
} else if (_curChoice == 137) {
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case dGUARDIAN18:
|
||||
if ((_curChoice == 151) || (_curChoice == 152)) {
|
||||
_vm->_inventoryObj[kItemRubysPhoto]._action = 1465;
|
||||
_vm->_obj[oTESSERA1A]._action = 238;
|
||||
if (_vm->_obj[oTESSERA1A].isFlagExtra()) {
|
||||
toggleChoice(154, true);
|
||||
toggleChoice(153, false);
|
||||
} else
|
||||
toggleChoice(153, true);
|
||||
} else if (_curChoice == 154) {
|
||||
if (_vm->_obj[oTESSERA1A].isFlagExtra())
|
||||
toggleChoice(183, true);
|
||||
} else if (_curChoice == 155)
|
||||
_vm->_obj[ocGUARD18]._action = 228;
|
||||
break;
|
||||
case dF213B:
|
||||
case dF213:
|
||||
_vm->_logicMgr->setupAltRoom(kRoom21, true);
|
||||
break;
|
||||
|
||||
case dF212B:
|
||||
case dF212:
|
||||
_vm->_logicMgr->setupAltRoom(kRoom21, false);
|
||||
break;
|
||||
|
||||
case dF321:
|
||||
_vm->removeIcon(kItemMakeshiftTorch);
|
||||
_vm->_flagShowCharacter = false;
|
||||
break;
|
||||
|
||||
case dF4A3:
|
||||
_vm->_obj[oCHOCOLATES4A]._examine = 1105;
|
||||
_vm->_obj[oCHOCOLATES4A]._action = 1106;
|
||||
_vm->_obj[oDOORC4A]._action = 1118;
|
||||
_vm->_animMgr->_animTab[aBKG4A].toggleAnimArea(1, false);
|
||||
_vm->setObjectVisible(ocHELLEN4A, false);
|
||||
_vm->setObjectVisible(oHELLENA4A, true);
|
||||
break;
|
||||
|
||||
case dC581:
|
||||
_vm->setObjectVisible(oWINDOWB58, true);
|
||||
if (_curChoice == 262)
|
||||
_vm->_obj[oKEYBOARD56]._examine = 1307;
|
||||
break;
|
||||
|
||||
case dF542:
|
||||
_vm->setObjectVisible(oGRATAC54, false);
|
||||
_vm->setObjectVisible(oDOORC54, false);
|
||||
_vm->setObjectVisible(oLAVATRICEL54, false);
|
||||
_vm->setObjectVisible(oLAVATRICEF54, false);
|
||||
_vm->setObjectVisible(oGRATAA54, true);
|
||||
_vm->setObjectVisible(oCHIAVI54, true);
|
||||
_vm->setObjectVisible(od54TO55, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// If the player chose to exit the dialog
|
||||
if (_choice[_curChoice]._flag & DLGCHOICE_EXITDLG) {
|
||||
_vm->_animMgr->stopFullMotion();
|
||||
|
||||
switch (_curDialog) {
|
||||
case dPOLIZIOTTO16:
|
||||
if ((isDialogFinished(61)) && (isDialogFinished(62)) && _vm->_obj[ocPOLIZIOTTO16].isFlagExtra())
|
||||
_vm->setObjectVisible(ocPOLIZIOTTO16, false);
|
||||
break;
|
||||
|
||||
case dTRAMP171:
|
||||
if (_curChoice == 77) {
|
||||
_vm->_obj[ocTRAMP17]._action = 211;
|
||||
_vm->_obj[ocTRAMP17].setFlagPerson(false);
|
||||
} else if (_curChoice == 80)
|
||||
_vm->_obj[ocTRAMP17]._action = 213;
|
||||
else if (_curChoice == 122)
|
||||
_vm->_obj[ocTRAMP17]._action = 211;
|
||||
break;
|
||||
|
||||
case dGUARDIAN18:
|
||||
if (_curChoice == 152)
|
||||
_vm->setObjectVisible(ocGUARD18, false);
|
||||
else if (_curChoice == 155)
|
||||
_vm->startCharacterAction(a184ENTRACLUB, kRoom19, 2, 0);
|
||||
break;
|
||||
|
||||
case dEVA19:
|
||||
_vm->_obj[oDOORC18].setFlagRoomOut(false);
|
||||
_vm->_obj[oDOORC18]._action = 221;
|
||||
_vm->_obj[ocEVA19]._action = 1999;
|
||||
_vm->_obj[ocEVA19].setFlagPerson(false);
|
||||
break;
|
||||
|
||||
case dSHOPKEEPER1A:
|
||||
if (_curChoice == 185) {
|
||||
_vm->changeRoom(kRoom18, a1810ENTRADALNEGOZIO, 10);
|
||||
_vm->_obj[oDOORN18].setFlagRoomOut(false);
|
||||
_vm->_obj[oDOORN18]._action = 218;
|
||||
_vm->setObjectAnim(oDOORN18, 0);
|
||||
} else if (_curChoice == 183)
|
||||
_vm->_obj[oTESSERA1A]._action = 239;
|
||||
break;
|
||||
|
||||
case dF181:
|
||||
_vm->setObjectVisible(oRETE17, true);
|
||||
_vm->_obj[oDOORA17]._examine = 196;
|
||||
_vm->_obj[oDOORUA17]._examine = 187;
|
||||
_vm->_obj[oDOORUB17]._examine = 192;
|
||||
_vm->_obj[oDOORA17]._action = 188;
|
||||
_vm->_obj[oDOORUA17]._action = 193;
|
||||
_vm->_obj[oDOORUB17]._action = 197;
|
||||
_vm->setObjectVisible(oFINGERPAD17, false);
|
||||
_vm->_room[kRoom17].setDone(false);
|
||||
_vm->_room[kRoom17].setExtra(true);
|
||||
break;
|
||||
|
||||
case dF1C1:
|
||||
_vm->_textMgr->characterSay(kSentenceMapZoo);
|
||||
break;
|
||||
|
||||
case dF1D1:
|
||||
_vm->_textMgr->characterSay(kSentenceItWorked);
|
||||
break;
|
||||
|
||||
case dF2E1:
|
||||
_vm->_textMgr->characterSay(kSentenceGoodDeterrent);
|
||||
_vm->_obj[oCATWALKA2E]._action = 622;
|
||||
break;
|
||||
|
||||
case dF2E2:
|
||||
_vm->_textMgr->characterSay(kSentenceWastedCritter);
|
||||
_vm->_inventoryObj[kItemMicrowaveGun]._examine = 1562;
|
||||
break;
|
||||
|
||||
case dF231:
|
||||
_vm->_obj[od21TO23]._goRoom = kRoom23B;
|
||||
_vm->_obj[od24TO23]._goRoom = kRoom23B;
|
||||
break;
|
||||
|
||||
case dF291:
|
||||
_vm->_obj[oSWITCH29]._action = 479;
|
||||
_vm->_obj[od22TO29]._goRoom = kRoom29L;
|
||||
_vm->_obj[od2ATO29]._goRoom = kRoom29L;
|
||||
_vm->setObjectVisible(od22TO29, false);
|
||||
_vm->setObjectVisible(od22TO29I, true);
|
||||
break;
|
||||
|
||||
case dF2G1:
|
||||
_vm->_obj[oPANELM2G]._action = 660;
|
||||
_vm->_textMgr->characterSay(kSentenceHopeDidntWasteTheKid);
|
||||
break;
|
||||
|
||||
case dF2G2:
|
||||
_vm->_obj[od26TO2G]._goRoom = kRoom2GV;
|
||||
_vm->replaceIcon(kItemMinicom, kItemDamagedMinicom);
|
||||
break;
|
||||
|
||||
case dF321:
|
||||
_vm->startCharacterAction(a3111TRASCINA, 0, 11, 0);
|
||||
break;
|
||||
|
||||
case dF331:
|
||||
_vm->_obj[oTUBET33]._area = Common::Rect(0, 0, 0, 0);
|
||||
_vm->_textMgr->characterSay(kSentenceSecretPassage);
|
||||
break;
|
||||
|
||||
case dF362:
|
||||
playDialog(dC381);
|
||||
break;
|
||||
|
||||
case dC381:
|
||||
playDialog(dF381);
|
||||
break;
|
||||
|
||||
case dF381:
|
||||
_vm->changeRoom(kRoom41, 0, 18);
|
||||
_vm->_cyberInventory = _vm->_inventory;
|
||||
_vm->_iconBase = 0;
|
||||
_vm->_inventory.clear();
|
||||
_vm->_inventory.push_back(kItemPositioner);
|
||||
break;
|
||||
|
||||
case dF371:
|
||||
_vm->setObjectAnim(oSCAFFALE36, a3615AAPRENDESCAFFALE);
|
||||
_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
|
||||
break;
|
||||
|
||||
case dF431:
|
||||
_vm->_flagShowCharacter = true;
|
||||
_vm->startCharacterAction(aWALKIN, 0, 11, 0);
|
||||
break;
|
||||
|
||||
case dF451:
|
||||
_vm->_obj[od44TO45]._goRoom = kRoom45S;
|
||||
_vm->_textMgr->characterSay(kSentenceTheSpiderHasEscaped);
|
||||
break;
|
||||
|
||||
case dF491:
|
||||
for (int c = oPULSANTE1AD; c <= oPULSANTE33AD; ++c) {
|
||||
if (!_vm->_obj[c]._goRoom) {
|
||||
_vm->_obj[c]._goRoom = kRoom4A;
|
||||
_vm->setObjectVisible(c, true);
|
||||
_vm->setObjectVisible(c - 40, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_vm->removeIcon(kItemShaft);
|
||||
playDialog(dC4A1);
|
||||
_vm->_pathFind->setPosition(12);
|
||||
break;
|
||||
|
||||
case dC4A1:
|
||||
_vm->_flagShowCharacter = true;
|
||||
_vm->_actor->actorStop();
|
||||
_vm->_pathFind->nextStep();
|
||||
break;
|
||||
|
||||
case dF4C1:
|
||||
_vm->_inventory = _vm->_cyberInventory;
|
||||
_vm->_iconBase = 0;
|
||||
_vm->removeIcon(kItemLiftCard);
|
||||
_vm->removeIcon(kItemPen);
|
||||
_vm->removeIcon(kItemLetterboxKey);
|
||||
_vm->removeIcon(kItemLetter);
|
||||
_vm->removeIcon(kItemSubwayCard);
|
||||
_vm->removeIcon(kItemRubysPhoto);
|
||||
_vm->removeIcon(kItemPistol);
|
||||
_vm->removeIcon(kItemRubysReport);
|
||||
_vm->removeIcon(kItemMembershipCard);
|
||||
_vm->removeIcon(kItemMicrowaveGun);
|
||||
_vm->removeIcon(kItemFaultyBulb);
|
||||
_vm->removeIcon(kItemElevatorRemoteControl);
|
||||
_vm->removeIcon(kItemSecurityCard);
|
||||
_vm->removeIcon(kItemSecuritySystemSequence);
|
||||
_vm->removeIcon(kItemStethoscope);
|
||||
_vm->removeIcon(kItemRubysMedicalReport);
|
||||
_vm->removeIcon(kItemEgyptologyBook);
|
||||
_vm->addIcon(kItemPrisonMap);
|
||||
_vm->addIcon(kItemParallelCutter);
|
||||
_vm->addIcon(kItemWristComm);
|
||||
_vm->startCharacterAction(a511, 0, 1, 0);
|
||||
break;
|
||||
|
||||
case dF4P1:
|
||||
_vm->_textMgr->characterSay(kSentenceItDidntWork);
|
||||
break;
|
||||
|
||||
case dF4P2:
|
||||
_vm->_textMgr->characterSay(kSentenceTakeThatWolfman);
|
||||
break;
|
||||
|
||||
case dF562:
|
||||
_vm->_obj[oDOOR58C55]._action = 1287;
|
||||
_vm->setObjectAnim(oDOOR58C55, 0);
|
||||
_vm->_obj[oWINDOW58P55]._action = 1292;
|
||||
_vm->setObjectVisible(oWINDOW58P55, true);
|
||||
_vm->setObjectAnim(oWINDOW58P55, 0);
|
||||
break;
|
||||
|
||||
case dF5A1:
|
||||
_vm->_obj[oDOOR58C55]._action = 1286;
|
||||
_vm->_obj[oWINDOW58P55]._action = 1291;
|
||||
_vm->_obj[oWINDOWA5A]._action = 1403;
|
||||
_vm->setObjectVisible(oGUARDIA58, true);
|
||||
_choice[286]._flag |= kObjFlagDone;
|
||||
break;
|
||||
|
||||
case dC581:
|
||||
if (!isDialogFinished(886) && isDialogFinished(258)) {
|
||||
_vm->_pathFind->setPosition(1);
|
||||
playDialog(dF581);
|
||||
}
|
||||
break;
|
||||
|
||||
case dC582:
|
||||
_vm->setObjectVisible(oWINDOWA58, true);
|
||||
_vm->addIcon(kItemGovernorsCode);
|
||||
break;
|
||||
|
||||
case dC5A1:
|
||||
_vm->_obj[oWINDOWA5A]._action = 1402;
|
||||
if (_vm->_room[kRoom5A].hasExtra())
|
||||
playDialog(dF5A1);
|
||||
break;
|
||||
|
||||
case dFLOG:
|
||||
playDialog(dINTRO);
|
||||
break;
|
||||
|
||||
case dINTRO:
|
||||
_vm->changeRoom(kRoom11);
|
||||
break;
|
||||
|
||||
case dF582:
|
||||
playDialog(dFCRED);
|
||||
break;
|
||||
|
||||
case dFCRED:
|
||||
_vm->quitGame();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If another dialog starts
|
||||
if (_choice[_curChoice]._nextDialog != 0) {
|
||||
_curDialog = _choice[_curChoice]._nextDialog;
|
||||
_vm->_flagDialogActive = true;
|
||||
_curChoice = 0;
|
||||
|
||||
dialog = &_dialog[_curDialog];
|
||||
|
||||
// If there is a pre-dialog
|
||||
if (_dialog[_curDialog]._startLen > 0) {
|
||||
_vm->_animMgr->playMovie(_dialog[_curDialog]._startAnim, 1, _dialog[_curDialog]._startLen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately starts the fraud choice
|
||||
for (int c = dialog->_firstChoice; c < dialog->_firstChoice + dialog->_choiceNumb; ++c) {
|
||||
if ((_choice[c]._flag & DLGCHOICE_FRAUD) && isChoiceVisible(c)) {
|
||||
const bool singleChoice = dialog->_choiceNumb == 1;
|
||||
playChoice(c, singleChoice);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's only one option, show it immediately, otherwise show available choices
|
||||
int res = 0;
|
||||
for (int c = dialog->_firstChoice; c < dialog->_firstChoice + dialog->_choiceNumb; ++c) {
|
||||
if (isChoiceVisible(c)) {
|
||||
if (_choice[c]._flag & DLGCHOICE_EXITNOW) {
|
||||
if (res == 0)
|
||||
res = c;
|
||||
else {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res != 0) {
|
||||
const bool singleChoice = dialog->_choiceNumb == 1;
|
||||
playChoice(res, singleChoice);
|
||||
return;
|
||||
}
|
||||
|
||||
// If no option is visible, close the dialog
|
||||
res = 0;
|
||||
for (int c = dialog->_firstChoice; c < dialog->_firstChoice + dialog->_choiceNumb; ++c) {
|
||||
if (isChoiceVisible(c))
|
||||
++res;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
_vm->_animMgr->stopFullMotion();
|
||||
if (_curDialog == dC381)
|
||||
playDialog(dF381);
|
||||
return;
|
||||
}
|
||||
|
||||
showChoices(_curDialog);
|
||||
}
|
||||
|
||||
void DialogManager::dialogHandler(int numFrame) {
|
||||
if (_vm->_flagDialogActive && !_vm->_flagDialogMenuActive) {
|
||||
_vm->_graphicsMgr->hideCursor();
|
||||
if (numFrame == _subTitles[_curSubTitle]._startFrame) {
|
||||
int i = _curSubTitle;
|
||||
++_curSubTitle;
|
||||
_vm->_drawText._rect.left = _subTitles[i]._x;
|
||||
_vm->_drawText._rect.top = _subTitles[i]._y;
|
||||
_vm->_drawText._textColor = _subTitles[i]._color;
|
||||
_vm->_drawText._text = _vm->_sentence[_subTitles[i]._sentence];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DialogManager::playChoice(uint16 i, bool singleChoice) {
|
||||
assert(i < MAXCHOICE);
|
||||
|
||||
DialogChoice *choice = &_choice[i];
|
||||
const int startFrame = choice->_startFrame;
|
||||
const int endSubTitle = choice->_firstSubTitle + choice->_subTitleNumb;
|
||||
int totalLength = 0;
|
||||
|
||||
_vm->_graphicsMgr->clearScreenBufferTop();
|
||||
_vm->_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
_curChoice = i;
|
||||
_curSubTitle = choice->_firstSubTitle;
|
||||
_vm->_flagDialogMenuActive = false;
|
||||
|
||||
choice->_flag |= kObjFlagDone;
|
||||
|
||||
// if it was 'one time', disable it
|
||||
if (choice->_flag & DLGCHOICE_ONETIME)
|
||||
toggleChoice(i, false);
|
||||
|
||||
// Disable other choices
|
||||
for (int c = 0; c < MAXDISPCHOICES; ++c) {
|
||||
toggleChoice(choice->_off[c], false);
|
||||
toggleChoice(choice->_on[c], true);
|
||||
}
|
||||
|
||||
for (int c = _curSubTitle; c < endSubTitle; ++c)
|
||||
totalLength += _subTitles[c]._length - 1;
|
||||
|
||||
_vm->_graphicsMgr->hideCursor();
|
||||
_vm->_animMgr->playMovie(_dialog[_curDialog]._startAnim, startFrame, startFrame + totalLength - 1, singleChoice);
|
||||
}
|
||||
|
||||
void DialogManager::doDialog() {
|
||||
switch (_vm->_curMessage->_event) {
|
||||
case ME_STARTDIALOG:
|
||||
playDialog(_vm->_curMessage->_u16Param1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogManager::showCharacterAfterDialog() const {
|
||||
switch (_curDialog) {
|
||||
case dF321:
|
||||
case dF431:
|
||||
case dF4C1:
|
||||
case dASCENSORE12:
|
||||
case dASCENSORE13:
|
||||
case dASCENSORE16:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogManager::handleShopKeeperDialog(uint16 curObj) {
|
||||
for (int c = _dialog[dSHOPKEEPER1A]._firstChoice; c < (_dialog[dSHOPKEEPER1A]._firstChoice + _dialog[dSHOPKEEPER1A]._choiceNumb); ++c) {
|
||||
if (isChoiceVisible(c)) {
|
||||
playDialog(_vm->_obj[curObj]._goRoom);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DialogManager::syncGameStream(Common::Serializer &ser) {
|
||||
for (int i = 0; i < MAXCHOICE; ++i) {
|
||||
DialogChoice *choice = &_choice[i];
|
||||
ser.syncAsUint16LE(choice->_flag);
|
||||
ser.syncAsUint16LE(choice->_sentenceIndex);
|
||||
ser.syncAsUint16LE(choice->_firstSubTitle);
|
||||
ser.syncAsUint16LE(choice->_subTitleNumb);
|
||||
for (int j = 0; j < MAXDISPCHOICES; ++j)
|
||||
ser.syncAsUint16LE(choice->_on[j]);
|
||||
for (int j = 0; j < MAXDISPCHOICES; ++j)
|
||||
ser.syncAsUint16LE(choice->_off[j]);
|
||||
ser.syncAsUint16LE(choice->_startFrame);
|
||||
ser.syncAsUint16LE(choice->_nextDialog);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXDIALOG; ++i) {
|
||||
Dialog *dialog = &_dialog[i];
|
||||
ser.syncAsUint16LE(dialog->_flag);
|
||||
ser.syncAsUint16LE(dialog->_interlocutor);
|
||||
ser.syncBytes((byte *)dialog->_startAnim, 14);
|
||||
ser.syncAsUint16LE(dialog->_startLen);
|
||||
ser.syncAsUint16LE(dialog->_firstChoice);
|
||||
ser.syncAsUint16LE(dialog->_choiceNumb);
|
||||
for (int j = 0; j < MAXNEWSMKPAL; ++j)
|
||||
ser.syncAsUint16LE(dialog->_newPal[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogManager::loadData(Common::SeekableReadStreamEndian *stream) {
|
||||
for (int i = 0; i < MAXDIALOG; ++i) {
|
||||
Dialog *dialog = &_dialog[i];
|
||||
|
||||
dialog->_flag = stream->readUint16();
|
||||
dialog->_interlocutor = stream->readUint16();
|
||||
|
||||
stream->read(&dialog->_startAnim, 14);
|
||||
|
||||
dialog->_startLen = stream->readUint16();
|
||||
dialog->_firstChoice = stream->readUint16();
|
||||
dialog->_choiceNumb = stream->readUint16();
|
||||
|
||||
for (int j = 0; j < MAXNEWSMKPAL; ++j)
|
||||
dialog->_newPal[j] = stream->readUint16();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXCHOICE; ++i) {
|
||||
DialogChoice *choice = &_choice[i];
|
||||
|
||||
choice->_flag = stream->readUint16();
|
||||
choice->_sentenceIndex = stream->readUint16();
|
||||
choice->_firstSubTitle = stream->readUint16();
|
||||
choice->_subTitleNumb = stream->readUint16();
|
||||
|
||||
for (int j = 0; j < MAXDISPCHOICES; ++j)
|
||||
choice->_on[j] = stream->readUint16();
|
||||
|
||||
for (int j = 0; j < MAXDISPCHOICES; ++j)
|
||||
choice->_off[j] = stream->readUint16();
|
||||
|
||||
choice->_startFrame = stream->readUint16();
|
||||
choice->_nextDialog = stream->readUint16();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXSUBTITLES; ++i) {
|
||||
DialogSubTitle *subTitle = &_subTitles[i];
|
||||
|
||||
subTitle->_sentence = stream->readUint16();
|
||||
subTitle->_x = stream->readUint16();
|
||||
subTitle->_y = stream->readUint16();
|
||||
subTitle->_color = stream->readUint16();
|
||||
subTitle->_startFrame = stream->readUint16();
|
||||
subTitle->_length = stream->readUint16();
|
||||
}
|
||||
|
||||
if (_vm->isDemo()) {
|
||||
_subTitles[975]._length = 113;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
112
engines/trecision/dialog.h
Normal file
112
engines/trecision/dialog.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_DIALOG_H
|
||||
#define TRECISION_DIALOG_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Trecision {
|
||||
class TrecisionEngine;
|
||||
|
||||
#define MAXDISPCHOICES 5
|
||||
#define MAXSUBTITLES 1500
|
||||
#define MAXDIALOG 70
|
||||
#define MAXCHOICE 1000
|
||||
#define MAXNEWSMKPAL 40
|
||||
|
||||
struct Dialog {
|
||||
uint16 _flag; // DONT_SKIP .. and more
|
||||
uint16 _interlocutor; // Person I'm talking to... Maybe it's not needed
|
||||
char _startAnim[14]; // aANIMATION or text table index by filename.
|
||||
uint16 _startLen;
|
||||
uint16 _firstChoice;
|
||||
uint16 _choiceNumb;
|
||||
uint16 _newPal[MAXNEWSMKPAL];
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct DialogSubTitle {
|
||||
uint16 _sentence;
|
||||
uint16 _x, _y, _color; // you can compact this info using a bit field
|
||||
uint16 _startFrame, _length; // Frame at which the subtitle starts and its length
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct DialogChoice {
|
||||
uint16 _flag; // DLGCHOICE_HIDE|DLGCHOICE_ONETIME|DLGCHOICE_FRAUD...if used...
|
||||
uint16 _sentenceIndex; // Index in the sentence array.
|
||||
uint16 _firstSubTitle, _subTitleNumb; // starting index and number of sub title sentences
|
||||
uint16 _on[MAXDISPCHOICES], _off[MAXDISPCHOICES];
|
||||
uint16 _startFrame; // Starting frame of the choice
|
||||
uint16 _nextDialog;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
class DialogManager {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
void showChoices(uint16 i);
|
||||
void playChoice(uint16 i, bool singleChoice);
|
||||
|
||||
Dialog _dialog[MAXDIALOG];
|
||||
DialogChoice _choice[MAXCHOICE];
|
||||
|
||||
int16 _curPos;
|
||||
int16 _lastPos;
|
||||
uint16 _dispChoice[MAXDISPCHOICES];
|
||||
uint16 _curDispChoice;
|
||||
DialogSubTitle _subTitles[MAXSUBTITLES];
|
||||
uint16 _curSubTitle;
|
||||
uint16 _curDialog;
|
||||
uint16 _curChoice;
|
||||
|
||||
public:
|
||||
DialogManager(TrecisionEngine *vm);
|
||||
~DialogManager();
|
||||
|
||||
void dialogPrint(int x, int y, int c, const Common::String &txt);
|
||||
void updateChoices(int16 dmx, int16 dmy);
|
||||
void selectChoice(int16 dmx, int16 dmy);
|
||||
void playDialog(uint16 i);
|
||||
void toggleChoice(uint16 choice, bool enable);
|
||||
void clearExitFlag(uint16 choice);
|
||||
bool isChoiceVisible(uint16 choice) const;
|
||||
bool isDialogFinished(uint16 choice) const;
|
||||
void afterChoice();
|
||||
void dialogHandler(int numFrame);
|
||||
void doDialog();
|
||||
bool showCharacterAfterDialog() const;
|
||||
bool handleShopKeeperDialog(uint16 curObj);
|
||||
uint16 getCurDialog() const { return _curDialog; }
|
||||
uint16 getCurChoice() const { return _curChoice; }
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void loadData(Common::SeekableReadStreamEndian *stream);
|
||||
};
|
||||
// end of class
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
193
engines/trecision/fastfile.cpp
Normal file
193
engines/trecision/fastfile.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/file.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/fastfile.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
FastFile::FastFile() : Common::Archive(), _stream(nullptr), _compStream(nullptr), _compBuffer(nullptr) {
|
||||
}
|
||||
|
||||
FastFile::~FastFile() {
|
||||
close();
|
||||
}
|
||||
|
||||
const FileEntry *FastFile::getEntry(const Common::Path &name) const {
|
||||
for (Common::Array<FileEntry>::const_iterator it = _fileEntries.begin(); it != _fileEntries.end(); ++it) {
|
||||
if (it->name.equalsIgnoreCase(name))
|
||||
return it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FastFile::open(TrecisionEngine *vm, const Common::Path &name) {
|
||||
close();
|
||||
|
||||
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
|
||||
if (!stream)
|
||||
return false;
|
||||
_stream = vm->readEndian(stream);
|
||||
|
||||
int numFiles = _stream->readUint32();
|
||||
_fileEntries.resize(numFiles);
|
||||
for (int i = 0; i < numFiles; ++i) {
|
||||
FileEntry *entry = &_fileEntries[i];
|
||||
entry->name = Common::Path(_stream->readString(0, 12));
|
||||
entry->offset = _stream->readUint32();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FastFile::close() {
|
||||
delete _stream;
|
||||
_stream = nullptr;
|
||||
delete _compStream;
|
||||
_compStream = nullptr;
|
||||
_fileEntries.clear();
|
||||
}
|
||||
|
||||
bool FastFile::hasFile(const Common::Path &path) const {
|
||||
const FileEntry *entry = getEntry(path);
|
||||
return entry != nullptr;
|
||||
}
|
||||
|
||||
int FastFile::listMembers(Common::ArchiveMemberList &list) const {
|
||||
list.clear();
|
||||
for (Common::Array<FileEntry>::const_iterator it = _fileEntries.begin(); it != _fileEntries.end(); ++it)
|
||||
list.push_back(getMember(it->name));
|
||||
|
||||
return list.size();
|
||||
}
|
||||
|
||||
const Common::ArchiveMemberPtr FastFile::getMember(const Common::Path &path) const {
|
||||
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *FastFile::createReadStreamForMember(const Common::Path &path) const {
|
||||
if (!_stream)
|
||||
return nullptr;
|
||||
|
||||
Common::SeekableReadStream *stream = nullptr;
|
||||
const FileEntry *entry = getEntry(path);
|
||||
if (entry) {
|
||||
uint32 size = (entry + 1)->offset - entry->offset;
|
||||
if ((int32)(entry->offset + size) <= _stream->size()) {
|
||||
// Load data from fast file
|
||||
stream = new Common::SeekableSubReadStream(_stream, entry->offset, entry->offset + size);
|
||||
}
|
||||
}
|
||||
if (!stream) {
|
||||
// Load data from external file
|
||||
Common::File *file = new Common::File();
|
||||
if (file->open(path)) {
|
||||
stream = file;
|
||||
} else {
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
if (!stream) {
|
||||
warning("FastFile - %s not found", path.toString().c_str());
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
void FastFile::decompress(const uint8 *src, uint32 srcSize, uint8 *dst, uint32 decompSize) {
|
||||
const uint16 *sw = (const uint16 *)(src + srcSize);
|
||||
uint8 *d = dst;
|
||||
uint32 bytesWritten = 0;
|
||||
const uint8 *s = src;
|
||||
unsigned short ctrl = 0, ctrl_cnt = 1;
|
||||
|
||||
while (s < (const uint8 *)sw) {
|
||||
if (!--ctrl_cnt) {
|
||||
ctrl = READ_LE_UINT16(--sw);
|
||||
ctrl_cnt = 16;
|
||||
} else {
|
||||
ctrl <<= 1;
|
||||
}
|
||||
|
||||
if (ctrl & 0x8000) {
|
||||
uint16 foo = READ_LE_UINT16(--sw);
|
||||
const uint8 *cs = d - (foo >> 4);
|
||||
|
||||
uint16 num = 16 - (foo & 0xF);
|
||||
|
||||
for (uint16 i = 0; i < num; ++i) {
|
||||
*d++ = *cs++;
|
||||
++bytesWritten;
|
||||
assert(bytesWritten <= decompSize);
|
||||
}
|
||||
|
||||
*d++ = *cs++;
|
||||
*d++ = *cs;
|
||||
bytesWritten += 2;
|
||||
assert(bytesWritten <= decompSize);
|
||||
} else {
|
||||
*d++ = *s++;
|
||||
++bytesWritten;
|
||||
assert(bytesWritten <= decompSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define FAST_COOKIE 0xFA57F00D
|
||||
Common::SeekableReadStream *FastFile::createReadStreamForCompressedMember(const Common::Path &name) {
|
||||
Common::SeekableReadStream *ff = createReadStreamForMember(name);
|
||||
if (ff == nullptr)
|
||||
error("createReadStreamForCompressedMember - File not found %s", name.toString().c_str());
|
||||
|
||||
const int32 dataSize = ff->size() - 8;
|
||||
|
||||
const uint32 signature = ff->readUint32LE();
|
||||
if (signature != FAST_COOKIE)
|
||||
error("createReadStreamForCompressedMember - %s has a bad signature and can't be loaded", name.toString().c_str());
|
||||
|
||||
const int32 decompSize = ff->readSint32LE();
|
||||
|
||||
uint8 *ibuf = new uint8[dataSize];
|
||||
const int32 realSize = MAX(dataSize, decompSize) + 8 + 100; // add extra padding for the decompressor
|
||||
|
||||
delete _compStream;
|
||||
_compBuffer = (uint8 *) malloc (realSize);
|
||||
|
||||
ff->read(ibuf, dataSize);
|
||||
delete ff;
|
||||
|
||||
if (dataSize < decompSize)
|
||||
decompress(ibuf, dataSize, _compBuffer, realSize);
|
||||
else
|
||||
memcpy(_compBuffer, ibuf, dataSize);
|
||||
|
||||
delete[] ibuf;
|
||||
|
||||
_compStream = new Common::MemoryReadStream(_compBuffer, realSize, DisposeAfterUse::YES);
|
||||
return _compStream;
|
||||
}
|
||||
} // End of namespace Trecision
|
||||
66
engines/trecision/fastfile.h
Normal file
66
engines/trecision/fastfile.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_FASTFILE_H
|
||||
#define TRECISION_FASTFILE_H
|
||||
|
||||
#include "common/archive.h"
|
||||
#include "common/array.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
struct FileEntry {
|
||||
Common::Path name;
|
||||
uint32 offset;
|
||||
};
|
||||
|
||||
class FastFile : public Common::Archive {
|
||||
public:
|
||||
FastFile();
|
||||
~FastFile() override;
|
||||
|
||||
bool open(TrecisionEngine *vm, const Common::Path &filename);
|
||||
void close();
|
||||
bool isOpen() const { return _stream != 0; }
|
||||
Common::SeekableReadStream *createReadStreamForCompressedMember(const Common::Path &name);
|
||||
|
||||
// Common::Archive API implementation
|
||||
bool hasFile(const Common::Path &path) const override;
|
||||
int listMembers(Common::ArchiveMemberList &list) const override;
|
||||
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
|
||||
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
|
||||
|
||||
private:
|
||||
Common::SeekableReadStreamEndian *_stream;
|
||||
Common::SeekableReadStream *_compStream;
|
||||
Common::Array<FileEntry> _fileEntries;
|
||||
|
||||
uint8 *_compBuffer;
|
||||
const FileEntry *getEntry(const Common::Path &name) const;
|
||||
void decompress(const uint8 *src, uint32 srcSize, uint8 *dst, uint32 decompSize);
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
|
||||
#endif
|
||||
840
engines/trecision/graphics.cpp
Normal file
840
engines/trecision/graphics.cpp
Normal file
@@ -0,0 +1,840 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/system.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/renderer3d.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
GraphicsManager::GraphicsManager(TrecisionEngine *vm) : _vm(vm), _rgb555Format(2, 5, 5, 5, 0, 10, 5, 0, 0) {
|
||||
for (int i = 0; i < 3; ++i)
|
||||
_bitMask[i] = 0;
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
_fonts[i]._width = 0;
|
||||
_fonts[i]._data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsManager::~GraphicsManager() {
|
||||
_screenBuffer.free();
|
||||
_background.free();
|
||||
_smkBackground.free();
|
||||
_leftInventoryArrow.free();
|
||||
_rightInventoryArrow.free();
|
||||
_inventoryIcons.free();
|
||||
_saveSlotThumbnails.free();
|
||||
_textureMat.free();
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
delete[] _fonts[i]._data;
|
||||
}
|
||||
|
||||
bool GraphicsManager::init() {
|
||||
// Find a suitable 16-bit format, currently we don't support other color depths
|
||||
Common::List<Graphics::PixelFormat> formats = g_system->getSupportedFormats();
|
||||
for (Common::List<Graphics::PixelFormat>::iterator it = formats.begin(); it != formats.end(); ++it) {
|
||||
if (it->bytesPerPixel != 2 || it->aBits()) {
|
||||
it = formats.reverse_erase(it);
|
||||
} else if (*it == _rgb555Format) {
|
||||
formats.clear();
|
||||
formats.push_back(_rgb555Format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (formats.empty())
|
||||
return false;
|
||||
|
||||
initGraphics(MAXX, MAXY, formats);
|
||||
|
||||
_screenFormat = g_system->getScreenFormat();
|
||||
if (_screenFormat.bytesPerPixel != 2)
|
||||
return false;
|
||||
_bitMask[0] = _screenFormat.rMax() << _screenFormat.rShift;
|
||||
_bitMask[1] = _screenFormat.gMax() << _screenFormat.gShift;
|
||||
_bitMask[2] = _screenFormat.bMax() << _screenFormat.bShift;
|
||||
|
||||
clearScreen();
|
||||
|
||||
_screenBuffer.create(MAXX, MAXY, _screenFormat);
|
||||
_background.create(MAXX, MAXY, _screenFormat);
|
||||
_smkBackground.create(MAXX, AREA, _screenFormat);
|
||||
_saveSlotThumbnails.create(READICON * ICONDX, ICONDY, _screenFormat);
|
||||
|
||||
loadData();
|
||||
initCursor();
|
||||
hideCursor();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicsManager::addDirtyRect(Common::Rect rect, bool translateRect) {
|
||||
if (translateRect)
|
||||
rect.translate(0, TOP);
|
||||
|
||||
_dirtyRects.push_back(rect);
|
||||
}
|
||||
|
||||
void GraphicsManager::drawObj(int index, bool mask, Common::Rect drawRect, Common::Rect drawObjRect, bool includeDirtyRect) {
|
||||
if (drawObjRect.left > MAXX || drawObjRect.top > MAXY)
|
||||
return;
|
||||
|
||||
// If we have a valid object, draw it, otherwise erase it
|
||||
// by using the background buffer
|
||||
const uint16 *buf = index >= 0 ? _vm->_objectGraphics[index].buf : (uint16 *)_smkBackground.getPixels();
|
||||
if (mask && index >= 0) {
|
||||
uint8 *maskPtr = _vm->_objectGraphics[index].mask;
|
||||
|
||||
for (uint16 y = drawRect.top; y < drawRect.bottom; ++y) {
|
||||
uint16 x = 0;
|
||||
bool copyBytes = false;
|
||||
while (x < drawRect.width()) {
|
||||
if (!copyBytes) { // jump
|
||||
x += *maskPtr;
|
||||
++maskPtr;
|
||||
|
||||
copyBytes = true;
|
||||
} else { // copy
|
||||
const uint16 maskOffset = *maskPtr;
|
||||
|
||||
if (maskOffset != 0 && y >= drawRect.top + drawObjRect.top && y < drawRect.top + drawObjRect.bottom) {
|
||||
const void *src = (x >= drawObjRect.left) ? buf : buf + drawObjRect.left - x;
|
||||
int offset = (x >= drawObjRect.left) ? x : drawObjRect.left;
|
||||
void *dst = _screenBuffer.getBasePtr(offset + drawRect.left, y);
|
||||
|
||||
if (x >= drawObjRect.left && x + maskOffset < drawObjRect.right)
|
||||
memcpy(dst, src, maskOffset * 2);
|
||||
else if (x < drawObjRect.left && x + maskOffset < drawObjRect.right && x + maskOffset >= drawObjRect.left)
|
||||
memcpy(dst, src, (maskOffset + x - drawObjRect.left) * 2);
|
||||
else if (x >= drawObjRect.left && x + maskOffset >= drawObjRect.right && x < drawObjRect.right)
|
||||
memcpy(dst, src, (drawObjRect.right - x) * 2);
|
||||
else if (x < drawObjRect.left && x + maskOffset >= drawObjRect.right)
|
||||
memcpy(dst, src, (drawObjRect.right - drawObjRect.left) * 2);
|
||||
}
|
||||
x += *maskPtr;
|
||||
buf += *maskPtr++;
|
||||
copyBytes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const uint16 x = drawRect.left + drawObjRect.left;
|
||||
|
||||
if (x + drawObjRect.width() > MAXX || drawObjRect.top + drawObjRect.height() > MAXY) {
|
||||
warning("drawObj: Invalid surface, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16 y = drawObjRect.top; y < drawObjRect.bottom; ++y) {
|
||||
memcpy(_screenBuffer.getBasePtr(x, drawRect.top + y),
|
||||
buf + (y * drawRect.width()) + drawObjRect.left, drawObjRect.width() * 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (includeDirtyRect)
|
||||
addDirtyRect(drawObjRect, true);
|
||||
}
|
||||
|
||||
void GraphicsManager::eraseObj(Common::Rect drawObjRect) {
|
||||
Common::Rect eraseRect = drawObjRect;
|
||||
eraseRect.translate(0, TOP);
|
||||
if (eraseRect.isValidRect())
|
||||
_screenBuffer.fillRect(eraseRect, 0);
|
||||
}
|
||||
|
||||
void GraphicsManager::clearScreen() {
|
||||
g_system->fillScreen(0);
|
||||
}
|
||||
|
||||
void GraphicsManager::copyToScreenBuffer(const Graphics::Surface *surface, int x, int y, const byte *palette) {
|
||||
Graphics::Surface *surface16 = surface->convertTo(_screenFormat, palette);
|
||||
|
||||
copyToScreenBufferInner(surface16, x, y);
|
||||
|
||||
surface16->free();
|
||||
delete surface16;
|
||||
}
|
||||
|
||||
void GraphicsManager::copyToScreenBufferInner(const Graphics::Surface *surface, int x, int y) {
|
||||
if (x + surface->w > MAXX || y + surface->h > MAXY) {
|
||||
warning("copyToScreenBufferInner: Invalid surface, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int curY = 0; curY < surface->h; ++curY) {
|
||||
// NOTE: We use surface width for the pitch so that memcpy works
|
||||
// correctly with surfaces from getSubArea()
|
||||
memcpy(_screenBuffer.getBasePtr(x, y + curY), surface->getBasePtr(0, curY), surface->w * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsManager::blitToScreenBuffer(const Graphics::Surface *surface, int x, int y, const byte *palette, bool useSmkBg) {
|
||||
if (x + surface->w > MAXX || y + surface->h > MAXY) {
|
||||
warning("blitToScreenBuffer: Invalid surface, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16 mask = (uint16)_screenFormat.RGBToColor(palette[0], palette[1], palette[2]);
|
||||
Graphics::Surface *surface16 = surface->convertTo(_screenFormat, palette);
|
||||
|
||||
for (int curY = 0; curY < surface16->h; ++curY) {
|
||||
for (int curX = 0; curX < surface16->w; ++curX) {
|
||||
const int destX = x + curX;
|
||||
const int destY = y + curY;
|
||||
const uint16 pixel = (uint16)surface16->getPixel(curX, curY);
|
||||
if (pixel != mask) {
|
||||
_screenBuffer.setPixel(destX, destY, pixel);
|
||||
if (useSmkBg)
|
||||
_smkBackground.setPixel(destX, destY - TOP, pixel);
|
||||
} else if (useSmkBg) {
|
||||
const uint16 bgPixel = _background.getPixel(destX, destY - TOP);
|
||||
_screenBuffer.setPixel(destX, destY, bgPixel);
|
||||
_smkBackground.setPixel(destX, destY - TOP, bgPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surface16->free();
|
||||
delete surface16;
|
||||
}
|
||||
|
||||
void GraphicsManager::copyToScreen(int x, int y, int w, int h) {
|
||||
g_system->copyRectToScreen(
|
||||
_screenBuffer.getBasePtr(x, y),
|
||||
MAXX * 2, x, y, w, h
|
||||
);
|
||||
}
|
||||
|
||||
void GraphicsManager::readSurface(Common::SeekableReadStream *stream, Graphics::Surface *surface, uint16 width, uint16 height, uint16 count) {
|
||||
surface->create(width * count, height, _rgb555Format);
|
||||
|
||||
for (uint16 i = 0; i < count; ++i) {
|
||||
for (uint16 y = 0; y < height; ++y) {
|
||||
for (uint16 x = 0; x < width; ++x) {
|
||||
surface->setPixel(width * i + x, y, stream->readUint16LE());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surface->convertToInPlace(_screenFormat);
|
||||
}
|
||||
|
||||
void GraphicsManager::readTexture(Common::SeekableReadStream *stream) {
|
||||
readSurface(stream, &_textureMat, 91, 256);
|
||||
}
|
||||
|
||||
void GraphicsManager::drawTexturePixel(uint16 textureX, uint16 textureY, uint16 screenX, uint16 screenY) {
|
||||
const uint16 texturePixel = (uint16)_textureMat.getPixel(textureX, textureY);
|
||||
_screenBuffer.setPixel(screenX, screenY, texturePixel);
|
||||
}
|
||||
|
||||
void GraphicsManager::loadBackground(Common::SeekableReadStream *stream) {
|
||||
SObject bgInfo;
|
||||
bgInfo.readRect(stream);
|
||||
|
||||
readSurface(stream, &_background, bgInfo._rect.width(), bgInfo._rect.height());
|
||||
_smkBackground.copyFrom(_background);
|
||||
memcpy(_screenBuffer.getBasePtr(0, TOP), _background.getPixels(), _background.pitch * _background.h);
|
||||
}
|
||||
|
||||
void GraphicsManager::loadData() {
|
||||
Common::SeekableReadStream *arrowsDataFile = _vm->_dataFile.createReadStreamForMember("frecc.bm");
|
||||
// The data file contains images for deactivated arrows, which aren't used. Skip them.
|
||||
arrowsDataFile->skip(ICONMARGDX * ICONDY * 2 * 3);
|
||||
readSurface(arrowsDataFile, &_leftInventoryArrow, ICONMARGSX, ICONDY);
|
||||
readSurface(arrowsDataFile, &_rightInventoryArrow, ICONMARGSX, ICONDY);
|
||||
delete arrowsDataFile;
|
||||
|
||||
Common::SeekableReadStream *iconsDataFile = _vm->_dataFile.createReadStreamForMember("icone.bm");
|
||||
readSurface(iconsDataFile, &_inventoryIcons, ICONDX, ICONDY, READICON);
|
||||
delete iconsDataFile;
|
||||
|
||||
loadFont();
|
||||
}
|
||||
|
||||
void GraphicsManager::setSaveSlotThumbnail(byte iconSlot, const Graphics::Surface *thumbnail) {
|
||||
Graphics::Surface *scaled = thumbnail->scale(ICONDX, ICONDY);
|
||||
scaled->convertToInPlace(_screenFormat);
|
||||
|
||||
for (uint16 y = 0; y < ICONDY; ++y) {
|
||||
memcpy(_saveSlotThumbnails.getBasePtr(ICONDX * iconSlot, y), scaled->getBasePtr(0, y), ICONDX * 2);
|
||||
}
|
||||
|
||||
scaled->free();
|
||||
delete scaled;
|
||||
}
|
||||
|
||||
void GraphicsManager::drawLeftInventoryArrow(byte startLine) {
|
||||
Graphics::Surface arrow = _leftInventoryArrow.getSubArea(Common::Rect(
|
||||
0, startLine, _leftInventoryArrow.w, _leftInventoryArrow.h
|
||||
));
|
||||
copyToScreenBufferInner(&arrow, 0, FIRSTLINE);
|
||||
}
|
||||
|
||||
void GraphicsManager::drawRightInventoryArrow(byte startLine) {
|
||||
Graphics::Surface arrow = _rightInventoryArrow.getSubArea(Common::Rect(
|
||||
0, startLine, _rightInventoryArrow.w, _rightInventoryArrow.h
|
||||
));
|
||||
copyToScreenBufferInner(&arrow, MAXX - ICONMARGDX, FIRSTLINE);
|
||||
}
|
||||
|
||||
void GraphicsManager::drawInventoryIcon(byte iconIndex, byte iconSlot, byte startLine) {
|
||||
Graphics::Surface icon = _inventoryIcons.getSubArea(Common::Rect(
|
||||
iconIndex * ICONDX,
|
||||
startLine,
|
||||
iconIndex * ICONDX + ICONDX,
|
||||
_inventoryIcons.h
|
||||
));
|
||||
copyToScreenBufferInner(&icon, iconSlot * ICONDX + ICONMARGSX, FIRSTLINE);
|
||||
}
|
||||
|
||||
void GraphicsManager::drawSaveSlotThumbnail(byte iconIndex, byte iconSlot, byte startLine) {
|
||||
Graphics::Surface icon = _saveSlotThumbnails.getSubArea(Common::Rect(
|
||||
iconIndex * ICONDX,
|
||||
startLine,
|
||||
iconIndex * ICONDX + ICONDX,
|
||||
_saveSlotThumbnails.h
|
||||
));
|
||||
copyToScreenBufferInner(&icon, iconSlot * ICONDX + ICONMARGSX, FIRSTLINE);
|
||||
}
|
||||
|
||||
void GraphicsManager::clearScreenBuffer() {
|
||||
_screenBuffer.fillRect(Common::Rect(0, 0, MAXX, MAXY), 0);
|
||||
}
|
||||
|
||||
void GraphicsManager::clearScreenBufferTop() {
|
||||
// Clears lines 0 - 60
|
||||
_screenBuffer.fillRect(Common::Rect(0, 0, MAXX, TOP), 0);
|
||||
}
|
||||
|
||||
void GraphicsManager::clearScreenBufferInventory() {
|
||||
// Clears lines 420 - 480
|
||||
_screenBuffer.fillRect(Common::Rect(0, FIRSTLINE, MAXX, MAXY), 0);
|
||||
}
|
||||
|
||||
void GraphicsManager::clearScreenBufferSaveSlotDescriptions() {
|
||||
// Clears lines 470 - 480
|
||||
_screenBuffer.fillRect(Common::Rect(0, FIRSTLINE + ICONDY + 10, MAXX, MAXY), 0);
|
||||
}
|
||||
|
||||
uint16 GraphicsManager::convertToScreenFormat(uint16 color) const {
|
||||
uint8 r, g, b;
|
||||
_rgb555Format.colorToRGB(color, r, g, b);
|
||||
return (uint16)_screenFormat.RGBToColor(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shadow Pixel
|
||||
* (dark) 0..8 (light)
|
||||
*/
|
||||
void GraphicsManager::shadow(uint16 x, uint16 y, uint8 num) {
|
||||
if (x > MAXX || y > MAXY) {
|
||||
warning("shadow: Invalid pixel, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16 val = (uint16)_screenBuffer.getPixel(x, y);
|
||||
const uint16 shadowVal =
|
||||
((((val & _bitMask[2]) * num >> 7) & _bitMask[2]) |
|
||||
(((val & _bitMask[1]) * num >> 7) & _bitMask[1]) |
|
||||
(((val & _bitMask[0]) * num >> 7) & _bitMask[0]));
|
||||
_screenBuffer.setPixel(x, y, shadowVal);
|
||||
}
|
||||
|
||||
void GraphicsManager::pixelAliasing(uint16 x, uint16 y) {
|
||||
if (x > MAXX || y > MAXY) {
|
||||
warning("pixelAliasing: Invalid pixel, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
int px1 = _screenBuffer.getPixel(x - 1, y);
|
||||
int px2 = _screenBuffer.getPixel(x, y);
|
||||
|
||||
_screenBuffer.setPixel(x - 1, y, aliasing(px1, px2, 6)); // 75% 25%
|
||||
_screenBuffer.setPixel(x, y, aliasing(px1, px2, 2)); // 25% 75%
|
||||
}
|
||||
|
||||
/**
|
||||
* Aliasing Pixel
|
||||
*/
|
||||
uint16 GraphicsManager::aliasing(uint32 val1, uint32 val2, uint8 num) {
|
||||
// 0: 0% val1 100% val2
|
||||
// 1: 12% val1 87% val2
|
||||
// 2: 25% val1 75% val2
|
||||
// 3: 37% val1 62% val2
|
||||
// 4: 50% val1 50% val2
|
||||
// 5: 62% val1 37% val2
|
||||
// 6: 75% val1 25% val2
|
||||
// 7: 87% val1 12% val2
|
||||
// 8: 100% val1 0% val2
|
||||
|
||||
return (((((val1 & _bitMask[2]) * num + (val2 & _bitMask[2]) * (8 - num)) >> 3) & _bitMask[2]) |
|
||||
((((val1 & _bitMask[1]) * num + (val2 & _bitMask[1]) * (8 - num)) >> 3) & _bitMask[1]) |
|
||||
((((val1 & _bitMask[0]) * num + (val2 & _bitMask[0]) * (8 - num)) >> 3) & _bitMask[0]));
|
||||
}
|
||||
|
||||
void GraphicsManager::dissolve() {
|
||||
const uint16 val = 30;
|
||||
uint16 centerX = MAXX / 2;
|
||||
uint16 centerY = MAXY / 2;
|
||||
|
||||
int lastv = 9000;
|
||||
|
||||
uint32 sv = _vm->readTime();
|
||||
uint32 cv = _vm->readTime();
|
||||
|
||||
while (sv + val > cv) {
|
||||
_vm->checkSystem();
|
||||
if (lastv + cv < sv + val) {
|
||||
cv = _vm->readTime();
|
||||
continue;
|
||||
}
|
||||
|
||||
lastv = (sv - cv) + val;
|
||||
|
||||
const float a = (float)(((centerX + 200) / val) * lastv);
|
||||
const float b = (float)((centerY / val) * lastv);
|
||||
|
||||
float x = 0.0f;
|
||||
float y = b;
|
||||
|
||||
if (centerY - (int)y > TOP)
|
||||
memset(_screenBuffer.getBasePtr(0, TOP), 0, (centerY - (int)y - TOP) * MAXX * 2);
|
||||
if (AREA + TOP > centerY + (int)y)
|
||||
memset(_screenBuffer.getBasePtr(0, centerY + (int)y), 0, (AREA + TOP - (centerY + (int)y)) * MAXX * 2);
|
||||
|
||||
float d1 = b * b - a * a * b + a * a / 4.0f;
|
||||
while (_vm->floatComp(a * a * (y - 0.5f), b * b * (x + 1.0f)) == 1) {
|
||||
if (_vm->floatComp(d1, 0.0f) == -1)
|
||||
d1 += b * b * (2.0f * x + 3.0f);
|
||||
else {
|
||||
d1 += b * b * (2.0f * x + 3.0f) + a * a * (-2.0f * y + 2.0f);
|
||||
y -= 1.0f;
|
||||
}
|
||||
x += 1.0f;
|
||||
|
||||
int rightX = centerX + (int)x;
|
||||
int maxY = centerY + (int)y;
|
||||
int minY = centerY - (int)y;
|
||||
if (rightX < MAXX) {
|
||||
if (maxY < MAXY)
|
||||
memset(_screenBuffer.getBasePtr(rightX, maxY), 0, (MAXX - rightX) * 2);
|
||||
if (minY >= 0)
|
||||
memset(_screenBuffer.getBasePtr(rightX, minY), 0, (MAXX - rightX) * 2);
|
||||
}
|
||||
int leftX = centerX - (int)x;
|
||||
if (leftX > 0) {
|
||||
if (maxY < MAXY)
|
||||
memset(_screenBuffer.getBasePtr(0, maxY), 0, leftX * 2);
|
||||
if (minY >= 0)
|
||||
memset(_screenBuffer.getBasePtr(0, minY), 0, leftX * 2);
|
||||
}
|
||||
}
|
||||
|
||||
float d2 = b * b * (x + 0.5f) * (x + 0.5f) + a * a * (y - 1.0f) * (y - 1.0f) - a * a * b * b;
|
||||
while (_vm->floatComp(y, 0.0f) == 1) {
|
||||
if (_vm->floatComp(d2, 0.0f) == -1) {
|
||||
d2 += b * b * (2.0f * x + 2.0f) + a * a * (-2.0f * y + 3.0f);
|
||||
x += 1.0f;
|
||||
} else
|
||||
d2 += a * a * (-2.0f * y + 3.0f);
|
||||
y -= 1.0f;
|
||||
|
||||
int rightX = centerX + (int)x;
|
||||
int maxY = centerY + (int)y;
|
||||
int minY = centerY - (int)y;
|
||||
if (rightX < MAXX) {
|
||||
if (maxY < MAXY)
|
||||
memset(_screenBuffer.getBasePtr(rightX, maxY), 0, (MAXX - rightX) * 2);
|
||||
if (minY >= 0)
|
||||
memset(_screenBuffer.getBasePtr(rightX, minY), 0, (MAXX - rightX) * 2);
|
||||
}
|
||||
int leftX = centerX - (int)x;
|
||||
if (leftX > 0) {
|
||||
if (maxY < MAXY)
|
||||
memset(_screenBuffer.getBasePtr(0, maxY), 0, leftX * 2);
|
||||
if (minY >= 0)
|
||||
memset(_screenBuffer.getBasePtr(0, minY), 0, leftX * 2);
|
||||
}
|
||||
}
|
||||
|
||||
copyToScreen(0, 0, MAXX, MAXY);
|
||||
cv = _vm->readTime();
|
||||
}
|
||||
|
||||
clearScreen();
|
||||
}
|
||||
|
||||
void GraphicsManager::paintScreen(bool flag) {
|
||||
_vm->_animTypeMgr->next();
|
||||
|
||||
_dirtyRects.clear();
|
||||
_vm->_flagPaintCharacter = true; // always redraws the character
|
||||
|
||||
// erase character
|
||||
if (_vm->_flagShowCharacter && _vm->_actor->actorRectIsValid()) { // if a description exists
|
||||
Common::Rect actorRect = _vm->_actor->getActorRect();
|
||||
actorRect.translate(0, -TOP);
|
||||
drawObj(-1, false, Common::Rect(0, TOP, MAXX, AREA + TOP), actorRect);
|
||||
} else if (_vm->_animMgr->_animRect.left != MAXX) {
|
||||
drawObj(-1, false, Common::Rect(0, TOP, MAXX, AREA + TOP), _vm->_animMgr->_animRect);
|
||||
}
|
||||
|
||||
// If there's text to remove
|
||||
if (_vm->_textStatus & TEXT_DEL) {
|
||||
// remove text
|
||||
Common::Rect drawObjRect = _vm->_textMgr->getOldTextRect();
|
||||
drawObjRect.translate(0, -TOP);
|
||||
|
||||
if (drawObjRect.top >= 0 && drawObjRect.bottom < AREA) {
|
||||
drawObj(-1, false, Common::Rect(0, TOP, MAXX, MAXY + TOP), drawObjRect);
|
||||
} else {
|
||||
eraseObj(drawObjRect);
|
||||
}
|
||||
_vm->_textMgr->clearOldText();
|
||||
|
||||
if (!(_vm->_textStatus & TEXT_DRAW)) // if there's no new text
|
||||
_vm->_textStatus = TEXT_OFF; // stop updating text
|
||||
}
|
||||
|
||||
// Suppress all the objects you removed
|
||||
for (Common::List<SSortTable>::iterator it = _vm->_sortTable.begin(); it != _vm->_sortTable.end(); ++it) {
|
||||
if (it->_remove) {
|
||||
drawObj(-1, false, Common::Rect(0, TOP, MAXX, AREA + TOP), _vm->_obj[it->_objectId]._rect);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the position of the character
|
||||
_vm->_pathFind->actorOrder();
|
||||
|
||||
// For every box from the horizon forward...
|
||||
// Copy per level
|
||||
for (int liv = _vm->_pathFind->_numSortPanel; liv >= 0; --liv) {
|
||||
uint16 curBox = _vm->_pathFind->_sortPan[liv]._num;
|
||||
|
||||
// draws all objects and animations that intersect the boundaries and refer to the current box
|
||||
paintObjAnm(curBox);
|
||||
}
|
||||
|
||||
if (_vm->_textStatus & TEXT_DRAW) {
|
||||
_vm->_textMgr->drawCurString();
|
||||
_vm->_textStatus = TEXT_DRAW; // Activate text update
|
||||
}
|
||||
|
||||
_vm->_actor->updateStepSound();
|
||||
|
||||
if (!flag && !_vm->_flagDialogActive) {
|
||||
copyToScreen(0, 0, MAXX, MAXY);
|
||||
}
|
||||
|
||||
_vm->_sortTable.clear();
|
||||
|
||||
_vm->_flagPaintCharacter = false;
|
||||
_vm->_flagWaitRegen = false;
|
||||
|
||||
// Handle papaverine delayed action
|
||||
if (_vm->_curRoom == kRoom4A && _vm->_obj[oCHOCOLATES4A].isFlagExtra()) {
|
||||
if (_vm->_animMgr->smkCurFrame(kSmackerBackground) > 480) {
|
||||
_vm->playScript(s4AHELLEN);
|
||||
_vm->_obj[oCHOCOLATES4A].setFlagExtra(false);
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw all objects and animations that intersect
|
||||
* boundaries belonging to curbox
|
||||
*/
|
||||
void GraphicsManager::paintObjAnm(uint16 curBox) {
|
||||
_vm->_animMgr->refreshAnim(curBox);
|
||||
|
||||
// draws new cards belonging to the current box
|
||||
for (Common::List<SSortTable>::iterator it = _vm->_sortTable.begin(); it != _vm->_sortTable.end(); ++it) {
|
||||
if (!it->_remove && _vm->_obj[it->_objectId]._nbox == curBox) {
|
||||
// the bitmap object at the desired level
|
||||
SObject obj = _vm->_obj[it->_objectId];
|
||||
Common::Rect drawRect = obj._rect;
|
||||
drawRect.translate(0, TOP);
|
||||
drawObj(_vm->getRoomObjectIndex(it->_objectId), obj.isModeMask(), drawRect, Common::Rect(drawRect.width(), drawRect.height()), false);
|
||||
_dirtyRects.push_back(drawRect);
|
||||
}
|
||||
}
|
||||
|
||||
for (DirtyRectsIterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
|
||||
for (int i = 0; i < MAXOBJINROOM; ++i) {
|
||||
const uint16 curObject = _vm->_room[_vm->_curRoom]._object[i];
|
||||
if (!curObject)
|
||||
break;
|
||||
|
||||
SObject obj = _vm->_obj[curObject];
|
||||
|
||||
if ((obj.isModeFull() || obj.isModeMask()) && _vm->isObjectVisible(curObject) && (obj._nbox == curBox)) {
|
||||
Common::Rect r = *it;
|
||||
Common::Rect r2 = obj._rect;
|
||||
|
||||
r2.translate(0, TOP);
|
||||
|
||||
// Include the bottom right of the rect in the intersects() check
|
||||
++r2.bottom;
|
||||
++r2.right;
|
||||
|
||||
if (r.intersects(r2)) {
|
||||
Common::Rect drawRect = obj._rect;
|
||||
drawRect.translate(0, TOP);
|
||||
|
||||
// Restore the bottom right of the rect
|
||||
--r2.bottom;
|
||||
--r2.right;
|
||||
|
||||
// TODO: Simplify this?
|
||||
const int16 xr1 = (r2.left > r.left) ? 0 : r.left - r2.left;
|
||||
const int16 yr1 = (r2.top > r.top) ? 0 : r.top - r2.top;
|
||||
const int16 xr2 = MIN<int16>(r.right, r2.right) - r2.left;
|
||||
const int16 yr2 = MIN<int16>(r.bottom, r2.bottom) - r2.top;
|
||||
drawObj(i, obj.isModeMask(), drawRect, Common::Rect(xr1, yr1, xr2, yr2), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_vm->_pathFind->getActorPos() == curBox && _vm->_flagShowCharacter) {
|
||||
_vm->_renderer->drawCharacter(CALCPOINTS);
|
||||
|
||||
if (_vm->_actor->actorRectIsValid()) {
|
||||
const Common::Rect actorRect = _vm->_actor->getActorRect();
|
||||
// enlarge the last dirty rectangle with the actor's rectangle
|
||||
if (!_dirtyRects.empty())
|
||||
_dirtyRects.back().extend(actorRect);
|
||||
|
||||
_vm->_renderer->resetZBuffer(actorRect);
|
||||
}
|
||||
|
||||
_vm->_renderer->drawCharacter(DRAWFACES);
|
||||
|
||||
} else if (_vm->_pathFind->getActorPos() == curBox && !_vm->_flagDialogActive) {
|
||||
_vm->_animMgr->refreshActionAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
uint16 GraphicsManager::getCharWidth(byte character) {
|
||||
return _fonts[character]._width;
|
||||
}
|
||||
|
||||
void GraphicsManager::drawChar(byte curChar, uint16 textColor, uint16 line, Common::Rect rect, Common::Rect subtitleRect, uint16 inc, Graphics::Surface *externalSurface) {
|
||||
uint16 fontDataOffset = 0;
|
||||
const uint16 charWidth = getCharWidth(curChar);
|
||||
|
||||
for (uint16 y = line * CARHEI; y < (line + 1) * CARHEI; ++y) {
|
||||
uint16 curPos = 0;
|
||||
uint16 curColor = MASKCOL;
|
||||
|
||||
while (curPos <= charWidth - 1) {
|
||||
if (y >= subtitleRect.top && y < subtitleRect.bottom) {
|
||||
if (curColor != MASKCOL && _fonts[curChar]._data[fontDataOffset]) {
|
||||
const uint16 charLeft = inc + curPos;
|
||||
const uint16 charRight = charLeft + _fonts[curChar]._data[fontDataOffset];
|
||||
drawCharPixel(
|
||||
y,
|
||||
charLeft,
|
||||
charRight,
|
||||
rect,
|
||||
subtitleRect,
|
||||
curColor,
|
||||
externalSurface
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
curPos += _fonts[curChar]._data[fontDataOffset];
|
||||
++fontDataOffset;
|
||||
|
||||
if (curColor == MASKCOL)
|
||||
curColor = 0;
|
||||
else if (curColor == 0)
|
||||
curColor = textColor;
|
||||
else if (curColor == textColor)
|
||||
curColor = MASKCOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsManager::drawCharPixel(uint16 y, uint16 charLeft, uint16 charRight, Common::Rect rect, Common::Rect subtitleRect, uint16 color, Graphics::Surface *externalSurface) {
|
||||
Graphics::Surface *surface = externalSurface ? externalSurface : &_screenBuffer;
|
||||
uint16 *dst1 = (uint16 *)surface->getBasePtr(rect.left + charLeft, rect.top + y);
|
||||
uint16 *dst2 = (uint16 *)surface->getBasePtr(rect.left + subtitleRect.left, rect.top + y);
|
||||
uint16 *dst = nullptr;
|
||||
uint16 size = 0;
|
||||
|
||||
if (charLeft >= subtitleRect.left && charRight < subtitleRect.right) {
|
||||
dst = dst1;
|
||||
size = charRight - charLeft;
|
||||
} else if (charLeft < subtitleRect.left && charRight < subtitleRect.right && charRight > subtitleRect.left) {
|
||||
dst = dst2;
|
||||
size = charRight - subtitleRect.left;
|
||||
} else if (charLeft >= subtitleRect.left && charRight >= subtitleRect.right && subtitleRect.right > charLeft) {
|
||||
dst = dst1;
|
||||
size = subtitleRect.right - charLeft;
|
||||
} else if (charLeft < subtitleRect.left && charRight >= subtitleRect.right && subtitleRect.right > charLeft) {
|
||||
dst = dst2;
|
||||
size = subtitleRect.right - subtitleRect.left;
|
||||
}
|
||||
|
||||
if (dst && size > 0) {
|
||||
uint16 *d = dst;
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
*d++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsManager::initCursor() {
|
||||
const int cw = 21, ch = 21;
|
||||
const int cx = 10, cy = 10;
|
||||
uint16 cursor[cw * ch];
|
||||
memset(cursor, 0, ARRAYSIZE(cursor) * 2);
|
||||
|
||||
const uint16 cursorColor = (uint16)_screenFormat.RGBToColor(255, 255, 255);
|
||||
|
||||
for (int i = 0; i < cw; ++i) {
|
||||
if (i >= 8 && i <= 12 && i != 10)
|
||||
continue;
|
||||
cursor[cx * cw + i] = cursorColor; // horizontal
|
||||
cursor[cx + cw * i] = cursorColor; // vertical
|
||||
}
|
||||
|
||||
CursorMan.pushCursor(cursor, cw, ch, cx, cy, 0, false, &_screenFormat);
|
||||
}
|
||||
|
||||
void GraphicsManager::showCursor() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void GraphicsManager::hideCursor() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void GraphicsManager::loadFont() {
|
||||
const char *fileName = "nlfont.fnt";
|
||||
Common::SeekableReadStream *fontStream = _vm->_dataFile.createReadStreamForMember(fileName);
|
||||
if (fontStream == nullptr)
|
||||
error("readData(): File %s not found", fileName);
|
||||
|
||||
uint16 fontDataOffset = 768;
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
uint16 offset = fontStream->readSint16LE();
|
||||
_fonts[i]._width = fontStream->readByte();
|
||||
|
||||
int tmpPos = fontStream->pos();
|
||||
fontStream->seek(offset + fontDataOffset);
|
||||
|
||||
int cpt = 0;
|
||||
for (uint16 y = 0; y < CARHEI; ++y) {
|
||||
uint16 curPos = 0;
|
||||
while (curPos <= _fonts[i]._width - 1) {
|
||||
curPos += fontStream->readByte();
|
||||
++cpt;
|
||||
}
|
||||
}
|
||||
|
||||
fontStream->seek(offset + fontDataOffset);
|
||||
_fonts[i]._data = new int8[cpt];
|
||||
fontStream->read(_fonts[i]._data, cpt);
|
||||
fontStream->seek(tmpPos);
|
||||
}
|
||||
|
||||
// Fix o+e ligature character (lowercase and uppercase). Ticket #12623
|
||||
|
||||
// Format is :
|
||||
// - Each line represents a line of pixels
|
||||
// - colors are in this order : none, shadow, text. Colors are looping until the total number of pixels corresponds to the character width
|
||||
// - each number correspond to a number of pixels of the corresponding color
|
||||
// So, 1, 6, 0, 2 means : 1 pixel unchanged, 6 pixels shadow, 0 pixel in text color, 2 pixels unchanged
|
||||
static const int8 fix140[67] = {
|
||||
1, 8,
|
||||
0, 2, 2, 0, 1, 3, 0, 1,
|
||||
0, 1, 1, 0, 2, 2, 0, 3,
|
||||
0, 1, 1, 0, 3, 1, 0, 2, 0, 1,
|
||||
0, 1, 1, 0, 3, 2, 0, 1, 0, 1,
|
||||
0, 1, 1, 0, 3, 1, 0, 2, 0, 1,
|
||||
0, 1, 1, 0, 2, 2, 0, 3,
|
||||
0, 2, 2, 0, 1, 3, 0, 1,
|
||||
1, 8,
|
||||
9
|
||||
};
|
||||
|
||||
static const int8 fix156[54] = {
|
||||
9,
|
||||
9,
|
||||
1, 6, 0, 2,
|
||||
0, 2, 2, 0, 1, 2, 0, 1, 0, 1,
|
||||
0, 1, 1, 0, 2, 1, 0, 2, 1, 0, 1,
|
||||
0, 1, 1, 0, 2, 4, 0, 1,
|
||||
0, 1, 1, 0, 2, 1, 0, 4,
|
||||
0, 2, 2, 0, 1, 3, 0, 1,
|
||||
1, 8,
|
||||
9
|
||||
};
|
||||
|
||||
delete _fonts[140]._data;
|
||||
delete _fonts[156]._data;
|
||||
_fonts[140]._width = _fonts[156]._width = 9;
|
||||
_fonts[140]._data = new int8[67];
|
||||
_fonts[156]._data = new int8[54];
|
||||
|
||||
memcpy(_fonts[140]._data, fix140, 67);
|
||||
memcpy(_fonts[156]._data, fix156, 54);
|
||||
}
|
||||
|
||||
bool GraphicsManager::isCursorVisible() {
|
||||
return CursorMan.isVisible();
|
||||
}
|
||||
|
||||
void GraphicsManager::showDemoPic() {
|
||||
Common::File file;
|
||||
if (file.open("EndPic.bm")) {
|
||||
readSurface(&file, &_screenBuffer, MAXX, MAXY);
|
||||
copyToScreen(0, 0, MAXX, MAXY);
|
||||
g_system->updateScreen();
|
||||
|
||||
_vm->freeKey();
|
||||
_vm->_mouseLeftBtn = _vm->_mouseRightBtn = false;
|
||||
_vm->waitKey();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
116
engines/trecision/graphics.h
Normal file
116
engines/trecision/graphics.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_GRAPHICS_H
|
||||
#define TRECISION_GRAPHICS_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
|
||||
namespace Trecision {
|
||||
class TrecisionEngine;
|
||||
|
||||
struct Font {
|
||||
int8 *_data;
|
||||
uint16 _width;
|
||||
};
|
||||
|
||||
class GraphicsManager {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
Graphics::Surface _screenBuffer;
|
||||
Graphics::Surface _background;
|
||||
Graphics::Surface _smkBackground;
|
||||
Graphics::Surface _leftInventoryArrow;
|
||||
Graphics::Surface _rightInventoryArrow;
|
||||
Graphics::Surface _inventoryIcons;
|
||||
Graphics::Surface _saveSlotThumbnails;
|
||||
Graphics::Surface _textureMat;
|
||||
|
||||
Graphics::PixelFormat _screenFormat;
|
||||
uint16 _bitMask[3];
|
||||
Font _fonts[256];
|
||||
|
||||
Common::List<Common::Rect> _dirtyRects;
|
||||
|
||||
const Graphics::PixelFormat _rgb555Format;
|
||||
|
||||
uint16 aliasing(uint32 val1, uint32 val2, uint8 num);
|
||||
void drawCharPixel(uint16 y, uint16 charLeft, uint16 charRight, Common::Rect rect, Common::Rect subtitleRect, uint16 color, Graphics::Surface *externalSurface = nullptr);
|
||||
void initCursor();
|
||||
void copyToScreenBufferInner(const Graphics::Surface *surface, int x, int y);
|
||||
void paintObjAnm(uint16 curBox);
|
||||
void drawObj(int index, bool mask, Common::Rect drawRect, Common::Rect drawObjRect, bool includeDirtyRect = true);
|
||||
void eraseObj(Common::Rect drawObjRect);
|
||||
|
||||
public:
|
||||
GraphicsManager(TrecisionEngine *vm);
|
||||
~GraphicsManager();
|
||||
|
||||
bool init();
|
||||
void clearScreen();
|
||||
void copyToScreen(int x, int y, int w, int h);
|
||||
void copyToScreenBuffer(const Graphics::Surface *surface, int x, int y, const byte *palette);
|
||||
void blitToScreenBuffer(const Graphics::Surface *surface, int x, int y, const byte *palette, bool useSmkBg);
|
||||
void paintScreen(bool flag);
|
||||
void loadBackground(Common::SeekableReadStream *stream);
|
||||
void clearScreenBuffer();
|
||||
void clearScreenBufferTop();
|
||||
void clearScreenBufferInventory();
|
||||
void clearScreenBufferSaveSlotDescriptions();
|
||||
void drawLeftInventoryArrow(byte startLine);
|
||||
void drawRightInventoryArrow(byte startLine);
|
||||
void drawInventoryIcon(byte iconIndex, byte iconSlot, byte startLine);
|
||||
void drawSaveSlotThumbnail(byte iconIndex, byte iconSlot, byte startLine);
|
||||
void setSaveSlotThumbnail(byte iconSlot, const Graphics::Surface *thumbnail);
|
||||
void readSurface(Common::SeekableReadStream *stream, Graphics::Surface *surface, uint16 width, uint16 height, uint16 count = 1);
|
||||
void readTexture(Common::SeekableReadStream *stream);
|
||||
void drawTexturePixel(uint16 textureX, uint16 textureY, uint16 screenX, uint16 screenY);
|
||||
|
||||
uint16 convertToScreenFormat(uint16 color) const;
|
||||
|
||||
void shadow(uint16 x, uint16 y, uint8 num);
|
||||
void pixelAliasing(uint16 x, uint16 y);
|
||||
void dissolve();
|
||||
|
||||
void addDirtyRect(Common::Rect rect, bool translateRect);
|
||||
|
||||
uint16 getCharWidth(byte character);
|
||||
void drawChar(byte curChar, uint16 textColor, uint16 line, Common::Rect rect, Common::Rect subtitleRect, uint16 inc, Graphics::Surface *externalSurface);
|
||||
|
||||
bool isCursorVisible();
|
||||
void showCursor();
|
||||
void hideCursor();
|
||||
|
||||
void loadFont();
|
||||
void loadData();
|
||||
void showDemoPic();
|
||||
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
377
engines/trecision/inventory.cpp
Normal file
377
engines/trecision/inventory.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
void TrecisionEngine::refreshInventory(uint8 startIcon, uint8 startLine) {
|
||||
if (startLine > ICONDY)
|
||||
return;
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
|
||||
for (uint8 iconSlot = 0; iconSlot < ICONSHOWN; iconSlot++) {
|
||||
uint8 i = iconSlot + startIcon;
|
||||
if (i >= _inventory.size())
|
||||
break;
|
||||
const byte iconIndex = _inventory[i];
|
||||
if (iconIndex == _lightIcon)
|
||||
continue;
|
||||
|
||||
if (iconIndex <= EMPTYSLOT)
|
||||
_graphicsMgr->drawInventoryIcon(iconIndex - 1, iconSlot, startLine);
|
||||
else
|
||||
_graphicsMgr->drawSaveSlotThumbnail(iconIndex - EMPTYSLOT - 1, iconSlot, startLine);
|
||||
}
|
||||
|
||||
if (startIcon != 0)
|
||||
_graphicsMgr->drawLeftInventoryArrow(startLine);
|
||||
|
||||
if (startIcon + ICONSHOWN < (int)_inventory.size())
|
||||
_graphicsMgr->drawRightInventoryArrow(startLine);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE, MAXX, ICONDY);
|
||||
}
|
||||
|
||||
void TrecisionEngine::setInventoryStart(uint8 startIcon, uint8 startLine) {
|
||||
_inventoryRefreshStartIcon = startIcon;
|
||||
_inventoryRefreshStartLine = startLine;
|
||||
}
|
||||
|
||||
void TrecisionEngine::moveInventoryLeft() {
|
||||
if (_iconBase < _inventory.size() - ICONSHOWN)
|
||||
++_iconBase;
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
}
|
||||
|
||||
void TrecisionEngine::moveInventoryRight() {
|
||||
if (_iconBase > 0)
|
||||
--_iconBase;
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
}
|
||||
|
||||
void TrecisionEngine::showIconName() {
|
||||
if (isIconArea(_mousePos)) {
|
||||
if (_inventoryStatus != INV_ON)
|
||||
openInventory();
|
||||
_curInventory = whatIcon(_mousePos);
|
||||
showInventoryName(_curInventory, true);
|
||||
|
||||
if (!_flagUseWithStarted && !_flagSomeoneSpeaks) {
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
}
|
||||
} else if (isInventoryArea(_mousePos)) {
|
||||
showInventoryName(NO_OBJECTS, true);
|
||||
if (!_flagUseWithStarted) {
|
||||
_lightIcon = 0xFF;
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::openInventory() {
|
||||
if (!_flagInventoryLocked && (_inventoryStatus == INV_OFF) && !_flagDialogActive) {
|
||||
_inventoryCounter = INVENTORY_HIDE;
|
||||
_inventorySpeedIndex = 0;
|
||||
_inventoryStatus = INV_PAINT;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::closeInventory() {
|
||||
if (!_flagInventoryLocked && (_inventoryStatus == INV_INACTION) && !_flagDialogActive) {
|
||||
_inventoryCounter = INVENTORY_SHOW;
|
||||
_inventorySpeedIndex = 0;
|
||||
_inventoryStatus = INV_DEPAINT;
|
||||
_lightIcon = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::closeInventoryImmediately() {
|
||||
_inventoryStatus = INV_OFF;
|
||||
_lightIcon = 0xFF;
|
||||
_flagInventoryLocked = false;
|
||||
_inventoryRefreshStartLine = INVENTORY_HIDE;
|
||||
_inventoryCounter = INVENTORY_HIDE;
|
||||
setInventoryStart(_inventoryRefreshStartIcon, INVENTORY_HIDE);
|
||||
refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
|
||||
}
|
||||
|
||||
void TrecisionEngine::examineItem() {
|
||||
_curInventory = whatIcon(_mousePos);
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
if (_flagUseWithStarted) {
|
||||
endUseWith();
|
||||
} else
|
||||
doInvExamine();
|
||||
}
|
||||
|
||||
void TrecisionEngine::useItem() {
|
||||
_curInventory = whatIcon(_mousePos);
|
||||
if (_curInventory == 0)
|
||||
return;
|
||||
|
||||
if (_flagUseWithStarted) {
|
||||
endUseWith();
|
||||
} else if (_inventoryObj[_curInventory].isUseWith()) {
|
||||
if (_curInventory == kItemFlare && _curRoom == kRoom29) {
|
||||
_textMgr->characterSay(kSentenceOnlyGotOne);
|
||||
return;
|
||||
}
|
||||
_animMgr->startSmkAnim(_inventoryObj[_curInventory]._anim);
|
||||
_lightIcon = _curInventory;
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
_flagInventoryLocked = true;
|
||||
_flagUseWithStarted = true;
|
||||
_useWith[USED] = _curInventory;
|
||||
_useWithInv[USED] = true;
|
||||
showInventoryName(_curInventory, true);
|
||||
} else
|
||||
doInvOperate();
|
||||
}
|
||||
|
||||
void TrecisionEngine::endUseWith() {
|
||||
_flagInventoryLocked = false;
|
||||
_flagUseWithStarted = false;
|
||||
_useWith[WITH] = _curInventory;
|
||||
_useWithInv[WITH] = true;
|
||||
_lightIcon = 0xFF;
|
||||
|
||||
if (_useWith[USED] != _curInventory) {
|
||||
doUseWith();
|
||||
} else {
|
||||
_animMgr->smkStop(kSmackerIcon);
|
||||
showInventoryName(_curInventory, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::clearUseWith() {
|
||||
if (_flagUseWithStarted) {
|
||||
if (_useWithInv[USED]) {
|
||||
_lightIcon = 0xFF;
|
||||
_animMgr->smkStop(kSmackerIcon);
|
||||
setInventoryStart(_inventoryRefreshStartIcon, INVENTORY_HIDE);
|
||||
_flagInventoryLocked = false;
|
||||
}
|
||||
_useWith[USED] = 0;
|
||||
_useWith[WITH] = 0;
|
||||
_useWithInv[USED] = false;
|
||||
_useWithInv[WITH] = false;
|
||||
_flagUseWithStarted = false;
|
||||
_textMgr->clearLastText();
|
||||
}
|
||||
}
|
||||
|
||||
uint8 TrecisionEngine::whatIcon(Common::Point pos) {
|
||||
if (pos.x < ICONMARGSX || pos.x > MAXX - ICONMARGDX)
|
||||
return 0;
|
||||
|
||||
int index = _iconBase + ((pos.x - ICONMARGSX) / (ICONDX));
|
||||
|
||||
return index < (int)_inventory.size() ? _inventory[index] : 0;
|
||||
}
|
||||
|
||||
int8 TrecisionEngine::iconPos(uint8 icon) {
|
||||
for (uint8 i = 0; i < _inventory.size(); i++) {
|
||||
if (_inventory[i] == icon)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TrecisionEngine::showInventoryName(uint16 obj, bool showhide) {
|
||||
if (_logicMgr->isCloseupOrControlRoom() || _flagSomeoneSpeaks)
|
||||
return;
|
||||
|
||||
if (_lastObj) {
|
||||
_textMgr->clearLastText();
|
||||
_lastObj = 0;
|
||||
}
|
||||
|
||||
if (_flagUseWithStarted) {
|
||||
if (!showhide) {
|
||||
_textMgr->clearLastText();
|
||||
_lastInv = 0;
|
||||
return;
|
||||
}
|
||||
if ((obj | 0x8000) == _lastInv)
|
||||
return;
|
||||
|
||||
Common::String desc = _sysText[kMessageUse];
|
||||
if (_useWithInv[USED]) {
|
||||
desc += _objName[_inventoryObj[_useWith[USED]]._name];
|
||||
desc += _sysText[kMessageWith];
|
||||
if (obj && (_inventoryObj[_useWith[USED]]._name != _inventoryObj[obj]._name))
|
||||
desc += _objName[_inventoryObj[obj]._name];
|
||||
} else {
|
||||
if (_obj[_useWith[USED]].isModeHidden())
|
||||
desc += "?"; // dunno
|
||||
else
|
||||
desc += _objName[_obj[_useWith[USED]]._name];
|
||||
desc += _sysText[kMessageWith];
|
||||
if (obj && (_obj[_useWith[USED]]._name != _inventoryObj[obj]._name))
|
||||
desc += _objName[_inventoryObj[obj]._name];
|
||||
}
|
||||
|
||||
const uint16 lenText = textLength(desc);
|
||||
Common::Point pos(CLIP(320 - (lenText / 2), 2, MAXX - 2 - lenText), MAXY - CARHEI);
|
||||
|
||||
_lastInv = (obj | 0x8000);
|
||||
if (_lastInv)
|
||||
_textMgr->clearLastText();
|
||||
_textMgr->addText(pos, desc.c_str(), COLOR_INVENTORY);
|
||||
} else {
|
||||
if (obj == _lastInv)
|
||||
return;
|
||||
|
||||
if (!obj || !showhide) {
|
||||
_textMgr->clearLastText();
|
||||
_lastInv = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16 lenText = textLength(_objName[_inventoryObj[obj]._name]);
|
||||
uint16 posX = ICONMARGSX + ((iconPos(_curInventory) - _iconBase) * (ICONDX)) + ICONDX / 2;
|
||||
posX = CLIP(posX - (lenText / 2), 2, MAXX - 2 - lenText);
|
||||
Common::Point pos(posX, MAXY - CARHEI);
|
||||
|
||||
_lastInv = obj;
|
||||
|
||||
if (_lastInv)
|
||||
_textMgr->clearLastText();
|
||||
|
||||
if (_inventoryObj[obj]._name)
|
||||
_textMgr->addText(pos, _objName[_inventoryObj[obj]._name], COLOR_INVENTORY);
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::removeIcon(uint8 icon) {
|
||||
const int8 pos = iconPos(icon);
|
||||
if (pos == -1)
|
||||
return;
|
||||
|
||||
_inventory.remove_at(pos);
|
||||
_iconBase = _inventory.size() <= ICONSHOWN ? 0 : _inventory.size() - ICONSHOWN;
|
||||
|
||||
_textMgr->redrawString();
|
||||
}
|
||||
|
||||
void TrecisionEngine::addIcon(uint8 icon) {
|
||||
if (iconPos(icon) != -1)
|
||||
return;
|
||||
|
||||
_inventory.push_back(icon);
|
||||
_iconBase = _inventory.size() <= ICONSHOWN ? 0 : _inventory.size() - ICONSHOWN;
|
||||
|
||||
// To show the icon that enters the inventory
|
||||
// doEvent(MC_INVENTORY,ME_OPEN,MP_DEFAULT,0,0,0,0);
|
||||
// FlagForceRegenInventory = true;
|
||||
_textMgr->redrawString();
|
||||
}
|
||||
|
||||
void TrecisionEngine::replaceIcon(uint8 oldIcon, uint8 newIcon) {
|
||||
int8 pos = iconPos(oldIcon);
|
||||
if (pos >= 0)
|
||||
_inventory[pos] = newIcon;
|
||||
}
|
||||
|
||||
void TrecisionEngine::rollInventory(uint8 status) {
|
||||
static const int16 inventorySpeed[8] = { 20, 10, 5, 3, 2, 0, 0, 0 };
|
||||
|
||||
if (status == INV_PAINT) {
|
||||
_inventoryCounter -= inventorySpeed[_inventorySpeedIndex++];
|
||||
if (_inventoryCounter <= INVENTORY_SHOW || _inventorySpeedIndex > 5) {
|
||||
_inventorySpeedIndex = 0;
|
||||
setInventoryStart(_iconBase, INVENTORY_SHOW);
|
||||
_inventoryStatus = INV_INACTION;
|
||||
_inventoryCounter = INVENTORY_SHOW;
|
||||
if (!isInventoryArea(_mousePos))
|
||||
closeInventory();
|
||||
_textMgr->redrawString();
|
||||
return;
|
||||
}
|
||||
} else if (status == INV_DEPAINT) {
|
||||
_inventoryCounter += inventorySpeed[_inventorySpeedIndex++];
|
||||
|
||||
if (_inventoryCounter > INVENTORY_HIDE || _inventorySpeedIndex > 5) {
|
||||
_inventorySpeedIndex = 0;
|
||||
setInventoryStart(_iconBase, INVENTORY_HIDE);
|
||||
_inventoryStatus = INV_OFF;
|
||||
_inventoryCounter = INVENTORY_HIDE;
|
||||
if (isInventoryArea(_mousePos) && !(_flagDialogActive || _flagDialogMenuActive))
|
||||
openInventory();
|
||||
else
|
||||
_textMgr->redrawString();
|
||||
return;
|
||||
}
|
||||
}
|
||||
setInventoryStart(_iconBase, _inventoryCounter);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doScrollInventory(Common::Point pos) {
|
||||
if (_inventoryStatus != INV_INACTION)
|
||||
return;
|
||||
|
||||
if (pos.x <= ICONMARGSX && _iconBase)
|
||||
moveInventoryRight();
|
||||
else if (isBetween(MAXX - ICONMARGDX, pos.x, MAXX) && (_iconBase + ICONSHOWN < (int)_inventory.size()))
|
||||
moveInventoryLeft();
|
||||
}
|
||||
|
||||
void TrecisionEngine::syncInventory(Common::Serializer &ser) {
|
||||
if (ser.isLoading()) {
|
||||
_inventory.clear();
|
||||
_cyberInventory.clear();
|
||||
}
|
||||
|
||||
for (uint which = 0; which <= 1; which++) {
|
||||
for (uint i = 0; i < MAXICON; i++) {
|
||||
byte val = 0;
|
||||
if (ser.isSaving()) {
|
||||
if (which == 0)
|
||||
val = i < _inventory.size() ? _inventory[i] : 0;
|
||||
else
|
||||
val = i < _cyberInventory.size() ? _cyberInventory[i] : 0;
|
||||
ser.syncAsByte(val);
|
||||
} else {
|
||||
ser.syncAsByte(val);
|
||||
if (val != kItemNull) {
|
||||
if (which == 0)
|
||||
_inventory.push_back(val);
|
||||
else
|
||||
_cyberInventory.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
4123
engines/trecision/logic.cpp
Normal file
4123
engines/trecision/logic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
103
engines/trecision/logic.h
Normal file
103
engines/trecision/logic.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_LOGIC_H
|
||||
#define TRECISION_LOGIC_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Trecision {
|
||||
class TrecisionEngine;
|
||||
|
||||
class LogicManager {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
// panel puzzle 35
|
||||
uint16 _comb35[7];
|
||||
uint16 _count35;
|
||||
|
||||
// sundial puzzle 49
|
||||
uint16 _comb49[4];
|
||||
|
||||
// sundial puzzle 4CT
|
||||
uint16 _comb4CT[6];
|
||||
|
||||
// keyboard puzzle 58
|
||||
uint16 _comb58[6];
|
||||
uint16 _count58;
|
||||
|
||||
// SlotMachine41
|
||||
uint16 _slotMachine41Counter;
|
||||
|
||||
// special management
|
||||
uint16 _wheel;
|
||||
uint16 _wheelPos[3];
|
||||
|
||||
void initInventory();
|
||||
|
||||
public:
|
||||
LogicManager(TrecisionEngine *vm);
|
||||
~LogicManager();
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
|
||||
void setupAltRoom(uint16 room, bool altRoomFl);
|
||||
void endChangeRoom();
|
||||
|
||||
void useInventoryWithInventory();
|
||||
void useInventoryWithScreen();
|
||||
bool useScreenWithScreen();
|
||||
void roomOut(uint16 curObj, uint16 *action, uint16 *pos);
|
||||
bool mouseExamine(uint16 curObj);
|
||||
bool mouseOperate(uint16 curObj);
|
||||
bool mouseTake(uint16 curObj);
|
||||
bool mouseTalk(uint16 curObj);
|
||||
bool mouseClick(uint16 curObj);
|
||||
bool operateInventory();
|
||||
|
||||
void doMouseGame();
|
||||
bool doMouseInventory();
|
||||
void doMouseLeftRight();
|
||||
|
||||
void doSystemChangeRoom(uint16 room);
|
||||
|
||||
bool isCloseupOrControlRoom() const;
|
||||
|
||||
private:
|
||||
void startCharacterAnimations();
|
||||
bool startPlayDialog();
|
||||
void initControlPanel();
|
||||
|
||||
void handleClickControlPanel(uint16 curObj);
|
||||
void handleClickSphinxPuzzle();
|
||||
void handleClickPositioner();
|
||||
void handleClickSnakeEscape();
|
||||
void handleClickCloseup();
|
||||
void handleClickGameArea();
|
||||
void handleClickInventoryArea();
|
||||
void handleChangeRoomObjects();
|
||||
};
|
||||
// end of class
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
207
engines/trecision/metaengine.cpp
Normal file
207
engines/trecision/metaengine.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/detection.h"
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
|
||||
{
|
||||
GAMEOPTION_ORIGINAL_SAVELOAD,
|
||||
{
|
||||
_s("Use original save/load screens"),
|
||||
_s("Use the original save/load screens instead of the ScummVM ones"),
|
||||
"originalsaveload",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class TrecisionMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
const char *getName() const override {
|
||||
return "trecision";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
void getSavegameThumbnail(Graphics::Surface &thumb) override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
Common::Error TrecisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
*engine = new Trecision::TrecisionEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void TrecisionMetaEngine::getSavegameThumbnail(Graphics::Surface &thumb) {
|
||||
// We are referencing g_engine here, but this should be safe, as this
|
||||
// method is only used while the engine is running.
|
||||
// TODO: Is there a better way to do this?
|
||||
|
||||
Trecision::TrecisionEngine *engine = (Trecision::TrecisionEngine *)g_engine;
|
||||
|
||||
if (engine->_controlPanelSave)
|
||||
thumb.copyFrom(engine->_thumbnail);
|
||||
else
|
||||
MetaEngine::getSavegameThumbnail(thumb);
|
||||
}
|
||||
|
||||
SaveStateDescriptor TrecisionMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
Common::ScopedPtr<Common::InSaveFile> saveFile(g_system->getSavefileManager()->openForLoading(
|
||||
getSavegameFile(slot, target)));
|
||||
|
||||
if (saveFile) {
|
||||
const byte version = saveFile->readByte();
|
||||
|
||||
if (version >= SAVE_VERSION_ORIGINAL_MIN && version <= SAVE_VERSION_ORIGINAL_MAX) {
|
||||
// Original saved game, convert
|
||||
Common::String saveName = saveFile->readString(0, 40);
|
||||
|
||||
SaveStateDescriptor desc(this, slot, saveName);
|
||||
|
||||
// This is freed inside SaveStateDescriptor
|
||||
const Graphics::PixelFormat kImageFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
|
||||
Graphics::Surface *thumbnail = new Graphics::Surface();
|
||||
thumbnail->create(ICONDX, ICONDY, kImageFormat);
|
||||
saveFile->read(thumbnail->getPixels(), ICONDX * ICONDY * kImageFormat.bytesPerPixel);
|
||||
desc.setThumbnail(thumbnail);
|
||||
|
||||
return desc;
|
||||
} else if (version >= SAVE_VERSION_SCUMMVM_MIN) {
|
||||
saveFile->seek(0);
|
||||
return MetaEngine::querySaveMetaInfos(target, slot);
|
||||
}
|
||||
}
|
||||
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
Common::KeymapArray TrecisionMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Trecision;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "trecision-default", _("Default keymappings"));
|
||||
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
|
||||
Action *act;
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Left click"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action(kStandardActionRightClick, _("Right click"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SKIP", _("Skip video"));
|
||||
act->setCustomEngineActionEvent(kActionSkipVideo);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
// I18N: Toggles walking speed of actor
|
||||
act = new Action("FASTWALK", _("Toggle fast walk"));
|
||||
act->setCustomEngineActionEvent(kActionFastWalk);
|
||||
act->addDefaultInputMapping("CAPSLOCK");
|
||||
act->addDefaultInputMapping("JOY_CENTER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("PAUSE", _("Pause game"));
|
||||
act->setCustomEngineActionEvent(kActionPause);
|
||||
act->addDefaultInputMapping("p");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("QUIT", _("Quit game"));
|
||||
act->setCustomEngineActionEvent(kActionQuit);
|
||||
act->addDefaultInputMapping("q");
|
||||
act->addDefaultInputMapping("Q");
|
||||
act->addDefaultInputMapping("JOY_LEFT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SYSMENU", _("Open system menu"));
|
||||
act->setCustomEngineActionEvent(kActionSystemMenu);
|
||||
act->addDefaultInputMapping("F1");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SAVEGAME", _("Save game"));
|
||||
act->setCustomEngineActionEvent(kActionSave);
|
||||
act->addDefaultInputMapping("F2");
|
||||
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("LOADGAME", _("Load game"));
|
||||
act->setCustomEngineActionEvent(kActionLoad);
|
||||
act->addDefaultInputMapping("F3");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("YESKEY", _("Press \"Yes\" key"));
|
||||
act->setCustomEngineActionEvent(kActionYes);
|
||||
act->addDefaultInputMapping("y");
|
||||
act->addDefaultInputMapping("j");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
KeymapArray keymaps(2);
|
||||
keymaps[0] = engineKeyMap;
|
||||
keymaps[1] = gameKeyMap;
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
bool Trecision::TrecisionEngine::hasFeature(EngineFeature f) const {
|
||||
return (f == kSupportsSubtitleOptions) ||
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsChangingOptionsDuringRuntime);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(TRECISION)
|
||||
REGISTER_PLUGIN_DYNAMIC(TRECISION, PLUGIN_TYPE_ENGINE, TrecisionMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(TRECISION, PLUGIN_TYPE_ENGINE, TrecisionMetaEngine);
|
||||
#endif
|
||||
36
engines/trecision/module.mk
Normal file
36
engines/trecision/module.mk
Normal file
@@ -0,0 +1,36 @@
|
||||
MODULE := engines/trecision
|
||||
|
||||
MODULE_OBJS = \
|
||||
console.o \
|
||||
actor.o \
|
||||
animmanager.o \
|
||||
animtype.o \
|
||||
dialog.o \
|
||||
fastfile.o \
|
||||
graphics.o \
|
||||
inventory.o \
|
||||
logic.o \
|
||||
metaengine.o \
|
||||
pathfinding3d.o \
|
||||
renderer3d.o \
|
||||
resource.o \
|
||||
sound.o \
|
||||
saveload.o \
|
||||
scheduler.o \
|
||||
script.o \
|
||||
struct.o \
|
||||
text.o \
|
||||
trecision.o \
|
||||
utils.o \
|
||||
video.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_TRECISION), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
1698
engines/trecision/pathfinding3d.cpp
Normal file
1698
engines/trecision/pathfinding3d.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
engines/trecision/pathfinding3d.h
Normal file
149
engines/trecision/pathfinding3d.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_PATHFINDING_H
|
||||
#define TRECISION_PATHFINDING_H
|
||||
|
||||
#include "trecision/struct.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
struct SSortPan {
|
||||
int _num;
|
||||
float _min;
|
||||
};
|
||||
|
||||
struct SPathNode {
|
||||
float _x, _z;
|
||||
float _dist;
|
||||
int16 _oldPanel;
|
||||
int16 _curPanel;
|
||||
|
||||
void clear() {
|
||||
_x = _z = 0.0f;
|
||||
_dist = 0.0f;
|
||||
_oldPanel = 0;
|
||||
_curPanel = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct SPan {
|
||||
float _x1, _z1;
|
||||
float _x2, _z2;
|
||||
float _h;
|
||||
int _flags;
|
||||
int16 _nearPanel1;
|
||||
int16 _nearPanel2;
|
||||
int8 _col1;
|
||||
int8 _col2;
|
||||
|
||||
void clear() {
|
||||
_x1 = _z1 = 0.0f;
|
||||
_x2 = _z2 = 0.0f;
|
||||
_h = 0.0f;
|
||||
_flags = 0;
|
||||
_nearPanel1 = _nearPanel2 = 0;
|
||||
_col1 = _col2 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct SStep {
|
||||
float _px, _pz;
|
||||
float _dx, _dz;
|
||||
float _theta;
|
||||
int _curAction;
|
||||
int _curFrame;
|
||||
int16 _curPanel;
|
||||
|
||||
void clear() {
|
||||
_px = _pz = 0.0f;
|
||||
_dx = _dz = 0.0f;
|
||||
_theta = 0.0f;
|
||||
_curAction = 0;
|
||||
_curFrame = 0;
|
||||
_curPanel = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class PathFinding3D {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
SPathNode _pathNode[MAXPATHNODES];
|
||||
float _invP[3][3];
|
||||
int _numPathNodes;
|
||||
float _x3d, _y3d, _z3d;
|
||||
float _curX, _curZ;
|
||||
float _lookX, _lookZ;
|
||||
int32 _panelNum;
|
||||
int16 _oldPanel;
|
||||
int _actorPos;
|
||||
int _forcedActorPos;
|
||||
|
||||
bool pointInside(int pan, float x, float z) const;
|
||||
void sortPanel();
|
||||
void pointOut();
|
||||
void invPointProject(int x, int y);
|
||||
bool intersectLinePanel(SPan *p, float x, float y, float z);
|
||||
bool intersectLineFloor(float x, float y, float z);
|
||||
bool intersectLineLine(float xa, float ya, float xb, float yb, float xc, float yc, float xd, float yd);
|
||||
void findShortPath();
|
||||
float evalPath(int a, float destX, float destZ, int nearP);
|
||||
void lookAt(float x, float z);
|
||||
void buildFramelist();
|
||||
void displayPath();
|
||||
bool findAttachedPanel(int16 srcPanel, int16 destPanel);
|
||||
void sortPath();
|
||||
|
||||
public:
|
||||
PathFinding3D(TrecisionEngine *vm);
|
||||
~PathFinding3D();
|
||||
|
||||
int _curStep;
|
||||
int _lastStep;
|
||||
int16 _curPanel;
|
||||
int _numSortPanel;
|
||||
|
||||
int8 _characterGoToPosition;
|
||||
bool _characterInMovement;
|
||||
SSortPan _sortPan[32];
|
||||
SStep _step[MAXSTEP];
|
||||
SPan _panel[MAXPANELSINROOM];
|
||||
|
||||
void findPath();
|
||||
void setPosition(int num);
|
||||
void goToPosition(int num);
|
||||
int nextStep();
|
||||
void initSortPan();
|
||||
void read3D(Common::SeekableReadStreamEndian *ff);
|
||||
void reset(uint16 idx, float px, float pz, float theta);
|
||||
void whereIs(int px, int py);
|
||||
void actorOrder();
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
int getActorPos() const { return _actorPos; }
|
||||
void setForcedActorPos(int actorPos) { _forcedActorPos = actorPos; }
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
828
engines/trecision/renderer3d.cpp
Normal file
828
engines/trecision/renderer3d.cpp
Normal file
@@ -0,0 +1,828 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/renderer3d.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
#define SHADOWVERTSNUM 42
|
||||
|
||||
static const int16 _shadowVerts[SHADOWVERTSNUM] = {
|
||||
6, 15, 23,
|
||||
24, 32, 78,
|
||||
80, 81, 83,
|
||||
86, 90, 99,
|
||||
107, 108, 116,
|
||||
155, 157, 158,
|
||||
160, 164, 168,
|
||||
169, 173, 174,
|
||||
187, 188, 192,
|
||||
193, 213, 215,
|
||||
227, 229, 235,
|
||||
238, 249, 250,
|
||||
252, 253, 299,
|
||||
306, 330, 336
|
||||
};
|
||||
#define SHADOWFACESNUM 48
|
||||
|
||||
const int16 _shadowFaces[SHADOWFACESNUM][3] = {
|
||||
{22, 21, 5}, {7, 5, 22},
|
||||
{7, 19, 5}, {5, 2, 19},
|
||||
{27, 24, 16}, {27, 16, 18},
|
||||
{18, 16, 9}, {18, 13, 9},
|
||||
{13, 9, 2}, {3, 19, 12},
|
||||
{25, 26, 17}, {17, 15, 25},
|
||||
{17, 19, 15}, {15, 12, 19},
|
||||
{20, 23, 8}, {8, 6, 20},
|
||||
{6, 9, 3}, {3, 8, 6},
|
||||
{12, 3, 4}, {4, 11, 12},
|
||||
{35, 4, 11}, {13, 2, 1},
|
||||
{1, 14, 13}, {14, 37, 1},
|
||||
{1, 34, 37}, {31, 36, 37},
|
||||
{37, 30, 31}, {29, 34, 35},
|
||||
{35, 29, 28}, {36, 11, 31},
|
||||
{30, 37, 14}, {29, 1, 34},
|
||||
{28, 4, 35}, {36, 10, 35},
|
||||
{35, 32, 10}, {37, 0, 34},
|
||||
{37, 33, 0}, {0, 33, 39},
|
||||
{39, 40, 0}, {10, 38, 32},
|
||||
{32, 41, 38}, {36, 35, 34},
|
||||
{36, 37, 35}, {11, 36, 35},
|
||||
{38, 40, 41}, {41, 38, 39},
|
||||
{2, 19, 13}, {3, 9, 12}
|
||||
};
|
||||
|
||||
Renderer3D::Renderer3D(TrecisionEngine *vm) : _vm(vm) {
|
||||
_zBuffer = new int16[ZBUFFERSIZE / 2];
|
||||
|
||||
_minXClip = 0;
|
||||
_minYClip = 0;
|
||||
_maxXClip = 0;
|
||||
_maxYClip = 0;
|
||||
_zBufStartX = 0;
|
||||
_zBufStartY = 0;
|
||||
_zBufWid = 0;
|
||||
_shadowLightNum = 0;
|
||||
_totalShadowVerts = 0;
|
||||
|
||||
// data for the triangle routines
|
||||
for (int i = 0; i < 480; ++i) {
|
||||
_lEdge[i] = 0;
|
||||
_rEdge[i] = 0;
|
||||
_lColor[i] = 0;
|
||||
_rColor[i] = 0;
|
||||
_lZ[i] = 0;
|
||||
_rZ[i] = 0;
|
||||
_lTextX[i] = 0;
|
||||
_rTextX[i] = 0;
|
||||
_lTextY[i] = 0;
|
||||
_rTextY[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
_shadowIntens[i] = 0;
|
||||
|
||||
for (int i = 0; i < MAXVERTEX; ++i) {
|
||||
_vVertex[i].clear();
|
||||
_shVertex[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
Renderer3D::~Renderer3D() {
|
||||
delete[] _zBuffer;
|
||||
}
|
||||
|
||||
void Renderer3D::textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1,
|
||||
int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2,
|
||||
int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3,
|
||||
const STexture *t) {
|
||||
if (y1 > _maxYClip)
|
||||
y1 = _maxYClip;
|
||||
if (y1 < _minYClip)
|
||||
y1 = _minYClip;
|
||||
|
||||
int16 yBottom = y1;
|
||||
int16 yTop = y1;
|
||||
const uint8 *texture = t->_texture;
|
||||
|
||||
if (yBottom > y2) {
|
||||
if (y2 < _minYClip)
|
||||
y2 = _minYClip;
|
||||
yBottom = y2;
|
||||
}
|
||||
if (yTop < y2) {
|
||||
if (y2 > _maxYClip)
|
||||
y2 = _maxYClip;
|
||||
yTop = y2;
|
||||
}
|
||||
if (yBottom > y3) {
|
||||
if (y3 < _minYClip)
|
||||
y3 = _minYClip;
|
||||
yBottom = y3;
|
||||
}
|
||||
if (yTop < y3) {
|
||||
if (y3 > _maxYClip)
|
||||
y3 = _maxYClip;
|
||||
yTop = y3;
|
||||
}
|
||||
for (int16 y = yBottom; y < yTop; ++y) {
|
||||
_lEdge[y] = _maxXClip;
|
||||
_rEdge[y] = _minXClip;
|
||||
}
|
||||
|
||||
// scan the edges of the triangle
|
||||
textureScanEdge(x1, y1, z1, c1, tx1, ty1, x2, y2, z2, c2, tx2, ty2);
|
||||
textureScanEdge(x2, y2, z2, c2, tx2, ty2, x3, y3, z3, c3, tx3, ty3);
|
||||
textureScanEdge(x3, y3, z3, c3, tx3, ty3, x1, y1, z1, c1, tx1, ty1);
|
||||
|
||||
// Gouraud fill the horizontal scanlines
|
||||
for (int16 y = yBottom; y < yTop; ++y) {
|
||||
int32 el = _lEdge[y];
|
||||
if (el < _minXClip)
|
||||
el = _minXClip;
|
||||
int32 er = _rEdge[y];
|
||||
if (er > _maxXClip)
|
||||
er = _maxXClip;
|
||||
|
||||
// edge right - edge left
|
||||
int16 dx = er - el;
|
||||
|
||||
if (dx > 0) {
|
||||
// color of left edge of horizontal scanline
|
||||
int32 cl = _lColor[y];
|
||||
// slope dc/_dx
|
||||
int32 mc = ((int16)(_rColor[y] - cl) << 8) / dx;
|
||||
// zbuffer of left edge of horizontal scanline
|
||||
int32 zl = _lZ[y];
|
||||
// slope _dz/_dx
|
||||
int32 mz = ((int32)(_rZ[y] - zl) << 16) / dx;
|
||||
// texture x of left edge of horizontal scanline
|
||||
int32 olx = _lTextX[y];
|
||||
// slope dty/_dx
|
||||
int32 mtx = ((int32)(_rTextX[y] - olx) << 16) / dx;
|
||||
// texture y of left edge of horizontal scanline
|
||||
int32 oly = _lTextY[y];
|
||||
// slope dty/_dx
|
||||
int32 mty = ((int32)(_rTextY[y] - oly) << 16) / dx;
|
||||
// pointer to zbuffer
|
||||
int16 *z = _zBuffer + (y - _zBufStartY) * _zBufWid + (el - _zBufStartX);
|
||||
uint16 x = el;
|
||||
|
||||
zl <<= 16;
|
||||
cl <<= 8;
|
||||
olx <<= 16;
|
||||
oly <<= 16;
|
||||
// loop through every pixel in horizontal scanline
|
||||
while (dx) {
|
||||
const int32 screenOffset = zl >> 16;
|
||||
if (*z > screenOffset) {
|
||||
const uint16 textureX = (uint16)(cl >> 9);
|
||||
const uint16 textureY = texture[(olx >> 16) + t->_dx * (oly >> 16)];
|
||||
_vm->_graphicsMgr->drawTexturePixel(textureX, textureY, x, y);
|
||||
*z = (int16)screenOffset;
|
||||
}
|
||||
++x; // increase screen x
|
||||
++z; // increase zbuffer
|
||||
zl += mz; // increase the zbuffer by _dz/_dx
|
||||
cl += mc; // increase the color by dc/_dx
|
||||
olx += mtx;
|
||||
oly += mty;
|
||||
--dx; // pixel to do --
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2) {
|
||||
// make sure that edge goes from top to bottom
|
||||
int16 dy = y2 - y1;
|
||||
if (dy < 0) {
|
||||
SWAP(y1, y2);
|
||||
SWAP(x1, x2);
|
||||
SWAP(c1, c2);
|
||||
SWAP(z1, z2);
|
||||
SWAP(tx1, tx2);
|
||||
SWAP(ty1, ty2);
|
||||
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
if (dy == 0)
|
||||
dy = 1;
|
||||
|
||||
// initialize for stepping
|
||||
int32 mx = ((x2 - x1) << 16) / dy; // dx/dy
|
||||
int32 mz = ((z2 - z1) << 16) / dy; // dz/dy
|
||||
int32 mc = ((c2 - c1) << 8) / dy; // dc/dy
|
||||
int32 mtx = ((tx2 - tx1) << 16) / dy;
|
||||
int32 mty = ((ty2 - ty1) << 16) / dy;
|
||||
|
||||
x1 <<= 16; // starting x coordinate
|
||||
z1 <<= 16; // starting z coordinate
|
||||
c1 <<= 8; // starting c color
|
||||
|
||||
tx1 <<= 16;
|
||||
ty1 <<= 16;
|
||||
|
||||
// step through edge and record color values along the way
|
||||
for (int32 count = y1; count < y2; ++count) {
|
||||
int16 x = (uint16)(x1 >> 16);
|
||||
if (x < _lEdge[count]) {
|
||||
_lEdge[count] = x;
|
||||
_lZ[count] = (int16)(z1 >> 16);
|
||||
_lTextX[count] = (uint16)(tx1 >> 16);
|
||||
_lTextY[count] = (uint16)(ty1 >> 16);
|
||||
_lColor[count] = (uint8)(c1 >> 8);
|
||||
}
|
||||
if (x > _rEdge[count]) {
|
||||
_rEdge[count] = x;
|
||||
_rZ[count] = (int16)(z1 >> 16);
|
||||
_rTextX[count] = (uint16)(tx1 >> 16);
|
||||
_rTextY[count] = (uint16)(ty1 >> 16);
|
||||
_rColor[count] = (uint8)(c1 >> 8);
|
||||
}
|
||||
|
||||
x1 += mx; // x = x + dx/dy
|
||||
c1 += mc; // c = c + dc/dy
|
||||
z1 += mz; // z = z + dz/dy
|
||||
|
||||
tx1 += mtx;
|
||||
ty1 += mty;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2,
|
||||
int32 x3, int32 y3, uint8 cv, int32 zv) {
|
||||
if (y1 > _maxYClip)
|
||||
y1 = _maxYClip;
|
||||
if (y1 < _minYClip)
|
||||
y1 = _minYClip;
|
||||
|
||||
int16 yBottom = y1;
|
||||
int16 yTop = y1;
|
||||
|
||||
if (yBottom > y2) {
|
||||
if (y2 < _minYClip)
|
||||
y2 = _minYClip;
|
||||
yBottom = y2;
|
||||
}
|
||||
if (yTop < y2) {
|
||||
if (y2 > _maxYClip)
|
||||
y2 = _maxYClip;
|
||||
yTop = y2;
|
||||
}
|
||||
if (yBottom > y3) {
|
||||
if (y3 < _minYClip)
|
||||
y3 = _minYClip;
|
||||
yBottom = y3;
|
||||
}
|
||||
if (yTop < y3) {
|
||||
if (y3 > _maxYClip)
|
||||
y3 = _maxYClip;
|
||||
yTop = y3;
|
||||
}
|
||||
|
||||
for (int16 y = yBottom; y < yTop; ++y) {
|
||||
_lEdge[y] = _maxXClip;
|
||||
_rEdge[y] = _minXClip;
|
||||
}
|
||||
|
||||
// scan the edges of the triangle
|
||||
shadowScanEdge(x1, y1, x2, y2);
|
||||
shadowScanEdge(x2, y2, x3, y3);
|
||||
shadowScanEdge(x3, y3, x1, y1);
|
||||
|
||||
// gouraud fill the horizontal scanlines
|
||||
for (int16 y = yBottom; y < yTop; ++y) {
|
||||
// coordinate of left edge of horizontal scanline
|
||||
int32 el = _lEdge[y];
|
||||
if (el < _minXClip)
|
||||
el = _minXClip;
|
||||
// coordinate of right edge of horizontal scanline
|
||||
int32 er = _rEdge[y];
|
||||
if (er > _maxXClip)
|
||||
er = _maxXClip;
|
||||
|
||||
// edge right - edge left
|
||||
int16 dx = er - el;
|
||||
|
||||
if (dx > 0) {
|
||||
// screen offset
|
||||
int16 x = el;
|
||||
int16 *zBufferPtr = _zBuffer + (y - _zBufStartY) * _zBufWid + (el - _zBufStartX);
|
||||
|
||||
// loop through every pixel in horizontal scanline
|
||||
while (dx) {
|
||||
if (*zBufferPtr != zv) {
|
||||
_vm->_graphicsMgr->shadow(x, y, cv);
|
||||
*zBufferPtr = zv;
|
||||
}
|
||||
++x; // increase screen x
|
||||
++zBufferPtr; // increase zbuffer
|
||||
--dx; // pixel to do --
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
// make sure that edge goes from top to bottom
|
||||
int16 dy = y2 - y1;
|
||||
if (dy < 0) {
|
||||
SWAP(y1, y2);
|
||||
SWAP(x1, x2);
|
||||
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
if (dy == 0)
|
||||
dy = 1;
|
||||
|
||||
// initialize for stepping
|
||||
int32 mx = ((x2 - x1) << 16) / dy; // slope dx/dy
|
||||
|
||||
x1 <<= 16; // starting x coordinate
|
||||
|
||||
// step through edge and record color values along the way
|
||||
for (int32 count = y1; count < y2; ++count) {
|
||||
int16 x = (int16)(x1 >> 16);
|
||||
if (x < _lEdge[count])
|
||||
_lEdge[count] = x;
|
||||
|
||||
if (x > _rEdge[count])
|
||||
_rEdge[count] = x;
|
||||
|
||||
x1 += mx; // x = x + dx/dy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a 3D Room
|
||||
*/
|
||||
void Renderer3D::init3DRoom() {
|
||||
_vm->_cx = (MAXX - 1) / 2;
|
||||
_vm->_cy = (MAXY - 1) / 2;
|
||||
|
||||
for (int c = 0; c < ZBUFFERSIZE / 2; ++c)
|
||||
_zBuffer[c] = 0x7FFF;
|
||||
}
|
||||
|
||||
void Renderer3D::resetZBuffer(Common::Rect area) {
|
||||
if (!area.isValidRect())
|
||||
return;
|
||||
|
||||
int size = area.width() * area.height();
|
||||
if (size * 2 > ZBUFFERSIZE)
|
||||
warning("Warning: _zBuffer size %d!\n", size * 2);
|
||||
|
||||
int16 *d = _zBuffer;
|
||||
for (int i = 0; i < size; ++i)
|
||||
*d++ = 0x7FFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the clipping area
|
||||
*/
|
||||
void Renderer3D::setClipping(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
_minXClip = x1;
|
||||
_minYClip = y1;
|
||||
_maxXClip = x2;
|
||||
_maxYClip = y2;
|
||||
}
|
||||
|
||||
void Renderer3D::setZBufferRegion(int16 sx, int16 sy, int16 dx) {
|
||||
_zBufStartX = sx;
|
||||
_zBufStartY = sy;
|
||||
_zBufWid = dx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a triangle has clockwise
|
||||
* or counterclockwise vertices
|
||||
*/
|
||||
int8 Renderer3D::clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3) {
|
||||
x2 -= x1;
|
||||
y2 -= y1;
|
||||
|
||||
x3 -= x1;
|
||||
y3 -= y1;
|
||||
|
||||
int32 a1 = ((int32)x2) * y3;
|
||||
int32 a2 = ((int32)y2) * x3;
|
||||
|
||||
if (a1 > a2)
|
||||
return 1; // clockwise
|
||||
if (a1 < a2)
|
||||
return -1; // counterclockwise
|
||||
|
||||
a1 = ((int32)x2) * x3;
|
||||
a2 = ((int32)y2) * y3;
|
||||
if (a1 < 0 || a2 < 0)
|
||||
return -1;
|
||||
|
||||
a1 = ((int32)x2) * x2 + ((int32)y2) * y2;
|
||||
a2 = ((int32)x3) * x3 + ((int32)y3) * y3;
|
||||
if (a1 < a2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Renderer3D::calcCharacterPoints() {
|
||||
Actor *actor = _vm->_actor;
|
||||
SCamera *camera = actor->_camera;
|
||||
SLight *light = actor->_light;
|
||||
int vertexNum = actor->_vertexNum;
|
||||
|
||||
if (actor->_curAction > hLAST)
|
||||
error("Error in drawCharacter() - _curAction > hLAST");
|
||||
|
||||
int cfp = 0;
|
||||
int cur = 0;
|
||||
while (cur < actor->_curAction)
|
||||
cfp += defActionLen[cur++];
|
||||
|
||||
if (actor->_curAction == hWALKOUT)
|
||||
cfp = 1;
|
||||
|
||||
cfp += actor->_curFrame;
|
||||
|
||||
if (actor->_curAction == hLAST)
|
||||
cfp = 0;
|
||||
|
||||
actor->_vertex = &actor->_characterArea[cfp * actor->_vertexNum];
|
||||
|
||||
_shadowLightNum = 0;
|
||||
_totalShadowVerts = 0;
|
||||
|
||||
// camera matrix
|
||||
float e10 = camera->_e1[0];
|
||||
float e11 = camera->_e1[1];
|
||||
float e12 = camera->_e1[2];
|
||||
|
||||
float e20 = camera->_e2[0];
|
||||
float e21 = camera->_e2[1];
|
||||
float e22 = camera->_e2[2];
|
||||
|
||||
float e30 = camera->_e3[0];
|
||||
float e31 = camera->_e3[1];
|
||||
float e32 = camera->_e3[2];
|
||||
|
||||
// Light directions
|
||||
float l0 = 0.0f;
|
||||
float l1 = 0.0f;
|
||||
float l2 = 0.0f;
|
||||
|
||||
actor->_area[0] = 32000;
|
||||
actor->_area[1] = -32000;
|
||||
actor->_area[2] = 32000;
|
||||
actor->_area[3] = -32000;
|
||||
actor->_area[4] = 32000;
|
||||
actor->_area[5] = -32000;
|
||||
|
||||
float t = (actor->_theta * M_PI * 2) / 360.0;
|
||||
float cost = cos(t);
|
||||
float sint = sin(t);
|
||||
|
||||
// Put all vertices in dark color
|
||||
for (int i = 0; i < MAXVERTEX; ++i)
|
||||
_vVertex[i]._angle = 180;
|
||||
|
||||
float dist;
|
||||
float tx = 0.0f;
|
||||
float ty = 0.0f;
|
||||
float tz = 0.0f;
|
||||
float pa0, pa1, pa2;
|
||||
|
||||
for (uint32 i = 0; i < actor->_lightNum; ++i) {
|
||||
// if off lint == 0
|
||||
// if it has a shadow lint & 0x80
|
||||
|
||||
int lint = light->_inten & 0x7F;
|
||||
if (lint) { // if it's not turned off
|
||||
tx = light->_x - actor->_px - actor->_dx; // computes direction vector
|
||||
tz = light->_z - actor->_pz - actor->_dz; // between light and actor
|
||||
ty = light->_y;
|
||||
|
||||
if (light->_position) { // if it's attenuated
|
||||
dist = sqrt(tx * tx + ty * ty + tz * tz); // Distance light <--> actor
|
||||
|
||||
// adjust light intensity due to the distance
|
||||
if (_vm->floatComp(dist, light->_outr) == 1) // if it's out of range it's off
|
||||
lint = 0;
|
||||
else if (_vm->floatComp(dist, light->_inr) == 1) // if it's inside the circle it's decreased
|
||||
lint = (int)((float)lint * (light->_outr - dist) / (light->_outr - light->_inr));
|
||||
}
|
||||
}
|
||||
|
||||
if (lint) { // If it's still on
|
||||
// Light rotates around the actor
|
||||
l0 = tx * cost - tz * sint;
|
||||
l2 = tx * sint + tz * cost;
|
||||
l1 = ty;
|
||||
t = sqrt(l0 * l0 + l1 * l1 + l2 * l2);
|
||||
l0 /= t;
|
||||
l1 /= t;
|
||||
l2 /= t;
|
||||
|
||||
// Adjust light intensity according to the spot
|
||||
tx = (float)light->_fallOff;
|
||||
if (light->_fallOff) { // for light spot only
|
||||
ty = (float)light->_hotspot;
|
||||
|
||||
pa0 = light->_dx * cost - light->_dz * sint;
|
||||
pa1 = light->_dy;
|
||||
pa2 = light->_dx * sint + light->_dz * cost;
|
||||
|
||||
t = sqrt(pa0 * pa0 + pa1 * pa1 + pa2 * pa2);
|
||||
pa0 /= t;
|
||||
pa1 /= t;
|
||||
pa2 /= t;
|
||||
|
||||
tz = acos((pa0 * l0) + (pa1 * l1) + (pa2 * l2)) * 360.0 / (M_PI * 2);
|
||||
tz = CLIP(tz, 0.f, 180.f);
|
||||
|
||||
// tx falloff
|
||||
// ty hotspot
|
||||
// tz current angle
|
||||
|
||||
_shadowIntens[_shadowLightNum] = SHADOWAMBIENT;
|
||||
|
||||
if (_vm->floatComp(tz, tx) == 1) { // tz > tx - if it's out of the falloff
|
||||
lint = 0;
|
||||
_shadowIntens[_shadowLightNum] = 0;
|
||||
} else if (_vm->floatComp(tz, ty) == 1) { // tz > ty - if it's between the falloff and the hotspot
|
||||
lint = (int)((float)lint * (tx - tz) / (tx - ty));
|
||||
_shadowIntens[_shadowLightNum] = (int)((float)_shadowIntens[_shadowLightNum] * (tx - tz) / (tx - ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((light->_inten & 0x80) && lint) { // if it's shadowed and still on
|
||||
|
||||
// casts shadow vertices
|
||||
for (int j = 0; j < SHADOWVERTSNUM; ++j) {
|
||||
pa0 = actor->_vertex[_shadowVerts[j]]._x;
|
||||
pa1 = actor->_vertex[_shadowVerts[j]]._y;
|
||||
pa2 = actor->_vertex[_shadowVerts[j]]._z;
|
||||
|
||||
_shVertex[vertexNum + _totalShadowVerts + j]._x = pa0 - (pa1 * l0);
|
||||
_shVertex[vertexNum + _totalShadowVerts + j]._z = pa2 - (pa1 * l2);
|
||||
_shVertex[vertexNum + _totalShadowVerts + j]._y = 0;
|
||||
}
|
||||
|
||||
// per default all shadows are equally faint
|
||||
// _shadowIntens[_shadowLightNum] = SHADOWAMBIENT;
|
||||
|
||||
++_shadowLightNum;
|
||||
_totalShadowVerts += SHADOWVERTSNUM;
|
||||
}
|
||||
|
||||
if (lint) { // if still on
|
||||
// adapts the light vector o its intensity
|
||||
t = (float)(lint) / 127.0;
|
||||
l0 = l0 * t;
|
||||
l1 = l1 * t;
|
||||
l2 = l2 * t;
|
||||
|
||||
SVertex *curVertex = actor->_vertex;
|
||||
for (int j = 0; j < vertexNum; ++j) {
|
||||
pa0 = curVertex->_nx;
|
||||
pa1 = curVertex->_ny;
|
||||
pa2 = curVertex->_nz;
|
||||
|
||||
lint = (int)((acos(pa0 * l0 + pa1 * l1 + pa2 * l2) * 360.0) / M_PI);
|
||||
lint = CLIP(lint, 0, 180);
|
||||
|
||||
_vVertex[j]._angle -= (180 - lint);
|
||||
++curVertex;
|
||||
}
|
||||
}
|
||||
|
||||
++light;
|
||||
}
|
||||
|
||||
// rearranged light values so they can be viewed
|
||||
for (int i = 0; i < vertexNum; ++i)
|
||||
_vVertex[i]._angle = CLIP<int32>(_vVertex[i]._angle, 0, 180);
|
||||
|
||||
// Calculate the distance of the character from the room
|
||||
tx = camera->_ex - actor->_px;
|
||||
ty = camera->_ey;
|
||||
tz = camera->_ez - actor->_pz;
|
||||
|
||||
dist = tx * e30 + ty * e31 + tz * e32;
|
||||
|
||||
SVertex *curVertex = actor->_vertex;
|
||||
|
||||
for (int i = 0; i < vertexNum + _totalShadowVerts; ++i) {
|
||||
if (i < vertexNum) {
|
||||
l0 = curVertex->_x;
|
||||
l1 = curVertex->_z;
|
||||
pa1 = ty - curVertex->_y;
|
||||
} else {
|
||||
l0 = _shVertex[i]._x;
|
||||
l1 = _shVertex[i]._z;
|
||||
pa1 = ty - _shVertex[i]._y;
|
||||
}
|
||||
|
||||
pa0 = tx - (l0 * cost + l1 * sint); // rotate _curVertex
|
||||
pa2 = tz - (-l0 * sint + l1 * cost);
|
||||
|
||||
l0 = pa0 * e10 + pa1 * e11 + pa2 * e12; // project _curVertex
|
||||
l1 = pa0 * e20 + pa1 * e21 + pa2 * e22;
|
||||
l2 = pa0 * e30 + pa1 * e31 + pa2 * e32;
|
||||
|
||||
int x2d = _vm->_cx + (int)((l0 * camera->_fovX) / l2);
|
||||
int y2d = _vm->_cy + (int)((l1 * camera->_fovY) / l2);
|
||||
|
||||
_vVertex[i]._x = x2d;
|
||||
_vVertex[i]._y = y2d;
|
||||
_vVertex[i]._z = (int32)((dist - l2) * 128.0);
|
||||
|
||||
actor->_area[0] = MIN(x2d, actor->_area[0]);
|
||||
actor->_area[1] = MAX(x2d, actor->_area[1]);
|
||||
actor->_area[2] = MIN(y2d, actor->_area[2]);
|
||||
actor->_area[3] = MAX(y2d, actor->_area[3]);
|
||||
|
||||
actor->_area[4] = MIN<int32>(_vVertex[i]._z, actor->_area[4]);
|
||||
actor->_area[5] = MAX<int32>(_vVertex[i]._z, actor->_area[5]);
|
||||
|
||||
++curVertex;
|
||||
}
|
||||
actor->_area[4] = (int)dist;
|
||||
actor->_area[5] = (int)dist;
|
||||
|
||||
// vertex clipping
|
||||
if (actor->_area[0] <= _minXClip + 1) {
|
||||
actor->_area[0] = _minXClip;
|
||||
} else {
|
||||
--actor->_area[0];
|
||||
}
|
||||
|
||||
if (actor->_area[1] >= _maxXClip - 1) {
|
||||
actor->_area[1] = _maxXClip;
|
||||
} else {
|
||||
++actor->_area[1];
|
||||
}
|
||||
|
||||
if (actor->_area[2] <= _minYClip + 1) {
|
||||
actor->_area[2] = _minYClip;
|
||||
} else {
|
||||
--actor->_area[2];
|
||||
}
|
||||
|
||||
if (actor->_area[3] >= _maxYClip - 1) {
|
||||
actor->_area[3] = _maxYClip;
|
||||
} else {
|
||||
++actor->_area[3];
|
||||
}
|
||||
|
||||
if (actor->_curAction == hLAST) // exit displacer
|
||||
actor->_area[2] = actor->_area[3] - (((actor->_area[3] - actor->_area[2]) * actor->_curFrame) / defActionLen[hLAST]);
|
||||
|
||||
// set zbuffer vars
|
||||
setZBufferRegion(actor->_area[0], actor->_area[2], actor->_area[1] - actor->_area[0]);
|
||||
}
|
||||
|
||||
void Renderer3D::drawCharacterFaces() {
|
||||
Actor *actor = _vm->_actor;
|
||||
STexture *textures = actor->_textures;
|
||||
SFace *face = actor->_face;
|
||||
int vertexNum = actor->_vertexNum;
|
||||
|
||||
if (actor->_curAction == hLAST)
|
||||
setClipping(0, actor->_area[2], MAXX, actor->_area[3]);
|
||||
|
||||
for (int i = 0; i < _shadowLightNum; ++i) {
|
||||
for (int j = 0; j < SHADOWFACESNUM; ++j) {
|
||||
int p0 = _shadowFaces[j][0] + vertexNum + i * SHADOWVERTSNUM;
|
||||
int p1 = _shadowFaces[j][1] + vertexNum + i * SHADOWVERTSNUM;
|
||||
int p2 = _shadowFaces[j][2] + vertexNum + i * SHADOWVERTSNUM;
|
||||
|
||||
int px0 = _vVertex[p0]._x;
|
||||
int py0 = _vVertex[p0]._y;
|
||||
int px1 = _vVertex[p1]._x;
|
||||
int py1 = _vVertex[p1]._y;
|
||||
int px2 = _vVertex[p2]._x;
|
||||
int py2 = _vVertex[p2]._y;
|
||||
|
||||
shadowTriangle(px0, py0, px1, py1, px2, py2, 127 - _shadowIntens[i], (int16)(0x7FF0 + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < actor->_faceNum; ++i) {
|
||||
int p0 = face->_a;
|
||||
int p1 = face->_b;
|
||||
int p2 = face->_c;
|
||||
|
||||
int px0 = _vVertex[p0]._x;
|
||||
int py0 = _vVertex[p0]._y;
|
||||
int px1 = _vVertex[p1]._x;
|
||||
int py1 = _vVertex[p1]._y;
|
||||
int px2 = _vVertex[p2]._x;
|
||||
int py2 = _vVertex[p2]._y;
|
||||
|
||||
if (clockWise(px0, py0, px1, py1, px2, py2) > 0) {
|
||||
uint16 textureId = face->_mat;
|
||||
if (textureId < MAXMAT && textures[textureId].isActive()) {
|
||||
textureTriangle(px0, py0, _vVertex[p0]._z, _vVertex[p0]._angle, actor->_textureCoord[i][0][0], actor->_textureCoord[i][0][1],
|
||||
px1, py1, _vVertex[p1]._z, _vVertex[p1]._angle, actor->_textureCoord[i][1][0], actor->_textureCoord[i][1][1],
|
||||
px2, py2, _vVertex[p2]._z, _vVertex[p2]._angle, actor->_textureCoord[i][2][0], actor->_textureCoord[i][2][1],
|
||||
&textures[textureId]);
|
||||
}
|
||||
}
|
||||
|
||||
++face;
|
||||
}
|
||||
|
||||
int p0 = 0;
|
||||
for (int i = _zBufStartY; i < actor->_area[3]; ++i) {
|
||||
for (int j = 1; j < _zBufWid; ++j) {
|
||||
int py1 = (_zBuffer[p0] >= 0x7FF0) * 0x8000;
|
||||
int py2 = (_zBuffer[p0 + 1] >= 0x7FF0) * 0x8000;
|
||||
|
||||
int p1 = _zBuffer[p0] < 0x7FFF;
|
||||
int p2 = _zBuffer[p0 + 1] < 0x7FFF;
|
||||
|
||||
if (p1 != p2) {
|
||||
_vm->_graphicsMgr->pixelAliasing(j + _zBufStartX, i);
|
||||
|
||||
// if the first is the character
|
||||
if (p1)
|
||||
_zBuffer[p0] = 0x00BF | py1;
|
||||
else
|
||||
_zBuffer[p0] = 0x003F | py2;
|
||||
|
||||
if (j + 1 < _zBufWid) {
|
||||
++p0;
|
||||
++j;
|
||||
|
||||
// if the second is the character
|
||||
if (p2)
|
||||
_zBuffer[p0] = 0x00BF | py2;
|
||||
else
|
||||
_zBuffer[p0] = 0x003F | py1;
|
||||
}
|
||||
} else {
|
||||
// set value alpha max
|
||||
if (p1)
|
||||
_zBuffer[p0] = 0x00FF | py1;
|
||||
else
|
||||
_zBuffer[p0] = 0x0000 | py1;
|
||||
}
|
||||
|
||||
++p0;
|
||||
|
||||
// if it's the last of the line
|
||||
if (j == _zBufWid - 1) {
|
||||
if (p2)
|
||||
_zBuffer[p0] = 0x00FF | py2;
|
||||
else
|
||||
_zBuffer[p0] = 0x0000 | py2;
|
||||
}
|
||||
}
|
||||
++p0;
|
||||
}
|
||||
if (actor->_curAction == hLAST)
|
||||
setClipping(0, TOP, MAXX, AREA + TOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the character
|
||||
*/
|
||||
void Renderer3D::drawCharacter(uint8 flag) {
|
||||
if (!_vm->_flagShowCharacter)
|
||||
return;
|
||||
|
||||
// Compute pointer to frame
|
||||
if (flag & CALCPOINTS)
|
||||
calcCharacterPoints();
|
||||
|
||||
if (flag & DRAWFACES)
|
||||
drawCharacterFaces();
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
95
engines/trecision/renderer3d.h
Normal file
95
engines/trecision/renderer3d.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_RENDERER3D_H
|
||||
#define TRECISION_RENDERER3D_H
|
||||
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
struct SVVertex {
|
||||
int32 _x, _y, _z;
|
||||
int32 _angle;
|
||||
|
||||
void clear() {
|
||||
_x = _y = _z = 0;
|
||||
_angle = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class Renderer3D {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
int16 _minXClip;
|
||||
int16 _minYClip;
|
||||
int16 _maxXClip;
|
||||
int16 _maxYClip;
|
||||
|
||||
int16 *_zBuffer;
|
||||
|
||||
int16 _zBufStartX;
|
||||
int16 _zBufStartY;
|
||||
int16 _zBufWid;
|
||||
|
||||
int16 _shadowLightNum;
|
||||
int16 _totalShadowVerts;
|
||||
uint8 _shadowIntens[10];
|
||||
|
||||
SVVertex _vVertex[MAXVERTEX];
|
||||
SVertex _shVertex[MAXVERTEX];
|
||||
|
||||
// data for the triangle routines
|
||||
int16 _lEdge[480];
|
||||
int16 _rEdge[480];
|
||||
uint8 _lColor[480];
|
||||
uint8 _rColor[480];
|
||||
int16 _lZ[480];
|
||||
int16 _rZ[480];
|
||||
uint16 _lTextX[480];
|
||||
uint16 _rTextX[480];
|
||||
uint16 _lTextY[480];
|
||||
uint16 _rTextY[480];
|
||||
|
||||
void setZBufferRegion(int16 sx, int16 sy, int16 dx);
|
||||
int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3);
|
||||
void textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2, int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3, const STexture *t);
|
||||
void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2);
|
||||
void shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 cv, int32 zv);
|
||||
void shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
void calcCharacterPoints();
|
||||
void drawCharacterFaces();
|
||||
|
||||
public:
|
||||
Renderer3D(TrecisionEngine *vm);
|
||||
~Renderer3D();
|
||||
|
||||
void init3DRoom();
|
||||
void resetZBuffer(Common::Rect area);
|
||||
void setClipping(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
void drawCharacter(uint8 flag);
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
227
engines/trecision/resource.cpp
Normal file
227
engines/trecision/resource.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/str.h"
|
||||
#include "common/substream.h"
|
||||
#include "gui/saveload.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/renderer3d.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
Common::SeekableReadStreamEndian *TrecisionEngine::readEndian(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) {
|
||||
return new Common::SeekableReadStreamEndianWrapper(stream, isAmiga(), dispose);
|
||||
}
|
||||
|
||||
void TrecisionEngine::loadAll() {
|
||||
Common::File dataNl;
|
||||
|
||||
if (!dataNl.open("DATA.NL"))
|
||||
error("loadAll : Couldn't open DATA.NL");
|
||||
Common::SeekableReadStreamEndian *data = readEndian(&dataNl, DisposeAfterUse::NO);
|
||||
|
||||
for (int i = 0; i < MAXROOMS; ++i)
|
||||
_room[i].loadRoom(data);
|
||||
|
||||
for (int i = 0; i < MAXOBJ; ++i)
|
||||
_obj[i].loadObj(data);
|
||||
|
||||
for (int i = 0; i < MAXINVENTORY; ++i)
|
||||
_inventoryObj[i].loadObj(data);
|
||||
|
||||
_soundMgr->loadSamples(data);
|
||||
|
||||
// TODO: Unused Amiga data?
|
||||
if (isAmiga()) {
|
||||
data->skip(12 * 12 + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXSCRIPTFRAME; ++i) {
|
||||
_scriptFrame[i]._class = data->readByte();
|
||||
_scriptFrame[i]._event = data->readByte();
|
||||
_scriptFrame[i]._u8Param = data->readByte();
|
||||
data->readByte(); // Padding
|
||||
_scriptFrame[i]._u16Param1 = data->readUint16();
|
||||
_scriptFrame[i]._u16Param2 = data->readUint16();
|
||||
_scriptFrame[i]._u32Param = data->readUint16();
|
||||
_scriptFrame[i]._noWait = !(data->readSint16() == 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAXSCRIPT; ++i) {
|
||||
_scriptFirstFrame[i] = data->readUint16();
|
||||
data->readByte(); // unused field
|
||||
data->readByte(); // Padding
|
||||
}
|
||||
|
||||
_animMgr->loadAnimTab(data);
|
||||
_dialogMgr->loadData(data);
|
||||
|
||||
data->skip(620); // actions (unused)
|
||||
|
||||
int numFileRef = data->readSint32();
|
||||
data->skip(numFileRef * (12 + 4)); // fileRef name + offset
|
||||
|
||||
_textArea = new char[MAXTEXTAREA];
|
||||
data->read(_textArea, MAXTEXTAREA);
|
||||
|
||||
_textPtr = _textArea;
|
||||
|
||||
for (int i = 0; i < MAXOBJNAME; i++)
|
||||
_objName[i] = getNextSentence();
|
||||
|
||||
for (int i = 0; i < MAXSENTENCE; i++)
|
||||
_sentence[i] = getNextSentence();
|
||||
|
||||
for (int i = 0; i < MAXSYSTEXT; i++)
|
||||
_sysText[i] = getNextSentence();
|
||||
|
||||
delete data;
|
||||
dataNl.close();
|
||||
}
|
||||
|
||||
byte *TrecisionEngine::readData(const Common::Path &fileName) {
|
||||
Common::SeekableReadStream *stream = _dataFile.createReadStreamForMember(fileName);
|
||||
if (stream == nullptr)
|
||||
error("readData(): File %s not found", fileName.toString().c_str());
|
||||
|
||||
byte *buf = new byte[stream->size()];
|
||||
stream->read(buf, stream->size());
|
||||
delete stream;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void TrecisionEngine::read3D(const Common::Path &filename) {
|
||||
Common::SeekableReadStreamEndian *ff = readEndian(_dataFile.createReadStreamForMember(filename));
|
||||
if (ff == nullptr)
|
||||
error("read3D: Can't open 3D file %s", filename.toString().c_str());
|
||||
|
||||
_actor->read3D(ff);
|
||||
_pathFind->read3D(ff);
|
||||
|
||||
delete ff;
|
||||
|
||||
_cx = 320;
|
||||
_cy = 240;
|
||||
|
||||
_pathFind->initSortPan();
|
||||
|
||||
_renderer->init3DRoom();
|
||||
_renderer->setClipping(0, TOP, MAXX, AREA + TOP);
|
||||
}
|
||||
|
||||
void TrecisionEngine::readObject(Common::SeekableReadStream *stream, uint16 objIndex, uint16 objectId) {
|
||||
SObject *obj = &_obj[objectId];
|
||||
|
||||
if (obj->isModeFull()) {
|
||||
obj->readRect(stream);
|
||||
|
||||
uint32 size = obj->_rect.width() * obj->_rect.height();
|
||||
delete[] _objectGraphics[objIndex].buf;
|
||||
_objectGraphics[objIndex].buf = new uint16[size];
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
_objectGraphics[objIndex].buf[i] = _graphicsMgr->convertToScreenFormat(stream->readUint16LE());
|
||||
}
|
||||
|
||||
if (obj->isModeMask()) {
|
||||
obj->readRect(stream);
|
||||
|
||||
uint32 size = stream->readUint32LE();
|
||||
delete[] _objectGraphics[objIndex].buf;
|
||||
_objectGraphics[objIndex].buf = new uint16[size];
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
_objectGraphics[objIndex].buf[i] = _graphicsMgr->convertToScreenFormat(stream->readUint16LE());
|
||||
|
||||
size = stream->readUint32LE();
|
||||
delete[] _objectGraphics[objIndex].mask;
|
||||
_objectGraphics[objIndex].mask = new uint8[size];
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
_objectGraphics[objIndex].mask[i] = (uint8)stream->readByte();
|
||||
}
|
||||
|
||||
refreshObject(objectId);
|
||||
}
|
||||
|
||||
void TrecisionEngine::readObj(Common::SeekableReadStream *stream) {
|
||||
if (!_room[_curRoom]._object[0])
|
||||
return;
|
||||
|
||||
for (uint16 objIndex = 0; objIndex < MAXOBJINROOM; objIndex++) {
|
||||
const uint16 objectId = _room[_curRoom]._object[objIndex];
|
||||
if (!objectId)
|
||||
break;
|
||||
|
||||
if (_curRoom == kRoom41D && objIndex == PATCHOBJ_ROOM41D)
|
||||
break;
|
||||
|
||||
if (_curRoom == kRoom2C && objIndex == PATCHOBJ_ROOM2C)
|
||||
break;
|
||||
|
||||
readObject(stream, objIndex, objectId);
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::readExtraObj2C() {
|
||||
if (!_room[_curRoom]._object[32])
|
||||
return;
|
||||
|
||||
Common::SeekableReadStream *ff = _dataFile.createReadStreamForMember("2c2.bm");
|
||||
|
||||
for (uint16 objIndex = PATCHOBJ_ROOM2C; objIndex < MAXOBJINROOM; objIndex++) {
|
||||
const uint16 objectId = _room[_curRoom]._object[objIndex];
|
||||
if (!objectId)
|
||||
break;
|
||||
|
||||
readObject(ff, objIndex, objectId);
|
||||
}
|
||||
|
||||
delete ff;
|
||||
}
|
||||
|
||||
void TrecisionEngine::readPositionerSnapshots() {
|
||||
if (!_room[_curRoom]._object[32])
|
||||
return;
|
||||
|
||||
Common::SeekableReadStream *ff = _dataFile.createReadStreamForMember("41d2.bm");
|
||||
for (uint16 objIndex = PATCHOBJ_ROOM41D; objIndex < MAXOBJINROOM; objIndex++) {
|
||||
const uint16 objectId = _room[_curRoom]._object[objIndex];
|
||||
if (!objectId)
|
||||
break;
|
||||
|
||||
readObject(ff, objIndex, objectId);
|
||||
}
|
||||
delete ff;
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
467
engines/trecision/saveload.cpp
Normal file
467
engines/trecision/saveload.cpp
Normal file
@@ -0,0 +1,467 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/saveload.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
void TrecisionEngine::loadSaveSlots(Common::StringArray &saveNames) {
|
||||
for (uint i = 0; i < ICONSHOWN; ++i) {
|
||||
SaveStateDescriptor saveState = getMetaEngine()->querySaveMetaInfos(_targetName.c_str(), i + 1);
|
||||
if (saveState.getSaveSlot() == -1) {
|
||||
saveNames.push_back(_sysText[kMessageEmptySpot]);
|
||||
_inventory.push_back(EMPTYSLOT);
|
||||
} else {
|
||||
saveNames.push_back(saveState.getDescription());
|
||||
_inventory.push_back(EMPTYSLOT + i + 1);
|
||||
_graphicsMgr->setSaveSlotThumbnail(i, saveState.getThumbnail());
|
||||
}
|
||||
}
|
||||
|
||||
refreshInventory(0, 0);
|
||||
}
|
||||
|
||||
bool TrecisionEngine::dataSave() {
|
||||
const Common::Array<byte> savedInventory = _inventory;
|
||||
const uint8 savedIconBase = _iconBase;
|
||||
Common::StringArray saveNames;
|
||||
saveNames.reserve(MAXSAVEFILE);
|
||||
uint16 posx, LenText;
|
||||
bool ret = true;
|
||||
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
|
||||
if (!ConfMan.getBool("originalsaveload")) {
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
|
||||
int saveSlot = dialog->runModalWithCurrentTarget();
|
||||
Common::String saveName = dialog->getResultString();
|
||||
bool skipSave = saveSlot == -1;
|
||||
delete dialog;
|
||||
|
||||
// Remove the mouse click event from the save/load dialog
|
||||
eventLoop();
|
||||
_mouseLeftBtn = _mouseRightBtn = false;
|
||||
|
||||
if (!skipSave)
|
||||
saveGameState(saveSlot, saveName);
|
||||
|
||||
return skipSave;
|
||||
}
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
SDText drawText;
|
||||
drawText.set(
|
||||
Common::Rect(0, TOP - 20, MAXX, CARHEI + (TOP - 20)),
|
||||
Common::Rect(0, 0, MAXX, CARHEI),
|
||||
MOUSECOL,
|
||||
_sysText[kMessageSavePosition]);
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
_graphicsMgr->copyToScreen(0, TOP + AREA, MAXX, TOP);
|
||||
|
||||
_scheduler->resetQueues();
|
||||
|
||||
freeKey();
|
||||
|
||||
// Reset the inventory and turn it into save slots
|
||||
_inventory.clear();
|
||||
_iconBase = 0;
|
||||
|
||||
insave:
|
||||
|
||||
int8 CurPos = -1;
|
||||
int8 OldPos = -1;
|
||||
bool skipSave = false;
|
||||
|
||||
loadSaveSlots(saveNames);
|
||||
|
||||
for (;;) {
|
||||
checkSystem();
|
||||
getKey();
|
||||
|
||||
int16 mx = _mousePos.x;
|
||||
int16 my = _mousePos.y;
|
||||
|
||||
if (my >= FIRSTLINE &&
|
||||
my < FIRSTLINE + ICONDY &&
|
||||
mx >= ICONMARGSX &&
|
||||
mx < MAXX - ICONMARGDX) {
|
||||
OldPos = CurPos;
|
||||
CurPos = ((mx - ICONMARGSX) / ICONDX);
|
||||
|
||||
if (OldPos != CurPos) {
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
|
||||
posx = ICONMARGSX + ((CurPos) * (ICONDX)) + ICONDX / 2;
|
||||
LenText = textLength(saveNames[CurPos]);
|
||||
|
||||
posx = CLIP(posx - (LenText / 2), 2, MAXX - 2 - LenText);
|
||||
drawText.set(
|
||||
Common::Rect(posx, FIRSTLINE + ICONDY + 10, LenText + posx, CARHEI + (FIRSTLINE + ICONDY + 10)),
|
||||
Common::Rect(0, 0, LenText, CARHEI),
|
||||
MOUSECOL,
|
||||
saveNames[CurPos].c_str());
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
if (_mouseLeftBtn) {
|
||||
_mouseLeftBtn = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (OldPos != -1) {
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
OldPos = -1;
|
||||
CurPos = -1;
|
||||
|
||||
if (_mouseLeftBtn || _mouseRightBtn) {
|
||||
_mouseLeftBtn = _mouseRightBtn = false;
|
||||
skipSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipSave) {
|
||||
if (_inventory[CurPos] == EMPTYSLOT) {
|
||||
saveNames[CurPos].clear();
|
||||
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_keybInput = true;
|
||||
checkSystem();
|
||||
uint16 ch = getKey();
|
||||
freeKey();
|
||||
|
||||
_keybInput = false;
|
||||
|
||||
if (ch == 0x1B) {
|
||||
ch = 0;
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
|
||||
goto insave;
|
||||
}
|
||||
|
||||
if (ch == 8) // Backspace
|
||||
saveNames[CurPos].deleteLastChar();
|
||||
else if (ch == 13) // Enter
|
||||
break;
|
||||
else if (saveNames[CurPos].size() < 39 && Common::isPrint(ch))
|
||||
saveNames[CurPos] += ch;
|
||||
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
|
||||
saveNames[CurPos] += '_'; // add blinking cursor
|
||||
|
||||
posx = ICONMARGSX + ((CurPos) * (ICONDX)) + ICONDX / 2;
|
||||
LenText = textLength(saveNames[CurPos]);
|
||||
|
||||
posx = CLIP(posx - (LenText / 2), 2, MAXX - 2 - LenText);
|
||||
drawText.set(
|
||||
Common::Rect(posx, FIRSTLINE + ICONDY + 10, LenText + posx, CARHEI + (FIRSTLINE + ICONDY + 10)),
|
||||
Common::Rect(0, 0, LenText, CARHEI),
|
||||
MOUSECOL,
|
||||
saveNames[CurPos].c_str());
|
||||
|
||||
const bool hideLastChar = (readTime() / 8) & 1;
|
||||
drawText.draw(this, hideLastChar);
|
||||
|
||||
saveNames[CurPos].deleteLastChar(); // remove blinking cursor
|
||||
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
|
||||
ret = false;
|
||||
|
||||
// Restore the inventory
|
||||
_inventory = savedInventory;
|
||||
_curInventory = 0;
|
||||
_iconBase = savedIconBase;
|
||||
|
||||
saveGameState(CurPos + 1, saveNames[CurPos]);
|
||||
}
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE, MAXX, TOP);
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
// Restore the inventory
|
||||
_inventory = savedInventory;
|
||||
_curInventory = 0;
|
||||
_iconBase = savedIconBase;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TrecisionEngine::dataLoad() {
|
||||
const Common::Array<byte> savedInventory = _inventory;
|
||||
const uint8 savedIconBase = _iconBase;
|
||||
Common::StringArray saveNames;
|
||||
saveNames.reserve(MAXSAVEFILE);
|
||||
bool retval = true;
|
||||
|
||||
if (!ConfMan.getBool("originalsaveload")) {
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false);
|
||||
int saveSlot = dialog->runModalWithCurrentTarget();
|
||||
bool skipLoad = saveSlot == -1;
|
||||
delete dialog;
|
||||
|
||||
// Remove the mouse click event from the save/load dialog
|
||||
eventLoop();
|
||||
_mouseLeftBtn = _mouseRightBtn = false;
|
||||
|
||||
if (!skipLoad)
|
||||
loadGameState(saveSlot);
|
||||
|
||||
return !skipLoad;
|
||||
}
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
_graphicsMgr->showCursor();
|
||||
|
||||
SDText drawText;
|
||||
drawText.set(
|
||||
Common::Rect(0, TOP - 20, MAXX, CARHEI + (TOP - 20)),
|
||||
Common::Rect(0, 0, MAXX, CARHEI),
|
||||
MOUSECOL,
|
||||
_sysText[kMessageLoadPosition]);
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
_graphicsMgr->copyToScreen(0, TOP + AREA, MAXX, TOP);
|
||||
|
||||
_scheduler->resetQueues();
|
||||
|
||||
freeKey();
|
||||
|
||||
// Reset the inventory and turn it into save slots
|
||||
_inventory.clear();
|
||||
_iconBase = 0;
|
||||
|
||||
loadSaveSlots(saveNames);
|
||||
|
||||
bool skipLoad = false;
|
||||
int8 curPos = -1;
|
||||
int8 oldPos = -1;
|
||||
|
||||
for (;;) {
|
||||
checkSystem();
|
||||
getKey();
|
||||
|
||||
if (_mousePos.y >= FIRSTLINE &&
|
||||
_mousePos.y < (FIRSTLINE + ICONDY) &&
|
||||
_mousePos.x >= ICONMARGSX &&
|
||||
(_mousePos.x < (MAXX - ICONMARGDX))) {
|
||||
oldPos = curPos;
|
||||
curPos = (_mousePos.x - ICONMARGSX) / ICONDX;
|
||||
|
||||
if (oldPos != curPos) {
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
|
||||
uint16 posX = ICONMARGSX + ((curPos) * (ICONDX)) + ICONDX / 2;
|
||||
uint16 lenText = textLength(saveNames[curPos]);
|
||||
if (posX - (lenText / 2) < 2)
|
||||
posX = 2;
|
||||
else
|
||||
posX = posX - (lenText / 2);
|
||||
if (posX + lenText > MAXX - 2)
|
||||
posX = MAXX - 2 - lenText;
|
||||
|
||||
drawText.set(
|
||||
Common::Rect(posX, FIRSTLINE + ICONDY + 10, lenText + posX, CARHEI + (FIRSTLINE + ICONDY + 10)),
|
||||
Common::Rect(0, 0, lenText, CARHEI),
|
||||
MOUSECOL,
|
||||
saveNames[curPos].c_str());
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
if (_mouseLeftBtn && (_inventory[curPos] != EMPTYSLOT)) {
|
||||
_mouseLeftBtn = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (oldPos != -1) {
|
||||
_graphicsMgr->clearScreenBufferSaveSlotDescriptions();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE + ICONDY + 10, MAXX, CARHEI);
|
||||
}
|
||||
|
||||
oldPos = -1;
|
||||
curPos = -1;
|
||||
|
||||
if (_mouseLeftBtn || _mouseRightBtn) {
|
||||
_mouseLeftBtn = _mouseRightBtn = false;
|
||||
retval = false;
|
||||
skipLoad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipLoad) {
|
||||
loadGameState(curPos + 1);
|
||||
} else {
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
checkSystem();
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE, MAXX, TOP);
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
if (_flagScriptActive) {
|
||||
_graphicsMgr->hideCursor();
|
||||
}
|
||||
|
||||
// Restore the inventory
|
||||
_inventory = savedInventory;
|
||||
_curInventory = 0;
|
||||
_iconBase = savedIconBase;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Common::Error TrecisionEngine::loadGameStream(Common::SeekableReadStream *stream) {
|
||||
const byte version = stream->readByte();
|
||||
Common::Serializer ser(stream, nullptr);
|
||||
ser.setVersion(version);
|
||||
syncGameStream(ser);
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
|
||||
_flagNoPaintScreen = true;
|
||||
_curStack = 0;
|
||||
_flagScriptActive = false;
|
||||
|
||||
_oldRoom = _curRoom;
|
||||
changeRoom(_curRoom);
|
||||
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
checkSystem();
|
||||
|
||||
_graphicsMgr->clearScreenBufferInventory();
|
||||
_graphicsMgr->copyToScreen(0, FIRSTLINE, MAXX, TOP);
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
if (_flagScriptActive) {
|
||||
_graphicsMgr->hideCursor();
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error TrecisionEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
||||
const byte version = SAVE_VERSION_SCUMMVM;
|
||||
Common::Serializer ser(nullptr, stream);
|
||||
ser.setVersion(version);
|
||||
stream->writeByte(version);
|
||||
syncGameStream(ser);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool TrecisionEngine::syncGameStream(Common::Serializer &ser) {
|
||||
uint16 unused = 0;
|
||||
|
||||
if (ser.isLoading()) {
|
||||
ser.skip(40, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // description
|
||||
ser.skip(ICONDX * ICONDY * sizeof(uint16), SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // thumbnail
|
||||
}
|
||||
|
||||
ser.syncAsUint16LE(_curRoom);
|
||||
ser.syncAsByte(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _inventorySize
|
||||
ser.syncAsByte(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _cyberInventorySize
|
||||
ser.syncAsByte(_iconBase);
|
||||
ser.syncAsSint16LE(_flagSkipTalk);
|
||||
ser.syncAsSint16LE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _flagSkipEnable
|
||||
ser.syncAsSint16LE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _flagMouseEnabled
|
||||
ser.syncAsSint16LE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _flagScreenRefreshed
|
||||
ser.syncAsSint16LE(_flagPaintCharacter);
|
||||
ser.syncAsSint16LE(_flagSomeoneSpeaks);
|
||||
ser.syncAsSint16LE(_flagCharacterSpeak);
|
||||
ser.syncAsSint16LE(_flagInventoryLocked);
|
||||
ser.syncAsSint16LE(_flagUseWithStarted);
|
||||
ser.syncAsSint16LE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _flagMousePolling
|
||||
ser.syncAsSint16LE(unused, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // _flagDialogSolitaire
|
||||
ser.syncAsSint16LE(unused); // _flagCharacterExists
|
||||
|
||||
syncInventory(ser);
|
||||
_actor->syncGameStream(ser);
|
||||
_pathFind->syncGameStream(ser);
|
||||
|
||||
for (int i = 0; i < MAXROOMS; i++)
|
||||
_room[i].syncGameStream(ser);
|
||||
|
||||
for (int i = 0; i < MAXOBJ; i++)
|
||||
_obj[i].syncGameStream(ser);
|
||||
|
||||
for (int i = 0; i < MAXINVENTORY; i++)
|
||||
_inventoryObj[i].syncGameStream(ser);
|
||||
|
||||
_animMgr->syncGameStream(ser);
|
||||
ser.skip(NUMSAMPLES * 2, SAVE_VERSION_ORIGINAL_MIN, SAVE_VERSION_ORIGINAL_MAX); // SoundManager::syncGameStream()
|
||||
_dialogMgr->syncGameStream(ser);
|
||||
_logicMgr->syncGameStream(ser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
164
engines/trecision/scheduler.cpp
Normal file
164
engines/trecision/scheduler.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/scheduler.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
Scheduler::Scheduler(TrecisionEngine *vm) : _vm(vm) {
|
||||
_token = CLASS_CHAR;
|
||||
_counter = 0;
|
||||
|
||||
Message msg = { MC_IDLE, 0, MP_DEFAULT, 0, 0, 0, 0 };
|
||||
_idleMsg = _msg = msg;
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler() {
|
||||
}
|
||||
|
||||
void Scheduler::process() {
|
||||
bool retry = true;
|
||||
|
||||
while (retry) {
|
||||
retry = false;
|
||||
switch (_token) {
|
||||
case CLASS_GAME:
|
||||
if (_counter <= 30) {
|
||||
++_counter;
|
||||
_token = CLASS_CHAR;
|
||||
if (!_gameQueue.empty()) {
|
||||
_msg = _gameQueue.front();
|
||||
_vm->_curMessage = &_msg;
|
||||
_gameQueue.pop_front();
|
||||
} else {
|
||||
_vm->_curMessage = &_idleMsg;
|
||||
}
|
||||
} else {
|
||||
_counter = 0;
|
||||
_vm->_curMessage = &_idleMsg;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASS_CHAR:
|
||||
_token = CLASS_GAME;
|
||||
if (_vm->_flagPaintCharacter || _characterQueue.empty()) {
|
||||
retry = true;
|
||||
} else {
|
||||
_msg = _characterQueue.front();
|
||||
_vm->_curMessage = &_msg;
|
||||
_characterQueue.pop_front();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MessageComparator {
|
||||
bool operator()(const Message &x, const Message &y) const {
|
||||
return x._priority < y._priority;
|
||||
}
|
||||
};
|
||||
|
||||
void Scheduler::doEvent(uint8 cls, uint8 event, uint8 priority,
|
||||
uint16 u16Param1, uint16 u16Param2,
|
||||
uint8 u8Param, uint32 u32Param) {
|
||||
Message m;
|
||||
|
||||
m._class = cls;
|
||||
m._event = event;
|
||||
m._priority = priority;
|
||||
m._u16Param1 = u16Param1;
|
||||
m._u16Param2 = u16Param2;
|
||||
m._u8Param = u8Param;
|
||||
m._u32Param = u32Param;
|
||||
|
||||
if (cls <= CLASS_GAME) {
|
||||
_gameQueue.push_back(m);
|
||||
Common::sort(_gameQueue.begin(), _gameQueue.end(), MessageComparator());
|
||||
} else {
|
||||
_characterQueue.push_back(m);
|
||||
Common::sort(_characterQueue.begin(), _characterQueue.end(), MessageComparator());
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::leftClick(uint16 x, uint16 y) {
|
||||
doEvent(MC_MOUSE, ME_MLEFT, MP_DEFAULT, x, y, 0, 0);
|
||||
}
|
||||
|
||||
void Scheduler::rightClick(uint16 x, uint16 y) {
|
||||
doEvent(MC_MOUSE, ME_MRIGHT, MP_DEFAULT, x, y, 0, 0);
|
||||
}
|
||||
|
||||
void Scheduler::mouseExamine(uint16 object) {
|
||||
doEvent(MC_ACTION, ME_MOUSEEXAMINE, MP_DEFAULT, 0, 0, 0, object);
|
||||
}
|
||||
|
||||
void Scheduler::mouseOperate(uint16 object) {
|
||||
doEvent(MC_ACTION, ME_MOUSEOPERATE, MP_DEFAULT, 0, 0, 0, object);
|
||||
}
|
||||
|
||||
void Scheduler::init() {
|
||||
resetQueues();
|
||||
|
||||
_vm->_curMessage = &_idleMsg;
|
||||
}
|
||||
|
||||
void Scheduler::resetQueues() {
|
||||
_gameQueue.clear();
|
||||
_characterQueue.clear();
|
||||
}
|
||||
|
||||
void Scheduler::initCharacterQueue() {
|
||||
_characterQueue.clear();
|
||||
}
|
||||
|
||||
bool Scheduler::testEmptyQueues() {
|
||||
bool onlyDialogEventsInGameQueue = true;
|
||||
bool noActionInProgress = true;
|
||||
|
||||
for (Common::List<Message>::iterator it = _gameQueue.begin(); it != _gameQueue.end(); ++it) {
|
||||
if (it->_class != MC_DIALOG) {
|
||||
onlyDialogEventsInGameQueue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (Common::List<Message>::iterator it = _characterQueue.begin(); it != _characterQueue.end(); ++it) {
|
||||
if (it->_class == MC_CHARACTER) {
|
||||
if (it->_event == ME_CHARACTERACTION ||
|
||||
it->_event == ME_CHARACTERGOTO ||
|
||||
it->_event == ME_CHARACTERGOTOACTION ||
|
||||
it->_event == ME_CHARACTERGOTOEXAMINE ||
|
||||
it->_event == ME_CHARACTERCONTINUEACTION) {
|
||||
noActionInProgress = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return noActionInProgress && onlyDialogEventsInGameQueue;
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
85
engines/trecision/scheduler.h
Normal file
85
engines/trecision/scheduler.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_SCHEDULER_H
|
||||
#define TRECISION_SCHEDULER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/list.h"
|
||||
|
||||
#define MAXMESSAGE 128
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
struct Message {
|
||||
uint8 _class; // message class
|
||||
uint8 _event; // message name
|
||||
uint8 _priority; // message priority
|
||||
|
||||
uint8 _u8Param;
|
||||
uint16 _u16Param1; // byte parameter 1
|
||||
uint16 _u16Param2; // byte parameter 2
|
||||
uint32 _u32Param; // int parameter
|
||||
|
||||
void set(Message *src) {
|
||||
_class = src->_class;
|
||||
_event = src->_event;
|
||||
_priority = src->_priority;
|
||||
_u8Param = src->_u8Param;
|
||||
_u16Param1 = src->_u16Param1;
|
||||
_u16Param2 = src->_u16Param2;
|
||||
_u32Param = src->_u32Param;
|
||||
}
|
||||
};
|
||||
|
||||
class Scheduler {
|
||||
TrecisionEngine *_vm;
|
||||
uint8 _token;
|
||||
uint8 _counter;
|
||||
|
||||
// Message system
|
||||
Message _idleMsg;
|
||||
Message _msg;
|
||||
Common::List<Message> _gameQueue;
|
||||
Common::List<Message> _characterQueue;
|
||||
|
||||
public:
|
||||
Scheduler(TrecisionEngine *vm);
|
||||
~Scheduler();
|
||||
|
||||
void process();
|
||||
void doEvent(uint8 cls, uint8 event, uint8 priority, uint16 u16Param1, uint16 u16Param2, uint8 u8Param, uint32 u32Param);
|
||||
void leftClick(uint16 x, uint16 y);
|
||||
void rightClick(uint16 x, uint16 y);
|
||||
void mouseExamine(uint16 object);
|
||||
void mouseOperate(uint16 object);
|
||||
|
||||
void init();
|
||||
void resetQueues();
|
||||
void initCharacterQueue();
|
||||
bool testEmptyQueues();
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
665
engines/trecision/script.cpp
Normal file
665
engines/trecision/script.cpp
Normal file
@@ -0,0 +1,665 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/scaler.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/renderer3d.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
void SScriptFrame::clear() {
|
||||
_class = MC_IDLE;
|
||||
_event = ME_MOUSEOPERATE;
|
||||
_u8Param = 0;
|
||||
_u16Param1 = _u16Param2 = 0;
|
||||
_u32Param = 0;
|
||||
|
||||
_noWait = false;
|
||||
}
|
||||
|
||||
void SScriptFrame::sendFrame(Scheduler *scheduler) {
|
||||
scheduler->doEvent(_class, _event, MP_DEFAULT, _u16Param1, _u16Param2, _u8Param, _u32Param);
|
||||
}
|
||||
|
||||
void TrecisionEngine::endScript() {
|
||||
--_curStack;
|
||||
if (_curStack == 0) {
|
||||
_flagScriptActive = false;
|
||||
_graphicsMgr->showCursor();
|
||||
_textMgr->redrawString();
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::playScript(uint16 id) {
|
||||
++_curStack;
|
||||
_flagScriptActive = true;
|
||||
_graphicsMgr->hideCursor();
|
||||
_curScriptFrame[_curStack] = _scriptFirstFrame[id];
|
||||
|
||||
processScriptFrame();
|
||||
}
|
||||
|
||||
void TrecisionEngine::evalScript() {
|
||||
if (_scheduler->testEmptyQueues()) {
|
||||
++_curScriptFrame[_curStack];
|
||||
_graphicsMgr->hideCursor();
|
||||
|
||||
processScriptFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::processScriptFrame() {
|
||||
SScriptFrame *curFrame = &_scriptFrame[_curScriptFrame[_curStack]];
|
||||
// If the event is empty, terminate the script
|
||||
if (curFrame->isEmptyEvent()) {
|
||||
endScript();
|
||||
return;
|
||||
}
|
||||
|
||||
bool loop = true;
|
||||
while (loop) {
|
||||
loop = false;
|
||||
curFrame = &_scriptFrame[_curScriptFrame[_curStack]];
|
||||
SScriptFrame *nextFrame = &_scriptFrame[_curScriptFrame[_curStack] + 1];
|
||||
curFrame->sendFrame(_scheduler);
|
||||
if (curFrame->_noWait && !nextFrame->isEmptyEvent()) {
|
||||
++_curScriptFrame[_curStack];
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TrecisionEngine::quitPrompt() {
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
SDText drawText;
|
||||
drawText.set(
|
||||
Common::Rect(0, TOP - 20, MAXX, CARHEI + (TOP - 20)),
|
||||
Common::Rect(0, 0, MAXX, CARHEI),
|
||||
MOUSECOL,
|
||||
_sysText[kMessageConfirmExit]
|
||||
);
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
freeKey();
|
||||
checkSystem();
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
waitKey();
|
||||
Common::CustomEventType customType = _curAction;
|
||||
_curAction = kActionNone;
|
||||
return (customType == kActionYes); // German confirmation is J, English and French use 'Y'
|
||||
}
|
||||
|
||||
void TrecisionEngine::demoOver() {
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
|
||||
SDText drawText;
|
||||
drawText.set(
|
||||
Common::Rect(0, TOP - 20, MAXX, CARHEI + (TOP - 20)),
|
||||
Common::Rect(0, 0, MAXX, CARHEI),
|
||||
MOUSECOL,
|
||||
_sysText[kMessageDemoOver]
|
||||
);
|
||||
drawText.draw(this);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, TOP);
|
||||
|
||||
freeKey();
|
||||
waitKey();
|
||||
quitGame();
|
||||
}
|
||||
|
||||
void TrecisionEngine::doAction() {
|
||||
if (_curMessage->_event == ME_MOUSEOPERATE || _curMessage->_event == ME_MOUSEEXAMINE) {
|
||||
// Action in the game area
|
||||
_curObj = _curMessage->_u32Param;
|
||||
if (_curObj == oLASTLEV5)
|
||||
_textMgr->characterSay(kSentencePutHimOutOfAction);
|
||||
|
||||
if (!_curObj || !isObjectVisible(_curObj))
|
||||
return;
|
||||
|
||||
if (_obj[_curObj].isModeHidden())
|
||||
_obj[_curObj].setModeHidden(false);
|
||||
|
||||
if (_flagUseWithStarted) {
|
||||
if ((_obj[_curObj].isFlagRoomOut() || _obj[_curObj].isFlagRoomIn()) && !_obj[_curObj].isFlagExamine())
|
||||
return;
|
||||
_flagUseWithStarted = false;
|
||||
_flagInventoryLocked = false;
|
||||
_useWith[WITH] = _curObj;
|
||||
_useWithInv[WITH] = false;
|
||||
_lightIcon = 0xFF;
|
||||
|
||||
if (!_useWithInv[USED] && _curObj == _useWith[USED]) {
|
||||
_useWith[USED] = 0;
|
||||
_useWith[WITH] = 0;
|
||||
_useWithInv[USED] = false;
|
||||
_useWithInv[WITH] = false;
|
||||
_flagUseWithStarted = false;
|
||||
_textMgr->clearLastText();
|
||||
} else
|
||||
doUseWith();
|
||||
_curObj = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_curMessage->_event == ME_MOUSEOPERATE && _obj[_curObj].isFlagUseWith()) {
|
||||
_flagUseWithStarted = true;
|
||||
_flagInventoryLocked = true;
|
||||
_useWith[USED] = _curObj;
|
||||
_useWith[WITH] = 0;
|
||||
_useWithInv[USED] = false;
|
||||
_useWithInv[WITH] = false;
|
||||
_textMgr->showObjName(_curObj, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (_curMessage->_event) {
|
||||
case ME_MOUSEOPERATE:
|
||||
if (_obj[_curObj].isFlagRoomIn())
|
||||
doRoomIn(_curObj);
|
||||
else if (_obj[_curObj].isFlagPerson())
|
||||
doMouseTalk(_curObj);
|
||||
else if (_obj[_curObj].isFlagRoomOut())
|
||||
doRoomOut(_curObj);
|
||||
else if (_obj[_curObj].isFlagTake())
|
||||
doMouseTake(_curObj);
|
||||
else
|
||||
doMouseOperate(_curObj);
|
||||
break;
|
||||
|
||||
case ME_MOUSEEXAMINE:
|
||||
if (_obj[_curObj].isFlagExamine())
|
||||
doMouseExamine(_curObj);
|
||||
else if (_obj[_curObj].isFlagRoomIn())
|
||||
doRoomIn(_curObj);
|
||||
else if (_obj[_curObj].isFlagPerson())
|
||||
doMouseExamine(_curObj);
|
||||
else if (_obj[_curObj].isFlagRoomOut())
|
||||
doRoomOut(_curObj);
|
||||
else
|
||||
doMouseExamine(_curObj);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::processMouseMovement() {
|
||||
if (isGameArea(_mousePos)) {
|
||||
// Game area
|
||||
if (_flagSomeoneSpeaks || _flagDialogMenuActive || _flagDialogActive)
|
||||
return;
|
||||
|
||||
checkMask(_mousePos);
|
||||
_logicMgr->doMouseGame();
|
||||
} else if (isInventoryArea(_mousePos)) {
|
||||
if (_logicMgr->doMouseInventory())
|
||||
return;
|
||||
if ((_flagSomeoneSpeaks && !_flagCharacterSpeak) || _flagDialogMenuActive || _flagDialogActive)
|
||||
return;
|
||||
if (_animMgr->isActionActive())
|
||||
return;
|
||||
|
||||
if (_inventoryStatus == INV_OFF)
|
||||
openInventory();
|
||||
else if (_inventoryStatus == INV_INACTION)
|
||||
showIconName();
|
||||
} else {
|
||||
// Up area
|
||||
if (_curRoom == kRoomControlPanel)
|
||||
return;
|
||||
|
||||
_curObj = 0;
|
||||
_textMgr->showObjName(_curObj, true);
|
||||
|
||||
if (_flagDialogMenuActive)
|
||||
_dialogMgr->updateChoices(_mousePos.x, _mousePos.y);
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::doMouse() {
|
||||
switch (_curMessage->_event) {
|
||||
case ME_MRIGHT:
|
||||
case ME_MLEFT:
|
||||
if (_flagSomeoneSpeaks) {
|
||||
_flagSkipTalk = true;
|
||||
break;
|
||||
}
|
||||
if (_actor->_curAction > hWALKIN)
|
||||
break;
|
||||
|
||||
if (_flagDialogActive && _flagDialogMenuActive) {
|
||||
_dialogMgr->selectChoice(_mousePos.x, _mousePos.y);
|
||||
break;
|
||||
}
|
||||
|
||||
_logicMgr->doMouseLeftRight();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::doCharacter() {
|
||||
switch (_curMessage->_event) {
|
||||
case ME_CHARACTERDOACTION:
|
||||
case ME_CHARACTERGOTOACTION:
|
||||
case ME_CHARACTERGOTOEXAMINE:
|
||||
case ME_CHARACTERGOTOEXIT:
|
||||
case ME_CHARACTERGOTO:
|
||||
|
||||
if (_pathFind->nextStep()) {
|
||||
_pathFind->_characterInMovement = false;
|
||||
_pathFind->_characterGoToPosition = -1;
|
||||
_flagWaitRegen = true;
|
||||
} else
|
||||
_pathFind->_characterInMovement = true;
|
||||
|
||||
if (_fastWalk) {
|
||||
if (_pathFind->nextStep()) {
|
||||
_pathFind->_characterInMovement = false;
|
||||
_pathFind->_characterGoToPosition = -1;
|
||||
_flagWaitRegen = true;
|
||||
} else
|
||||
_pathFind->_characterInMovement = true;
|
||||
}
|
||||
|
||||
_flagPaintCharacter = true;
|
||||
|
||||
if (_pathFind->_characterInMovement)
|
||||
reEvent();
|
||||
else {
|
||||
_graphicsMgr->showCursor();
|
||||
|
||||
if (_curMessage->_event == ME_CHARACTERGOTOACTION)
|
||||
_scheduler->mouseOperate((uint16)_curMessage->_u32Param);
|
||||
else if (_curMessage->_event == ME_CHARACTERGOTOEXAMINE)
|
||||
_scheduler->mouseExamine((uint16)_curMessage->_u32Param);
|
||||
else if (_curMessage->_event == ME_CHARACTERGOTOEXIT) {
|
||||
_flagShowCharacter = false;
|
||||
changeRoom(_curMessage->_u16Param1, _curMessage->_u16Param2, _curMessage->_u8Param);
|
||||
} else if (_curMessage->_event == ME_CHARACTERDOACTION) {
|
||||
_lastObj = 0;
|
||||
_textMgr->showObjName(_curObj, true);
|
||||
refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_CHARACTERACTION:
|
||||
if (_flagWaitRegen)
|
||||
reEvent();
|
||||
_scheduler->initCharacterQueue();
|
||||
_inventoryRefreshStartLine = INVENTORY_HIDE;
|
||||
refreshInventory(_inventoryRefreshStartIcon, INVENTORY_HIDE);
|
||||
_inventoryStatus = INV_OFF;
|
||||
if (_curMessage->_u16Param1 > hLAST) {
|
||||
_animMgr->startSmkAnim(_curMessage->_u16Param1);
|
||||
_animTypeMgr->init(_curMessage->_u16Param1, _curMessage->_u32Param);
|
||||
_graphicsMgr->hideCursor();
|
||||
_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERCONTINUEACTION, _curMessage->_priority, _curMessage->_u16Param1, _curMessage->_u16Param2, _curMessage->_u8Param, _curMessage->_u32Param);
|
||||
} else
|
||||
_actor->actorDoAction(_curMessage->_u16Param1);
|
||||
|
||||
_textMgr->clearLastText();
|
||||
break;
|
||||
|
||||
case ME_CHARACTERCONTINUEACTION:
|
||||
_flagShowCharacter = false;
|
||||
_animTypeMgr->handler(kAnimTypeCharacter);
|
||||
// If the animation is over
|
||||
if (!_animMgr->isActionActive()) {
|
||||
_graphicsMgr->showCursor();
|
||||
_flagShowCharacter = true;
|
||||
_pathFind->_characterInMovement = false;
|
||||
_scheduler->initCharacterQueue();
|
||||
_animTypeMgr->end(kAnimTypeCharacter);
|
||||
_flagWaitRegen = true;
|
||||
_lastObj = 0;
|
||||
_textMgr->showObjName(_curObj, true);
|
||||
// If the room changes at the end
|
||||
if (_curMessage->_u16Param2) {
|
||||
_flagShowCharacter = false;
|
||||
changeRoom(_curMessage->_u16Param2, 0, _curMessage->_u8Param);
|
||||
} else if (_curMessage->_u8Param)
|
||||
_pathFind->setPosition(_curMessage->_u8Param);
|
||||
|
||||
if ((_curMessage->_u16Param1 == _obj[oCANCELLATA1B]._anim) && !isObjectVisible(oBOTTIGLIA1D) && !isObjectVisible(oRETE17)) {
|
||||
_dialogMgr->playDialog(dF181);
|
||||
_pathFind->setPosition(1);
|
||||
}
|
||||
} else
|
||||
reEvent();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::changeRoom(uint16 room, uint16 action, byte position) {
|
||||
if (_curRoom == 0)
|
||||
return;
|
||||
|
||||
// if regen still has to occur
|
||||
if (_flagWaitRegen)
|
||||
reEvent();
|
||||
|
||||
_logicMgr->doSystemChangeRoom(room);
|
||||
|
||||
_pathFind->setPosition(position);
|
||||
_actor->actorStop();
|
||||
|
||||
if (action)
|
||||
startCharacterAction(action, 0, 0, 0);
|
||||
|
||||
_logicMgr->endChangeRoom();
|
||||
|
||||
// WORKAROUND: Set position *again*. Fixes entering some rooms
|
||||
// (e.g. kRoom23A, kRoom2D, kRoom28).
|
||||
// The first two checks have been duplicated from endChangeRoom()
|
||||
if (_curRoom == kRoom31 && !_room[kRoom31].isDone())
|
||||
_pathFind->setPosition(14);
|
||||
else if (_oldRoom == kRoom41D && _inventoryObj[kItemPositioner].isFlagExtra())
|
||||
_pathFind->setPosition(30);
|
||||
else
|
||||
_pathFind->setPosition(position);
|
||||
|
||||
_room[_curRoom].setDone(true); // Visited
|
||||
_renderer->drawCharacter(CALCPOINTS); // for right _actorPos entrance
|
||||
}
|
||||
|
||||
void TrecisionEngine::doIdle() {
|
||||
uint16 a = getAction();
|
||||
switch (a) {
|
||||
case kActionQuit:
|
||||
if (!_flagDialogActive && !_flagDialogMenuActive) {
|
||||
if (quitPrompt())
|
||||
quitGame();
|
||||
}
|
||||
break;
|
||||
case kActionSkipVideo:
|
||||
if (canPlayerInteract()) {
|
||||
::createThumbnailFromScreen(&_thumbnail);
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
_graphicsMgr->showCursor();
|
||||
_obj[o00EXIT]._goRoom = _curRoom;
|
||||
changeRoom(kRoomControlPanel);
|
||||
_flagShowCharacter = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionSystemMenu:
|
||||
if (canPlayerInteract()) {
|
||||
::createThumbnailFromScreen(&_thumbnail);
|
||||
_actor->actorStop();
|
||||
_pathFind->nextStep();
|
||||
_graphicsMgr->showCursor();
|
||||
_obj[o00EXIT]._goRoom = _curRoom;
|
||||
changeRoom(kRoomControlPanel);
|
||||
_flagShowCharacter = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionSave:
|
||||
if (canPlayerInteract()) {
|
||||
::createThumbnailFromScreen(&_thumbnail);
|
||||
dataSave();
|
||||
showInventoryName(NO_OBJECTS, false);
|
||||
showIconName();
|
||||
refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionLoad:
|
||||
if (canPlayerInteract()) {
|
||||
::createThumbnailFromScreen(&_thumbnail);
|
||||
if (!dataLoad()) {
|
||||
showInventoryName(NO_OBJECTS, false);
|
||||
showIconName();
|
||||
refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isGameArea(_mousePos) && ((_inventoryStatus == INV_ON) || (_inventoryStatus == INV_INACTION)))
|
||||
closeInventory();
|
||||
|
||||
if (_inventoryScrollTime > _curTime)
|
||||
_inventoryScrollTime = _curTime;
|
||||
|
||||
if (isInventoryArea(_mousePos) && (_curTime > (INVSCROLLSP + _inventoryScrollTime))) {
|
||||
doScrollInventory(_mousePos);
|
||||
_inventoryScrollTime = _curTime;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::doRoomIn(uint16 curObj) {
|
||||
_graphicsMgr->hideCursor();
|
||||
|
||||
uint16 curAction = _obj[curObj]._anim;
|
||||
uint16 curPos = _obj[curObj]._ninv;
|
||||
|
||||
changeRoom(_obj[curObj]._goRoom, curAction, curPos);
|
||||
|
||||
_obj[curObj].setFlagDone(true);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doRoomOut(uint16 curObj) {
|
||||
_graphicsMgr->hideCursor();
|
||||
|
||||
uint16 curAction, curPos;
|
||||
_logicMgr->roomOut(curObj, &curAction, &curPos);
|
||||
|
||||
if (curAction)
|
||||
_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERACTION, MP_DEFAULT, curAction, _obj[curObj]._goRoom, curPos, curObj);
|
||||
|
||||
_obj[curObj].setFlagDone(true);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doMouseExamine(uint16 curObj) {
|
||||
if (!curObj)
|
||||
warning("doMouseExamine - curObj not set");
|
||||
|
||||
bool printSentence = _logicMgr->mouseExamine(curObj);
|
||||
|
||||
if (printSentence && _obj[curObj]._examine)
|
||||
_textMgr->characterSay(_obj[curObj]._examine);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doMouseOperate(uint16 curObj) {
|
||||
if (!curObj)
|
||||
warning("doMouseOperate - curObj not set");
|
||||
|
||||
bool printSentence = _logicMgr->mouseOperate(curObj);
|
||||
|
||||
if (printSentence && _obj[curObj]._action)
|
||||
_textMgr->characterSay(_obj[curObj]._action);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doMouseTake(uint16 curObj) {
|
||||
if (!curObj)
|
||||
warning("doMouseTake - curObj not set");
|
||||
|
||||
bool del = _logicMgr->mouseTake(curObj);
|
||||
uint16 curAction = _obj[curObj]._anim;
|
||||
|
||||
if (curAction)
|
||||
_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERACTION, MP_DEFAULT, curAction, 0, 0, curObj);
|
||||
|
||||
// Remove object being taken
|
||||
if (del) {
|
||||
if (curAction) {
|
||||
for (uint16 j = 0; j < MAXATFRAME; ++j) {
|
||||
SAtFrame *frame = &_animMgr->_animTab[curAction]._atFrame[j];
|
||||
if (frame->_type == ATFCLR && frame->_index == curObj)
|
||||
break;
|
||||
|
||||
if (frame->_type == ATFNONE) {
|
||||
frame->_area = 0;
|
||||
frame->_numFrame = 1;
|
||||
frame->_type = ATFCLR;
|
||||
frame->_index = curObj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setObjectVisible(curObj, false);
|
||||
}
|
||||
}
|
||||
addIcon(_obj[_curObj]._ninv);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doMouseTalk(uint16 curObj) {
|
||||
if (!curObj)
|
||||
warning("doMouseTalk - curObj not set");
|
||||
|
||||
bool printSentence = _logicMgr->mouseTalk(curObj);
|
||||
|
||||
if (printSentence)
|
||||
_dialogMgr->playDialog(_obj[curObj]._goRoom);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doUseWith() {
|
||||
_textMgr->showObjName(0, false);
|
||||
|
||||
if (_useWithInv[USED]) {
|
||||
if (_useWithInv[WITH])
|
||||
_logicMgr->useInventoryWithInventory();
|
||||
else
|
||||
_logicMgr->useInventoryWithScreen();
|
||||
} else
|
||||
doScreenUseWithScreen();
|
||||
|
||||
_useWith[USED] = 0;
|
||||
_useWith[WITH] = 0;
|
||||
_useWithInv[USED] = false;
|
||||
_useWithInv[WITH] = false;
|
||||
_flagUseWithStarted = false;
|
||||
}
|
||||
|
||||
void TrecisionEngine::doScreenUseWithScreen() {
|
||||
if (!_useWith[USED] || !_useWith[WITH])
|
||||
warning("doScreenUseWithScreen - _useWith not set properly");
|
||||
|
||||
if (_pathFind->_characterInMovement)
|
||||
return;
|
||||
|
||||
bool printSentence = _logicMgr->useScreenWithScreen();
|
||||
|
||||
if (printSentence)
|
||||
_textMgr->characterSay(_obj[_useWith[USED]]._action);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doInvExamine() {
|
||||
if (!_curInventory)
|
||||
warning("doInvExamine - _curInventory not set properly");
|
||||
|
||||
if (_inventoryObj[_curInventory]._examine)
|
||||
_textMgr->characterSay(_inventoryObj[_curInventory]._examine);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doInvOperate() {
|
||||
if (!_curInventory)
|
||||
warning("doInvOperate - _curInventory not set properly");
|
||||
|
||||
const bool printSentence = _logicMgr->operateInventory();
|
||||
if (_inventoryObj[_curInventory]._action && printSentence)
|
||||
_textMgr->characterSay(_inventoryObj[_curInventory]._action);
|
||||
}
|
||||
|
||||
void TrecisionEngine::doScript() {
|
||||
Message *message = _curMessage;
|
||||
const uint16 index = message->_u16Param1;
|
||||
const uint16 index2 = message->_u16Param2;
|
||||
const uint32 value = message->_u32Param;
|
||||
|
||||
switch (message->_event) {
|
||||
case ME_CHANGER:
|
||||
changeRoom(index, index2, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::processCurrentMessage() {
|
||||
switch (_curMessage->_class) {
|
||||
case MC_CHARACTER:
|
||||
doCharacter();
|
||||
break;
|
||||
|
||||
case MC_IDLE:
|
||||
doIdle();
|
||||
break;
|
||||
|
||||
case MC_MOUSE:
|
||||
doMouse();
|
||||
break;
|
||||
|
||||
case MC_ACTION:
|
||||
doAction();
|
||||
break;
|
||||
|
||||
case MC_STRING:
|
||||
_textMgr->doString();
|
||||
break;
|
||||
|
||||
case MC_DIALOG:
|
||||
_dialogMgr->doDialog();
|
||||
break;
|
||||
|
||||
case MC_SCRIPT:
|
||||
doScript();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
289
engines/trecision/sound.cpp
Normal file
289
engines/trecision/sound.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/defines.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
SoundManager::SoundManager(TrecisionEngine *vm) : _vm(vm) {
|
||||
if (!_speechFile.open(_vm, "nlspeech.cd0"))
|
||||
warning("SoundManager - nlspeech.cd0 is missing - skipping");
|
||||
|
||||
_stepLeftStream = nullptr;
|
||||
_stepRightStream = nullptr;
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager() {
|
||||
g_system->getMixer()->stopAll();
|
||||
_speechFile.close();
|
||||
stopAll();
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *SoundManager::loadWAV(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
|
||||
if (_vm->isAmiga()) {
|
||||
return Audio::makeRawStream(stream, 11025, 0, disposeAfterUse);
|
||||
} else {
|
||||
return Audio::makeWAVStream(stream, disposeAfterUse);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::play(int soundId) {
|
||||
SRoom *curRoom = &_vm->_room[_vm->_curRoom];
|
||||
|
||||
for (uint16 soundSlot = 0; soundSlot < MAXSOUNDSINROOM; soundSlot++) {
|
||||
if (curRoom->_sounds[soundSlot] == 0)
|
||||
return;
|
||||
|
||||
if (curRoom->_sounds[soundSlot] == soundId) {
|
||||
const SoundType soundType = (_gSample[soundId]._flag & kSoundFlagBgMusic) ? kSoundTypeMusic : kSoundTypeSfx;
|
||||
Common::SeekableReadStream *soundFileStream = _vm->_dataFile.createReadStreamForMember(Common::Path(_gSample[soundId]._name));
|
||||
if (!soundFileStream)
|
||||
continue;
|
||||
|
||||
// We need to copy this WAV to memory since it will be streamed
|
||||
Common::SeekableReadStream *memStream = soundFileStream->readStream(soundFileStream->size());
|
||||
delete soundFileStream;
|
||||
|
||||
stopSoundType(soundType);
|
||||
|
||||
Audio::Mixer::SoundType type =
|
||||
(_gSample[soundId]._flag & kSoundFlagBgMusic) ?
|
||||
Audio::Mixer::kMusicSoundType :
|
||||
Audio::Mixer::kSFXSoundType;
|
||||
|
||||
int volume = VOLUME(_gSample[soundId]._volume);
|
||||
|
||||
// FIXME: This looks wrong - it makes the room music silent
|
||||
/*if (_gSample[soundId]._flag & kSoundFlagSoundOn) {
|
||||
volume = 0;
|
||||
}*/
|
||||
|
||||
Audio::AudioStream *stream = nullptr;
|
||||
|
||||
if (_gSample[soundId]._flag & kSoundFlagSoundLoop)
|
||||
stream = Audio::makeLoopingAudioStream(loadWAV(memStream), 0);
|
||||
else
|
||||
stream = loadWAV(memStream);
|
||||
|
||||
g_system->getMixer()->playStream(
|
||||
type,
|
||||
&_soundHandles[soundType],
|
||||
stream,
|
||||
-1,
|
||||
volume,
|
||||
0,
|
||||
DisposeAfterUse::YES
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::stopAll() {
|
||||
for (int i = 0; i < MAXSOUNDS; i++) {
|
||||
g_system->getMixer()->stopHandle(_soundHandles[i]);
|
||||
}
|
||||
|
||||
delete _stepLeftStream;
|
||||
_stepLeftStream = nullptr;
|
||||
delete _stepRightStream;
|
||||
_stepRightStream = nullptr;
|
||||
}
|
||||
|
||||
void SoundManager::stopAllExceptMusic() {
|
||||
for (int i = 0; i < MAXSOUNDS; i++) {
|
||||
if (i != kSoundTypeMusic) {
|
||||
g_system->getMixer()->stopHandle(_soundHandles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
delete _stepLeftStream;
|
||||
_stepLeftStream = nullptr;
|
||||
delete _stepRightStream;
|
||||
_stepRightStream = nullptr;
|
||||
}
|
||||
|
||||
void SoundManager::stopSoundType(SoundType type) {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_soundHandles[type])) {
|
||||
g_system->getMixer()->stopHandle(_soundHandles[type]);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::soundStep(int midx, int midz, int act, int frame) {
|
||||
SRoom *curRoom = &_vm->_room[_vm->_curRoom];
|
||||
bool stepRight = false;
|
||||
bool stepLeft = false;
|
||||
|
||||
switch (act) {
|
||||
case hWALK:
|
||||
if (frame == 3)
|
||||
stepLeft = true;
|
||||
else if (frame == 8)
|
||||
stepRight = true;
|
||||
break;
|
||||
|
||||
case hWALKIN:
|
||||
if (frame == 3)
|
||||
stepLeft = true;
|
||||
else if (frame == 9)
|
||||
stepRight = true;
|
||||
break;
|
||||
|
||||
case hWALKOUT:
|
||||
if (frame == 5)
|
||||
stepLeft = true;
|
||||
else if (frame == 10)
|
||||
stepRight = true;
|
||||
break;
|
||||
|
||||
case hSTOP0:
|
||||
case hSTOP1:
|
||||
case hSTOP2:
|
||||
case hSTOP3:
|
||||
case hSTOP9:
|
||||
if (frame >= defActionLen[act] - 1)
|
||||
stepLeft = true;
|
||||
break;
|
||||
case hSTOP4:
|
||||
case hSTOP5:
|
||||
case hSTOP6:
|
||||
case hSTOP7:
|
||||
case hSTOP8:
|
||||
if (frame >= defActionLen[act] - 1)
|
||||
stepRight = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stepRight && !stepLeft)
|
||||
return;
|
||||
|
||||
int soundId;
|
||||
for (int soundSlot = 0; soundSlot < MAXSOUNDSINROOM; soundSlot++) {
|
||||
soundId = curRoom->_sounds[soundSlot];
|
||||
|
||||
if (stepRight && (_gSample[soundId]._flag & kSoundFlagStepRight)) {
|
||||
if (!_stepRightStream) {
|
||||
Common::SeekableReadStream *soundFileStream = _vm->_dataFile.createReadStreamForMember(Common::Path(_gSample[soundId]._name));
|
||||
_stepRightStream = loadWAV(soundFileStream);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (stepLeft && (_gSample[soundId]._flag & kSoundFlagStepLeft)) {
|
||||
if (!_stepLeftStream) {
|
||||
Common::SeekableReadStream *soundFileStream = _vm->_dataFile.createReadStreamForMember(Common::Path(_gSample[soundId]._name));
|
||||
_stepLeftStream = loadWAV(soundFileStream);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (soundId == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
midz = ((int)(_gSample[soundId]._volume) * 1000) / ABS(midz);
|
||||
|
||||
if (midz > 255)
|
||||
midz = 255;
|
||||
|
||||
g_system->getMixer()->stopHandle(_soundHandles[kSoundTypeStep]);
|
||||
|
||||
Audio::SeekableAudioStream *stream = stepLeft ? _stepLeftStream : _stepRightStream;
|
||||
stream->rewind();
|
||||
|
||||
const int panpos = ((midx - 320) * 127 / 320) / 2;
|
||||
|
||||
g_system->getMixer()->playStream(
|
||||
Audio::Mixer::kSFXSoundType,
|
||||
&_soundHandles[kSoundTypeStep],
|
||||
stream,
|
||||
-1,
|
||||
VOLUME(midz),
|
||||
panpos,
|
||||
DisposeAfterUse::NO
|
||||
);
|
||||
}
|
||||
|
||||
int32 SoundManager::talkStart(const Common::Path &name) {
|
||||
if (!_speechFile.isOpen())
|
||||
return 0;
|
||||
|
||||
stopSoundType(kSoundTypeSpeech);
|
||||
|
||||
Common::SeekableReadStream *stream = _speechFile.createReadStreamForMember(name);
|
||||
if (!stream)
|
||||
return 0;
|
||||
|
||||
Audio::SeekableAudioStream *audioStream = loadWAV(stream);
|
||||
|
||||
g_system->getMixer()->playStream(
|
||||
Audio::Mixer::kSpeechSoundType,
|
||||
&_soundHandles[kSoundTypeSpeech],
|
||||
audioStream,
|
||||
-1,
|
||||
Audio::Mixer::kMaxChannelVolume, // TODO
|
||||
0,
|
||||
DisposeAfterUse::YES
|
||||
);
|
||||
_vm->_characterSpeakTime = _vm->readTime();
|
||||
|
||||
return TIME(audioStream->getLength().msecs());
|
||||
}
|
||||
|
||||
void SoundManager::loadRoomSounds() {
|
||||
SRoom *curRoom = &_vm->_room[_vm->_curRoom];
|
||||
|
||||
stopAll();
|
||||
|
||||
for (uint16 soundSlot = 0; soundSlot < MAXSOUNDSINROOM; soundSlot++) {
|
||||
const uint16 soundId = curRoom->_sounds[soundSlot];
|
||||
|
||||
if (soundId == 0)
|
||||
break;
|
||||
|
||||
if (_gSample[soundId]._name.equalsIgnoreCase("RUOTE2C.WAV"))
|
||||
break;
|
||||
|
||||
if ((_gSample[soundId]._flag & kSoundFlagBgMusic) || (_gSample[soundId]._flag & kSoundFlagSoundOn))
|
||||
play(soundId);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::loadSamples(Common::SeekableReadStreamEndian *stream) {
|
||||
for (int i = 0; i < NUMSAMPLES; ++i) {
|
||||
_gSample[i]._name = stream->readString(0, 14);
|
||||
_gSample[i]._volume = stream->readByte();
|
||||
_gSample[i]._flag = stream->readByte();
|
||||
_gSample[i]._panning = stream->readSByte();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
89
engines/trecision/sound.h
Normal file
89
engines/trecision/sound.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_SOUND_H
|
||||
#define TRECISION_SOUND_H
|
||||
|
||||
#include "trecision/fastfile.h"
|
||||
#include "common/stream.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
#define SOUND_OFF 0
|
||||
#define SOUND_ON 1
|
||||
|
||||
#define MAXSOUNDS 4
|
||||
#define SAMPLEVOICES 6
|
||||
#define NUMSAMPLES 145 // Maximum number of samples in the game
|
||||
|
||||
#define VOLUME(a) ( (a * 255) / 127 )
|
||||
#define TIME(a) ( (a * 3) / 50 )
|
||||
|
||||
struct SSound {
|
||||
Common::String _name;
|
||||
uint8 _volume;
|
||||
uint8 _flag;
|
||||
int8 _panning;
|
||||
};
|
||||
|
||||
enum SoundType {
|
||||
kSoundTypeMusic = 0,
|
||||
kSoundTypeSpeech = 1,
|
||||
kSoundTypeSfx = 2,
|
||||
kSoundTypeStep = 3
|
||||
};
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class SoundManager {
|
||||
public:
|
||||
SoundManager(TrecisionEngine *vm);
|
||||
~SoundManager();
|
||||
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
FastFile _speechFile; // nlspeech.cd0
|
||||
|
||||
Audio::SoundHandle _soundHandles[MAXSOUNDS];
|
||||
SSound _gSample[NUMSAMPLES];
|
||||
|
||||
Audio::SeekableAudioStream *_stepLeftStream;
|
||||
Audio::SeekableAudioStream *_stepRightStream;
|
||||
|
||||
public:
|
||||
Audio::SeekableAudioStream *loadWAV(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
|
||||
void play(int soundId);
|
||||
void stopSoundType(SoundType type);
|
||||
void stopAll();
|
||||
void stopAllExceptMusic();
|
||||
void soundStep(int midx, int midz, int act, int frame);
|
||||
int32 talkStart(const Common::Path &name);
|
||||
void loadRoomSounds();
|
||||
|
||||
void loadSamples(Common::SeekableReadStreamEndian *stream);
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Trecision
|
||||
|
||||
#endif
|
||||
164
engines/trecision/struct.cpp
Normal file
164
engines/trecision/struct.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
void SRoom::loadRoom(Common::SeekableReadStreamEndian *stream) {
|
||||
stream->read(&_baseName, 4);
|
||||
_flag = stream->readByte();
|
||||
stream->readByte(); // Padding
|
||||
_bkgAnim = stream->readUint16();
|
||||
for (int j = 0; j < MAXOBJINROOM; ++j)
|
||||
_object[j] = stream->readUint16();
|
||||
for (int j = 0; j < MAXSOUNDSINROOM; ++j)
|
||||
_sounds[j] = stream->readUint16();
|
||||
for (int j = 0; j < MAXACTIONINROOM; ++j)
|
||||
_actions[j] = stream->readUint16();
|
||||
}
|
||||
|
||||
void SRoom::syncGameStream(Common::Serializer &ser) {
|
||||
ser.syncBytes((byte *)_baseName, 4);
|
||||
for (int i = 0; i < MAXACTIONINROOM; i++)
|
||||
ser.syncAsUint16LE(_actions[i]);
|
||||
ser.syncAsByte(_flag);
|
||||
ser.syncAsUint16LE(_bkgAnim);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void SObject::readRect(Common::SeekableReadStream *stream) {
|
||||
_rect.left = stream->readUint16LE();
|
||||
_rect.top = stream->readUint16LE();
|
||||
_rect.setWidth(stream->readUint16LE());
|
||||
_rect.setHeight(stream->readUint16LE());
|
||||
}
|
||||
|
||||
void SObject::syncGameStream(Common::Serializer &ser) {
|
||||
ser.syncAsUint16LE(_area.left);
|
||||
ser.syncAsUint16LE(_area.top);
|
||||
ser.syncAsUint16LE(_area.right);
|
||||
ser.syncAsUint16LE(_area.bottom);
|
||||
ser.syncAsUint16LE(_name);
|
||||
ser.syncAsUint16LE(_examine);
|
||||
ser.syncAsUint16LE(_action);
|
||||
ser.syncAsUint16LE(_anim);
|
||||
ser.syncAsByte(_mode);
|
||||
ser.syncAsByte(_flag);
|
||||
ser.syncAsByte(_goRoom);
|
||||
ser.syncAsByte(_nbox);
|
||||
ser.syncAsByte(_ninv);
|
||||
ser.syncAsSByte(_position);
|
||||
}
|
||||
|
||||
void SObject::loadObj(Common::SeekableReadStreamEndian *stream) {
|
||||
uint16 w = stream->readUint16();
|
||||
uint16 h = stream->readUint16();
|
||||
_rect.left = stream->readUint16();
|
||||
_rect.top = stream->readUint16();
|
||||
_rect.setWidth(w);
|
||||
_rect.setHeight(h);
|
||||
|
||||
_area.left = stream->readUint16();
|
||||
_area.top = stream->readUint16();
|
||||
_area.right = stream->readUint16();
|
||||
_area.bottom = stream->readUint16();
|
||||
|
||||
_position = stream->readSByte();
|
||||
stream->readByte(); // Padding
|
||||
_name = stream->readUint16();
|
||||
_examine = stream->readUint16();
|
||||
_action = stream->readUint16();
|
||||
_goRoom = stream->readByte();
|
||||
_nbox = stream->readByte();
|
||||
_ninv = stream->readByte();
|
||||
_mode = stream->readByte();
|
||||
_flag = stream->readByte();
|
||||
stream->readByte(); // Padding
|
||||
_anim = stream->readUint16();
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void SInvObject::syncGameStream(Common::Serializer &ser) {
|
||||
ser.syncAsUint16LE(_name);
|
||||
ser.syncAsUint16LE(_examine);
|
||||
ser.syncAsUint16LE(_action);
|
||||
ser.syncAsUint16LE(_anim);
|
||||
ser.syncAsByte(_flag);
|
||||
}
|
||||
|
||||
void SInvObject::loadObj(Common::SeekableReadStreamEndian *stream) {
|
||||
_name = stream->readUint16();
|
||||
_examine = stream->readUint16();
|
||||
_action = stream->readUint16();
|
||||
_flag = stream->readByte();
|
||||
stream->readByte(); // Padding
|
||||
_anim = stream->readUint16();
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void STexture::clear() {
|
||||
_dx = _dy = _angle = 0;
|
||||
_texture = nullptr;
|
||||
_active = false;
|
||||
}
|
||||
|
||||
void STexture::set(int16 x, int16 y, uint8 *buffer) {
|
||||
_dx = x;
|
||||
_dy = y;
|
||||
_angle = 0;
|
||||
|
||||
_active = true;
|
||||
_texture = buffer;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void SVertex::clear() {
|
||||
_x = _y = _z = 0.0f;
|
||||
_nx = _ny = _nz = 0.0f;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void SLight::clear() {
|
||||
_x = _y = _z = 0.0f;
|
||||
_dx = _dy = _dz = 0.0f;
|
||||
_inr = _outr = 0.0f;
|
||||
_hotspot = 0;
|
||||
_fallOff = 0;
|
||||
_inten = 0;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
void SCamera::clear() {
|
||||
_ex = _ey = _ez = 0.0f;
|
||||
_fovX = _fovY = 0.0f;
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
_e1[i] = _e2[i] = _e3[i] = 0.0f;
|
||||
}
|
||||
|
||||
} // namespace Trecision
|
||||
250
engines/trecision/struct.h
Normal file
250
engines/trecision/struct.h
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_STRUCT_H
|
||||
#define TRECISION_STRUCT_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/serializer.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "trecision/defines.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
struct SRoom {
|
||||
char _baseName[4]; // Room name
|
||||
uint16 _bkgAnim; // Background animation
|
||||
uint16 _object[MAXOBJINROOM]; // Objects in the room
|
||||
uint16 _sounds[MAXSOUNDSINROOM]; // Sounds of the room
|
||||
uint16 _actions[MAXACTIONINROOM]; // Character actions in the room
|
||||
|
||||
bool hasExtra() { return _flag & kObjFlagExtra; }
|
||||
bool isDone() { return _flag & kObjFlagDone; }
|
||||
void setExtra(bool on) { if (on) _flag |= kObjFlagExtra; else _flag &= ~kObjFlagExtra; }
|
||||
void setDone(bool on) { if (on) _flag |= kObjFlagDone; else _flag &= ~kObjFlagDone; }
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void loadRoom(Common::SeekableReadStreamEndian *stream);
|
||||
|
||||
private:
|
||||
uint8 _flag; // Room visited or not, extra or not
|
||||
};
|
||||
|
||||
struct SObject {
|
||||
Common::Rect _rect;
|
||||
Common::Rect _area;
|
||||
int8 _position; // -1 if no position
|
||||
uint16 _name;
|
||||
uint16 _examine;
|
||||
uint16 _action;
|
||||
uint8 _goRoom; // If direction room num - if person num dialog
|
||||
uint8 _nbox; // Which 3d box the object is associated with
|
||||
uint8 _ninv; // ptr inventory
|
||||
uint16 _anim;
|
||||
|
||||
void readRect(Common::SeekableReadStream *stream);
|
||||
void setFlagDone(bool on) { if (on) _flag |= kObjFlagDone; else _flag &= ~kObjFlagDone; }
|
||||
void setFlagExamine(bool on) { if (on) _flag |= kObjFlagExamine; else _flag &= ~kObjFlagExamine; }
|
||||
void setFlagExtra(bool on) { if (on) _flag |= kObjFlagExtra; else _flag &= ~kObjFlagExtra; }
|
||||
void setFlagPerson(bool on) { if (on) _flag |= kObjFlagPerson; else _flag &= ~kObjFlagPerson; }
|
||||
void setFlagRoomOut(bool on) { if (on) _flag |= kObjFlagRoomOut; else _flag &= ~kObjFlagRoomOut; }
|
||||
void setFlagRoomIn(bool on) { if (on) _flag |= kObjFlagRoomIn; else _flag &= ~kObjFlagRoomIn; }
|
||||
void setFlagTake(bool on) { if (on) _flag |= kObjFlagTake; else _flag &= ~kObjFlagTake; }
|
||||
|
||||
bool isFlagDone() { return _flag & kObjFlagDone; }
|
||||
bool isFlagExamine() { return _flag & kObjFlagExamine; }
|
||||
bool isFlagExtra() { return _flag & kObjFlagExtra; }
|
||||
bool isFlagPerson() { return _flag & kObjFlagPerson; }
|
||||
bool isFlagRoomIn() { return _flag & kObjFlagRoomIn; }
|
||||
bool isFlagRoomOut() { return _flag & kObjFlagRoomOut; }
|
||||
bool isFlagTake() { return _flag & kObjFlagTake; }
|
||||
bool isFlagUseWith() { return _flag & kObjFlagUseWith; }
|
||||
|
||||
bool isModeHidden() { return _mode & OBJMODE_HIDDEN; }
|
||||
bool isModeFull() { return _mode & OBJMODE_FULL; }
|
||||
bool isModeMask() { return _mode & OBJMODE_MASK; }
|
||||
bool isModeLim() { return _mode & OBJMODE_LIM; }
|
||||
bool isModeStatus() { return _mode & OBJMODE_OBJSTATUS; }
|
||||
|
||||
void setModeHidden(bool on) { if (on) _mode |= OBJMODE_HIDDEN; else _mode &= ~OBJMODE_HIDDEN; }
|
||||
void setModeFull(bool on) { if (on) _mode |= OBJMODE_FULL; else _mode &= ~OBJMODE_FULL; }
|
||||
void setModeMask(bool on) { if (on) _mode |= OBJMODE_MASK; else _mode &= ~OBJMODE_MASK; }
|
||||
void setModeLim(bool on) { if (on) _mode |= OBJMODE_LIM; else _mode &= ~OBJMODE_LIM; }
|
||||
void setModeStatus(bool on) { if (on) _mode |= OBJMODE_OBJSTATUS; else _mode &= ~OBJMODE_OBJSTATUS; }
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void loadObj(Common::SeekableReadStreamEndian *stream);
|
||||
|
||||
private:
|
||||
uint8 _flag;
|
||||
uint8 _mode;
|
||||
};
|
||||
|
||||
struct SInvObject {
|
||||
uint16 _name; // Object name in the inventory
|
||||
uint16 _examine; // Sentence if examined
|
||||
uint16 _action;
|
||||
uint16 _anim;
|
||||
|
||||
void setFlagExtra(bool on) { if (on) _flag |= kObjFlagExtra; else _flag &= ~kObjFlagExtra; }
|
||||
|
||||
bool isFlagExtra() { return _flag & kObjFlagExtra; }
|
||||
bool isUseWith() { return _flag & kObjFlagUseWith; }
|
||||
|
||||
void syncGameStream(Common::Serializer &ser);
|
||||
void loadObj(Common::SeekableReadStreamEndian *stream);
|
||||
|
||||
private:
|
||||
uint8 _flag;
|
||||
};
|
||||
|
||||
struct SAtFrame {
|
||||
uint8 _type; //ATFTEXT, ATFSND, ATFEVENT
|
||||
uint8 _area; // 0 1 2 3 4
|
||||
uint16 _numFrame;
|
||||
uint16 _index;
|
||||
};
|
||||
|
||||
// Shifted left by 1 - 4, depending on the subarea
|
||||
#define SMKANIM_OFF_BASE 16
|
||||
|
||||
struct SAnim {
|
||||
char _name[14];
|
||||
uint16 _flag; // 1- background 2- icon 3- action 4- active - 4bits per child
|
||||
Common::Rect _area[MAXAREA];
|
||||
uint8 _nbox;
|
||||
SAtFrame _atFrame[MAXATFRAME];
|
||||
|
||||
/**
|
||||
* Toggle the animation of a subarea
|
||||
* @param area: 1 - 4
|
||||
* @param show: show or hide the animation area
|
||||
*/
|
||||
void toggleAnimArea(uint8 area, bool show) {
|
||||
assert(area >= 1 && area <= 4);
|
||||
if (show)
|
||||
_flag &= ~(SMKANIM_OFF_BASE << area);
|
||||
else
|
||||
_flag |= (SMKANIM_OFF_BASE << area);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an animation subarea is shown
|
||||
* @param area: 1 - 4
|
||||
* @return true if the subarea is shown
|
||||
*/
|
||||
bool isAnimAreaShown(uint8 area) {
|
||||
assert(area >= 1 && area <= 4);
|
||||
return !(_flag & (SMKANIM_OFF_BASE << area));
|
||||
}
|
||||
};
|
||||
|
||||
struct SSortTable {
|
||||
uint16 _objectId; // Object ID
|
||||
bool _remove; // Whether to copy or remove
|
||||
};
|
||||
|
||||
class Scheduler;
|
||||
|
||||
struct SScriptFrame {
|
||||
uint8 _class;
|
||||
uint8 _event;
|
||||
|
||||
uint8 _u8Param;
|
||||
|
||||
uint16 _u16Param1;
|
||||
uint16 _u16Param2;
|
||||
|
||||
uint16 _u32Param;
|
||||
|
||||
bool _noWait;
|
||||
|
||||
void clear();
|
||||
void sendFrame(Scheduler *scheduler);
|
||||
bool isEmptyEvent() const { return _class == 0 && _event == 0; }
|
||||
};
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
struct SDText {
|
||||
Common::Rect _rect;
|
||||
Common::Rect _subtitleRect;
|
||||
uint16 _textColor;
|
||||
Common::String _text;
|
||||
Common::String _drawTextLines[MAXDTEXTLINES];
|
||||
|
||||
void set(SDText *org);
|
||||
void set(Common::Rect rect, Common::Rect subtitleRect, uint16 textCol, const Common::String &text);
|
||||
|
||||
void draw(TrecisionEngine *vm, bool hideLastChar = false, Graphics::Surface *externalSurface = nullptr);
|
||||
uint16 calcHeight(TrecisionEngine *vm);
|
||||
};
|
||||
|
||||
struct STexture {
|
||||
int16 _dx, _dy, _angle;
|
||||
uint8 *_texture;
|
||||
|
||||
void clear();
|
||||
void set(int16 x, int16 y, uint8 *buffer);
|
||||
bool isActive() { return _active; };
|
||||
|
||||
private:
|
||||
bool _active;
|
||||
};
|
||||
|
||||
struct SVertex {
|
||||
float _x, _y, _z;
|
||||
float _nx, _ny, _nz;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct SFace {
|
||||
uint16 _a, _b, _c;
|
||||
uint16 _mat;
|
||||
};
|
||||
|
||||
struct SLight {
|
||||
float _x, _y, _z;
|
||||
float _dx, _dy, _dz;
|
||||
float _inr, _outr;
|
||||
uint8 _hotspot;
|
||||
uint8 _fallOff;
|
||||
int8 _inten;
|
||||
int8 _position;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct SCamera {
|
||||
float _ex, _ey, _ez;
|
||||
float _e1[3];
|
||||
float _e2[3];
|
||||
float _e3[3];
|
||||
float _fovX, _fovY;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
481
engines/trecision/text.cpp
Normal file
481
engines/trecision/text.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
TextManager::TextManager(TrecisionEngine *vm) : _vm(vm) {
|
||||
_someoneSpeakTime = 0;
|
||||
_subStringAgain = false;
|
||||
_talkTime = 0;
|
||||
for (int i = 0; i < MAXSUBSTRING; ++i) {
|
||||
for (int j = 0; j < MAXLENSUBSTRING; ++j) {
|
||||
_subString[i][j] = 0;
|
||||
}
|
||||
}
|
||||
_subStringUsed = 0;
|
||||
_subStringStart = 0;
|
||||
_curSentenceId = 0;
|
||||
_curSubString = 0;
|
||||
_talkingPersonId = 0;
|
||||
}
|
||||
|
||||
TextManager::~TextManager() {
|
||||
}
|
||||
|
||||
Common::Point TextManager::positionString(uint16 x, uint16 y, const char *string, bool characterFl) {
|
||||
uint16 lenText = _vm->textLength(string);
|
||||
Common::Point pos;
|
||||
|
||||
if (lenText > 960)
|
||||
lenText = (lenText * 2 / 5);
|
||||
else if (lenText > 320)
|
||||
lenText = (lenText * 3 / 5);
|
||||
|
||||
if (x > (lenText >> 1))
|
||||
x -= (lenText >> 1);
|
||||
else
|
||||
x = 0;
|
||||
|
||||
pos.x = CLIP<uint16>(x, 5, MAXX - lenText - 5);
|
||||
|
||||
pos.y = characterFl ? 0 : VIDEOTOP;
|
||||
pos.y += y - 1; //15
|
||||
if (pos.y <= VIDEOTOP)
|
||||
pos.y = VIDEOTOP + 1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void TextManager::formattingSuperString() {
|
||||
_subStringUsed = 0;
|
||||
_subStringAgain = true;
|
||||
while (_subStringAgain) {
|
||||
formattingOneString();
|
||||
++_subStringUsed;
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::formattingOneString() {
|
||||
uint16 i;
|
||||
memset(_subString[_subStringUsed], '\0', MAXLENSUBSTRING);
|
||||
|
||||
const uint16 available = (_superString.size() - _subStringStart);
|
||||
for (i = 0; i < available; ++i) {
|
||||
switch (_superString[i + _subStringStart]) {
|
||||
case '\0':
|
||||
_subStringAgain = false;
|
||||
return;
|
||||
|
||||
case '@':
|
||||
_subStringAgain = true;
|
||||
_subStringStart += (i + 1);
|
||||
return;
|
||||
|
||||
default:
|
||||
_subString[_subStringUsed][i] = _superString[i + _subStringStart];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_subString[_subStringUsed][i] = '\0';
|
||||
_subStringAgain = false;
|
||||
}
|
||||
|
||||
void TextManager::characterTalk(Common::String s) {
|
||||
_vm->_flagSomeoneSpeaks = true;
|
||||
_vm->_flagCharacterSpeak = true;
|
||||
_vm->_flagSkipTalk = false;
|
||||
|
||||
_superString = s;
|
||||
_subStringStart = 0;
|
||||
_curSubString = 0;
|
||||
formattingSuperString();
|
||||
|
||||
characterContinueTalk();
|
||||
|
||||
_vm->_scheduler->initCharacterQueue();
|
||||
_vm->_actor->actorStop();
|
||||
}
|
||||
|
||||
void TextManager::characterContinueTalk() {
|
||||
Common::Point pos;
|
||||
|
||||
_vm->_flagSkipTalk = false;
|
||||
_vm->_characterSpeakTime = _vm->_curTime;
|
||||
|
||||
_subStringAgain = (_curSubString < (_subStringUsed - 1));
|
||||
|
||||
if (_vm->_flagShowCharacter || _vm->_animMgr->isActionActive())
|
||||
pos = positionString(_vm->_actor->_area[0], _vm->_actor->_area[2], _subString[_curSubString], true);
|
||||
else
|
||||
pos = positionString(MAXX / 2, 30, _subString[_curSubString], false);
|
||||
|
||||
clearLastText();
|
||||
if (ConfMan.getBool("subtitles"))
|
||||
addText(pos, _subString[_curSubString], COLOR_OBJECT);
|
||||
|
||||
if (!_vm->_flagDialogActive) {
|
||||
if (_curSubString)
|
||||
_lastFilename = Common::Path(Common::String::format("s%04d%c.wav", _curSentenceId, _curSubString + 'a'));
|
||||
else
|
||||
_lastFilename = Common::Path(Common::String::format("s%04d.wav", _curSentenceId));
|
||||
}
|
||||
|
||||
_talkTime = _vm->_soundMgr->talkStart(_lastFilename);
|
||||
if (!_talkTime)
|
||||
_talkTime = Common::String(_subString[_curSubString]).size() * 5 / 2 + 50;
|
||||
|
||||
++_curSubString;
|
||||
|
||||
_vm->_scheduler->doEvent(MC_STRING, ME_CHARACTERSPEAKING, MP_DEFAULT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void TextManager::characterMute() {
|
||||
_vm->_flagSomeoneSpeaks = false;
|
||||
_vm->_flagCharacterSpeak = false;
|
||||
_vm->_flagSkipTalk = false;
|
||||
_vm->_characterSpeakTime = 0;
|
||||
|
||||
clearLastText();
|
||||
_vm->_lastObj = 0;
|
||||
_vm->_lastInv = 0;
|
||||
|
||||
redrawString();
|
||||
_vm->_soundMgr->stopSoundType(kSoundTypeSpeech);
|
||||
|
||||
if ((_vm->_curRoom == kRoom12CU) || (_vm->_curRoom == kRoom13CU))
|
||||
_vm->changeRoom(_vm->_oldRoom);
|
||||
}
|
||||
|
||||
void TextManager::someoneContinueTalk() {
|
||||
_someoneSpeakTime = _vm->_curTime;
|
||||
_vm->_flagSkipTalk = false;
|
||||
|
||||
_subStringAgain = (_curSubString < (_subStringUsed - 1));
|
||||
|
||||
Common::Point pos;
|
||||
if (_talkingPersonId)
|
||||
pos = positionString(_vm->_obj[_talkingPersonId]._area.left, _vm->_obj[_talkingPersonId]._area.top, _subString[_curSubString], false);
|
||||
else
|
||||
pos = positionString(_vm->_actor->_area[0], _vm->_actor->_area[2], _subString[_curSubString], true);
|
||||
|
||||
clearLastText();
|
||||
if (ConfMan.getBool("subtitles"))
|
||||
addText(pos, _subString[_curSubString], HYELLOW);
|
||||
|
||||
if (_curSubString)
|
||||
_lastFilename = Common::Path(Common::String::format("s%04d%c.wav", _curSentenceId, _curSubString + 'a'));
|
||||
else
|
||||
_lastFilename = Common::Path(Common::String::format("s%04d.wav", _curSentenceId));
|
||||
|
||||
_talkTime = _vm->_soundMgr->talkStart(_lastFilename);
|
||||
if (!_talkTime)
|
||||
_talkTime = Common::String(_subString[_curSubString]).size() * 5 / 2 + 50;
|
||||
|
||||
++_curSubString;
|
||||
_vm->_scheduler->doEvent(MC_STRING, ME_SOMEONESPEAKING, MP_DEFAULT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void TextManager::someoneMute() {
|
||||
_vm->_flagCharacterSpeak = false;
|
||||
_vm->_flagSkipTalk = false;
|
||||
_vm->_flagSomeoneSpeaks = false;
|
||||
_someoneSpeakTime = 0;
|
||||
|
||||
clearLastText();
|
||||
_vm->_lastObj = 0;
|
||||
_vm->_lastInv = 0;
|
||||
|
||||
redrawString();
|
||||
_vm->_soundMgr->stopSoundType(kSoundTypeSpeech);
|
||||
}
|
||||
|
||||
// ******************************************************* //
|
||||
|
||||
void TextManager::doString() {
|
||||
switch (_vm->_curMessage->_event) {
|
||||
|
||||
case ME_CHARACTERSPEAKING:
|
||||
if (_vm->_flagCharacterSpeak) {
|
||||
if (_vm->_flagSkipTalk || (_vm->_curTime > _talkTime + _vm->_characterSpeakTime)) {
|
||||
if (_subStringAgain)
|
||||
characterContinueTalk();
|
||||
else
|
||||
characterMute();
|
||||
} else
|
||||
_vm->reEvent();
|
||||
}
|
||||
break;
|
||||
|
||||
case ME_SOMEONESPEAKING:
|
||||
if (_vm->_flagSomeoneSpeaks) {
|
||||
if (_vm->_flagSkipTalk || (_vm->_curTime >= (_talkTime + _someoneSpeakTime))) {
|
||||
if (_subStringAgain)
|
||||
someoneContinueTalk();
|
||||
else {
|
||||
someoneMute();
|
||||
}
|
||||
} else
|
||||
_vm->reEvent();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::showObjName(uint16 obj, bool show) {
|
||||
static const char *dunno = "?";
|
||||
Common::String desc;
|
||||
|
||||
if (_vm->_flagSomeoneSpeaks)
|
||||
return;
|
||||
|
||||
if (_vm->_lastInv) {
|
||||
clearLastText();
|
||||
_vm->_lastInv = 0;
|
||||
}
|
||||
|
||||
if (_vm->_flagUseWithStarted) {
|
||||
if (!show) {
|
||||
clearLastText();
|
||||
_vm->_lastObj = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_vm->_obj[_vm->_curObj].isFlagRoomOut() || _vm->_obj[_vm->_curObj].isFlagRoomIn()) && !_vm->_obj[_vm->_curObj].isFlagExamine())
|
||||
return;
|
||||
|
||||
desc = _vm->_sysText[kMessageUse];
|
||||
|
||||
if (_vm->_useWithInv[USED])
|
||||
desc += _vm->_objName[_vm->_inventoryObj[_vm->_useWith[USED]]._name];
|
||||
else if (_vm->_obj[_vm->_useWith[USED]].isModeHidden())
|
||||
desc += dunno;
|
||||
else
|
||||
desc += _vm->_objName[_vm->_obj[_vm->_useWith[USED]]._name];
|
||||
|
||||
desc += _vm->_sysText[kMessageWith];
|
||||
if (obj && (_vm->_useWithInv[USED] || (obj != _vm->_useWith[USED]))) {
|
||||
if (_vm->_obj[obj].isModeHidden())
|
||||
desc += dunno;
|
||||
else
|
||||
desc += _vm->_objName[_vm->_obj[obj]._name];
|
||||
}
|
||||
|
||||
_vm->_lastObj = (obj | 0x8000);
|
||||
const uint16 lenText = _vm->textLength(desc);
|
||||
const Common::Point pos(CLIP(320 - (lenText / 2), 2, MAXX - 2 - lenText), MAXY - CARHEI);
|
||||
|
||||
if (_vm->_lastObj)
|
||||
clearLastText();
|
||||
addText(pos, desc.c_str(), COLOR_INVENTORY);
|
||||
} else {
|
||||
if (!obj || !show) {
|
||||
clearLastText();
|
||||
_vm->_lastObj = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj == _vm->_lastObj)
|
||||
return;
|
||||
if (!_vm->_obj[obj].isFlagExamine()) {
|
||||
if (_vm->_obj[obj].isFlagDone() || _vm->_room[_vm->_obj[obj]._goRoom].isDone()) {
|
||||
desc = _vm->_sysText[kMessageGoto];
|
||||
if (_vm->_obj[obj].isModeHidden())
|
||||
desc += dunno;
|
||||
else
|
||||
desc += _vm->_objName[_vm->_obj[obj]._name];
|
||||
} else
|
||||
desc = _vm->_sysText[kMessageGoto2];
|
||||
} else if (_vm->_obj[obj].isModeHidden())
|
||||
desc = dunno;
|
||||
else
|
||||
desc = _vm->_objName[_vm->_obj[obj]._name];
|
||||
|
||||
const uint16 x = (_vm->_obj[obj]._area.left + _vm->_obj[obj]._area.right) / 2;
|
||||
const uint16 y = (obj == oWHEELS2C) ? 187 : _vm->_obj[obj]._area.top;
|
||||
Common::Point pos = positionString(x, y, desc.c_str(), false);
|
||||
|
||||
if (_vm->_lastObj)
|
||||
clearLastText();
|
||||
_vm->_lastObj = obj;
|
||||
addText(pos, desc.c_str(), COLOR_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::someoneSay(uint16 sentence, uint16 person) {
|
||||
_talkingPersonId = person;
|
||||
_vm->_flagSomeoneSpeaks = true;
|
||||
_vm->_flagSkipTalk = false;
|
||||
|
||||
_curSentenceId = sentence;
|
||||
_superString = _vm->_sentence[sentence];
|
||||
_subStringStart = 0;
|
||||
_curSubString = 0;
|
||||
|
||||
formattingSuperString();
|
||||
someoneContinueTalk();
|
||||
}
|
||||
|
||||
void TextManager::characterSay(uint16 i) {
|
||||
_curSentenceId = i;
|
||||
|
||||
// if he took some action
|
||||
if (_vm->_sentence[i][0] == '*' && !_vm->_animMgr->isActionActive())
|
||||
_vm->startCharacterAction(hBOH, 0, 0, 0);
|
||||
else
|
||||
characterTalk(_vm->_sentence[i]);
|
||||
}
|
||||
|
||||
void TextManager::characterSayInAction(uint16 ss) {
|
||||
const char *s = _vm->_sentence[ss];
|
||||
|
||||
if (s[0] == '*')
|
||||
return;
|
||||
_curSentenceId = ss;
|
||||
|
||||
_vm->_flagSomeoneSpeaks = true;
|
||||
_vm->_flagCharacterSpeak = true;
|
||||
_vm->_flagSkipTalk = false;
|
||||
|
||||
_superString = s;
|
||||
_subStringStart = 0;
|
||||
_curSubString = 0;
|
||||
formattingSuperString();
|
||||
|
||||
characterContinueTalk();
|
||||
}
|
||||
|
||||
void TextManager::addText(Common::Point pos, const char *text, uint16 textCol) {
|
||||
StackText t;
|
||||
t._x = pos.x;
|
||||
t._y = pos.y;
|
||||
t._textColor = textCol;
|
||||
t._clear = false;
|
||||
t._text = text;
|
||||
|
||||
_textStack.push_back(t);
|
||||
}
|
||||
|
||||
void TextManager::clearLastText() {
|
||||
if (!_textStack.empty()) {
|
||||
if (!_textStack.back()._clear)
|
||||
// The last entry is a string to be shown, remove it
|
||||
_textStack.pop_back();
|
||||
} else {
|
||||
StackText t;
|
||||
t._clear = true;
|
||||
_textStack.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::drawText(StackText *text) {
|
||||
_curString._rect.left = text->_x;
|
||||
_curString._rect.top = text->_y;
|
||||
_curString._rect.setWidth(_vm->textLength(text->_text));
|
||||
int16 w = _curString._rect.width();
|
||||
|
||||
if (text->_y == MAXY - CARHEI && w > 600)
|
||||
w = w * 3 / 5;
|
||||
else if (text->_y != MAXY - CARHEI && w > 960)
|
||||
w = w * 2 / 5;
|
||||
else if (text->_y != MAXY - CARHEI && w > 320)
|
||||
w = w * 3 / 5;
|
||||
|
||||
_curString._rect.setWidth(w);
|
||||
|
||||
_curString._text = text->_text;
|
||||
uint16 height = _curString.calcHeight(_vm);
|
||||
_curString._subtitleRect = Common::Rect(_curString._rect.width(), height);
|
||||
_curString._rect.setHeight(height);
|
||||
_curString._textColor = text->_textColor;
|
||||
|
||||
if (_curString._rect.top <= height)
|
||||
_curString._rect.top += height;
|
||||
else
|
||||
_curString._rect.top -= height;
|
||||
|
||||
if (_curString._rect.top <= VIDEOTOP)
|
||||
_curString._rect.top = VIDEOTOP + 1;
|
||||
|
||||
_vm->_textStatus |= TEXT_DRAW;
|
||||
}
|
||||
|
||||
void TextManager::clearText() {
|
||||
if (_oldString._text.empty() && !_curString._text.empty()) {
|
||||
_oldString.set(&_curString);
|
||||
_curString._text.clear();
|
||||
|
||||
_vm->_textStatus |= TEXT_DEL;
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::drawTexts() {
|
||||
for (Common::List<StackText>::iterator it = _textStack.begin(); it != _textStack.end(); ++it) {
|
||||
if (it->_clear)
|
||||
clearText();
|
||||
else
|
||||
drawText(&*it);
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::redrawString() {
|
||||
if (!_vm->_flagDialogActive && !_vm->_flagDialogMenuActive && !_vm->_flagSomeoneSpeaks && !_vm->_flagScriptActive && _vm->_graphicsMgr->isCursorVisible()) {
|
||||
if (_vm->isInventoryArea(_vm->_mousePos))
|
||||
_vm->showIconName();
|
||||
else {
|
||||
_vm->checkMask(_vm->_mousePos);
|
||||
showObjName(_vm->_curObj, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextManager::clearTextStack() {
|
||||
_textStack.clear();
|
||||
}
|
||||
|
||||
void TextManager::drawCurString() {
|
||||
_curString.draw(_vm);
|
||||
_vm->_graphicsMgr->addDirtyRect(_curString._rect, false);
|
||||
}
|
||||
|
||||
Common::Rect TextManager::getOldTextRect() const {
|
||||
return _oldString._rect;
|
||||
}
|
||||
|
||||
void TextManager::clearOldText() {
|
||||
_oldString._text.clear();
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
96
engines/trecision/text.h
Normal file
96
engines/trecision/text.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_TEXT_H
|
||||
#define TRECISION_TEXT_H
|
||||
|
||||
#define MAXLENSUBSTRING 128
|
||||
#define MAXSUBSTRING 16
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
struct StackText {
|
||||
uint16 _x = 0;
|
||||
uint16 _y = 0;
|
||||
uint16 _textColor = 0;
|
||||
Common::String _text;
|
||||
bool _clear = false;
|
||||
};
|
||||
|
||||
class TextManager {
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
uint32 _someoneSpeakTime;
|
||||
bool _subStringAgain;
|
||||
uint32 _talkTime;
|
||||
char _subString[MAXSUBSTRING][MAXLENSUBSTRING];
|
||||
uint16 _subStringUsed;
|
||||
Common::String _superString;
|
||||
uint16 _subStringStart;
|
||||
uint16 _curSentenceId;
|
||||
uint16 _curSubString;
|
||||
Common::Path _lastFilename;
|
||||
uint16 _talkingPersonId;
|
||||
SDText _curString;
|
||||
SDText _oldString;
|
||||
|
||||
Common::List<StackText> _textStack;
|
||||
|
||||
Common::Point positionString(uint16 x, uint16 y, const char *string, bool characterFl);
|
||||
void formattingSuperString();
|
||||
void formattingOneString();
|
||||
void characterTalk(Common::String s);
|
||||
void characterContinueTalk();
|
||||
void characterMute();
|
||||
void someoneContinueTalk();
|
||||
void someoneMute();
|
||||
|
||||
public:
|
||||
TextManager(TrecisionEngine *vm);
|
||||
~TextManager();
|
||||
|
||||
void doString();
|
||||
void showObjName(uint16 obj, bool show);
|
||||
void someoneSay(uint16 sentence, uint16 person);
|
||||
void characterSay(uint16 i);
|
||||
void characterSayInAction(uint16 ss);
|
||||
|
||||
void addText(Common::Point pos, const char *text, uint16 textCol);
|
||||
void clearLastText();
|
||||
void drawText(StackText *text);
|
||||
void clearText();
|
||||
void drawTexts();
|
||||
void redrawString();
|
||||
void clearTextStack();
|
||||
Common::Rect getOldTextRect() const;
|
||||
void clearOldText();
|
||||
|
||||
void drawCurString();
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
|
||||
485
engines/trecision/trecision.cpp
Normal file
485
engines/trecision/trecision.cpp
Normal file
@@ -0,0 +1,485 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/error.h"
|
||||
#include "common/system.h"
|
||||
#include "common/events.h"
|
||||
#include "common/archive.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/str.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "trecision/animmanager.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/console.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/pathfinding3d.h"
|
||||
#include "trecision/renderer3d.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
TrecisionEngine::TrecisionEngine(OSystem *syst, const ADGameDescription *desc) : Engine(syst), _gameDescription(desc) {
|
||||
_gameId = !strcmp(_gameDescription->gameId, "nl") ? GID_NightLong : GID_ArkOfTime;
|
||||
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "AUTORUN");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "DATA");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "FMV");
|
||||
// Amiga version loads data files from directories
|
||||
if (isAmiga()) {
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "NLDATA.CD0");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "NLSPEECH.CD0");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "NLANIM.CDX");
|
||||
}
|
||||
|
||||
_curRoom = 0;
|
||||
_oldRoom = 0;
|
||||
|
||||
_curInventory = 0;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
_curScriptFrame[i] = 0;
|
||||
|
||||
_iconBase = 0;
|
||||
_inventoryRefreshStartIcon = 0;
|
||||
_curObj = 1;
|
||||
_inventoryRefreshStartLine = INVENTORY_HIDE;
|
||||
_lightIcon = 0xFF;
|
||||
_inventoryStatus = INV_OFF;
|
||||
_inventoryCounter = INVENTORY_HIDE;
|
||||
_flagInventoryLocked = false;
|
||||
_inventorySpeedIndex = 0;
|
||||
_inventoryScrollTime = 0;
|
||||
|
||||
_fastWalk = false;
|
||||
|
||||
// Use With
|
||||
_useWith[0] = _useWith[1] = 0;
|
||||
_useWithInv[0] = _useWithInv[1] = false;
|
||||
|
||||
// Messages
|
||||
for (int i = 0; i < MAXOBJNAME; ++i)
|
||||
_objName[i] = nullptr;
|
||||
|
||||
for (int i = 0; i < MAXSENTENCE; ++i)
|
||||
_sentence[i] = nullptr;
|
||||
|
||||
for (int i = 0; i < MAXSYSTEXT; ++i)
|
||||
_sysText[i] = nullptr;
|
||||
|
||||
_curMessage = nullptr;
|
||||
_animMgr = nullptr;
|
||||
_dialogMgr = nullptr;
|
||||
_graphicsMgr = nullptr;
|
||||
_logicMgr = nullptr;
|
||||
_soundMgr = nullptr;
|
||||
_renderer = nullptr;
|
||||
_pathFind = nullptr;
|
||||
_textMgr = nullptr;
|
||||
_animTypeMgr = nullptr;
|
||||
_nextRefresh = 0;
|
||||
|
||||
_curKey = Common::KEYCODE_INVALID;
|
||||
_curAction = kActionNone;
|
||||
_curAscii = 0;
|
||||
_mousePos = Common::Point(0, 0);
|
||||
_mouseMoved = _mouseLeftBtn = _mouseRightBtn = false;
|
||||
_keybInput = false;
|
||||
|
||||
_gamePaused = false;
|
||||
|
||||
_textPtr = nullptr;
|
||||
_lastInv = 0;
|
||||
_lastObj = 0;
|
||||
|
||||
_curStack = 0;
|
||||
|
||||
_flagScriptActive = false;
|
||||
|
||||
_actor = nullptr;
|
||||
|
||||
_flagDialogActive = false;
|
||||
_flagDialogMenuActive = false;
|
||||
_flagSkipTalk = false;
|
||||
_flagPaintCharacter = false;
|
||||
_flagShowCharacter = true;
|
||||
_flagSomeoneSpeaks = false;
|
||||
_flagCharacterSpeak = false;
|
||||
_flagUseWithStarted = false;
|
||||
_flagNoPaintScreen = false;
|
||||
_flagWaitRegen = false;
|
||||
|
||||
for (int i = 0; i < MAXOBJINROOM; ++i) {
|
||||
_objectGraphics[i].buf = nullptr;
|
||||
_objectGraphics[i].mask = nullptr;
|
||||
}
|
||||
|
||||
_curTime = 0;
|
||||
_characterSpeakTime = 0;
|
||||
_pauseStartTime = 0;
|
||||
_textStatus = TEXT_OFF;
|
||||
|
||||
_cx = _cy = 0;
|
||||
|
||||
_textArea = nullptr;
|
||||
Message msg = { MC_IDLE, 0, MP_DEFAULT, 0, 0, 0, 0 };
|
||||
_snake52 = msg;
|
||||
for (int i = 0; i < 50; ++i)
|
||||
_scriptFrame[i].clear();
|
||||
|
||||
_scheduler = nullptr;
|
||||
}
|
||||
|
||||
TrecisionEngine::~TrecisionEngine() {
|
||||
if (_animMgr)
|
||||
_animMgr->stopAllSmkAnims();
|
||||
|
||||
_dataFile.close();
|
||||
_thumbnail.free();
|
||||
|
||||
delete _animMgr;
|
||||
delete _dialogMgr;
|
||||
delete _graphicsMgr;
|
||||
delete _logicMgr;
|
||||
delete _soundMgr;
|
||||
delete _renderer;
|
||||
delete _pathFind;
|
||||
delete _textMgr;
|
||||
delete _scheduler;
|
||||
delete _animTypeMgr;
|
||||
|
||||
delete _actor;
|
||||
delete[] _textArea;
|
||||
|
||||
for (int i = 0; i < MAXOBJINROOM; ++i) {
|
||||
delete[] _objectGraphics[i].buf;
|
||||
delete[] _objectGraphics[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
Common::Error TrecisionEngine::run() {
|
||||
syncSoundSettings();
|
||||
|
||||
if (!_dataFile.open(this, "nldata.cd0"))
|
||||
error("Error opening nldata.cd0");
|
||||
|
||||
_graphicsMgr = new GraphicsManager(this);
|
||||
if (!_graphicsMgr->init())
|
||||
return Common::kUnsupportedColorMode;
|
||||
_animMgr = new AnimManager(this);
|
||||
_dialogMgr = new DialogManager(this);
|
||||
_logicMgr = new LogicManager(this);
|
||||
_soundMgr = new SoundManager(this);
|
||||
_pathFind = new PathFinding3D(this);
|
||||
_renderer = new Renderer3D(this);
|
||||
_textMgr = new TextManager(this);
|
||||
_scheduler = new Scheduler(this);
|
||||
_animTypeMgr = new AnimTypeManager(this);
|
||||
_actor = new Actor(this);
|
||||
|
||||
setDebugger(new Console(this));
|
||||
|
||||
initMain();
|
||||
|
||||
while (!shouldQuit()) {
|
||||
eventLoop();
|
||||
if (!_flagNoPaintScreen)
|
||||
processTime();
|
||||
|
||||
processMouse();
|
||||
_scheduler->process();
|
||||
|
||||
_animTypeMgr->handler(kAnimTypeBackground);
|
||||
|
||||
processCurrentMessage();
|
||||
|
||||
if (_flagScriptActive)
|
||||
evalScript();
|
||||
}
|
||||
|
||||
if (isDemo())
|
||||
_graphicsMgr->showDemoPic();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void TrecisionEngine::eventLoop() {
|
||||
Common::Event event;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
Common::Keymapper *keymapper = _eventMan->getKeymapper();
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_mouseMoved = true;
|
||||
_mousePos = event.mouse;
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_mouseLeftBtn = true;
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_mouseRightBtn = true;
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
|
||||
_curAction = event.customType;
|
||||
switch (event.customType) {
|
||||
case kActionFastWalk:
|
||||
_fastWalk ^= true;
|
||||
break;
|
||||
case kActionPause:
|
||||
if (!_gamePaused && !_keybInput) {
|
||||
_curKey = Common::KEYCODE_INVALID;
|
||||
_curAction = kActionNone;
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
|
||||
_gamePaused = true;
|
||||
waitKey();
|
||||
}
|
||||
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
_gamePaused = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
case Common::EVENT_KEYUP:
|
||||
_curKey = event.kbd.keycode;
|
||||
_curAscii = event.kbd.ascii;
|
||||
break;
|
||||
|
||||
case Common::EVENT_JOYBUTTON_UP:
|
||||
_joyButtonUp = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_system->delayMillis(10);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
void TrecisionEngine::initMain() {
|
||||
for (int c = 0; c < MAXOBJ; c++)
|
||||
_obj[c]._position = -1;
|
||||
|
||||
_curRoom = kRoomIntro;
|
||||
_scheduler->init();
|
||||
|
||||
loadAll();
|
||||
processTime();
|
||||
|
||||
// Check if a saved game is to be loaded from the launcher
|
||||
if (ConfMan.hasKey("save_slot"))
|
||||
loadGameState(ConfMan.getInt("save_slot"));
|
||||
else
|
||||
changeRoom(_curRoom);
|
||||
}
|
||||
|
||||
void TrecisionEngine::checkSystem() {
|
||||
eventLoop();
|
||||
}
|
||||
|
||||
void TrecisionEngine::startCharacterAction(uint16 action, uint16 newRoom, uint8 newPos, uint16 textId) {
|
||||
_scheduler->initCharacterQueue();
|
||||
|
||||
_flagInventoryLocked = false;
|
||||
if (action > hLAST) {
|
||||
_animMgr->startSmkAnim(action);
|
||||
_animTypeMgr->init(action, _curObj);
|
||||
_graphicsMgr->hideCursor();
|
||||
_flagShowCharacter = false;
|
||||
_scheduler->doEvent(MC_CHARACTER, ME_CHARACTERCONTINUEACTION, MP_DEFAULT, action, newRoom, newPos, _curObj);
|
||||
} else {
|
||||
if ((action == aWALKIN) || (action == aWALKOUT))
|
||||
_curObj = 0;
|
||||
_graphicsMgr->hideCursor();
|
||||
_actor->actorDoAction(action);
|
||||
_pathFind->nextStep();
|
||||
}
|
||||
|
||||
if (textId)
|
||||
_textMgr->characterSayInAction(textId);
|
||||
else
|
||||
_textMgr->clearLastText();
|
||||
}
|
||||
|
||||
bool TrecisionEngine::canPlayerInteract() {
|
||||
return (!_flagSomeoneSpeaks &&
|
||||
!_flagScriptActive &&
|
||||
!_flagDialogActive &&
|
||||
!_flagDialogMenuActive &&
|
||||
(_actor->_curAction < hWALKIN) &&
|
||||
!_flagUseWithStarted &&
|
||||
_flagShowCharacter &&
|
||||
!_animMgr->isActionActive());
|
||||
}
|
||||
|
||||
void TrecisionEngine::setObjectVisible(uint16 objectId, bool visible) {
|
||||
_obj[objectId].setModeStatus(visible);
|
||||
refreshObject(objectId);
|
||||
}
|
||||
|
||||
void TrecisionEngine::refreshObject(uint16 objectId) {
|
||||
for (int i = 0; i < MAXOBJINROOM; ++i) {
|
||||
if (!_room[_curRoom]._object[i])
|
||||
return; // reached the end of the list, object not found
|
||||
|
||||
if (objectId == _room[_curRoom]._object[i]) {
|
||||
break; // object found in room objects, continue
|
||||
}
|
||||
}
|
||||
|
||||
if (_obj[objectId].isModeMask() || _obj[objectId].isModeFull()) {
|
||||
SSortTable entry;
|
||||
entry._objectId = objectId;
|
||||
entry._remove = !isObjectVisible(objectId);
|
||||
_sortTable.push_back(entry);
|
||||
|
||||
// Remove previous instances
|
||||
for (Common::List<SSortTable>::iterator it = _sortTableReplay.begin(); it != _sortTableReplay.end(); ++it) {
|
||||
if (it->_objectId == objectId) {
|
||||
_sortTableReplay.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_sortTableReplay.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
bool TrecisionEngine::isObjectVisible(uint16 objectId) {
|
||||
return _obj[objectId].isModeStatus();
|
||||
}
|
||||
|
||||
void TrecisionEngine::setObjectAnim(uint16 objectId, uint16 animId) {
|
||||
_obj[objectId]._anim = animId;
|
||||
}
|
||||
|
||||
void TrecisionEngine::reEvent() {
|
||||
_scheduler->doEvent(_curMessage->_class, _curMessage->_event, _curMessage->_priority, _curMessage->_u16Param1, _curMessage->_u16Param2, _curMessage->_u8Param, _curMessage->_u32Param);
|
||||
}
|
||||
|
||||
Common::SeekableReadStreamEndian *TrecisionEngine::getLocStream() {
|
||||
Common::Path filename(_room[_curRoom]._baseName);
|
||||
|
||||
if (isAmiga()) {
|
||||
filename.appendInPlace(".bm");
|
||||
return readEndian(_dataFile.createReadStreamForMember(filename));
|
||||
} else {
|
||||
filename.appendInPlace(".cr");
|
||||
return readEndian(_dataFile.createReadStreamForCompressedMember(filename));
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::readLoc() {
|
||||
_soundMgr->stopAllExceptMusic();
|
||||
|
||||
_graphicsMgr->clearScreenBufferTop();
|
||||
_sortTable.clear();
|
||||
_sortTableReplay.clear();
|
||||
|
||||
Common::SeekableReadStreamEndian *picFile = getLocStream();
|
||||
_graphicsMgr->loadBackground(picFile);
|
||||
readObj(picFile);
|
||||
|
||||
_soundMgr->stopAll();
|
||||
|
||||
if (_room[_curRoom]._sounds[0] != 0)
|
||||
_soundMgr->loadRoomSounds();
|
||||
|
||||
Common::Path fname(Common::String::format("%s.3d", _room[_curRoom]._baseName));
|
||||
read3D(fname);
|
||||
|
||||
if (_room[_curRoom]._bkgAnim) {
|
||||
_animMgr->startSmkAnim(_room[_curRoom]._bkgAnim);
|
||||
} else
|
||||
_animMgr->smkStop(kSmackerBackground);
|
||||
|
||||
_animTypeMgr->init(_room[_curRoom]._bkgAnim, 0);
|
||||
}
|
||||
|
||||
void TrecisionEngine::redrawRoom() {
|
||||
const uint16 curDialog = _dialogMgr->getCurDialog();
|
||||
const uint16 curChoice = _dialogMgr->getCurChoice();
|
||||
const uint16 bgAnim = _room[_curRoom]._bkgAnim;
|
||||
static const ElevatorAction elevatorActions[6] = {
|
||||
{dASCENSORE12, 3, a129PARLACOMPUTERESCENDE, kRoom13},
|
||||
{dASCENSORE12, 4, a129PARLACOMPUTERESCENDE, kRoom16},
|
||||
{dASCENSORE13, 17, a139CHIUDONOPORTESU, kRoom12},
|
||||
{dASCENSORE13, 18, a1316CHIUDONOPORTEGIU, kRoom16},
|
||||
{dASCENSORE16, 32, a1616SALECONASCENSORE, kRoom12},
|
||||
{dASCENSORE16, 33, a1616SALECONASCENSORE, kRoom13},
|
||||
};
|
||||
|
||||
_flagShowCharacter = _dialogMgr->showCharacterAfterDialog();
|
||||
_flagPaintCharacter = true;
|
||||
_textStatus = TEXT_OFF;
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
if (curDialog == elevatorActions[i].dialog && curChoice == elevatorActions[i].choice) {
|
||||
startCharacterAction(elevatorActions[i].action, elevatorActions[i].newRoom, 20, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Common::SeekableReadStreamEndian *picFile = getLocStream();
|
||||
_graphicsMgr->loadBackground(picFile);
|
||||
_sortTable.clear();
|
||||
_sortTable = _sortTableReplay;
|
||||
|
||||
if (bgAnim)
|
||||
_animMgr->startSmkAnim(bgAnim);
|
||||
|
||||
if (_curRoom == kRoom4P && curDialog == dF4PI)
|
||||
_animMgr->smkGoto(kSmackerBackground, 21);
|
||||
|
||||
_graphicsMgr->paintScreen(true);
|
||||
}
|
||||
|
||||
void TrecisionEngine::tendIn() {
|
||||
_textStatus = TEXT_OFF;
|
||||
|
||||
_flagPaintCharacter = true;
|
||||
_graphicsMgr->paintScreen(true);
|
||||
|
||||
_graphicsMgr->copyToScreen(0, 0, MAXX, MAXY);
|
||||
}
|
||||
|
||||
} // End of namespace Trecision
|
||||
382
engines/trecision/trecision.h
Normal file
382
engines/trecision/trecision.h
Normal file
@@ -0,0 +1,382 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_TRECISION_H
|
||||
#define TRECISION_TRECISION_H
|
||||
|
||||
#include "common/str-array.h"
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/str.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/stream.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/fastfile.h"
|
||||
#include "trecision/struct.h"
|
||||
#include "trecision/scheduler.h"
|
||||
|
||||
namespace Trecision {
|
||||
class AnimManager;
|
||||
class DialogManager;
|
||||
class GraphicsManager;
|
||||
class LogicManager;
|
||||
class SoundManager;
|
||||
class Actor;
|
||||
class Renderer3D;
|
||||
class PathFinding3D;
|
||||
class TextManager;
|
||||
class Scheduler;
|
||||
class AnimTypeManager;
|
||||
|
||||
// Saved game versions
|
||||
// Version history:
|
||||
// - 102: Original PC full version
|
||||
// - 103: Original PC demo version
|
||||
// - 110: First ScummVM version
|
||||
#define SAVE_VERSION_ORIGINAL_MIN 102
|
||||
#define SAVE_VERSION_ORIGINAL_MAX 109
|
||||
#define SAVE_VERSION_SCUMMVM_MIN 110
|
||||
#define SAVE_VERSION_SCUMMVM 110
|
||||
|
||||
#define MAXROOMS 100 // Game rooms
|
||||
#define MAXOBJ 1400 // Game objects
|
||||
#define MAXINVENTORY 150 // Inventory Items
|
||||
#define MAXSAVEFILE 12
|
||||
|
||||
enum TrecisionGameId {
|
||||
GID_ArkOfTime = 0,
|
||||
GID_NightLong = 1
|
||||
};
|
||||
|
||||
enum TrecisionMessageIds {
|
||||
kMessageSavePosition = 9,
|
||||
kMessageEmptySpot = 10,
|
||||
kMessageLoadPosition = 11,
|
||||
kMessageConfirmExit = 13,
|
||||
kMessageDemoOver = 17,
|
||||
kMessageError = 19,
|
||||
kMessageUse = 23,
|
||||
kMessageWith = 24,
|
||||
kMessageGoto = 25,
|
||||
kMessageGoto2 = 26
|
||||
};
|
||||
|
||||
enum TRECISIONAction {
|
||||
kActionNone,
|
||||
kActionSkipVideo,
|
||||
kActionFastWalk,
|
||||
kActionPause,
|
||||
kActionQuit,
|
||||
kActionSystemMenu,
|
||||
kActionSave,
|
||||
kActionLoad,
|
||||
kActionYes
|
||||
};
|
||||
|
||||
typedef Common::List<Common::Rect>::iterator DirtyRectsIterator;
|
||||
|
||||
struct ElevatorAction {
|
||||
uint16 dialog;
|
||||
uint16 choice;
|
||||
uint16 action;
|
||||
uint16 newRoom;
|
||||
};
|
||||
|
||||
struct ObjectGraphics {
|
||||
uint16 *buf;
|
||||
uint8 *mask;
|
||||
};
|
||||
|
||||
class TrecisionEngine : public Engine {
|
||||
void initMain();
|
||||
void loadAll();
|
||||
void loadSaveSlots(Common::StringArray &saveNames);
|
||||
void eventLoop();
|
||||
|
||||
// Inventory
|
||||
void refreshInventory(uint8 startIcon, uint8 startLine);
|
||||
void moveInventoryLeft();
|
||||
void moveInventoryRight();
|
||||
void syncInventory(Common::Serializer &ser);
|
||||
void rollInventory(uint8 status);
|
||||
void doScrollInventory(Common::Point pos);
|
||||
void endUseWith();
|
||||
|
||||
// Script
|
||||
void endScript();
|
||||
void evalScript();
|
||||
void processScriptFrame();
|
||||
void doAction();
|
||||
void doMouse();
|
||||
void processMouseMovement();
|
||||
void doCharacter();
|
||||
void doIdle();
|
||||
void doRoomIn(uint16 curObj);
|
||||
void doRoomOut(uint16 curObj);
|
||||
void doMouseExamine(uint16 curObj);
|
||||
void doMouseOperate(uint16 curObj);
|
||||
void doMouseTake(uint16 curObj);
|
||||
void doUseWith();
|
||||
void doScreenUseWithScreen();
|
||||
void doInvExamine();
|
||||
void doInvOperate();
|
||||
void doScript();
|
||||
void processCurrentMessage();
|
||||
|
||||
// Utils
|
||||
char *getNextSentence();
|
||||
uint16 getKey();
|
||||
uint16 getAction();
|
||||
void processTime();
|
||||
void processMouse();
|
||||
static bool isBetween(int a, int x, int b);
|
||||
|
||||
// Others
|
||||
bool canPlayerInteract();
|
||||
|
||||
// Objects
|
||||
void readObj(Common::SeekableReadStream *stream);
|
||||
void readObject(Common::SeekableReadStream *stream, uint16 objIndex, uint16 objectId);
|
||||
|
||||
TrecisionGameId _gameId;
|
||||
|
||||
char *_textArea;
|
||||
uint16 _curScriptFrame[10];
|
||||
char *_textPtr;
|
||||
|
||||
uint16 _curAscii;
|
||||
bool _keybInput;
|
||||
bool _gamePaused;
|
||||
uint8 _curStack;
|
||||
|
||||
Common::List<SSortTable> _sortTableReplay;
|
||||
|
||||
public:
|
||||
TrecisionEngine(OSystem *syst, const ADGameDescription *desc);
|
||||
~TrecisionEngine() override;
|
||||
|
||||
// ScummVM
|
||||
Common::Error run() override;
|
||||
TrecisionGameId getGameId() const { return _gameId; }
|
||||
bool isDemo() const { return _gameDescription->flags & ADGF_DEMO; }
|
||||
bool isAmiga() const { return _gameDescription->platform == Common::kPlatformAmiga; }
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override { return canPlayerInteract() && _curRoom != kRoomIntro; }
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override { return canPlayerInteract() && _curRoom != kRoomIntro; }
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
bool syncGameStream(Common::Serializer &ser);
|
||||
|
||||
// Data files
|
||||
Common::SeekableReadStreamEndian *readEndian(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::YES);
|
||||
void read3D(const Common::Path &c);
|
||||
|
||||
// Inventory
|
||||
void setInventoryStart(uint8 startIcon, uint8 startLine);
|
||||
void showInventoryName(uint16 obj, bool showhide);
|
||||
void showIconName();
|
||||
uint8 whatIcon(Common::Point pos);
|
||||
int8 iconPos(uint8 icon);
|
||||
void removeIcon(uint8 icon);
|
||||
void addIcon(uint8 icon);
|
||||
void replaceIcon(uint8 oldIcon, uint8 newIcon);
|
||||
void openInventory();
|
||||
void closeInventory();
|
||||
void closeInventoryImmediately();
|
||||
void useItem();
|
||||
void examineItem();
|
||||
void clearUseWith();
|
||||
|
||||
// Script
|
||||
void playScript(uint16 id);
|
||||
bool quitPrompt();
|
||||
void demoOver();
|
||||
void startCharacterAction(uint16 action, uint16 newRoom, uint8 newPos, uint16 sent);
|
||||
void doMouseTalk(uint16 curObj);
|
||||
void changeRoom(uint16 room, uint16 action = 0, byte position = 0);
|
||||
|
||||
// Utils
|
||||
uint16 textLength(const Common::String &text, uint16 begin = 0, uint16 end = 0);
|
||||
Common::KeyCode waitKey();
|
||||
void waitDelay(uint32 val);
|
||||
void freeKey();
|
||||
uint32 readTime();
|
||||
bool checkMask(Common::Point pos);
|
||||
float sinCosAngle(float sinus, float cosinus);
|
||||
float dist2D(float x1, float y1, float x2, float y2);
|
||||
float dist3D(float x1, float y1, float z1, float x2, float y2, float z2);
|
||||
static bool isGameArea(Common::Point pos);
|
||||
static bool isInventoryArea(Common::Point pos);
|
||||
static bool isIconArea(Common::Point pos);
|
||||
int getRoomObjectIndex(uint16 objectId);
|
||||
int floatComp(float f1, float f2) const;
|
||||
|
||||
// Others
|
||||
void checkSystem();
|
||||
bool dataSave();
|
||||
bool dataLoad();
|
||||
void reEvent();
|
||||
|
||||
// Objects
|
||||
void setObjectVisible(uint16 objectId, bool visible);
|
||||
void refreshObject(uint16 objectId);
|
||||
bool isObjectVisible(uint16 objectId);
|
||||
void setObjectAnim(uint16 objectId, uint16 animId);
|
||||
void redrawRoom();
|
||||
void readLoc();
|
||||
Common::SeekableReadStreamEndian *getLocStream();
|
||||
void tendIn();
|
||||
void readExtraObj2C();
|
||||
void readPositionerSnapshots();
|
||||
|
||||
// Data files
|
||||
byte *readData(const Common::Path &fileName);
|
||||
|
||||
const ADGameDescription *_gameDescription;
|
||||
|
||||
Graphics::Surface _thumbnail;
|
||||
bool _controlPanelSave = false;
|
||||
|
||||
uint16 _curRoom;
|
||||
uint16 _oldRoom;
|
||||
SRoom _room[MAXROOMS];
|
||||
|
||||
Common::List<SSortTable> _sortTable;
|
||||
|
||||
uint16 _curObj;
|
||||
SObject _obj[MAXOBJ];
|
||||
|
||||
SDText _drawText;
|
||||
|
||||
// Inventory
|
||||
uint16 _curInventory;
|
||||
SInvObject _inventoryObj[MAXINVENTORY];
|
||||
Common::Array<byte> _inventory;
|
||||
Common::Array<byte> _cyberInventory;
|
||||
uint8 _iconBase;
|
||||
uint8 _inventoryStatus;
|
||||
uint8 _lightIcon;
|
||||
uint8 _inventoryRefreshStartIcon;
|
||||
uint8 _inventoryRefreshStartLine;
|
||||
int16 _inventoryCounter;
|
||||
bool _flagInventoryLocked;
|
||||
uint8 _inventorySpeedIndex;
|
||||
uint32 _inventoryScrollTime;
|
||||
uint16 _lastInv;
|
||||
uint16 _lastObj;
|
||||
|
||||
bool _fastWalk;
|
||||
|
||||
// Use With
|
||||
uint16 _useWith[2];
|
||||
bool _useWithInv[2];
|
||||
|
||||
// Messages
|
||||
const char *_objName[MAXOBJNAME];
|
||||
const char *_sentence[MAXSENTENCE];
|
||||
const char *_sysText[MAXSYSTEXT];
|
||||
|
||||
// Message system
|
||||
Message *_curMessage;
|
||||
// Snake management
|
||||
Message _snake52;
|
||||
|
||||
uint32 _nextRefresh;
|
||||
|
||||
Common::Point _mousePos;
|
||||
bool _mouseMoved, _mouseLeftBtn, _mouseRightBtn;
|
||||
Common::KeyCode _curKey;
|
||||
Common::CustomEventType _curAction;
|
||||
bool _joyButtonUp = false;
|
||||
|
||||
bool _flagScriptActive;
|
||||
SScriptFrame _scriptFrame[MAXSCRIPTFRAME];
|
||||
uint16 _scriptFirstFrame[MAXSCRIPT];
|
||||
|
||||
AnimManager *_animMgr;
|
||||
GraphicsManager *_graphicsMgr;
|
||||
DialogManager *_dialogMgr;
|
||||
LogicManager *_logicMgr;
|
||||
SoundManager *_soundMgr;
|
||||
Renderer3D *_renderer;
|
||||
PathFinding3D *_pathFind;
|
||||
TextManager *_textMgr;
|
||||
Scheduler *_scheduler;
|
||||
AnimTypeManager *_animTypeMgr;
|
||||
|
||||
Actor *_actor;
|
||||
|
||||
// Data files
|
||||
FastFile _dataFile; // nldata.cd0
|
||||
|
||||
bool _flagDialogActive;
|
||||
bool _flagDialogMenuActive;
|
||||
bool _flagSkipTalk;
|
||||
bool _flagPaintCharacter;
|
||||
bool _flagShowCharacter;
|
||||
bool _flagSomeoneSpeaks;
|
||||
bool _flagCharacterSpeak;
|
||||
bool _flagUseWithStarted;
|
||||
bool _flagNoPaintScreen;
|
||||
bool _flagWaitRegen;
|
||||
|
||||
ObjectGraphics _objectGraphics[MAXOBJINROOM];
|
||||
|
||||
uint32 _curTime;
|
||||
uint32 _characterSpeakTime;
|
||||
|
||||
int _cx, _cy;
|
||||
|
||||
uint8 _textStatus;
|
||||
|
||||
uint32 _pauseStartTime;
|
||||
};
|
||||
|
||||
uint8 static const defActionLen[hLAST + 1] = {
|
||||
/* STAND */ 1,
|
||||
/* PARTE */ 1,
|
||||
/* WALK */ 10,
|
||||
/* END */ 1,
|
||||
/* STOP0 */ 3,
|
||||
/* STOP1 */ 4,
|
||||
/* STOP2 */ 3,
|
||||
/* STOP3 */ 2,
|
||||
/* STOP4 */ 3,
|
||||
/* STOP5 */ 4,
|
||||
/* STOP6 */ 3,
|
||||
/* STOP7 */ 3,
|
||||
/* STOP8 */ 2,
|
||||
/* STOP9 */ 3,
|
||||
/* WALKI */ 12,
|
||||
/* BOH */ 9,
|
||||
/* UGG */ 41,
|
||||
/* UTT */ 35,
|
||||
/* WALKO */ 12,
|
||||
/* LAST */ 15
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
|
||||
#endif
|
||||
412
engines/trecision/utils.cpp
Normal file
412
engines/trecision/utils.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "trecision/scheduler.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
char *TrecisionEngine::getNextSentence() {
|
||||
while (*_textPtr) {
|
||||
*_textPtr = ~(*_textPtr);
|
||||
++_textPtr;
|
||||
}
|
||||
|
||||
++_textPtr;
|
||||
return _textPtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute string length from character begin to end
|
||||
*/
|
||||
uint16 TrecisionEngine::textLength(const Common::String &text, uint16 begin, uint16 end) {
|
||||
if (text.empty())
|
||||
return 0;
|
||||
|
||||
if (end == 0)
|
||||
end = text.size();
|
||||
|
||||
uint16 retVal = 0;
|
||||
for (uint16 c = begin; c < end; ++c)
|
||||
retVal += _graphicsMgr->getCharWidth(text[c]);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint16 TrecisionEngine::getKey() {
|
||||
Common::KeyCode key = _curKey;
|
||||
uint16 ascii = _curAscii;
|
||||
_curKey = Common::KEYCODE_INVALID;
|
||||
_curAscii = 0;
|
||||
|
||||
switch (key) {
|
||||
case Common::KEYCODE_SPACE:
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
case Common::KEYCODE_RETURN:
|
||||
case Common::KEYCODE_CLEAR:
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
return key;
|
||||
case Common::KEYCODE_F1:
|
||||
case Common::KEYCODE_F2:
|
||||
case Common::KEYCODE_F3:
|
||||
case Common::KEYCODE_F4:
|
||||
case Common::KEYCODE_F5:
|
||||
case Common::KEYCODE_F6:
|
||||
return 0x3B + key - Common::KEYCODE_F1;
|
||||
default:
|
||||
if (ascii)
|
||||
return ascii;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 TrecisionEngine::getAction() {
|
||||
Common::CustomEventType customType = _curAction;
|
||||
_curAction = kActionNone;
|
||||
|
||||
return customType;
|
||||
}
|
||||
|
||||
Common::KeyCode TrecisionEngine::waitKey() {
|
||||
_graphicsMgr->hideCursor();
|
||||
while (_curKey == Common::KEYCODE_INVALID && _curAction == kActionNone && !_joyButtonUp)
|
||||
checkSystem();
|
||||
_graphicsMgr->showCursor();
|
||||
|
||||
Common::KeyCode t = _curKey;
|
||||
_curKey = Common::KEYCODE_INVALID;
|
||||
_joyButtonUp = false;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void TrecisionEngine::waitDelay(uint32 val) {
|
||||
uint32 sv = readTime();
|
||||
|
||||
while (sv + val > readTime())
|
||||
checkSystem();
|
||||
}
|
||||
|
||||
void TrecisionEngine::freeKey() {
|
||||
_curKey = Common::KEYCODE_INVALID;
|
||||
}
|
||||
|
||||
uint32 TrecisionEngine::readTime() {
|
||||
return (g_system->getMillis() * 3) / 50;
|
||||
}
|
||||
|
||||
bool TrecisionEngine::checkMask(Common::Point pos) {
|
||||
for (int8 i = MAXOBJINROOM - 1; i >= 0; --i) {
|
||||
uint16 checkedObj = _room[_curRoom]._object[i];
|
||||
Common::Rect lim = _obj[checkedObj]._area;
|
||||
lim.translate(0, TOP);
|
||||
// Trecision includes the bottom and right coordinates
|
||||
++lim.right;
|
||||
++lim.bottom;
|
||||
|
||||
if (checkedObj && isObjectVisible(checkedObj)) {
|
||||
if (lim.contains(pos)) {
|
||||
|
||||
if (_obj[checkedObj].isModeFull() || _obj[checkedObj].isModeLim()) {
|
||||
_curObj = checkedObj;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_obj[checkedObj].isModeMask()) {
|
||||
uint8 *mask = _objectGraphics[i].mask;
|
||||
int16 d = _obj[checkedObj]._rect.left;
|
||||
uint16 max = _obj[checkedObj]._rect.bottom;
|
||||
|
||||
for (uint16 j = _obj[checkedObj]._rect.top; j < max; ++j) {
|
||||
bool insideObj = false;
|
||||
int16 e = 0;
|
||||
while (e < _obj[checkedObj]._rect.width()) {
|
||||
if (!insideObj) { // not inside an object
|
||||
if (j + TOP == pos.y) {
|
||||
if ((pos.x >= d + e) && (pos.x < d + e + *mask)) {
|
||||
_curObj = 0;
|
||||
}
|
||||
}
|
||||
|
||||
e += *mask;
|
||||
++mask;
|
||||
insideObj = true;
|
||||
} else { // inside an object
|
||||
if (j + TOP == pos.y) {
|
||||
if ((pos.x >= d + e) && (pos.x < d + e + *mask)) {
|
||||
_curObj = checkedObj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
e += *mask;
|
||||
++mask;
|
||||
insideObj = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_curObj = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
float TrecisionEngine::sinCosAngle(float sinus, float cosinus) {
|
||||
if (floatComp(sinus, 0.0f) == 0 && floatComp(cosinus, 0.0f) == 0)
|
||||
return 0;
|
||||
|
||||
float t = (float)sqrt((double)(sinus * sinus) + (double)(cosinus * cosinus));
|
||||
cosinus /= t;
|
||||
sinus /= t;
|
||||
|
||||
// 1e3 & 2e4 quad
|
||||
if (floatComp(sinus, 0.0f) >= 0)
|
||||
// 1 & 2 quad
|
||||
return (float)acos(cosinus);
|
||||
|
||||
// 3 quad
|
||||
return (M_PI * 2) - (float)acos(cosinus);
|
||||
}
|
||||
|
||||
void TrecisionEngine::processTime() {
|
||||
_curTime = readTime();
|
||||
|
||||
if (_curTime >= _nextRefresh) {
|
||||
if (_inventoryStatus == INV_PAINT || _inventoryStatus == INV_DEPAINT)
|
||||
rollInventory(_inventoryStatus);
|
||||
|
||||
if (_inventoryStatus != INV_OFF) {
|
||||
refreshInventory(_inventoryRefreshStartIcon, _inventoryRefreshStartLine);
|
||||
}
|
||||
|
||||
_textMgr->drawTexts();
|
||||
_graphicsMgr->paintScreen(false);
|
||||
_textMgr->clearTextStack();
|
||||
|
||||
uint32 paintTime = readTime();
|
||||
if (paintTime - _curTime >= 5)
|
||||
_nextRefresh = paintTime + 1;
|
||||
else
|
||||
_nextRefresh = _curTime + 5;
|
||||
}
|
||||
}
|
||||
|
||||
void TrecisionEngine::processMouse() {
|
||||
int16 mx = _mousePos.x;
|
||||
int16 my = _mousePos.y;
|
||||
|
||||
checkSystem();
|
||||
|
||||
if (!_graphicsMgr->isCursorVisible())
|
||||
return;
|
||||
|
||||
if (_mouseLeftBtn) {
|
||||
_scheduler->leftClick(mx, my);
|
||||
_mouseLeftBtn = false;
|
||||
} else if (_mouseRightBtn) {
|
||||
_scheduler->rightClick(mx, my);
|
||||
_mouseRightBtn = false;
|
||||
} else {
|
||||
if (!_flagScriptActive && _mouseMoved) {
|
||||
processMouseMovement();
|
||||
_mouseMoved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake distance between two 2D points
|
||||
*/
|
||||
float TrecisionEngine::dist2D(float x1, float y1, float x2, float y2) {
|
||||
const double dx = x1 - x2;
|
||||
const double dy = y1 - y2;
|
||||
|
||||
return (float)sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Distance between two 3D points
|
||||
*/
|
||||
float TrecisionEngine::dist3D(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
const double dx = x1 - x2;
|
||||
const double dy = y1 - y2;
|
||||
const double dz = z1 - z2;
|
||||
return (float)sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
bool TrecisionEngine::isBetween(int a, int x, int b) {
|
||||
return x >= a && x <= b;
|
||||
}
|
||||
|
||||
bool TrecisionEngine::isGameArea(Common::Point pos) {
|
||||
return isBetween(TOP, pos.y, TOP + AREA - 1);
|
||||
}
|
||||
|
||||
bool TrecisionEngine::isInventoryArea(Common::Point pos) {
|
||||
return pos.y >= TOP + AREA;
|
||||
}
|
||||
|
||||
bool TrecisionEngine::isIconArea(Common::Point pos) {
|
||||
return pos.y >= TOP + AREA && pos.y < MAXY && pos.x >= ICONMARGSX && pos.x <= MAXX - ICONMARGDX;
|
||||
}
|
||||
|
||||
int TrecisionEngine::getRoomObjectIndex(uint16 objectId) {
|
||||
for (uint16 index = 0; index < MAXOBJINROOM; ++index) {
|
||||
const uint16 curObjId = _room[_curRoom]._object[index];
|
||||
if (curObjId == 0)
|
||||
return -1;
|
||||
if (curObjId == objectId)
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* SDText
|
||||
************************************************/
|
||||
void SDText::set(SDText *org) {
|
||||
set(org->_rect, org->_subtitleRect, org->_textColor, org->_text);
|
||||
}
|
||||
|
||||
void SDText::set(Common::Rect rect, Common::Rect subtitleRect, uint16 textCol, const Common::String &text) {
|
||||
_rect = rect;
|
||||
_subtitleRect = subtitleRect;
|
||||
_textColor = textCol;
|
||||
_text = text;
|
||||
|
||||
// Clean output buffer
|
||||
for (int i = 0; i < MAXDTEXTLINES; ++i)
|
||||
_drawTextLines[i] = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* calcHeight - Computes and returns the dy of the current text
|
||||
*/
|
||||
uint16 SDText::calcHeight(TrecisionEngine *vm) {
|
||||
if (_text.empty())
|
||||
return 0;
|
||||
|
||||
uint8 curLine = 0;
|
||||
if (vm->textLength(_text) <= _rect.width()) {
|
||||
_drawTextLines[curLine] = _text;
|
||||
return CARHEI;
|
||||
}
|
||||
|
||||
uint16 index = 0;
|
||||
uint16 tmpDy = 0;
|
||||
uint16 lastSpace = 0;
|
||||
uint16 curInit = 0;
|
||||
|
||||
while (index < _text.size()) {
|
||||
++index;
|
||||
if (index < _text.size() && _text[index] == ' ') {
|
||||
if (vm->textLength(_text, curInit, index) <= _rect.width())
|
||||
lastSpace = index;
|
||||
else if (vm->textLength(_text, curInit, lastSpace) <= _rect.width()) {
|
||||
_drawTextLines[curLine] = _text.substr(curInit, lastSpace - curInit);
|
||||
|
||||
++curLine;
|
||||
curInit = lastSpace + 1;
|
||||
|
||||
tmpDy += CARHEI;
|
||||
index = curInit;
|
||||
} else
|
||||
return 0;
|
||||
} else if (index == _text.size()) {
|
||||
if (vm->textLength(_text, curInit, index) <= _rect.width()) {
|
||||
_drawTextLines[curLine] = _text.substr(curInit, index - curInit);
|
||||
|
||||
tmpDy += CARHEI;
|
||||
return tmpDy;
|
||||
}
|
||||
|
||||
if (vm->textLength(_text, curInit, lastSpace) <= _rect.width()) {
|
||||
_drawTextLines[curLine] = _text.substr(curInit, lastSpace - curInit);
|
||||
|
||||
++curLine;
|
||||
curInit = lastSpace + 1;
|
||||
tmpDy += CARHEI;
|
||||
|
||||
if (curInit < _text.size()) {
|
||||
_drawTextLines[curLine] = _text.substr(curInit);
|
||||
tmpDy += CARHEI;
|
||||
}
|
||||
return tmpDy;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SDText::draw(TrecisionEngine *vm, bool hideLastChar, Graphics::Surface *externalSurface) {
|
||||
uint16 textColor = vm->_graphicsMgr->convertToScreenFormat(_textColor);
|
||||
|
||||
if (_text.empty())
|
||||
return;
|
||||
|
||||
const uint16 curDy = calcHeight(vm);
|
||||
|
||||
for (uint16 line = 0; line < curDy / CARHEI; ++line) {
|
||||
Common::String curText = _drawTextLines[line];
|
||||
uint16 inc = (_rect.width() - vm->textLength(curText)) / 2;
|
||||
|
||||
if (curText.size() >= MAXCHARS) {
|
||||
curText = vm->_sysText[kMessageError];
|
||||
}
|
||||
|
||||
for (uint index = 0; index < curText.size(); ++index) {
|
||||
const byte curChar = curText[index];
|
||||
|
||||
if (index == curText.size() - 1 && hideLastChar)
|
||||
textColor = vm->_graphicsMgr->convertToScreenFormat(0);
|
||||
|
||||
vm->_graphicsMgr->drawChar(curChar, textColor, line, _rect, _subtitleRect, inc, externalSurface);
|
||||
|
||||
inc += vm->_graphicsMgr->getCharWidth(curChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int TrecisionEngine::floatComp(float f1, float f2) const {
|
||||
static const float epsilon = 1.0e-05f;
|
||||
|
||||
const float diff = f1 - f2;
|
||||
if (ABS(diff) < epsilon)
|
||||
// equality
|
||||
return 0;
|
||||
|
||||
if (f1 > f2)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
} // End of namespace Trecision
|
||||
214
engines/trecision/video.cpp
Normal file
214
engines/trecision/video.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/animtype.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/sound.h"
|
||||
#include "trecision/text.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/video.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
void NightlongVideoDecoder::muteTrack(uint track, bool mute) {
|
||||
// FIXME: In the Amiga version, there's only one audio track
|
||||
// for each video, so we silently ignore calls to mute the
|
||||
// second audio track. Is this correct?
|
||||
|
||||
Track *t = getTrack(track);
|
||||
if (t && t->getTrackType() == Track::kTrackTypeAudio) {
|
||||
((AudioTrack *)t)->setMute(mute);
|
||||
}
|
||||
}
|
||||
|
||||
void NightlongVideoDecoder::setMute(bool mute) {
|
||||
for (TrackList::iterator it = getTrackListBegin(); it != getTrackListEnd(); ++it) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
|
||||
((AudioTrack *)*it)->setMute(mute);
|
||||
}
|
||||
}
|
||||
|
||||
bool NightlongSmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
if (!SmackerDecoder::loadStream(stream))
|
||||
return false;
|
||||
|
||||
// Map audio tracks to sound types
|
||||
for (uint32 i = 0; i < 8; i++) {
|
||||
Track *t = getTrack(i);
|
||||
if (t && t->getTrackType() == Track::kTrackTypeAudio) {
|
||||
AudioTrack *audio = (AudioTrack *)t;
|
||||
audio->setMute(false);
|
||||
audio->setSoundType(i == 7 ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NightlongSmackerDecoder::forceSeekToFrame(uint frame) {
|
||||
const uint seekFrame = MAX<uint>(frame - 10, 0);
|
||||
|
||||
if (!isVideoLoaded())
|
||||
return true;
|
||||
|
||||
if (seekFrame >= getFrameCount())
|
||||
return false;
|
||||
|
||||
if (!rewind())
|
||||
return false;
|
||||
|
||||
stopAudio();
|
||||
SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0);
|
||||
uint32 startPos = _fileStream->pos();
|
||||
uint32 offset = 0;
|
||||
for (uint32 i = 0; i < seekFrame; i++) {
|
||||
videoTrack->increaseCurFrame();
|
||||
// Frames with palette data contain palette entries which use
|
||||
// the previous palette as their base. Therefore, we need to
|
||||
// parse all palette entries up to the requested frame
|
||||
if (_frameTypes[videoTrack->getCurFrame()] & 1) {
|
||||
_fileStream->seek(startPos + offset, SEEK_SET);
|
||||
videoTrack->unpackPalette(_fileStream);
|
||||
}
|
||||
offset += _frameSizes[i] & ~3;
|
||||
}
|
||||
|
||||
if (!_fileStream->seek(startPos + offset, SEEK_SET))
|
||||
return false;
|
||||
|
||||
while (getCurFrame() < (int)frame) {
|
||||
decodeNextFrame();
|
||||
}
|
||||
|
||||
_lastTimeChange = videoTrack->getFrameTime(frame);
|
||||
_startTime = g_system->getMillis() - (_lastTimeChange.msecs() / getRate()).toInt();
|
||||
startAudio();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Background videos only loop smoothly like this,
|
||||
// possibly an audio track bug?
|
||||
bool NightlongSmackerDecoder::endOfFrames() const {
|
||||
return getCurFrame() >= (int32)getFrameCount() - 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NightlongAmigaDecoder::AmigaVideoTrack::AmigaVideoTrack(Common::SeekableReadStream *stream) {
|
||||
memset(_palette, 0, sizeof(_palette));
|
||||
|
||||
_curFrame = 0;
|
||||
_frameCount = 10; // TODO: Anything > 1 to keep playing till the audio is done
|
||||
|
||||
// TODO: some videos have more than 256 entries
|
||||
/*uint16 palEntries = stream->readUint16LE();
|
||||
stream->skip(2); // unknown
|
||||
for (uint16 i = 0; i < palEntries; i++) {
|
||||
_palette[i * 3] = stream->readByte();
|
||||
_palette[i * 3 + 1] = stream->readByte();
|
||||
_palette[i * 3 + 2] = stream->readByte();
|
||||
stream->skip(1); // unused alpha channel
|
||||
}*/
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
uint16 NightlongAmigaDecoder::AmigaVideoTrack::getWidth() const {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 NightlongAmigaDecoder::AmigaVideoTrack::getHeight() const {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat NightlongAmigaDecoder::AmigaVideoTrack::getPixelFormat() const {
|
||||
// TODO
|
||||
return g_system->getScreenFormat();
|
||||
}
|
||||
|
||||
uint32 NightlongAmigaDecoder::AmigaVideoTrack::getNextFrameStartTime() const {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Graphics::Surface *NightlongAmigaDecoder::AmigaVideoTrack::decodeNextFrame() {
|
||||
// TODO
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NightlongAmigaDecoder::AmigaAudioTrack::AmigaAudioTrack(Common::SeekableReadStream *stream) :
|
||||
AudioTrack(Audio::Mixer::SoundType::kSFXSoundType) {
|
||||
_audioStream = Audio::makeRawStream(stream, 11025, 0, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
void NightlongAmigaDecoder::readNextPacket() {
|
||||
AmigaVideoTrack *videoTrack = (AmigaVideoTrack *)getTrack(0);
|
||||
|
||||
if (videoTrack->endOfTrack())
|
||||
return;
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
bool NightlongAmigaDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
addTrack(new AmigaVideoTrack(stream));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NightlongAmigaDecoder::addAudioSideTrack(const Common::Path &path) {
|
||||
Common::File *file = new Common::File();
|
||||
if (!file->open(path)) {
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
addTrack(new AmigaAudioTrack(file));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NightlongAmigaDecoder::forceSeekToFrame(uint frame) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
const Common::Rect *NightlongAmigaDecoder::getNextDirtyRect() {
|
||||
// TODO
|
||||
return &_lastDirtyRect;
|
||||
}
|
||||
|
||||
bool NightlongAmigaDecoder::endOfFrames() const {
|
||||
//return getCurFrame() >= (int32)getFrameCount() - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Trecision
|
||||
93
engines/trecision/video.h
Normal file
93
engines/trecision/video.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_VIDEO_H
|
||||
#define TRECISION_VIDEO_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/serializer.h"
|
||||
#include "video/smk_decoder.h"
|
||||
|
||||
#include "trecision/struct.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class TrecisionEngine;
|
||||
|
||||
class NightlongVideoDecoder : public Video::SmackerDecoder {
|
||||
public:
|
||||
void muteTrack(uint track, bool mute);
|
||||
void setMute(bool mute);
|
||||
virtual bool forceSeekToFrame(uint frame) { return false; }
|
||||
virtual bool endOfFrames() const { return false; }
|
||||
};
|
||||
|
||||
class NightlongSmackerDecoder : public NightlongVideoDecoder {
|
||||
public:
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
bool forceSeekToFrame(uint frame) override;
|
||||
bool endOfFrames() const override;
|
||||
};
|
||||
|
||||
class NightlongAmigaDecoder : public NightlongVideoDecoder {
|
||||
public:
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
bool addAudioSideTrack(const Common::Path &path);
|
||||
bool forceSeekToFrame(uint frame) override;
|
||||
bool endOfFrames() const override;
|
||||
const Common::Rect *getNextDirtyRect() override;
|
||||
|
||||
private:
|
||||
Common::Rect _lastDirtyRect;
|
||||
|
||||
void readNextPacket() override;
|
||||
|
||||
class AmigaVideoTrack : public VideoTrack {
|
||||
public:
|
||||
AmigaVideoTrack(Common::SeekableReadStream *stream);
|
||||
|
||||
private:
|
||||
byte _palette[3 * 256];
|
||||
int _curFrame;
|
||||
uint32 _frameCount;
|
||||
|
||||
uint16 getWidth() const override;
|
||||
uint16 getHeight() const override;
|
||||
Graphics::PixelFormat getPixelFormat() const override;
|
||||
int getCurFrame() const override { return _curFrame; }
|
||||
uint32 getNextFrameStartTime() const override;
|
||||
const Graphics::Surface *decodeNextFrame() override;
|
||||
int getFrameCount() const override { return _frameCount; }
|
||||
const byte *getPalette() const override { return _palette; }
|
||||
bool hasDirtyPalette() const override { return true; }
|
||||
};
|
||||
|
||||
class AmigaAudioTrack : public AudioTrack {
|
||||
public:
|
||||
AmigaAudioTrack(Common::SeekableReadStream *stream);
|
||||
private:
|
||||
Audio::AudioStream *getAudioStream() const override { return _audioStream; }
|
||||
Audio::AudioStream *_audioStream;
|
||||
};
|
||||
};
|
||||
|
||||
} // End of namespace Trecision
|
||||
#endif
|
||||
Reference in New Issue
Block a user